-
Notifications
You must be signed in to change notification settings - Fork 755
/
MeltingModifier.java
169 lines (155 loc) · 6.13 KB
/
MeltingModifier.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
package slimeknights.tconstruct.tools.modifiers.ability.tool;
import lombok.Getter;
import lombok.Setter;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.loot.LootContext;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.FluidType;
import slimeknights.tconstruct.common.config.Config;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.ModifierHooks;
import slimeknights.tconstruct.library.modifiers.hook.combat.MeleeHitModifierHook;
import slimeknights.tconstruct.library.modifiers.impl.NoLevelsModifier;
import slimeknights.tconstruct.library.modifiers.modules.fluid.TankModule;
import slimeknights.tconstruct.library.module.ModuleHookMap.Builder;
import slimeknights.tconstruct.library.recipe.TinkerRecipeTypes;
import slimeknights.tconstruct.library.recipe.entitymelting.EntityMeltingRecipe;
import slimeknights.tconstruct.library.recipe.entitymelting.EntityMeltingRecipeCache;
import slimeknights.tconstruct.library.recipe.melting.IMeltingContainer;
import slimeknights.tconstruct.library.recipe.melting.IMeltingRecipe;
import slimeknights.tconstruct.library.tools.context.ToolAttackContext;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import slimeknights.tconstruct.smeltery.block.entity.module.EntityMeltingModule;
import java.util.Iterator;
import java.util.List;
public class MeltingModifier extends NoLevelsModifier implements MeleeHitModifierHook {
/** Max temperature allowed for melting items */
private static final int MAX_TEMPERATURE = 1000;
/** Last melting recipe used */
private static IMeltingRecipe lastRecipe = null;
/** Inventory used for finding recipes */
private static final MeltingContainer inventory = new MeltingContainer();
private TankModule tank;
@Override
protected void registerHooks(Builder hookBuilder) {
super.registerHooks(hookBuilder);
tank = new TankModule(FluidType.BUCKET_VOLUME, true);
hookBuilder.addModule(tank);
hookBuilder.addHook(this, ModifierHooks.MELEE_HIT);
}
/**
* Gets the fluid for the given item
* @param stack Item
* @param world World instance
* @return Fluid
*/
private static FluidStack meltItem(ItemStack stack, Level world) {
inventory.setStack(stack);
// first, update inventory
IMeltingRecipe recipe = lastRecipe;
if (recipe == null || !recipe.matches(inventory, world)) {
recipe = world.getRecipeManager().getRecipeFor(TinkerRecipeTypes.MELTING.get(), inventory, world).orElse(null);
if (recipe == null) {
inventory.setStack(ItemStack.EMPTY);
return FluidStack.EMPTY;
}
lastRecipe = recipe;
}
// get the result if the temperature is right
FluidStack result = FluidStack.EMPTY;
if (recipe.getTemperature(inventory) <= MAX_TEMPERATURE) {
result = recipe.getOutput(inventory);
}
inventory.setStack(ItemStack.EMPTY);
return result;
}
@Override
public void processLoot(IToolStackView tool, int level, List<ItemStack> generatedLoot, LootContext context) {
// if tank is full, nothing to do
FluidStack current = tank.getFluid(tool);
int capacity = tank.getCapacity(tool);
if (current.getAmount() >= capacity) {
return;
}
// try melting each item dropped
Level world = context.getLevel();
Iterator<ItemStack> iterator = generatedLoot.iterator();
boolean isDirty = false;
while (iterator.hasNext()) {
ItemStack stack = iterator.next();
FluidStack output = meltItem(stack, world);
// fluid must match tank fluid
if (!output.isEmpty() && (current.isEmpty() || current.isFluidEqual(output))) {
// determine how many copies we can melt
int maxCopies = Math.min((capacity - current.getAmount()) / output.getAmount(), stack.getCount());
// if it fits in the tank, remove
if (maxCopies > 0) {
// fill fluid
int amount = output.getAmount() * maxCopies;
if (current.isEmpty()) {
output.setAmount(amount);
current = output;
} else {
current.setAmount(amount);
}
isDirty = true;
// decrease items dropped
stack.shrink(maxCopies);
if (stack.isEmpty()) {
iterator.remove();
}
}
}
}
if (isDirty) {
tank.setFluid(tool, current);
}
}
@Override
public void afterMeleeHit(IToolStackView tool, ModifierEntry modifier, ToolAttackContext context, float damageDealt) {
// must have done damage, and must be fully charged
if (damageDealt > 0 && context.isFullyCharged()) {
// first, find the proper recipe
LivingEntity target = context.getLivingTarget();
if (target != null) {
EntityMeltingRecipe recipe = EntityMeltingRecipeCache.findRecipe(context.getAttacker().level.getRecipeManager(), target.getType());
FluidStack output;
int damagePerOutput;
if (recipe != null) {
output = recipe.getOutput(target);
damagePerOutput = recipe.getDamage();
} else {
output = EntityMeltingModule.getDefaultFluid();
damagePerOutput = 2;
}
// recipe amount determines how much we get per hit, up to twice the recipe damage
int fluidAmount;
if (damageDealt < damagePerOutput * 2) {
fluidAmount = (int)(output.getAmount() * damageDealt / damagePerOutput);
} else {
fluidAmount = output.getAmount() * 2;
}
// fluid must match that which is stored in the tank
FluidStack fluid = tank.getFluid(tool);
if (fluid.isEmpty()) {
output.setAmount(fluidAmount);
fluid = output;
} else {
fluid.grow(fluidAmount);
}
tank.setFluid(tool, fluid);
}
}
}
/** Helper for finding recipes in melting */
private static class MeltingContainer implements IMeltingContainer {
@Getter @Setter
private ItemStack stack;
@Override
public IOreRate getOreRate() {
return Config.COMMON.melterOreRate;
}
}
}