Skip to content

Commit 89ba018

Browse files
committed
Port fabric-events-interaction-v0
1 parent 782eee3 commit 89ba018

15 files changed

Lines changed: 140 additions & 401 deletions

File tree

fabric-events-interaction-v0/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
version = getSubprojectVersion(project)
22

3-
moduleDependencies(project, ['fabric-api-base', 'fabric-networking-api-v1'])
3+
moduleDependencies(project, ['fabric-api-base'])
44

55
testDependencies(project, [
66
'fabric-client-gametest-api-v1'

fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/mixin/event/interaction/client/MinecraftMixin.java

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
package net.fabricmc.fabric.mixin.event.interaction.client;
1818

19-
import com.llamalad7.mixinextras.sugar.Local;
2019
import org.jspecify.annotations.Nullable;
2120
import org.spongepowered.asm.mixin.Final;
2221
import org.spongepowered.asm.mixin.Mixin;
@@ -30,18 +29,10 @@
3029
import net.minecraft.client.Minecraft;
3130
import net.minecraft.client.Options;
3231
import net.minecraft.client.multiplayer.ClientLevel;
33-
import net.minecraft.client.multiplayer.ClientPacketListener;
3432
import net.minecraft.client.multiplayer.MultiPlayerGameMode;
3533
import net.minecraft.client.player.LocalPlayer;
36-
import net.minecraft.network.protocol.game.ServerboundInteractPacket;
37-
import net.minecraft.world.InteractionHand;
38-
import net.minecraft.world.InteractionResult;
39-
import net.minecraft.world.entity.Entity;
40-
import net.minecraft.world.phys.EntityHitResult;
41-
import net.minecraft.world.phys.Vec3;
4234

4335
import net.fabricmc.fabric.api.event.client.player.ClientPreAttackCallback;
44-
import net.fabricmc.fabric.api.event.player.UseEntityCallback;
4536

4637
@Mixin(Minecraft.class)
4738
public abstract class MinecraftMixin {
@@ -51,9 +42,6 @@ public abstract class MinecraftMixin {
5142
@Shadow
5243
public LocalPlayer player;
5344

54-
@Shadow
55-
public abstract ClientPacketListener getConnection();
56-
5745
@Shadow
5846
@Final
5947
public Options options;
@@ -66,33 +54,6 @@ public abstract class MinecraftMixin {
6654
@Nullable
6755
public ClientLevel level;
6856

69-
@Inject(
70-
at = @At(
71-
value = "INVOKE",
72-
target = "Lnet/minecraft/client/multiplayer/MultiPlayerGameMode;interact(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/EntityHitResult;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/world/InteractionResult;"
73-
),
74-
method = "startUseItem",
75-
cancellable = true
76-
)
77-
private void injectUseEntityCallback(CallbackInfo ci, @Local(name = "hand") InteractionHand hand, @Local(name = "entityHit") EntityHitResult hitResult, @Local(name = "entity") Entity entity) {
78-
InteractionResult result = UseEntityCallback.EVENT.invoker().interact(player, player.level(), hand, entity, hitResult);
79-
80-
if (result != InteractionResult.PASS) {
81-
if (result.consumesAction()) {
82-
Vec3 hitVec = hitResult.getLocation().subtract(entity.getX(), entity.getY(), entity.getZ());
83-
getConnection().send(new ServerboundInteractPacket(entity.getId(), hand, hitVec, player.isShiftKeyDown()));
84-
}
85-
86-
if (result instanceof InteractionResult.Success success) {
87-
if (success.swingSource() == InteractionResult.SwingSource.CLIENT) {
88-
player.swing(hand);
89-
}
90-
}
91-
92-
ci.cancel();
93-
}
94-
}
95-
9657
@Inject(
9758
method = "handleKeybinds",
9859
at = @At(

fabric-events-interaction-v0/src/client/java/net/fabricmc/fabric/mixin/event/interaction/client/MultiPlayerGameModeMixin.java

Lines changed: 0 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -20,126 +20,25 @@
2020
import org.spongepowered.asm.mixin.Final;
2121
import org.spongepowered.asm.mixin.Mixin;
2222
import org.spongepowered.asm.mixin.Shadow;
23-
import org.spongepowered.asm.mixin.Unique;
2423
import org.spongepowered.asm.mixin.injection.At;
2524
import org.spongepowered.asm.mixin.injection.Inject;
26-
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
2725
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
2826

2927
import net.minecraft.client.Minecraft;
30-
import net.minecraft.client.multiplayer.ClientLevel;
31-
import net.minecraft.client.multiplayer.ClientPacketListener;
3228
import net.minecraft.client.multiplayer.MultiPlayerGameMode;
33-
import net.minecraft.client.multiplayer.prediction.PredictiveAction;
34-
import net.minecraft.client.player.LocalPlayer;
3529
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;
4530
import net.minecraft.world.level.block.state.BlockState;
46-
import net.minecraft.world.phys.BlockHitResult;
4731

4832
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;
5333

5434
@Mixin(MultiPlayerGameMode.class)
5535
public abstract class MultiPlayerGameModeMixin {
5636
@Shadow
5737
@Final
5838
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-
}
9239

9340
@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"))
9441
private void fabric$onBlockBroken(BlockPos pos, CallbackInfoReturnable<Boolean> cir, @Local(name = "oldState") BlockState oldState) {
9542
ClientPlayerBlockBreakEvents.AFTER.invoker().afterBlockBreak(minecraft.level, minecraft.player, pos, oldState);
9643
}
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-
}
14544
}

fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/api/entity/FakePlayer.java

Lines changed: 2 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,13 @@
1818

1919
import java.util.Map;
2020
import java.util.Objects;
21-
import java.util.OptionalInt;
2221
import java.util.UUID;
2322

2423
import com.google.common.collect.MapMaker;
2524
import com.mojang.authlib.GameProfile;
26-
import org.jspecify.annotations.Nullable;
2725

28-
import net.minecraft.core.BlockPos;
29-
import net.minecraft.server.level.ClientInformation;
3026
import net.minecraft.server.level.ServerLevel;
3127
import net.minecraft.server.level.ServerPlayer;
32-
import net.minecraft.stats.Stat;
33-
import net.minecraft.world.Container;
34-
import net.minecraft.world.MenuProvider;
35-
import net.minecraft.world.damagesource.DamageSource;
36-
import net.minecraft.world.entity.Entity;
37-
import net.minecraft.world.entity.animal.equine.AbstractHorse;
38-
import net.minecraft.world.level.block.entity.SignBlockEntity;
39-
import net.minecraft.world.scores.PlayerTeam;
4028

4129
import net.fabricmc.fabric.impl.event.interaction.FakePlayerPacketListener;
4230

@@ -61,7 +49,7 @@
6149
* In some edge cases, or for gameplay considerations, it might be necessary to check whether a {@link ServerPlayer} is a fake player.
6250
* This can be done with an {@code instanceof} check: {@code player instanceof FakePlayer}.
6351
*/
64-
public class FakePlayer extends ServerPlayer {
52+
public class FakePlayer extends net.neoforged.neoforge.common.util.FakePlayer {
6553
/**
6654
* Default UUID, for fake players not associated with a specific (human) player.
6755
*/
@@ -102,53 +90,8 @@ private record FakePlayerKey(ServerLevel level, GameProfile profile) { }
10290
private static final Map<FakePlayerKey, FakePlayer> FAKE_PLAYER_MAP = new MapMaker().weakValues().makeMap();
10391

10492
protected FakePlayer(ServerLevel level, GameProfile profile) {
105-
super(level.getServer(), level, profile, ClientInformation.createDefault());
93+
super(level, profile);
10694

10795
this.connection = new FakePlayerPacketListener(this);
10896
}
109-
110-
@Override
111-
public void tick() { }
112-
113-
@Override
114-
public void updateOptions(ClientInformation settings) { }
115-
116-
@Override
117-
public void awardStat(Stat<?> stat, int amount) { }
118-
119-
@Override
120-
public void resetStat(Stat<?> stat) { }
121-
122-
@Override
123-
public boolean isInvulnerableTo(ServerLevel level, DamageSource damageSource) {
124-
return true;
125-
}
126-
127-
@Nullable
128-
@Override
129-
public PlayerTeam getTeam() {
130-
// Scoreboard team is checked using the gameprofile name by default, which we don't want.
131-
return null;
132-
}
133-
134-
@Override
135-
public void startSleeping(BlockPos pos) {
136-
// Don't lock bed forever.
137-
}
138-
139-
@Override
140-
public boolean startRiding(Entity entity, boolean force, boolean emitEvent) {
141-
return false;
142-
}
143-
144-
@Override
145-
public void openTextEdit(SignBlockEntity sign, boolean front) { }
146-
147-
@Override
148-
public OptionalInt openMenu(@Nullable MenuProvider factory) {
149-
return OptionalInt.empty();
150-
}
151-
152-
@Override
153-
public void openHorseInventory(AbstractHorse horse, Container inventory) { }
15497
}

fabric-events-interaction-v0/src/main/java/net/fabricmc/fabric/impl/event/interaction/FakePlayerPacketListener.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,7 @@
2626
import net.minecraft.server.network.CommonListenerCookie;
2727
import net.minecraft.server.network.ServerGamePacketListenerImpl;
2828

29-
import net.fabricmc.fabric.impl.networking.UntrackedPacketListener;
30-
31-
public final class FakePlayerPacketListener extends ServerGamePacketListenerImpl implements UntrackedPacketListener {
29+
public final class FakePlayerPacketListener extends ServerGamePacketListenerImpl {
3230
private static final Connection FAKE_CONNECTION = new FakeConnection();
3331

3432
public FakePlayerPacketListener(ServerPlayer player) {

0 commit comments

Comments
 (0)