/
EnchantmentModule.java
220 lines (191 loc) · 10.3 KB
/
EnchantmentModule.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
package slimeknights.tconstruct.library.modifiers.modules.build;
import com.google.common.collect.ImmutableSet;
import lombok.AccessLevel;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.enchantment.Enchantment;
import net.minecraft.world.level.block.state.BlockState;
import slimeknights.mantle.data.loadable.Loadables;
import slimeknights.mantle.data.loadable.field.LoadableField;
import slimeknights.mantle.data.loadable.record.RecordLoadable;
import slimeknights.mantle.data.predicate.IJsonPredicate;
import slimeknights.mantle.data.predicate.block.BlockPredicate;
import slimeknights.mantle.data.predicate.entity.LivingEntityPredicate;
import slimeknights.mantle.data.registry.GenericLoaderRegistry.IGenericLoader;
import slimeknights.tconstruct.library.json.TinkerLoadables;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.ModifierHook;
import slimeknights.tconstruct.library.modifiers.TinkerHooks;
import slimeknights.tconstruct.library.modifiers.hook.behavior.EnchantmentModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.mining.BlockHarvestModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.mining.HarvestEnchantmentsModifierHook;
import slimeknights.tconstruct.library.modifiers.modules.IntLevelModule;
import slimeknights.tconstruct.library.modifiers.modules.ModifierModule;
import slimeknights.tconstruct.library.modifiers.modules.ModifierModuleCondition;
import slimeknights.tconstruct.library.modifiers.modules.ModifierModuleCondition.ConditionalModifierModule;
import slimeknights.tconstruct.library.tools.context.EquipmentContext;
import slimeknights.tconstruct.library.tools.context.ToolHarvestContext;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import java.util.List;
import java.util.Map;
import java.util.Set;
/** Modules that add enchantments to a tool. */
public interface EnchantmentModule extends ModifierModule, IntLevelModule, ConditionalModifierModule {
/* Common fields */
LoadableField<Enchantment,EnchantmentModule> ENCHANTMENT = Loadables.ENCHANTMENT.requiredField("name", EnchantmentModule::enchantment);
LoadableField<IJsonPredicate<BlockState>,EnchantmentModule> BLOCK = BlockPredicate.LOADER.defaultField("block", EnchantmentModule::block);
LoadableField<IJsonPredicate<LivingEntity>,EnchantmentModule> HOLDER = LivingEntityPredicate.LOADER.defaultField("holder", EnchantmentModule::holder);
/** Gets the enchantment for this module */
Enchantment enchantment();
/** Gets the block predicate, will be {@link BlockPredicate#ANY} for {@link Constant} */
default IJsonPredicate<BlockState> block() {
return BlockPredicate.ANY;
}
/** Gets the holder predicate, will be {@link LivingEntityPredicate#ANY} for {@link Constant} */
default IJsonPredicate<LivingEntity> holder() {
return LivingEntityPredicate.ANY;
}
/**
* Creates a builder for a constant enchantment
*/
static Builder builder(Enchantment enchantment) {
return new Builder(enchantment);
}
/**
* Shared builder instance
*/
@SuppressWarnings("unused") // API
@Setter
@Accessors(fluent = true)
@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
class Builder extends ModifierModuleCondition.Builder<Builder> {
private final Enchantment enchantment;
private int level = 1;
private IJsonPredicate<BlockState> block = BlockPredicate.ANY;
private IJsonPredicate<LivingEntity> holder = LivingEntityPredicate.ANY;
/** Builds a module for a constant enchantment */
public Constant constant() {
if (block != BlockPredicate.ANY || holder != LivingEntityPredicate.ANY) {
throw new IllegalStateException("Cannot build a constant enchantment module with block or holder conditions");
}
return new Constant(enchantment, level, condition);
}
/**
* Creates a new main hand harvest module
* @param key Key to use for checking conditions, needs to be unique. Recommend suffixing the modifier ID (using the modifier ID will conflict with incremental)
* @return Module instance
*/
public MainHandHarvest mainHandHarvest(ResourceLocation key) {
return new MainHandHarvest(enchantment, level, condition, key, block, holder);
}
/**
* Creates a new armor harvest module
* @param slots Slots to allow this to run
* @return Module instance
*/
public ArmorHarvest armorHarvest(EquipmentSlot... slots) {
if (slots.length == 0) {
throw new IllegalArgumentException("Must have at least 1 slot");
}
// immutable set preserves insertion order
Set<EquipmentSlot> set = ImmutableSet.copyOf(slots);
if (set.contains(EquipmentSlot.MAINHAND)) {
throw new IllegalArgumentException("Cannot create armor harvest for the main hand slot");
}
return new ArmorHarvest(enchantment, level, condition, set, block, holder);
}
/** Creates a new armor harvest module with the default slots */
public ArmorHarvest armorHarvest() {
return armorHarvest(HarvestEnchantmentsModifierHook.APPLICABLE_SLOTS);
}
}
/** Implementation of a simple constant enchantment for the current tool */
record Constant(Enchantment enchantment, int level, ModifierModuleCondition condition) implements EnchantmentModule, EnchantmentModifierHook {
private static final List<ModifierHook<?>> DEFAULT_HOOKS = ModifierModule.<Constant>defaultHooks(TinkerHooks.ENCHANTMENTS);
public static final RecordLoadable<Constant> LOADER = RecordLoadable.create(ENCHANTMENT, IntLevelModule.FIELD, ModifierModuleCondition.FIELD, Constant::new);
public Constant(Enchantment enchantment, int level) {
this(enchantment, level, ModifierModuleCondition.ANY);
}
@Override
public int updateEnchantmentLevel(IToolStackView tool, ModifierEntry modifier, Enchantment enchantment, int level) {
if (enchantment == this.enchantment() && condition().matches(tool, modifier)) {
level += getLevel(tool, modifier);
}
return level;
}
@Override
public void updateEnchantments(IToolStackView tool, ModifierEntry modifier, Map<Enchantment,Integer> map) {
if (condition().matches(tool, modifier)) {
EnchantmentModifierHook.addEnchantment(map, this.enchantment(), getLevel(tool, modifier));
}
}
@Override
public List<ModifierHook<?>> getDefaultHooks() {
return DEFAULT_HOOKS;
}
@Override
public IGenericLoader<? extends ModifierModule> getLoader() {
return LOADER;
}
}
/** Enchantment module that can condition on the block mined or the entity mining. */
record MainHandHarvest(Enchantment enchantment, int level, ModifierModuleCondition condition, ResourceLocation conditionFlag, IJsonPredicate<BlockState> block, IJsonPredicate<LivingEntity> holder) implements EnchantmentModule, EnchantmentModifierHook, BlockHarvestModifierHook {
private static final List<ModifierHook<?>> DEFAULT_HOOKS = ModifierModule.<MainHandHarvest>defaultHooks(TinkerHooks.ENCHANTMENTS, TinkerHooks.BLOCK_HARVEST);
public static final RecordLoadable<MainHandHarvest> LOADER = RecordLoadable.create(ENCHANTMENT, IntLevelModule.FIELD, ModifierModuleCondition.FIELD, Loadables.RESOURCE_LOCATION.requiredField("condition_flag", MainHandHarvest::conditionFlag), BLOCK, HOLDER, MainHandHarvest::new);
@Override
public void startHarvest(IToolStackView tool, ModifierEntry modifier, ToolHarvestContext context) {
if (condition.matches(tool, modifier) && block.matches(context.getState()) && holder.matches(context.getLiving())) {
tool.getPersistentData().putBoolean(conditionFlag, true);
}
BlockHarvestModifierHook.super.startHarvest(tool, modifier, context);
}
@Override
public void finishHarvest(IToolStackView tool, ModifierEntry modifier, ToolHarvestContext context, boolean didHarvest) {
tool.getPersistentData().remove(conditionFlag);
}
@Override
public int updateEnchantmentLevel(IToolStackView tool, ModifierEntry modifier, Enchantment enchantment, int level) {
if (enchantment == this.enchantment() && tool.getPersistentData().getBoolean(conditionFlag)) {
level += getLevel(tool, modifier);
}
return level;
}
@Override
public void updateEnchantments(IToolStackView tool, ModifierEntry modifier, Map<Enchantment,Integer> map) {
if (tool.getPersistentData().getBoolean(conditionFlag)) {
EnchantmentModifierHook.addEnchantment(map, this.enchantment(), getLevel(tool, modifier));
}
}
@Override
public List<ModifierHook<?>> getDefaultHooks() {
return DEFAULT_HOOKS;
}
@Override
public IGenericLoader<? extends ModifierModule> getLoader() {
return LOADER;
}
}
/** Enchantment module that can condition on the block mined or the entity mining on armor. Requires the harvesting be done with a tinker tool. */
record ArmorHarvest(Enchantment enchantment, int level, ModifierModuleCondition condition, Set<EquipmentSlot> slots, IJsonPredicate<BlockState> block, IJsonPredicate<LivingEntity> holder) implements EnchantmentModule, HarvestEnchantmentsModifierHook {
private static final List<ModifierHook<?>> DEFAULT_HOOKS = ModifierModule.<ArmorHarvest>defaultHooks(TinkerHooks.HARVEST_ENCHANTMENTS);
public static final RecordLoadable<ArmorHarvest> LOADER = RecordLoadable.create(ENCHANTMENT, IntLevelModule.FIELD, ModifierModuleCondition.FIELD, TinkerLoadables.EQUIPMENT_SLOT_SET.requiredField("slots", ArmorHarvest::slots), BLOCK, HOLDER, ArmorHarvest::new);
@Override
public void updateHarvestEnchantments(IToolStackView tool, ModifierEntry modifier, ToolHarvestContext context, EquipmentContext equipment, EquipmentSlot slot, Map<Enchantment,Integer> map) {
if (slots.contains(slot) && condition.matches(tool, modifier) && block.matches(context.getState()) && holder.matches(context.getLiving())) {
EnchantmentModifierHook.addEnchantment(map, enchantment, getLevel(tool, modifier));
}
}
@Override
public List<ModifierHook<?>> getDefaultHooks() {
return DEFAULT_HOOKS;
}
@Override
public IGenericLoader<? extends ModifierModule> getLoader() {
return LOADER;
}
}
}