Allow execution animation on other clients

This commit is contained in:
2026-01-07 18:14:25 +01:00
parent 976e73201e
commit 94fc6f79c6
6 changed files with 54 additions and 26 deletions
@@ -3,26 +3,37 @@ package net.fretux.knockedback;
import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.FriendlyByteBuf;
import net.minecraftforge.network.NetworkEvent; import net.minecraftforge.network.NetworkEvent;
import javax.annotation.Nullable;
import java.util.UUID;
import java.util.function.Supplier; import java.util.function.Supplier;
public class ExecutionProgressPacket { public class ExecutionProgressPacket {
private final int timeLeft; private final int timeLeft;
@Nullable
private final UUID executorId;
public ExecutionProgressPacket(int timeLeft) { public ExecutionProgressPacket(int timeLeft, @Nullable UUID executorId) {
this.timeLeft = timeLeft; this.timeLeft = timeLeft;
this.executorId = executorId;
} }
public static void encode(ExecutionProgressPacket msg, FriendlyByteBuf buf) { public static void encode(ExecutionProgressPacket msg, FriendlyByteBuf buf) {
buf.writeInt(msg.timeLeft); buf.writeInt(msg.timeLeft);
buf.writeBoolean(msg.executorId != null);
if (msg.executorId != null) {
buf.writeUUID(msg.executorId);
}
} }
public static ExecutionProgressPacket decode(FriendlyByteBuf buf) { public static ExecutionProgressPacket decode(FriendlyByteBuf buf) {
return new ExecutionProgressPacket(buf.readInt()); int timeLeft = buf.readInt();
UUID executorId = buf.readBoolean() ? buf.readUUID() : null;
return new ExecutionProgressPacket(timeLeft, executorId);
} }
public static void handle(ExecutionProgressPacket msg, Supplier<NetworkEvent.Context> ctx) { public static void handle(ExecutionProgressPacket msg, Supplier<NetworkEvent.Context> ctx) {
ctx.get().enqueueWork(() -> { ctx.get().enqueueWork(() -> {
net.fretux.knockedback.client.ClientExecutionState.setTimeLeft(msg.timeLeft); net.fretux.knockedback.client.ClientExecutionState.setExecution(msg.timeLeft, msg.executorId);
}); });
ctx.get().setPacketHandled(true); ctx.get().setPacketHandled(true);
} }
@@ -215,7 +215,7 @@ public class KnockedManager {
); );
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> sp), PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> sp),
@@ -65,7 +65,7 @@ public class MobKillHandler {
if (p instanceof ServerPlayer sp) { if (p instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
} }
setGripped(p, false); setGripped(p, false);
@@ -85,7 +85,7 @@ public class MobKillHandler {
if (knocked instanceof ServerPlayer sp) { if (knocked instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
} }
setGripped(knocked, false); setGripped(knocked, false);
@@ -100,7 +100,7 @@ public class MobKillHandler {
if (knocked instanceof ServerPlayer sp) { if (knocked instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
} }
setGripped(knocked, false); setGripped(knocked, false);
@@ -114,7 +114,7 @@ public class MobKillHandler {
if (knocked instanceof ServerPlayer sp) { if (knocked instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(attempt.timeLeft) new ExecutionProgressPacket(attempt.timeLeft, null)
); );
} }
if (attempt.timeLeft <= 0) { if (attempt.timeLeft <= 0) {
@@ -141,7 +141,7 @@ public class MobKillHandler {
if (knocked instanceof ServerPlayer sp) { if (knocked instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
} }
} }
@@ -90,7 +90,7 @@ public class PlayerExecutionHandler {
knocked.sendSystemMessage(Component.translatable("message.knockedback.execution_interrupted")); knocked.sendSystemMessage(Component.translatable("message.knockedback.execution_interrupted"));
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> knocked), PacketDistributor.PLAYER.with(() -> knocked),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
} }
ServerPlayer executor = getPlayerByUuid(attempt.executorUuid); ServerPlayer executor = getPlayerByUuid(attempt.executorUuid);
@@ -98,7 +98,7 @@ public class PlayerExecutionHandler {
executor.sendSystemMessage(Component.translatable("message.knockedback.execution_interrupted_executor")); executor.sendSystemMessage(Component.translatable("message.knockedback.execution_interrupted_executor"));
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> executor), PacketDistributor.PLAYER.with(() -> executor),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
} }
} }
@@ -128,12 +128,12 @@ public class PlayerExecutionHandler {
KnockedManager.unmarkKillInProgress(knockedPlayer); KnockedManager.unmarkKillInProgress(knockedPlayer);
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> executor), PacketDistributor.PLAYER.with(() -> executor),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
if (knockedPlayer instanceof ServerPlayer sp) { if (knockedPlayer instanceof ServerPlayer sp) {
NetworkHandler.CHANNEL.send( NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> sp), PacketDistributor.PLAYER.with(() -> sp),
new ExecutionProgressPacket(0) new ExecutionProgressPacket(0, null)
); );
} }
executor.sendSystemMessage(Component.translatable("message.knockedback.you_executed", knockedPlayer.getDisplayName(), "!")); executor.sendSystemMessage(Component.translatable("message.knockedback.you_executed", knockedPlayer.getDisplayName(), "!"));
@@ -160,8 +160,14 @@ public class PlayerExecutionHandler {
continue; continue;
} }
attempt.timeLeft--; attempt.timeLeft--;
NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> executor), new ExecutionProgressPacket(attempt.timeLeft)); NetworkHandler.CHANNEL.send(
NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> knocked), new ExecutionProgressPacket(attempt.timeLeft)); PacketDistributor.PLAYER.with(() -> executor),
new ExecutionProgressPacket(attempt.timeLeft, attempt.executorUuid)
);
NetworkHandler.CHANNEL.send(
PacketDistributor.PLAYER.with(() -> knocked),
new ExecutionProgressPacket(attempt.timeLeft, attempt.executorUuid)
);
if (attempt.timeLeft <= 0) { if (attempt.timeLeft <= 0) {
executeKnockedPlayer(executor, knocked); executeKnockedPlayer(executor, knocked);
} else { } else {
@@ -1,10 +1,16 @@
package net.fretux.knockedback.client; package net.fretux.knockedback.client;
import javax.annotation.Nullable;
import java.util.UUID;
public class ClientExecutionState { public class ClientExecutionState {
private static int timeLeft = 0; private static int timeLeft = 0;
@Nullable
private static UUID executorId;
public static void setTimeLeft(int ticks) { public static void setExecution(int ticks, @Nullable UUID executor) {
timeLeft = ticks; timeLeft = ticks;
executorId = ticks > 0 ? executor : null;
} }
public static int getTimeLeft() { public static int getTimeLeft() {
@@ -14,4 +20,8 @@ public class ClientExecutionState {
public static boolean isExecuting() { public static boolean isExecuting() {
return timeLeft > 0; return timeLeft > 0;
} }
public static boolean isExecutor(UUID playerId) {
return timeLeft > 0 && executorId != null && executorId.equals(playerId);
}
} }
@@ -6,6 +6,7 @@ import dev.kosmx.playerAnim.api.layered.ModifierLayer;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess; import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry; import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
import net.fretux.knockedback.KnockedBack; import net.fretux.knockedback.KnockedBack;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer; import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.resources.ResourceLocation; import net.minecraft.resources.ResourceLocation;
import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.Dist;
@@ -19,8 +20,8 @@ import java.util.UUID;
@Mod.EventBusSubscriber(modid = KnockedBack.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE) @Mod.EventBusSubscriber(modid = KnockedBack.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE)
public class PlayerAnimationHandler { public class PlayerAnimationHandler {
private static final ResourceLocation GRIP_ANIMATION_ID = private static final ResourceLocation EXECUTION_ANIMATION_ID =
ResourceLocation.fromNamespaceAndPath(KnockedBack.MOD_ID, "animation.model.gripping"); ResourceLocation.fromNamespaceAndPath(KnockedBack.MOD_ID, "animation.model.execution");
private static final Map<UUID, ModifierLayer<IAnimation>> layers = new HashMap<>(); private static final Map<UUID, ModifierLayer<IAnimation>> layers = new HashMap<>();
private static final Map<UUID, Boolean> activeStates = new HashMap<>(); private static final Map<UUID, Boolean> activeStates = new HashMap<>();
@@ -29,17 +30,17 @@ public class PlayerAnimationHandler {
if (event.phase != TickEvent.Phase.END) return; if (event.phase != TickEvent.Phase.END) return;
if (!(event.player instanceof AbstractClientPlayer player)) return; if (!(event.player instanceof AbstractClientPlayer player)) return;
UUID playerId = player.getUUID(); UUID playerId = player.getUUID();
boolean shouldGrip = ClientGrippedState.isGripped(playerId); boolean shouldPlayExecution = ClientExecutionState.isExecutor(playerId);
boolean wasGripping = activeStates.getOrDefault(playerId, false); boolean wasPlaying = activeStates.getOrDefault(playerId, false);
if (shouldGrip == wasGripping) return; if (shouldPlayExecution == wasPlaying) return;
activeStates.put(playerId, shouldGrip); activeStates.put(playerId, shouldPlayExecution);
ModifierLayer<IAnimation> layer = layers.computeIfAbsent(playerId, id -> { ModifierLayer<IAnimation> layer = layers.computeIfAbsent(playerId, id -> {
ModifierLayer<IAnimation> newLayer = new ModifierLayer<>(); ModifierLayer<IAnimation> newLayer = new ModifierLayer<>();
PlayerAnimationAccess.getPlayerAnimLayer(player).addAnimLayer(0, newLayer); PlayerAnimationAccess.getPlayerAnimLayer(player).addAnimLayer(0, newLayer);
return newLayer; return newLayer;
}); });
if (shouldGrip) { if (shouldPlayExecution) {
var animation = PlayerAnimationRegistry.getAnimation(GRIP_ANIMATION_ID); var animation = PlayerAnimationRegistry.getAnimation(EXECUTION_ANIMATION_ID);
if (animation != null) { if (animation != null) {
layer.setAnimation(new KeyframeAnimationPlayer(animation)); layer.setAnimation(new KeyframeAnimationPlayer(animation));
} }