P3-11 : add PacketPlayRigAnim + ModNetwork registration (handler stub)
Record packet S->C pour animations cinematic one-shot (capture NPC, hit stun, death). Carries entityId, animId (ResourceLocation), transitionTime (float), et priorityOrdinal (byte = Layer.Priority.ordinal()). Encode via writeVarInt/writeResourceLocation/writeFloat/writeByte ; decode symétrique. Factory PacketPlayRigAnim.of() pour build lisible avec Layer.Priority, et getter priority() avec fallback LOWEST si ordinal hors-range (masking & 0xFF pour gérer byte négatif). Handler client = stub qui LOGGER.debug + setPacketHandled. Le corps complet (resolve entity, lookup LivingEntityPatch, animator.playAnimation) viendra en P3-12 avec la méthode serveur playAnimationSync(). Registration ajoutée en fin de ModNetwork.register() — ID sequential 75 (76 packets total). 7 tests unitaires PacketPlayRigAnimTest : roundtrip nominal, entityId boundary (0/MAX/MIN), transitionTime zero+negative (pas de validation silencieuse), loop sur les 5 Layer.Priority, fallback LOWEST sur ordinal malformé (99, -1, PRIORITY_COUNT), ResourceLocation avec underscores et slashes, et sanity check equals. Rig tests : 65 -> 72 GREEN. Full suite : 162 GREEN, 0 failure.
This commit is contained in:
@@ -64,6 +64,7 @@ import com.tiedup.remake.network.sync.PacketSyncPetBedState;
|
||||
import com.tiedup.remake.network.sync.PacketSyncStruggleState;
|
||||
import com.tiedup.remake.network.trader.PacketBuyCaptive;
|
||||
import com.tiedup.remake.network.trader.PacketOpenTraderScreen;
|
||||
import com.tiedup.remake.rig.network.PacketPlayRigAnim;
|
||||
import com.tiedup.remake.v2.bondage.network.PacketSyncV2Equipment;
|
||||
import com.tiedup.remake.v2.bondage.network.PacketV2LockToggle;
|
||||
import com.tiedup.remake.v2.bondage.network.PacketV2SelfEquip;
|
||||
@@ -592,6 +593,14 @@ public class ModNetwork {
|
||||
PacketSyncMovementStyle::handle
|
||||
);
|
||||
|
||||
// RIG animation system (S2C cinematic one-shot)
|
||||
reg(
|
||||
PacketPlayRigAnim.class,
|
||||
PacketPlayRigAnim::encode,
|
||||
PacketPlayRigAnim::decode,
|
||||
PacketPlayRigAnim::handleOnClient
|
||||
);
|
||||
|
||||
TiedUpMod.LOGGER.info("Registered {} network packets", packetId);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* © 2026 TiedUp! Remake Contributors, distributed under GPLv3.
|
||||
*/
|
||||
|
||||
package com.tiedup.remake.rig.network;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
||||
import com.tiedup.remake.rig.anim.client.Layer;
|
||||
|
||||
/**
|
||||
* Packet S→C : déclenche une animation one-shot sur une entité distante.
|
||||
*
|
||||
* <p>Utilisé pour les animations cinematic serveur-authoritatives (NPC capture
|
||||
* grab, hit stun, death). Le client résout l'entité par ID, récupère son
|
||||
* {@code LivingEntityPatch} via {@code TiedUpCapabilities}, et appelle
|
||||
* {@code animator.playAnimation(anim, transitionTime)} avec la priorité donnée.
|
||||
*
|
||||
* <p>Le server-side dispatch (méthode {@code LivingEntityPatch.playAnimationSync})
|
||||
* sera implémenté en P3-12. Ici on pose juste l'infra packet + handler stub
|
||||
* qui log et termine.
|
||||
*
|
||||
* @param entityId ID runtime de l'entité ciblée (Entity.getId())
|
||||
* @param animId ResourceLocation de l'animation à jouer
|
||||
* @param transitionTime durée de blend en secondes (typiquement 0.15F = 3 ticks)
|
||||
* @param priorityOrdinal ordinal de Layer.Priority (LOWEST=0...HIGHEST=4),
|
||||
* transmis sous forme byte pour compacité
|
||||
*/
|
||||
public record PacketPlayRigAnim(
|
||||
int entityId,
|
||||
ResourceLocation animId,
|
||||
float transitionTime,
|
||||
byte priorityOrdinal
|
||||
) {
|
||||
public static final int PRIORITY_COUNT = Layer.Priority.values().length;
|
||||
|
||||
/** Factory avec Layer.Priority (plus expressif qu'un byte direct). */
|
||||
public static PacketPlayRigAnim of(int entityId, ResourceLocation animId, float transitionTime, Layer.Priority priority) {
|
||||
return new PacketPlayRigAnim(entityId, animId, transitionTime, (byte) priority.ordinal());
|
||||
}
|
||||
|
||||
public Layer.Priority priority() {
|
||||
// Guard out-of-range si un peer malveillant envoie un byte invalide
|
||||
int idx = priorityOrdinal & 0xFF;
|
||||
if (idx < 0 || idx >= PRIORITY_COUNT) {
|
||||
return Layer.Priority.LOWEST; // fallback safe
|
||||
}
|
||||
return Layer.Priority.values()[idx];
|
||||
}
|
||||
|
||||
public void encode(FriendlyByteBuf buf) {
|
||||
buf.writeVarInt(this.entityId);
|
||||
buf.writeResourceLocation(this.animId);
|
||||
buf.writeFloat(this.transitionTime);
|
||||
buf.writeByte(this.priorityOrdinal);
|
||||
}
|
||||
|
||||
public static PacketPlayRigAnim decode(FriendlyByteBuf buf) {
|
||||
int entityId = buf.readVarInt();
|
||||
ResourceLocation animId = buf.readResourceLocation();
|
||||
float transitionTime = buf.readFloat();
|
||||
byte priorityOrdinal = buf.readByte();
|
||||
return new PacketPlayRigAnim(entityId, animId, transitionTime, priorityOrdinal);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler client — stub P3-11. Le corps complet (resolve entity, lookup
|
||||
* patch, playAnimation) viendra en P3-12.
|
||||
*/
|
||||
public static void handleOnClient(PacketPlayRigAnim pkt, Supplier<NetworkEvent.Context> ctx) {
|
||||
ctx.get().enqueueWork(() -> {
|
||||
TiedUpRigConstants.LOGGER.debug(
|
||||
"[PacketPlayRigAnim] received (stub P3-11): entityId={}, animId={}, transition={}s, priority={}",
|
||||
pkt.entityId, pkt.animId, pkt.transitionTime, pkt.priority()
|
||||
);
|
||||
// TODO P3-12 : resolve entity + patch + animator.playAnimation
|
||||
});
|
||||
ctx.get().setPacketHandled(true);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user