|
20 | 20 | import org.spongepowered.asm.mixin.Final; |
21 | 21 | import org.spongepowered.asm.mixin.Mixin; |
22 | 22 | import org.spongepowered.asm.mixin.Shadow; |
23 | | -import org.spongepowered.asm.mixin.Unique; |
24 | 23 | import org.spongepowered.asm.mixin.injection.At; |
25 | 24 | import org.spongepowered.asm.mixin.injection.Inject; |
26 | | -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; |
27 | 25 | import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; |
28 | 26 |
|
29 | 27 | import net.minecraft.client.Minecraft; |
30 | | -import net.minecraft.client.multiplayer.ClientLevel; |
31 | | -import net.minecraft.client.multiplayer.ClientPacketListener; |
32 | 28 | import net.minecraft.client.multiplayer.MultiPlayerGameMode; |
33 | | -import net.minecraft.client.multiplayer.prediction.PredictiveAction; |
34 | | -import net.minecraft.client.player.LocalPlayer; |
35 | 29 | import net.minecraft.core.BlockPos; |
36 | | -import net.minecraft.core.Direction; |
37 | | -import net.minecraft.network.protocol.game.ServerboundAttackPacket; |
38 | | -import net.minecraft.network.protocol.game.ServerboundPlayerActionPacket; |
39 | | -import net.minecraft.network.protocol.game.ServerboundUseItemOnPacket; |
40 | | -import net.minecraft.network.protocol.game.ServerboundUseItemPacket; |
41 | | -import net.minecraft.world.InteractionHand; |
42 | | -import net.minecraft.world.InteractionResult; |
43 | | -import net.minecraft.world.entity.Entity; |
44 | | -import net.minecraft.world.entity.player.Player; |
45 | 30 | import net.minecraft.world.level.block.state.BlockState; |
46 | | -import net.minecraft.world.phys.BlockHitResult; |
47 | 31 |
|
48 | 32 | import net.fabricmc.fabric.api.event.client.player.ClientPlayerBlockBreakEvents; |
49 | | -import net.fabricmc.fabric.api.event.player.AttackBlockCallback; |
50 | | -import net.fabricmc.fabric.api.event.player.AttackEntityCallback; |
51 | | -import net.fabricmc.fabric.api.event.player.UseBlockCallback; |
52 | | -import net.fabricmc.fabric.api.event.player.UseItemCallback; |
53 | 33 |
|
54 | 34 | @Mixin(MultiPlayerGameMode.class) |
55 | 35 | public abstract class MultiPlayerGameModeMixin { |
56 | 36 | @Shadow |
57 | 37 | @Final |
58 | 38 | private Minecraft minecraft; |
59 | | - @Shadow |
60 | | - @Final |
61 | | - private ClientPacketListener connection; |
62 | | - |
63 | | - @Shadow |
64 | | - protected abstract void startPrediction(ClientLevel clientLevel, PredictiveAction predictiveAction); |
65 | | - |
66 | | - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getAbilities()Lnet/minecraft/world/entity/player/Abilities;", ordinal = 0), method = "startDestroyBlock", cancellable = true) |
67 | | - public void attackBlock(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> info) { |
68 | | - fabric_fireAttackBlockCallback(pos, direction, info); |
69 | | - } |
70 | | - |
71 | | - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;getAbilities()Lnet/minecraft/world/entity/player/Abilities;", ordinal = 0), method = "continueDestroyBlock", cancellable = true) |
72 | | - public void method_2902(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> info) { |
73 | | - if (this.minecraft.player.getAbilities().instabuild) { |
74 | | - fabric_fireAttackBlockCallback(pos, direction, info); |
75 | | - } |
76 | | - } |
77 | | - |
78 | | - @Unique |
79 | | - private void fabric_fireAttackBlockCallback(BlockPos pos, Direction direction, CallbackInfoReturnable<Boolean> info) { |
80 | | - InteractionResult result = AttackBlockCallback.EVENT.invoker().interact(minecraft.player, minecraft.level, InteractionHand.MAIN_HAND, pos, direction); |
81 | | - |
82 | | - if (result != InteractionResult.PASS) { |
83 | | - // Returning true will spawn particles and trigger the animation of the hand -> only for SUCCESS. |
84 | | - info.setReturnValue(result == InteractionResult.SUCCESS); |
85 | | - |
86 | | - // We also need to let the server process the action if it's accepted. |
87 | | - if (result.consumesAction()) { |
88 | | - startPrediction(minecraft.level, id -> new ServerboundPlayerActionPacket(ServerboundPlayerActionPacket.Action.START_DESTROY_BLOCK, pos, direction, id)); |
89 | | - } |
90 | | - } |
91 | | - } |
92 | 39 |
|
93 | 40 | @Inject(method = "destroyBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/Block;destroy(Lnet/minecraft/world/level/LevelAccessor;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;)V")) |
94 | 41 | private void fabric$onBlockBroken(BlockPos pos, CallbackInfoReturnable<Boolean> cir, @Local(name = "oldState") BlockState oldState) { |
95 | 42 | ClientPlayerBlockBreakEvents.AFTER.invoker().afterBlockBreak(minecraft.level, minecraft.player, pos, oldState); |
96 | 43 | } |
97 | | - |
98 | | - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;startPrediction(Lnet/minecraft/client/multiplayer/ClientLevel;Lnet/minecraft/client/multiplayer/prediction/PredictiveAction;)V"), method = "useItemOn", cancellable = true) |
99 | | - public void interactBlock(LocalPlayer player, InteractionHand hand, BlockHitResult blockHitResult, CallbackInfoReturnable<InteractionResult> info) { |
100 | | - // hook interactBlock between the world border check and the actual block interaction to invoke the use block event first |
101 | | - // this needs to be in interactBlock to avoid sending a packet in line with the event javadoc |
102 | | - |
103 | | - if (player.isSpectator()) return; // vanilla spectator check happens later, repeat it before the event to avoid false invocations |
104 | | - |
105 | | - InteractionResult result = UseBlockCallback.EVENT.invoker().interact(player, player.level(), hand, blockHitResult); |
106 | | - |
107 | | - if (result != InteractionResult.PASS) { |
108 | | - if (result.consumesAction()) { |
109 | | - // send interaction packet to the server with a new sequentially assigned id |
110 | | - startPrediction((ClientLevel) player.level(), id -> new ServerboundUseItemOnPacket(hand, blockHitResult, id)); |
111 | | - } |
112 | | - |
113 | | - info.setReturnValue(result); |
114 | | - } |
115 | | - } |
116 | | - |
117 | | - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;ensureHasSentCarriedItem()V", ordinal = 0), method = "useItem", cancellable = true) |
118 | | - public void interactItem(Player player, InteractionHand hand, CallbackInfoReturnable<InteractionResult> info) { |
119 | | - // hook interactBlock between the spectator check and sending the first packet to invoke the use item event first |
120 | | - // this needs to be in interactBlock to avoid sending a packet in line with the event javadoc |
121 | | - InteractionResult result = UseItemCallback.EVENT.invoker().interact(player, player.level(), hand); |
122 | | - |
123 | | - if (result != InteractionResult.PASS) { |
124 | | - if (result == InteractionResult.SUCCESS) { |
125 | | - // send interaction packet to the server with a new sequentially assigned id |
126 | | - startPrediction((ClientLevel) player.level(), id -> new ServerboundUseItemPacket(hand, id, player.getYRot(), player.getXRot())); |
127 | | - } |
128 | | - |
129 | | - info.setReturnValue(result); |
130 | | - } |
131 | | - } |
132 | | - |
133 | | - @Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/multiplayer/ClientPacketListener;send(Lnet/minecraft/network/protocol/Packet;)V", ordinal = 0), method = "attack", cancellable = true) |
134 | | - public void attackEntity(Player player, Entity entity, CallbackInfo info) { |
135 | | - InteractionResult result = AttackEntityCallback.EVENT.invoker().interact(player, player.level(), InteractionHand.MAIN_HAND /* TODO */, entity, null); |
136 | | - |
137 | | - if (result != InteractionResult.PASS) { |
138 | | - if (result == InteractionResult.SUCCESS) { |
139 | | - this.connection.send(new ServerboundAttackPacket(entity.getId())); |
140 | | - } |
141 | | - |
142 | | - info.cancel(); |
143 | | - } |
144 | | - } |
145 | 44 | } |
0 commit comments