Astral Sorcery

Astral Sorcery

63M Downloads

Make Scorching Heat drop Smelting Experience (Code Included!)

KdotJPG opened this issue ยท 1 comments

commented

Playing on a server with many mods including this one, I found that scorching heat causes me to lose out on the experience I would otherwise gain from smelting. This discourages me from using the enchantment, even with Fortune, because a large part of why I mine the ores is for the smelting XP. I decided to look into how this can be added. It's a bit more involved than I anticipated, but it works.

Due to the project license not lending itself well to Pull Requests, I'll include the main, non-derivative parts of the code here. These code snippets are provided under CC0.

First there needs to be a way to get the experience from the smelting recipe, and not just the result item. I created an ItemStackExperiencePair class and created the according public static Optional<ItemStackExperiencePair> findSmeltingResultWithExperience(...) methods as modified clones of the findSmeltingResult methods in RecipeHelper.java.

To return the experience, I replaced the return recipe map with the following. Since all three recipe types should be of type AbstractCookingRecipe, you can probably restructure to avoid this typecast and check. Requires import net.minecraft.item.crafting.AbstractCookingRecipe;.

        recipe -> {
        	ItemStack stack = [[place original map function contents here]]
        	float experience = 0;
        	if (recipe instanceof AbstractCookingRecipe) {
        		experience = ((AbstractCookingRecipe)recipe).getExperience();
        	}
        	return new ItemStackExperiencePair(stack, experience);
        }

EDIT: Probably also a good idea to change the recipe order to put campfire last, because campfire cooking doesn't return any XP. Won't affect anything I can think of, just the logical order.

Here's ItemStackExperiencePair. You can look for ways of doing this that don't require a one-off plain object class, but this is what worked for me. I put it in the package hellfirepvp.astralsorcery.common.util

// package declaration here
import net.minecraft.item.ItemStack;

public class ItemStackExperiencePair {
	
	private ItemStack stack;
	private float experience;
	
	public ItemStackExperiencePair(ItemStack stack, float experience) {
		this.stack = stack;
		this.experience = experience;
	}
	
	public ItemStack getItemStack() {
		return stack;
	}
	
	public void setItemStack(ItemStack stack) {
		this.stack = stack;
	}
	
	public float getExperience() {
		return experience;
	}
	
	public void setExperience(float experience) {
		this.experience = experience;
	}
	
}

To actually provide the XP, I modified LootModifierScorchingHeat.java to use the new findSmeltingResultWithExperience method, and then spawn in the appropriate experience orbs. Using the new method mostly requires changing things like result to result.getItemStack().

The tricky part: Smelting recipes yield fractional experience amounts, while the orbs only come in integer sizes. Furnaces handle this by accumulating the fractional XP and only dispensing integer amounts at a time (well, it keeps track of the accumulated recipes but to my understanding it's producing the same result by doing that). I don't know enough about NBT tags so I made it dispense a randomized amount with the appropriate odds. Minecraft actually provides more XP to ores which can be mined directly than when their silk-touched blocks are smelted, so various design choices could be made here.

Here's the code I added. I place this just inside the no-silk-touch conditional on line 67.

                                float smeltingExperience = result.getExperience();
                                if (smeltingExperience > 0) {
                                	int intSmeltingExperience = (int)smeltingExperience;
                                	float residualSmeltingExperience = smeltingExperience - intSmeltingExperience;
                                	
                                	if (residualSmeltingExperience > 0 && residualSmeltingExperience > context.getRandom().nextFloat()) {
                                		intSmeltingExperience += 1;
                                	}
                                	
                                	if (intSmeltingExperience >= 1) {
                                		Vector3d blockCenter = context.get(LootParameters.field_237457_g_);
                                		if (blockCenter != null) {
                                			ServerWorld world = context.getWorld();
                                			world.addEntity(new ExperienceOrbEntity(world, blockCenter.getX(), blockCenter.getY(), blockCenter.getZ(), intSmeltingExperience));
                                		}
                                	}
                                }

Import statements I needed to add:

import net.minecraft.entity.item.ExperienceOrbEntity;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.server.ServerWorld;

It looks like there are also a handful other features in the mod that use the findSmeltingResult methods, which I haven't gotten to yet in gameplay. Maybe they're well-suited to this too.

commented

Alternatively, I don't mind creating the Pull Request. Just give the the word! The snippets presented here will remain CC0, and the derivative work consisting of their integration into the Astral Sorcery codebase will fall under the appropriate license.

From LICENSE,

Any and all users are permitted to use the source for educational purposes, or to create derivative works
for private use only. GitHub forks and direct downloads are considered derivative works.
Unless given explicit written permission - electronic writing is acceptable - no user may redistribute this
source code nor any derivative works. These pre-approved works must prominently contain this copyright notice.
In all other cases, derivative mods using any or all of the source code or assets are EXPRESSLY FORBIDDEN.