diff --git a/src/main/java/net/fretux/knockedback/GrippedStatePacket.java b/src/main/java/net/fretux/knockedback/GrippedStatePacket.java new file mode 100644 index 0000000..1304fcc --- /dev/null +++ b/src/main/java/net/fretux/knockedback/GrippedStatePacket.java @@ -0,0 +1,32 @@ +package net.fretux.knockedback; + +import net.fretux.knockedback.client.ClientGrippedState; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import java.util.UUID; +import java.util.function.Supplier; + +public class GrippedStatePacket { + private final UUID playerId; + private final boolean gripped; + + public GrippedStatePacket(UUID playerId, boolean gripped) { + this.playerId = playerId; + this.gripped = gripped; + } + + public static void encode(GrippedStatePacket packet, FriendlyByteBuf buf) { + buf.writeUUID(packet.playerId); + buf.writeBoolean(packet.gripped); + } + + public static GrippedStatePacket decode(FriendlyByteBuf buf) { + return new GrippedStatePacket(buf.readUUID(), buf.readBoolean()); + } + + public static void handle(GrippedStatePacket packet, Supplier ctx) { + ctx.get().enqueueWork(() -> ClientGrippedState.setGripped(packet.playerId, packet.gripped)); + ctx.get().setPacketHandled(true); + } +} diff --git a/src/main/java/net/fretux/knockedback/KnockedManager.java b/src/main/java/net/fretux/knockedback/KnockedManager.java index 2a91506..6b355b8 100644 --- a/src/main/java/net/fretux/knockedback/KnockedManager.java +++ b/src/main/java/net/fretux/knockedback/KnockedManager.java @@ -11,6 +11,7 @@ import net.minecraftforge.event.entity.living.LivingHurtEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.network.PacketDistributor; +import net.minecraftforge.event.entity.player.PlayerEvent; import java.util.*; @@ -63,7 +64,7 @@ public class KnockedManager { public static void removeKnockedState(LivingEntity entity) { knockedEntities.remove(entity.getUUID()); - grippedEntities.remove(entity.getUUID()); + setGripped(entity, false); MobKillHandler.clearKillAttempt(entity.getUUID()); entity.setPose(null); if (entity instanceof ServerPlayer sp) { @@ -81,6 +82,12 @@ public class KnockedManager { } else { grippedEntities.remove(entity.getUUID()); } + if (entity instanceof ServerPlayer sp) { + NetworkHandler.CHANNEL.send( + PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> sp), + new GrippedStatePacket(sp.getUUID(), isGripped) + ); + } } public static Collection getKnockedUuids() { @@ -193,4 +200,25 @@ public class KnockedManager { knockedEntities.put(player.getUUID(), getKnockedDuration()); event.setCanceled(true); } -} \ No newline at end of file + + @SubscribeEvent + public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) { + if (!(event.getEntity() instanceof ServerPlayer sp)) return; + UUID playerId = sp.getUUID(); + knockedEntities.remove(playerId); + grippedEntities.remove(playerId); + MobKillHandler.clearKillAttempt(playerId); + NetworkHandler.CHANNEL.send( + PacketDistributor.PLAYER.with(() -> sp), + new KnockedTimePacket(0) + ); + NetworkHandler.CHANNEL.send( + PacketDistributor.PLAYER.with(() -> sp), + new ExecutionProgressPacket(0) + ); + NetworkHandler.CHANNEL.send( + PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> sp), + new GrippedStatePacket(playerId, false) + ); + } +} diff --git a/src/main/java/net/fretux/knockedback/MobKillHandler.java b/src/main/java/net/fretux/knockedback/MobKillHandler.java index 18c3389..65d10ed 100644 --- a/src/main/java/net/fretux/knockedback/MobKillHandler.java +++ b/src/main/java/net/fretux/knockedback/MobKillHandler.java @@ -91,7 +91,11 @@ public class MobKillHandler { setGripped(knocked, false); continue; } - Mob mob = getMobInRange(knocked); + KillAttempt attempt = killAttempts.get(knockedId); + Mob mob = attempt != null ? getMobInRangeById(knocked, attempt.mobUuid) : null; + if (mob == null) { + mob = getMobInRange(knocked); + } if (mob == null) { if (knocked instanceof ServerPlayer sp) { NetworkHandler.CHANNEL.send( @@ -103,7 +107,6 @@ public class MobKillHandler { continue; } setGripped(knocked, true); - KillAttempt attempt = killAttempts.get(knockedId); if (attempt == null || !attempt.mobUuid.equals(mob.getUUID())) { attempt = new KillAttempt(mob.getUUID(), getExecutionTime()); } else { @@ -157,6 +160,19 @@ public class MobKillHandler { .findAny().orElse(null); } + @Nullable + private Mob getMobInRangeById(Player p, UUID mobId) { + if (!(p.level() instanceof ServerLevel world)) return null; + double r = 2.5; + AABB box = new AABB( + p.getX() - r, p.getY() - r, p.getZ() - r, + p.getX() + r, p.getY() + r, p.getZ() + r + ); + return world.getEntitiesOfClass(Mob.class, box).stream() + .filter(m -> m.getUUID().equals(mobId)) + .findAny().orElse(null); + } + private boolean isHostile(Mob m) { return m instanceof net.minecraft.world.entity.monster.Monster; @@ -184,4 +200,4 @@ public class MobKillHandler { public static void clearKillAttempt(UUID playerUuid) { killAttempts.remove(playerUuid); } -} \ No newline at end of file +} diff --git a/src/main/java/net/fretux/knockedback/NetworkHandler.java b/src/main/java/net/fretux/knockedback/NetworkHandler.java index f67c437..a80b979 100644 --- a/src/main/java/net/fretux/knockedback/NetworkHandler.java +++ b/src/main/java/net/fretux/knockedback/NetworkHandler.java @@ -14,5 +14,6 @@ public class NetworkHandler { CHANNEL.registerMessage(id++, KnockedTimePacket.class, KnockedTimePacket::encode, KnockedTimePacket::decode, KnockedTimePacket::handle); CHANNEL.registerMessage(id++, ExecutionProgressPacket.class, ExecutionProgressPacket::encode, ExecutionProgressPacket::decode, ExecutionProgressPacket::handle); CHANNEL.registerMessage(id++, CarryTogglePacket.class, CarryTogglePacket::encode, CarryTogglePacket::decode, CarryTogglePacket::handle); + CHANNEL.registerMessage(id++, GrippedStatePacket.class, GrippedStatePacket::encode, GrippedStatePacket::decode, GrippedStatePacket::handle); } -} \ No newline at end of file +} diff --git a/src/main/java/net/fretux/knockedback/client/ClientGrippedState.java b/src/main/java/net/fretux/knockedback/client/ClientGrippedState.java new file mode 100644 index 0000000..c131917 --- /dev/null +++ b/src/main/java/net/fretux/knockedback/client/ClientGrippedState.java @@ -0,0 +1,21 @@ +package net.fretux.knockedback.client; + +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +public class ClientGrippedState { + private static final Set grippedPlayers = new HashSet<>(); + + public static void setGripped(UUID playerId, boolean gripped) { + if (gripped) { + grippedPlayers.add(playerId); + } else { + grippedPlayers.remove(playerId); + } + } + + public static boolean isGripped(UUID playerId) { + return grippedPlayers.contains(playerId); + } +} diff --git a/src/main/java/net/fretux/knockedback/client/PlayerAnimationHandler.java b/src/main/java/net/fretux/knockedback/client/PlayerAnimationHandler.java new file mode 100644 index 0000000..b25be40 --- /dev/null +++ b/src/main/java/net/fretux/knockedback/client/PlayerAnimationHandler.java @@ -0,0 +1,49 @@ +package net.fretux.knockedback.client; + +import dev.kosmx.playerAnim.api.layered.IAnimation; +import dev.kosmx.playerAnim.api.layered.ModifierLayer; +import dev.kosmx.playerAnim.core.player.KeyframeAnimationPlayer; +import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess; +import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry; +import net.fretux.knockedback.KnockedBack; +import net.minecraft.client.player.AbstractClientPlayer; +import net.minecraft.resources.ResourceLocation; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.event.TickEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; + +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +@Mod.EventBusSubscriber(modid = KnockedBack.MOD_ID, value = Dist.CLIENT, bus = Mod.EventBusSubscriber.Bus.FORGE) +public class PlayerAnimationHandler { + private static final ResourceLocation GRIP_ANIMATION_ID = new ResourceLocation(KnockedBack.MOD_ID, "animation.model.gripping"); + private static final Map> layers = new HashMap<>(); + private static final Map activeStates = new HashMap<>(); + + @SubscribeEvent + public static void onPlayerTick(TickEvent.PlayerTickEvent event) { + if (event.phase != TickEvent.Phase.END) return; + if (!(event.player instanceof AbstractClientPlayer player)) return; + UUID playerId = player.getUUID(); + boolean shouldGrip = ClientGrippedState.isGripped(playerId); + boolean wasGripping = activeStates.getOrDefault(playerId, false); + if (shouldGrip == wasGripping) return; + activeStates.put(playerId, shouldGrip); + ModifierLayer layer = layers.computeIfAbsent(playerId, id -> { + ModifierLayer newLayer = new ModifierLayer<>(); + PlayerAnimationAccess.getPlayerAnimLayer(player).addAnimLayer(newLayer); + return newLayer; + }); + if (shouldGrip) { + var animation = PlayerAnimationRegistry.getAnimation(GRIP_ANIMATION_ID); + if (animation != null) { + layer.setAnimation(new KeyframeAnimationPlayer(animation)); + } + } else { + layer.setAnimation(null); + } + } +}