From 15e405f5b0af6b3c0a88a64c1b42aff7e82f1043 Mon Sep 17 00:00:00 2001 From: notevil Date: Thu, 23 Apr 2026 13:02:44 +0200 Subject: [PATCH] P3-01 : add TiedUpLivingMotions enum (11 motions + UX additions) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nouvelle enum custom etendant LivingMotion — partage le meme ENUM_MANAGER que LivingMotions (vanilla EF), ordinals assignes a la suite sans collision. 8 motions design RIG : - POSE_DOG - POSE_PET_BED_SIT - POSE_PET_BED_SLEEP - POSE_FURNITURE_SEAT - POSE_KNEEL_BOUND - STRUGGLE_BOUND - WALK_BOUND - SNEAK_BOUND 3 ajouts UX (P0/P1) : - POSE_SLEEP_BOUND — sleep avec restraints (P0) - POSE_UNCONSCIOUS — steady-state post-capture (P0) - FALL_BOUND — no flailing en chute (P1) Class-load force dans TiedUpMod.commonSetup via values() — sans ca, les ordinals ne sont pas assignes tant que l'enum n'est pas touche (init lazy JLS). LivingMotions (vanilla) est class-loaded naturellement par les patches rig, pas besoin de force. Tests : 3 cas (11 entries, ordinals uniques intra-enum, pas de collision avec LivingMotions apres class-load croise). --- .../com/tiedup/remake/core/TiedUpMod.java | 5 ++ .../remake/rig/anim/TiedUpLivingMotions.java | 47 +++++++++++ .../rig/anim/TiedUpLivingMotionsTest.java | 84 +++++++++++++++++++ 3 files changed, 136 insertions(+) create mode 100644 src/main/java/com/tiedup/remake/rig/anim/TiedUpLivingMotions.java create mode 100644 src/test/java/com/tiedup/remake/rig/anim/TiedUpLivingMotionsTest.java diff --git a/src/main/java/com/tiedup/remake/core/TiedUpMod.java b/src/main/java/com/tiedup/remake/core/TiedUpMod.java index 4882a9f..e6157e7 100644 --- a/src/main/java/com/tiedup/remake/core/TiedUpMod.java +++ b/src/main/java/com/tiedup/remake/core/TiedUpMod.java @@ -138,6 +138,11 @@ public class TiedUpMod { // Register dispenser behaviors (must be on main thread) event.enqueueWork(DispenserBehaviors::register); + // RIG Phase 3 — force class-load des motions custom TiedUp! pour assigner + // les universalOrdinal() via ExtendableEnumManager (init lazy JLS sinon). + // LivingMotions (vanilla EF) est class-loaded naturellement par les patches. + com.tiedup.remake.rig.anim.TiedUpLivingMotions.values(); + // RIG Phase 2 — dispatcher EntityType → EntityPatch (PLAYER Phase 2, NPCs Phase 5) event.enqueueWork(com.tiedup.remake.rig.patch.EntityPatchProvider::registerEntityPatches); diff --git a/src/main/java/com/tiedup/remake/rig/anim/TiedUpLivingMotions.java b/src/main/java/com/tiedup/remake/rig/anim/TiedUpLivingMotions.java new file mode 100644 index 0000000..8c3378b --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/anim/TiedUpLivingMotions.java @@ -0,0 +1,47 @@ +/* + * © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.anim; + +/** + * Motions custom TiedUp! — extension de {@link LivingMotions} (motions vanilla EF). + * + * Chaque valeur partage le meme {@link LivingMotion#ENUM_MANAGER} que + * {@link LivingMotions} : les universalOrdinal() sont assignes a la suite, sans + * collision, a condition que les deux enums soient class-loaded avant usage. + * + * Les 8 premieres motions correspondent au design original RIG (cf. + * docs/plans/rig/). Les 3 dernieres sont des ajouts UX (P0/P1) : + * - POSE_SLEEP_BOUND : sleep avec restraints (P0) + * - POSE_UNCONSCIOUS : steady-state post-capture (P0) + * - FALL_BOUND : fall sans flailing (P1) + * + * Class-load force dans {@code TiedUpMod.commonSetup} via {@link #values()} — + * sans ca, les ordinals ne sont pas assignes tant que l'enum n'est pas touche + * (JLS : init lazy). + */ +public enum TiedUpLivingMotions implements LivingMotion { + POSE_DOG, + POSE_PET_BED_SIT, + POSE_PET_BED_SLEEP, + POSE_FURNITURE_SEAT, + POSE_KNEEL_BOUND, + STRUGGLE_BOUND, + WALK_BOUND, + SNEAK_BOUND, + POSE_SLEEP_BOUND, // UX P0 — sleep avec restraints + POSE_UNCONSCIOUS, // UX P0 — steady-state post-capture + FALL_BOUND; // UX P1 — no flailing en chute + + final int id; + + TiedUpLivingMotions() { + this.id = LivingMotion.ENUM_MANAGER.assign(this); + } + + @Override + public int universalOrdinal() { + return this.id; + } +} diff --git a/src/test/java/com/tiedup/remake/rig/anim/TiedUpLivingMotionsTest.java b/src/test/java/com/tiedup/remake/rig/anim/TiedUpLivingMotionsTest.java new file mode 100644 index 0000000..98f32e6 --- /dev/null +++ b/src/test/java/com/tiedup/remake/rig/anim/TiedUpLivingMotionsTest.java @@ -0,0 +1,84 @@ +/* + * © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig.anim; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +/** + * Tests de {@link TiedUpLivingMotions} — verifie le nombre d'entries, l'unicite + * des universalOrdinal() et l'absence de collision avec {@link LivingMotions}. + * + * Aucun MC runtime requis — les deux enums sont des enums Java purs partageant + * le meme {@link LivingMotion#ENUM_MANAGER}. Le test force le class-load des + * deux en appelant values() pour reproduire ce que TiedUpMod.commonSetup fait + * a l'init mod. + */ +class TiedUpLivingMotionsTest { + + /** L'enum doit contenir exactement 11 motions (8 design + 3 UX P0/P1). */ + @Test + void values_has11Entries() { + assertEquals(11, TiedUpLivingMotions.values().length, + "TiedUpLivingMotions doit contenir 11 motions (8 design + 3 UX)"); + } + + /** + * Chaque valeur doit avoir un universalOrdinal() unique a l'interieur de + * l'enum. Garantit qu'il n'y a pas de collision dans + * ExtendableEnumManager.assign() pour les motions TiedUp!. + */ + @Test + void allOrdinals_areUnique() { + TiedUpLivingMotions[] values = TiedUpLivingMotions.values(); + long unique = Arrays.stream(values) + .mapToInt(TiedUpLivingMotions::universalOrdinal) + .distinct() + .count(); + assertEquals(values.length, unique, + "Chaque TiedUpLivingMotions doit avoir un universalOrdinal unique"); + } + + /** + * Apres class-load des deux enums, aucune collision d'universalOrdinal ne + * doit exister entre {@link LivingMotions} (vanilla EF) et + * {@link TiedUpLivingMotions} (custom TiedUp!). Ils partagent le meme + * ENUM_MANAGER, donc les ordinals sont assignes a la suite sans doublon. + * + * Note : l'ordre de class-load (LivingMotions d'abord ou + * TiedUpLivingMotions d'abord) n'a pas d'importance pour la non-collision, + * mais affecte les ordinals exacts — ce test verifie seulement l'unicite + * croisee, pas des valeurs precises. + */ + @Test + void ordinals_doNotCollideWithLivingMotionsVanilla() { + // Force class-load des deux enums (idempotent — values() trigger static init) + LivingMotions[] vanilla = LivingMotions.values(); + TiedUpLivingMotions[] custom = TiedUpLivingMotions.values(); + + Set allOrdinals = new HashSet<>(); + for (LivingMotions m : vanilla) { + allOrdinals.add(m.universalOrdinal()); + } + for (TiedUpLivingMotions m : custom) { + boolean added = allOrdinals.add(m.universalOrdinal()); + if (!added) { + throw new AssertionError( + "Collision universalOrdinal: TiedUpLivingMotions." + m.name() + + " (ordinal=" + m.universalOrdinal() + + ") collide avec une entree de LivingMotions" + ); + } + } + + assertEquals(vanilla.length + custom.length, allOrdinals.size(), + "La somme des ordinals distincts doit egaler vanilla.length + custom.length"); + } +}