-
Notifications
You must be signed in to change notification settings - Fork 754
/
ToolDamageUtil.java
173 lines (154 loc) · 5.92 KB
/
ToolDamageUtil.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
package slimeknights.tconstruct.library.tools.helper;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.ModifierHooks;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import slimeknights.tconstruct.library.tools.nbt.ToolStack;
import slimeknights.tconstruct.library.tools.stat.ToolStats;
import javax.annotation.Nullable;
import java.util.function.Consumer;
/**
* Handles tool damage and repair, along with a quick broken check
*/
public class ToolDamageUtil {
/**
* Raw method to set a tool as broken. Bypasses {@link ToolStack} for the sake of things that may not be a full Tinker Tool
* @param stack Tool stack
*/
public static void breakTool(ItemStack stack) {
stack.getOrCreateTag().putBoolean(ToolStack.TAG_BROKEN, true);
}
/**
* Checks if the given stack is broken
* @param stack Stack to check
* @return True if broken
*/
public static boolean isBroken(ItemStack stack) {
CompoundTag nbt = stack.getTag();
return nbt != null && nbt.getBoolean(ToolStack.TAG_BROKEN);
}
/* Damaging and repairing */
/**
* Directly damages the tool, bypassing modifier hooks
* @param tool Tool to damage
* @param amount Amount to damage
* @param entity Entity holding the tool
* @param stack Stack being damaged
* @return True if the tool is broken now
*/
public static boolean directDamage(IToolStackView tool, int amount, @Nullable LivingEntity entity, @Nullable ItemStack stack) {
if (entity instanceof Player && ((Player)entity).isCreative()) {
return false;
}
int durability = tool.getStats().getInt(ToolStats.DURABILITY);
int damage = tool.getDamage();
int current = durability - damage;
amount = Math.min(amount, current);
if (amount > 0) {
// criteria updates
int newDamage = damage + amount;
// TODO: needed?
if (entity instanceof ServerPlayer) {
if (stack == null) {
stack = entity.getMainHandItem();
}
CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger((ServerPlayer)entity, stack, newDamage);
}
tool.setDamage(newDamage);
return newDamage >= durability;
}
return false;
}
/**
* Damages the tool by the given amount
* @param amount Amount to damage
* @param entity Entity for criteria updates, if null no updates run
* @param stack Stack to use for criteria updates, if null uses main hand stack
* @return true if the tool broke when damaging
*/
public static boolean damage(IToolStackView tool, int amount, @Nullable LivingEntity entity, @Nullable ItemStack stack) {
if (amount <= 0 || tool.isBroken() || tool.isUnbreakable()) {
return false;
}
// try each modifier
for (ModifierEntry entry : tool.getModifierList()) {
amount = entry.getHook(ModifierHooks.TOOL_DAMAGE).onDamageTool(tool, entry, amount, entity);
// if no more damage, done
if (amount <= 0) {
return false;
}
}
return directDamage(tool, amount, entity, stack);
}
/**
* Damages the tool and sends the break animation if it broke
* @param tool Tool to damage
* @param amount Amount of damage
* @param entity Entity for animation
* @param slot Slot containing the stack
*/
public static boolean damageAnimated(IToolStackView tool, int amount, LivingEntity entity, EquipmentSlot slot) {
if (damage(tool, amount, entity, entity.getItemBySlot(slot))) {
entity.broadcastBreakEvent(slot);
return true;
}
return false;
}
/**
* Damages the tool and sends the break animation if it broke
* @param tool Tool to damage
* @param amount Amount of damage
* @param entity Entity for animation
* @param hand Hand containing the stack
* @return true if the tool broke when damaging
*/
public static boolean damageAnimated(IToolStackView tool, int amount, LivingEntity entity, InteractionHand hand) {
if (damage(tool, amount, entity, entity.getItemInHand(hand))) {
entity.broadcastBreakEvent(hand);
return true;
}
return false;
}
/**
* Damages the tool in the main hand and sends the break animation if it broke
* @param tool Tool to damage
* @param amount Amount of damage
* @param entity Entity for animation
*/
public static boolean damageAnimated(IToolStackView tool, int amount, LivingEntity entity) {
return damageAnimated(tool, amount, entity, entity.isUsingItem() ? entity.getUsedItemHand() : InteractionHand.MAIN_HAND);
}
/** Implements {@link net.minecraft.world.item.Item#damageItem(ItemStack, int, LivingEntity, Consumer)} for a modifiable item */
public static <T extends LivingEntity> void handleDamageItem(ItemStack stack, int amount, T damager, Consumer<T> onBroken) {
// We basically emulate Itemstack.damageItem here. We always return 0 to skip the handling in ItemStack.
// If we don't tools ignore our damage logic
if (stack.getItem().canBeDepleted() && ToolDamageUtil.damage(ToolStack.from(stack), amount, damager, stack)) {
onBroken.accept(damager);
}
}
/**
* Repairs the given tool stack
* @param amount Amount to repair
*/
public static void repair(IToolStackView tool, int amount) {
if (amount <= 0) {
return;
}
// if undamaged, nothing to do
int damage = tool.getDamage();
if (damage == 0) {
return;
}
// note modifiers are run in the recipe instead
// ensure we never repair more than max durability
int newDamage = damage - Math.min(amount, damage);
tool.setDamage(newDamage);
}
}