diff --git a/src/main/java/com/tiedup/remake/rig/TiedUpArmatures.java b/src/main/java/com/tiedup/remake/rig/TiedUpArmatures.java new file mode 100644 index 0000000..c0f7d34 --- /dev/null +++ b/src/main/java/com/tiedup/remake/rig/TiedUpArmatures.java @@ -0,0 +1,193 @@ +/* + * Derived from Epic Fight (https://github.com/Epic-Fight/epicfight) + * by the Epic Fight Team, licensed under GPLv3. + * Modifications © 2026 TiedUp! Remake Contributors, distributed under GPLv3. + */ + +package com.tiedup.remake.rig; + +import java.util.LinkedHashMap; +import java.util.Map; + +import net.minecraft.resources.ResourceLocation; + +import com.tiedup.remake.rig.armature.HumanoidArmature; +import com.tiedup.remake.rig.armature.Joint; +import com.tiedup.remake.rig.asset.AssetAccessor; +import com.tiedup.remake.rig.math.OpenMatrix4f; + +/** + * Registry des armatures TiedUp exposé via {@link AssetAccessor} constants. + * + *
Cette classe construit le biped TiedUp from scratch en Java + * (hiérarchie + offsets identity). Suffisant pour débloquer le rendering RIG + * Phase 2.4 : les joints existent dans le map, {@code searchJointByName} + * fonctionne, le GLB → SkinnedMesh bridge a un mapping valide, etc.
+ * + *Phase 2.7 remplacera par un JSON Blender-authored hot-reloadable. + * Pour l'instant, les joints sont tous à l'identité (offset/rotation nuls). + * Visuellement ça donnera un biped "effondré" sur le point d'origine si on + * rend sans animation — c'est acceptable car :
+ *+ * Root + * ├─ Thigh_R ── Leg_R ── Knee_R + * ├─ Thigh_L ── Leg_L ── Knee_L + * └─ Torso + * └─ Chest + * ├─ Head + * ├─ Shoulder_R ── Arm_R ── Elbow_R ── Hand_R ── Tool_R + * └─ Shoulder_L ── Arm_L ── Elbow_L ── Hand_L ── Tool_L + *+ * + *
Noms conservés verbatim EF (pas renommés en TiedUp style) car :
+ *Si construit plus tôt (ex. static init combat-lourd avant FMLCommonSetup) + * risquerait de toucher des classes client — garder cet accès lazy si les + * call sites évoluent.
+ */ + private static HumanoidArmature BIPED_INSTANCE; + + /** + * AssetAccessor biped biped TiedUp. Construit à la première lecture de + * {@link AssetAccessor#get()}. + * + *Utilisé par {@link com.tiedup.remake.rig.patch.PlayerPatch#getArmature()} + * et par les futurs {@code StaticAnimation(… , BIPED)} Phase 2.7+.
+ */ + public static final AssetAccessorToutes les transforms sont identity — Phase 2.7 remplacera par les + * offsets Blender mesurés (cf. doc header).
+ */ + private static HumanoidArmature buildBiped() { + // Tous les joints (ID == ordre d'insertion dans la map). + // On utilise LinkedHashMap pour garantir l'ordre d'itération stable + // (OpenMatrix4f.allocateMatrixArray dimensionne sur jointCount). + MapVersion minimale : {@code overrideRender=true} (on veut que le renderer - * patched intercepte et dispatch au RIG), {@code getArmature=null} stub (TODO - * Phase 2.4), {@code updateMotion} no-op (Phase 2.7).
+ *Hérite tout de {@link PlayerPatch} : + * {@link #overrideRender()} = true, armature biped, updateMotion stub. + * Pour un remote player on veut systématiquement le rendering RIG — pas de + * cas où on voudrait le modèle vanilla MC (qui perdrait les items bondage + * RIG-attached Phase 3).
+ * + *Différence avec {@link LocalPlayerPatch} : ce dernier override + * {@link #overrideRender()} pour désactiver le render RIG en first-person + * (sinon on verrait l'intérieur du mesh). Les remote players ne sont jamais + * en first-person du point de vue de l'observer → pas besoin.
* *Forke conceptuellement {@code yesman.epicfight.client.world.capabilites.entitypatch.player.AbstractClientPlayerPatch} * (EF 479 LOC) mais réécrit from scratch (D-04) car ~80% du contenu original - * est combat/skill non réutilisable pour TiedUp.
+ * est combat/skill non réutilisable pour TiedUp (slim/default model switch, + * cape handling, skin tick — tout ça pourrait être utile Phase 5 si on + * restaure le rendering custom skin layer). + * + * @paramActuellement retourne toujours {@code false} — aucun item ne demande + * ce hide. Sera re-implémenté Phase 3 quand le + * {@code PlayerArmHideEventHandler} V2 sera porté en jointMask-based + * logic côté StaticAnimation (cf. + * {@code docs/plans/rig/V3_REWORK_BACKLOG.md} V3-REW-01).
+ * + *Appelé depuis le renderer patched Phase 2.5+ : si true, skip le + * draw du mesh player (mais draw les items bondage attachés).
+ * + * @return true si le player doit être invisible en first-person + */ + public boolean isFirstPersonHidden() { + // TODO Phase 3 (V3-REW-01) : check equipped items pour wrap / latex_sack. + return false; + } } diff --git a/src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java b/src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java index 829bf2b..f6cb02a 100644 --- a/src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java +++ b/src/main/java/com/tiedup/remake/rig/patch/LocalPlayerPatch.java @@ -6,25 +6,61 @@ package com.tiedup.remake.rig.patch; +import net.minecraft.client.Minecraft; import net.minecraft.client.player.LocalPlayer; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; /** - * Stub Phase 2.3 — patch spécifique au joueur local (self). Spécialisation de - * {@link ClientPlayerPatch} pour les hooks first-person / caméra / input - * capture bondage-specific (struggle keys, adjustment menu). + * Patch spécifique au joueur local (self). Override + * {@link #overrideRender()} pour gérer le cas first-person : * - *Version minimale : hérite de {@link ClientPlayerPatch} sans override. - * Phase 2.4 ajoutera les hooks first-person hide (arms/hands invisibles sous - * wrap/latex_sack), camera sync leash, etc.
+ *Forke conceptuellement {@code yesman.epicfight.client.world.capabilites.entitypatch.player.LocalPlayerPatch} - * (EF 572 LOC) mais réécrit from scratch (D-04) car skill UI state / input / - * camera cinematics non réutilisables.
+ *Pourquoi la check {@code entity == Minecraft.getInstance().player} : + * {@link LocalPlayerPatch} est attaché uniquement au LocalPlayer (cf. + * {@link EntityPatchProvider#registerEntityPatchesClient()}), donc en pratique + * {@code this.original == Minecraft.getInstance().player} toujours. Le check + * est une ceinture-bretelles au cas où le dispatcher change un jour pour + * attacher ce patch à autre chose (très improbable).
+ * + *Pattern EF équivalent : {@code LocalPlayerPatch.java:143-152} — + * même logique mais EF ajoute un toggle {@code ClientConfig.enableAnimatedFirstPersonModel} + * pour ceux qui veulent le biped rendu même en FP. TiedUp peut l'ajouter + * plus tard si demande gameplay, mais par défaut FP = vanilla.
+ * + *Hooks first-person hide specific bondage items (wrap / latex_sack / + * blindfold = vision obstruée) → Phase 3 via + * {@link ClientPlayerPatch#isFirstPersonHidden()} (V3-REW-01).
*/ @OnlyIn(Dist.CLIENT) public class LocalPlayerPatch extends ClientPlayerPatchÉtoffé à partir du stub Phase 0 pour :
+ *Ce qui manque vs EF PlayerPatch (766 LOC), voulu :
+ *TiedUp n'a pas de combat — ces features seraient dead code. Si on en + * veut une (ex. stamina pour struggle), on l'ajoutera au cas par cas (D-04).
*/ public abstract class PlayerPatchSource : EF {@code PlayerPatch:82}.
+ */ + protected static final float PLAYER_SCALE = 15.0F / 16.0F; + + /** + * Override — stub sans transition / sans vélocité. + * + *Phase 2.7+ implémentera la détection de motion (walk/run/sneak/sit/ + * swim/kneel pour TiedUp) via vélocité + state checks. Ici on ne fait + * rien pour que les {@link #currentLivingMotion} restent à IDLE par + * défaut (cf. {@link LivingEntityPatch}).
+ * + * @param considerInaction paramètre EF legacy — si true, l'impl complète + * doit bloquer la transition de motion si l'entité + * est dans une {@code inaction()}. Pas utilisé ici. + */ + @Override + public void updateMotion(boolean considerInaction) { + // Stub Phase 2.4 — pas de motion detection. + // Phase 2.7 : cf. EF LivingEntityPatch.updateMotion (velocity + state + // machine) + mapping sur LivingMotions TiedUp (idle/walk/kneel/sit). + } + + /** + * Retourne l'armature biped TiedUp — identique pour tous les players. + * + *Phase 2.4 : version procédurale ({@link TiedUpArmatures#BIPED} + * construit from scratch). Phase 2.7 remplacera par un chargement JSON + * avec offsets Blender-authored.
+ * + *Pattern EF : + * {@code AbstractClientPlayerPatch.java:~70} expose {@code this.armature} + * initialisé au constructor. On renvoie directement le singleton — léger + * et thread-safe (construction lazy dans {@link TiedUpArmatures#BIPED}).
+ */ + @Override + public HumanoidArmature getArmature() { + return TiedUpArmatures.BIPED.get(); + } + + /** + * Override — tous les players passent par le renderer RIG patched. + * + *{@link ServerPlayerPatch} ré-override à false (le serveur ne rend + * rien). {@link LocalPlayerPatch} ré-override pour gérer le cas + * first-person (cf. doc là-bas).
+ */ + @Override + public boolean overrideRender() { + return true; + } + + /** + * Model matrix pour le render : position identity (le renderer applique + * déjà la translation) + rotation yaw (le corps suit la caméra) + scale + * {@value #PLAYER_SCALE}. + * + *Simplifié vs EF : pas de handling {@code modelYRot} (self-managed + * rotation lerp pour turning lock) et pas de {@code ridingEntity} override + * — Phase 2.7+ si on ajoute un système de mount TiedUp (maid pet sitting + * etc.).
+ * + *Baby support (half scale) — EF applique 0.5 si {@code isBaby}. On + * garde pour cohérence (les NPCs Damsel n'ont pas d'état baby mais + * VillagerMCA si un jour on les patch le veut).
+ */ + @Override + public OpenMatrix4f getModelMatrix(float partialTick) { + float scale = (this.original.isBaby() ? 0.5F : 1.0F) * PLAYER_SCALE; + + // Signature : xPosO, xPos, yPosO, yPos, zPosO, zPos, xRotO, xRot, + // yRotO, yRot, partialTick, scaleX, scaleY, scaleZ + // On ignore pos/xRot (delta pose) — l'entity renderer applique déjà + // la position monde. Seul le yRot (yaw corps, pas tête) est utile + // pour que le mesh s'oriente avec l'entity. + return MathUtils.getModelMatrixIntegral( + 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, 0.0F, + 0.0F, 0.0F, + this.original.yBodyRotO, this.original.yBodyRot, + partialTick, scale, scale, scale + ); + } + + /** + * Hook {@link LivingEntityPatch#initAnimator(Animator)} : bind la motion + * IDLE sur l'animation "ne fait rien" par défaut. Phase 2.7 remplacera + * par {@code TiedUpAnimationRegistry.CONTEXT_STAND_IDLE} avec quelques + * keyframes de balancement. + * + *L'ordre EF ajoute ~25 motions différentes (WALK, RUN, SNEAK, SIT, + * SLEEP, etc.). On se limite à IDLE Phase 2.4 — ajouter les autres + * sans anim source = pollution registre pour rien. Au fur et à mesure + * que les JSON co-authored arrivent (Phase 2.7 / 4), on ajoute les + * binds correspondants.
+ */ + @Override + protected void initAnimator(Animator animator) { + super.initAnimator(animator); + animator.addLivingAnimation(LivingMotions.IDLE, TiedUpRigRegistry.EMPTY_ANIMATION); + } + } diff --git a/src/main/java/com/tiedup/remake/rig/patch/ServerPlayerPatch.java b/src/main/java/com/tiedup/remake/rig/patch/ServerPlayerPatch.java index 2d56af0..b1ea197 100644 --- a/src/main/java/com/tiedup/remake/rig/patch/ServerPlayerPatch.java +++ b/src/main/java/com/tiedup/remake/rig/patch/ServerPlayerPatch.java @@ -8,45 +8,41 @@ package com.tiedup.remake.rig.patch; import net.minecraft.server.level.ServerPlayer; -import com.tiedup.remake.rig.armature.Armature; -import com.tiedup.remake.rig.math.OpenMatrix4f; - /** - * Stub Phase 2.3 — patch côté serveur pour les joueurs. Version minimale pour - * débloquer le dispatch via {@link EntityPatchProvider}. La version complète - * (kidnap state sync, struggle progression, ownership) est Phase 2.4+. + * Patch côté serveur pour les joueurs. Hérite tout de {@link PlayerPatch} — + * on ne garde qu'un seul override : {@link #overrideRender()} forcé à + * {@code false}. * - *Garanties actuelles :
+ *Pourquoi override render → false : le serveur ne rend rien + * visuellement, mais l'animator continue de tourner pour calculer la pose + * "aveugle" (pos joints à un tick donné). Cette pose sert au tracker serveur + * (combat hitboxes EF, hook AI TiedUp). {@link PlayerPatch#overrideRender()} + * retourne {@code true} par défaut → si on oubliait l'override, un dispatcher + * de rendering théorique côté serveur (il n'y en a pas actuellement, mais + * l'API publique le permet) se déclencherait à tort.
+ * + *Ce qui est dans PlayerPatch et hérité ici :
*Phase 2.7+ : {@code serverTick} override pour poser motion + sync aux + * clients via packet (cf. EF {@code PlayerPatch.serverTick}). Phase 3+ : + * hooks struggle / kidnap state ici.
*/ public class ServerPlayerPatch extends PlayerPatch