/
SwappableModifierRecipe.java
159 lines (137 loc) · 7.1 KB
/
SwappableModifierRecipe.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
package slimeknights.tconstruct.library.recipe.modifiers.adding;
import com.google.common.collect.ImmutableList;
import com.google.gson.JsonObject;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.Ingredient;
import net.minecraft.world.item.crafting.RecipeSerializer;
import slimeknights.mantle.recipe.ingredient.SizedIngredient;
import slimeknights.mantle.util.JsonHelper;
import slimeknights.tconstruct.TConstruct;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.ModifierId;
import slimeknights.tconstruct.library.recipe.RecipeResult;
import slimeknights.tconstruct.library.recipe.modifiers.ModifierMatch;
import slimeknights.tconstruct.library.recipe.tinkerstation.ITinkerStationContainer;
import slimeknights.tconstruct.library.tools.SlotType.SlotCount;
import slimeknights.tconstruct.library.tools.nbt.ModDataNBT;
import slimeknights.tconstruct.library.tools.nbt.ToolStack;
import slimeknights.tconstruct.tools.TinkerModifiers;
import javax.annotation.Nullable;
import java.util.List;
import java.util.stream.Collectors;
/**
* Standard recipe to add a modifier
*/
public class SwappableModifierRecipe extends ModifierRecipe {
private static final String ALREADY_PRESENT = TConstruct.makeTranslationKey("recipe", "swappable.already_present");
/** Value of the modifier being swapped, distinguishing this recipe from others for the same modifier */
private final String value;
public SwappableModifierRecipe(ResourceLocation id, List<SizedIngredient> inputs, Ingredient toolRequirement, int maxToolSize, ModifierMatch requirements, String requirementsError, ModifierId result, String value, @Nullable SlotCount slots, boolean allowCrystal) {
super(id, inputs, toolRequirement, maxToolSize, requirements, requirementsError, new ModifierEntry(result, 1), 1, slots, allowCrystal);
this.value = value;
}
/** @deprecated use {@link SwappableModifierRecipe(ResourceLocation, List, Ingredient, int, ModifierMatch, String, ModifierId, String, SlotCount, boolean)} */
@Deprecated
public SwappableModifierRecipe(ResourceLocation id, List<SizedIngredient> inputs, Ingredient toolRequirement, int maxToolSize, ModifierMatch requirements, String requirementsError, ModifierId result, String value, @Nullable SlotCount slots) {
this(id, inputs, toolRequirement, maxToolSize, requirements, requirementsError, result, value, slots, false);
}
@Override
public RecipeResult<ItemStack> getValidatedResult(ITinkerStationContainer inv) {
ItemStack tinkerable = inv.getTinkerableStack();
ToolStack tool = ToolStack.from(tinkerable);
// if the tool has the modifier already, can skip most requirements
ModifierId modifier = result.getId();
Component commonError;
boolean needsModifier;
if (tool.getUpgrades().getLevel(modifier) == 0) {
needsModifier = true;
commonError = validatePrerequisites(tool);
} else {
needsModifier = false;
commonError = validateRequirements(tool);
}
if (commonError != null) {
return RecipeResult.failure(commonError);
}
// do not allow adding the modifier if this variant is already present
// TODO: include variant in name? need variant to be translatable for that probably
if (tool.getPersistentData().getString(modifier).equals(value)) {
return RecipeResult.failure(ALREADY_PRESENT, result.getModifier().getDisplayName());
}
// consume slots
tool = tool.copy();
ModDataNBT persistentData = tool.getPersistentData();
if (needsModifier) {
SlotCount slots = getSlots();
if (slots != null) {
persistentData.addSlots(slots.type(), -slots.count());
}
}
// set the new value to the modifier
persistentData.putString(modifier, value);
// add modifier if needed
if (needsModifier) {
tool.addModifier(result.getId(), 1);
} else {
tool.rebuildStats();
}
// ensure no modifier problems
Component toolValidation = tool.tryValidate();
if (toolValidation != null) {
return RecipeResult.failure(toolValidation);
}
return RecipeResult.success(tool.createStack(Math.min(tinkerable.getCount(), shrinkToolSlotBy())));
}
@Override
public RecipeSerializer<?> getSerializer() {
return TinkerModifiers.swappableModifierSerializer.get();
}
/* Display */
@Override
public List<ItemStack> getToolWithModifier() {
if (toolWithModifier == null) {
ResourceLocation id = result.getId();
toolWithModifier = getToolInputs().stream().map(stack -> IDisplayModifierRecipe.withModifiers(stack, requirements, result, data -> data.putString(id, value))).collect(Collectors.toList());
toolWithModifier = getToolInputs().stream().map(stack -> IDisplayModifierRecipe.withModifiers(stack, requirements, result, data -> data.putString(id, value))).collect(Collectors.toList());
}
return toolWithModifier;
}
public static class Serializer extends AbstractModifierRecipe.Serializer<SwappableModifierRecipe> {
@Override
protected ModifierEntry readResult(JsonObject json) {
JsonObject result = GsonHelper.getAsJsonObject(json, "result");
return new ModifierEntry(ModifierId.PARSER.getAndDeserialize(result, "name"), 1);
}
@Override
public SwappableModifierRecipe fromJson(ResourceLocation id, JsonObject json, Ingredient toolRequirement, int maxToolSize, ModifierMatch requirements,
String requirementsError, ModifierEntry result, int maxLevel, @Nullable SlotCount slots, boolean allowCrystal) {
List<SizedIngredient> ingredients = JsonHelper.parseList(json, "inputs", SizedIngredient::deserialize);
String value = GsonHelper.getAsString(GsonHelper.getAsJsonObject(json, "result"), "value");
return new SwappableModifierRecipe(id, ingredients, toolRequirement, maxToolSize, requirements, requirementsError, result.getId(), value, slots, allowCrystal);
}
@Override
public SwappableModifierRecipe fromNetwork(ResourceLocation id, FriendlyByteBuf buffer, Ingredient toolRequirement, int maxToolSize, ModifierMatch requirements,
String requirementsError, ModifierEntry result, int maxLevel, @Nullable SlotCount slots, boolean allowCrystal) {
int size = buffer.readVarInt();
ImmutableList.Builder<SizedIngredient> builder = ImmutableList.builder();
for (int i = 0; i < size; i++) {
builder.add(SizedIngredient.read(buffer));
}
String value = buffer.readUtf();
return new SwappableModifierRecipe(id, builder.build(), toolRequirement, maxToolSize, requirements, requirementsError, result.getId(), value, slots, allowCrystal);
}
@Override
public void toNetworkSafe(FriendlyByteBuf buffer, SwappableModifierRecipe recipe) {
super.toNetworkSafe(buffer, recipe);
buffer.writeVarInt(recipe.inputs.size());
for (SizedIngredient ingredient : recipe.inputs) {
ingredient.write(buffer);
}
buffer.writeUtf(recipe.value);
}
}
}