-
Notifications
You must be signed in to change notification settings - Fork 753
/
BlockTransformModule.java
129 lines (109 loc) · 5.01 KB
/
BlockTransformModule.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
package slimeknights.tconstruct.library.modifiers.modules.behavior;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.context.UseOnContext;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import slimeknights.tconstruct.library.modifiers.ModifierEntry;
import slimeknights.tconstruct.library.modifiers.ModifierHook;
import slimeknights.tconstruct.library.modifiers.TinkerHooks;
import slimeknights.tconstruct.library.modifiers.hook.interaction.BlockInteractionModifierHook;
import slimeknights.tconstruct.library.modifiers.hook.interaction.InteractionSource;
import slimeknights.tconstruct.library.modifiers.modules.ModifierHookProvider;
import slimeknights.tconstruct.library.modifiers.modules.ModifierModule;
import slimeknights.tconstruct.library.tools.definition.module.ToolHooks;
import slimeknights.tconstruct.library.tools.definition.module.aoe.AreaOfEffectIterator;
import slimeknights.tconstruct.library.tools.helper.ToolDamageUtil;
import slimeknights.tconstruct.library.tools.nbt.IToolStackView;
import slimeknights.tconstruct.library.utils.MutableUseOnContext;
import java.util.Iterator;
import java.util.List;
/**
* Shared logic for interaction actions which transform blocks
*/
public interface BlockTransformModule extends ModifierModule, BlockInteractionModifierHook {
List<ModifierHook<?>> DEFAULT_HOOKS = ModifierHookProvider.<BlockTransformModule>defaultHooks(TinkerHooks.BLOCK_INTERACT);
/** If true, disallows targeting the bottom face of the block to transform */
boolean requireGround();
@Override
default List<ModifierHook<?>> getDefaultHooks() {
return DEFAULT_HOOKS;
}
@Override
default InteractionResult afterBlockUse(IToolStackView tool, ModifierEntry modifier, UseOnContext context, InteractionSource source) {
// tool must not be broken
if (tool.isBroken() || !tool.getHook(ToolHooks.INTERACTION).canInteract(tool, modifier.getId(), source)) {
return InteractionResult.PASS;
}
Player player = context.getPlayer();
if (player != null && player.isShiftKeyDown()) {
return InteractionResult.PASS;
}
// for hoes and shovels, must have nothing but plants above
if (requireGround() && context.getClickedFace() == Direction.DOWN) {
return InteractionResult.PASS;
}
// must actually transform
Level world = context.getLevel();
BlockPos pos = context.getClickedPos();
BlockState original = world.getBlockState(pos);
ItemStack stack = context.getItemInHand();
boolean didTransform = transform(tool, context, original, true);
// if we made a successful transform, client can stop early
EquipmentSlot slotType = source.getSlot(context.getHand());
if (didTransform) {
if (world.isClientSide) {
return InteractionResult.SUCCESS;
}
// if the tool breaks or it was a campfire, we are done
if (ToolDamageUtil.damage(tool, 1, player, stack)) {
if (player != null) {
player.broadcastBreakEvent(slotType);
}
return InteractionResult.CONSUME;
}
}
// AOE transforming, run even if we did not transform the center
// note we consider anything effective, as hoes are not effective on all tillable blocks
if (player != null && !tool.isBroken()) {
int totalTransformed = 0;
Iterator<BlockPos> aoePos = tool.getHook(ToolHooks.AOE_ITERATOR).getBlocks(tool, stack, player, original, world, pos, context.getClickedFace(), AreaOfEffectIterator.AOEMatchType.TRANSFORM).iterator();
if (aoePos.hasNext()) {
MutableUseOnContext offsetContext = new MutableUseOnContext(context);
do {
BlockPos newPos = aoePos.next();
if (pos.equals(newPos)) {
continue;
}
// try interacting with the new position
offsetContext.setOffsetPos(newPos);
BlockState newTarget = world.getBlockState(newPos);
// limit to playing 40 sounds, that's more than enough for most transforms
if (transform(tool, offsetContext, newTarget, totalTransformed < 40)) {
totalTransformed++;
didTransform = true;
if (world.isClientSide) {
break;
}
// stop if the tool broke
if (ToolDamageUtil.damageAnimated(tool, 1, player, slotType)) {
break;
}
}
} while (aoePos.hasNext());
// sweep attack if we transformed any
if (totalTransformed > 0) {
player.sweepAttack();
}
}
}
// if anything happened, return success
return didTransform ? InteractionResult.sidedSuccess(world.isClientSide) : InteractionResult.PASS;
}
/** Applies this transformation */
boolean transform(IToolStackView tool, UseOnContext context, BlockState original, boolean playSound);
}