Phase 2.4 : étoffer PlayerPatch stubs + biped armature procédurale
PlayerPatch : getArmature→TiedUpArmatures.BIPED, overrideRender→true, getModelMatrix avec PLAYER_SCALE=15/16, initAnimator bind IDLE→EMPTY. ServerPlayerPatch : ré-override overrideRender→false (le serveur ne rend pas). ClientPlayerPatch : stub isFirstPersonHidden() pour Phase 3 (V3-REW-01). LocalPlayerPatch : override render→false si on est soi-même en first-person (laisse rendre les bras vanilla), true sinon. TiedUpArmatures.BIPED : HumanoidArmature procédurale 20 joints identity (Root → Thigh/Leg/Knee_R/L, Torso → Chest → Head + Shoulder/Arm/Elbow/ Hand/Tool_R/L). Phase 2.7 remplacera par JSON Blender-authored. Fixe P2-RISK-01 (InitAnimatorEvent listeners NPE si getArmature()=null). Tests : 11 bridge tests GREEN, full suite GREEN, compile clean.
This commit is contained in:
193
src/main/java/com/tiedup/remake/rig/TiedUpArmatures.java
Normal file
193
src/main/java/com/tiedup/remake/rig/TiedUpArmatures.java
Normal file
@@ -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.
|
||||
*
|
||||
* <h2>Phase 2.4 — version procédurale</h2>
|
||||
*
|
||||
* <p>Cette classe construit le biped TiedUp <b>from scratch en Java</b>
|
||||
* (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.</p>
|
||||
*
|
||||
* <p><b>Phase 2.7 remplacera par un JSON Blender-authored hot-reloadable</b>.
|
||||
* 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 :</p>
|
||||
* <ul>
|
||||
* <li>Phase 2.4 n'a pas encore de renderer player patched complet (Phase 2.5)</li>
|
||||
* <li>Phase 2.7 rechargera des offsets depuis {@code assets/tiedup/armatures/biped.json}
|
||||
* co-authored via addon Blender (cf. MIGRATION.md §2.2.1)</li>
|
||||
* <li>Les tests existants `GltfToSkinnedMeshTest` utilisent déjà le même pattern
|
||||
* (Armature identity, {@code bakeOriginMatrices}) et sont verts</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2>Hiérarchie biped EF (20 joints)</h2>
|
||||
*
|
||||
* <pre>
|
||||
* 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
|
||||
* </pre>
|
||||
*
|
||||
* <p><b>Noms conservés verbatim EF</b> (pas renommés en TiedUp style) car :</p>
|
||||
* <ul>
|
||||
* <li>Le {@code VanillaModelTransformer} forké EF (Phase 2.2) référence ces
|
||||
* noms dans ses AABB / {@code WEIGHT_ALONG_Y} / {@code yClipCoord}</li>
|
||||
* <li>Le bridge GLB ({@code LegacyJointNameMapper}) mappe déjà les joints
|
||||
* PlayerAnimator legacy sur ces noms-là</li>
|
||||
* <li>Re-authored serait un risque régression sans gain fonctionnel</li>
|
||||
* </ul>
|
||||
*/
|
||||
public final class TiedUpArmatures {
|
||||
|
||||
private TiedUpArmatures() {}
|
||||
|
||||
/** ResourceLocation registry pour l'accessor (même path que EF pour cohérence doc). */
|
||||
private static final ResourceLocation BIPED_REGISTRY_NAME =
|
||||
ResourceLocation.fromNamespaceAndPath(TiedUpRigConstants.MODID, "armature/biped");
|
||||
|
||||
/**
|
||||
* Singleton biped — chargé à la première ref (init order :
|
||||
* {@link TiedUpRigConstants} → chaînes d'ids → ici via
|
||||
* {@link com.tiedup.remake.rig.patch.PlayerPatch#getArmature()}).
|
||||
*
|
||||
* <p>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.</p>
|
||||
*/
|
||||
private static HumanoidArmature BIPED_INSTANCE;
|
||||
|
||||
/**
|
||||
* AssetAccessor biped biped TiedUp. Construit à la première lecture de
|
||||
* {@link AssetAccessor#get()}.
|
||||
*
|
||||
* <p>Utilisé par {@link com.tiedup.remake.rig.patch.PlayerPatch#getArmature()}
|
||||
* et par les futurs {@code StaticAnimation(… , BIPED)} Phase 2.7+.</p>
|
||||
*/
|
||||
public static final AssetAccessor<HumanoidArmature> BIPED = new AssetAccessor<>() {
|
||||
@Override
|
||||
public HumanoidArmature get() {
|
||||
if (BIPED_INSTANCE == null) {
|
||||
BIPED_INSTANCE = buildBiped();
|
||||
}
|
||||
return BIPED_INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation registryName() {
|
||||
return BIPED_REGISTRY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inRegistry() {
|
||||
// Pas dans un JsonAssetLoader registry tant que Phase 2.7 n'a pas
|
||||
// posé le biped.json. Une fois fait, ce flag repassera à true via
|
||||
// un nouveau registry layer.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Build procédural de la hiérarchie biped EF. 20 joints, IDs 0..19 dans
|
||||
* l'ordre d'insertion (important pour {@link Joint#getId()} stabilité
|
||||
* inter-runs).
|
||||
*
|
||||
* <p>Toutes les transforms sont identity — Phase 2.7 remplacera par les
|
||||
* offsets Blender mesurés (cf. doc header).</p>
|
||||
*/
|
||||
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).
|
||||
Map<String, Joint> joints = new LinkedHashMap<>(20);
|
||||
|
||||
// Pattern EF : tous les joints démarrent avec une localTransform identity.
|
||||
// bakeOriginMatrices() calcule ensuite les toOrigin relatives à la
|
||||
// hiérarchie parent→enfant.
|
||||
Joint root = joint(joints, "Root", 0);
|
||||
|
||||
// Jambes
|
||||
Joint thighR = joint(joints, "Thigh_R", 1);
|
||||
Joint legR = joint(joints, "Leg_R", 2);
|
||||
Joint kneeR = joint(joints, "Knee_R", 3);
|
||||
Joint thighL = joint(joints, "Thigh_L", 4);
|
||||
Joint legL = joint(joints, "Leg_L", 5);
|
||||
Joint kneeL = joint(joints, "Knee_L", 6);
|
||||
|
||||
// Tronc
|
||||
Joint torso = joint(joints, "Torso", 7);
|
||||
Joint chest = joint(joints, "Chest", 8);
|
||||
Joint head = joint(joints, "Head", 9);
|
||||
|
||||
// Bras droit
|
||||
Joint shoulderR = joint(joints, "Shoulder_R", 10);
|
||||
Joint armR = joint(joints, "Arm_R", 11);
|
||||
Joint elbowR = joint(joints, "Elbow_R", 12);
|
||||
Joint handR = joint(joints, "Hand_R", 13);
|
||||
Joint toolR = joint(joints, "Tool_R", 14);
|
||||
|
||||
// Bras gauche
|
||||
Joint shoulderL = joint(joints, "Shoulder_L", 15);
|
||||
Joint armL = joint(joints, "Arm_L", 16);
|
||||
Joint elbowL = joint(joints, "Elbow_L", 17);
|
||||
Joint handL = joint(joints, "Hand_L", 18);
|
||||
Joint toolL = joint(joints, "Tool_L", 19);
|
||||
|
||||
// Hiérarchie. addSubJoints est idempotent (skip si déjà présent) — safe
|
||||
// de le réappeler, utile si on étend plus tard.
|
||||
root.addSubJoints(thighR, thighL, torso);
|
||||
thighR.addSubJoints(legR);
|
||||
legR.addSubJoints(kneeR);
|
||||
thighL.addSubJoints(legL);
|
||||
legL.addSubJoints(kneeL);
|
||||
|
||||
torso.addSubJoints(chest);
|
||||
chest.addSubJoints(head, shoulderR, shoulderL);
|
||||
|
||||
shoulderR.addSubJoints(armR);
|
||||
armR.addSubJoints(elbowR);
|
||||
elbowR.addSubJoints(handR);
|
||||
handR.addSubJoints(toolR);
|
||||
|
||||
shoulderL.addSubJoints(armL);
|
||||
armL.addSubJoints(elbowL);
|
||||
elbowL.addSubJoints(handL);
|
||||
handL.addSubJoints(toolL);
|
||||
|
||||
HumanoidArmature arm = new HumanoidArmature("biped", joints.size(), root, joints);
|
||||
|
||||
// Calcule les toOrigin relatifs — obligatoire après la construction
|
||||
// sinon Pose.orElseEmpty retournerait des matrices non initialisées.
|
||||
arm.bakeOriginMatrices();
|
||||
|
||||
return arm;
|
||||
}
|
||||
|
||||
private static Joint joint(Map<String, Joint> target, String name, int id) {
|
||||
Joint j = new Joint(name, id, new OpenMatrix4f());
|
||||
target.put(name, j);
|
||||
return j;
|
||||
}
|
||||
}
|
||||
@@ -10,45 +10,50 @@ import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import com.tiedup.remake.rig.armature.Armature;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
|
||||
/**
|
||||
* Stub Phase 2.3 — patch côté client pour les joueurs remote (autres joueurs
|
||||
* dans une session multi). Etoffé Phase 2.4 avec la logique cape / scale /
|
||||
* slim vs default model selection.
|
||||
* Patch côté client pour les joueurs remote (autres joueurs en session multi).
|
||||
*
|
||||
* <p>Version 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).</p>
|
||||
* <p>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).</p>
|
||||
*
|
||||
* <p><b>Différence avec {@link LocalPlayerPatch}</b> : 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.</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
* 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).</p>
|
||||
*
|
||||
* @param <T> concrete type (remote player, et fallback pour LocalPlayer via
|
||||
* {@link LocalPlayerPatch})
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ClientPlayerPatch<T extends AbstractClientPlayer> extends PlayerPatch<T> {
|
||||
|
||||
@Override
|
||||
public void updateMotion(boolean considerInaction) {
|
||||
// no-op stub — Phase 2.7
|
||||
}
|
||||
|
||||
@Override
|
||||
public Armature getArmature() {
|
||||
// TODO Phase 2.4 — retourner TiedUpRigRegistry.BIPED.get()
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideRender() {
|
||||
// On veut que le render pipeline patched prenne la main pour les
|
||||
// remote players visibles.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenMatrix4f getModelMatrix(float partialTick) {
|
||||
return getMatrix(partialTick);
|
||||
}
|
||||
/**
|
||||
* Placeholder pour la logique "cacher le player en first-person pour les
|
||||
* items de type wrap / latex_sack / cape-over-head" (V3-REW-01, item
|
||||
* rework Phase 3).
|
||||
*
|
||||
* <p>Actuellement 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).</p>
|
||||
*
|
||||
* <p>Appelé depuis le renderer patched Phase 2.5+ : si true, skip le
|
||||
* draw du mesh player (mais draw les items bondage attachés).</p>
|
||||
*
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 :
|
||||
*
|
||||
* <p>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.</p>
|
||||
* <ul>
|
||||
* <li><b>First-person (F5 = first)</b> : retourne {@code false} — on laisse
|
||||
* le rendu vanilla Minecraft prendre la main (bras en FP, item held,
|
||||
* overlay mains). Rendre le biped TiedUp en FP donnerait une vue
|
||||
* depuis l'intérieur du mesh, illisible.</li>
|
||||
* <li><b>Third-person (F5 = third, either view)</b> ou tout autre cas :
|
||||
* retourne {@code true} — le renderer RIG patched prend la main et
|
||||
* dessine le biped TiedUp comme pour les autres players.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>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.</p>
|
||||
* <p><b>Pourquoi la check {@code entity == Minecraft.getInstance().player}</b> :
|
||||
* {@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).</p>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*
|
||||
* <p>Hooks first-person hide specific bondage items (wrap / latex_sack /
|
||||
* blindfold = vision obstruée) → Phase 3 via
|
||||
* {@link ClientPlayerPatch#isFirstPersonHidden()} (V3-REW-01).</p>
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class LocalPlayerPatch extends ClientPlayerPatch<LocalPlayer> {
|
||||
|
||||
// Hooks first-person / caméra / input → Phase 2.4
|
||||
/**
|
||||
* @return {@code false} si on est en first-person sur soi-même (laisse
|
||||
* rendre le vanilla), {@code true} dans tous les autres cas.
|
||||
*/
|
||||
@Override
|
||||
public boolean overrideRender() {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
// mc.player peut être null durant un rejoin (~1 tick entre
|
||||
// disconnect et respawn). Dans ce cas pas de FP à gérer, on tombe
|
||||
// sur le comportement parent (true).
|
||||
if (mc.player != null && this.original == mc.player) {
|
||||
if (mc.options.getCameraType().isFirstPerson()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return super.overrideRender();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,10 +8,151 @@ package com.tiedup.remake.rig.patch;
|
||||
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
import com.tiedup.remake.rig.TiedUpArmatures;
|
||||
import com.tiedup.remake.rig.TiedUpRigRegistry;
|
||||
import com.tiedup.remake.rig.anim.Animator;
|
||||
import com.tiedup.remake.rig.anim.LivingMotions;
|
||||
import com.tiedup.remake.rig.armature.HumanoidArmature;
|
||||
import com.tiedup.remake.rig.math.MathUtils;
|
||||
import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
|
||||
/**
|
||||
* Stub RIG Phase 0 — patch de capability attaché à un {@link Player}.
|
||||
* Re-implém complète Phase 2 (séparation ClientPlayerPatch / ServerPlayerPatch,
|
||||
* input handling, first-person, cam sync).
|
||||
* RIG Phase 2.4 — patch de capability attaché à un {@link Player}.
|
||||
*
|
||||
* <p>Étoffé à partir du stub Phase 0 pour :</p>
|
||||
* <ul>
|
||||
* <li>Fournir l'{@link #getArmature() armature biped} TiedUp
|
||||
* ({@link TiedUpArmatures#BIPED})</li>
|
||||
* <li>Activer le rendering RIG patched ({@link #overrideRender()} = true)
|
||||
* — {@link ServerPlayerPatch} ré-override à false et
|
||||
* {@link LocalPlayerPatch} gère le cas first-person</li>
|
||||
* <li>Fournir un {@link #getModelMatrix(float)} avec scale player vanilla
|
||||
* ({@value #PLAYER_SCALE}) — cf. EF {@code PlayerPatch:82,176}</li>
|
||||
* <li>Stub {@link #initAnimator(Animator)} qui bind
|
||||
* {@code LivingMotions.IDLE → EMPTY_ANIMATION} (Phase 2.7 remplacera par
|
||||
* {@code CONTEXT_STAND_IDLE} co-authored)</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p><b>Ce qui manque vs EF PlayerPatch (766 LOC)</b>, voulu :</p>
|
||||
* <ul>
|
||||
* <li>Stamina system ({@code STAMINA} EntityDataAccessor + regen logic)</li>
|
||||
* <li>PlayerMode VANILLA/EPICFIGHT toggle</li>
|
||||
* <li>modelYRot sync / turningLocked handling</li>
|
||||
* <li>xo/yo/zo previous pos caching</li>
|
||||
* <li>PlayerEventListener — remplacé par SystemMessageManager/events TiedUp</li>
|
||||
* <li>Skill system entièrement</li>
|
||||
* <li>Toute la logique attaque / damage / offhand / armor negation</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>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).</p>
|
||||
*/
|
||||
public abstract class PlayerPatch<T extends Player> extends LivingEntityPatch<T> {
|
||||
|
||||
/**
|
||||
* Scale vanilla player EF-identique (15/16 ≈ 0.9375). Le modèle vanilla
|
||||
* Minecraft rend le joueur à 15/16 de sa taille logique — si on ne
|
||||
* compense pas, le skinned mesh apparaît "trop grand" comparé à la hitbox.
|
||||
*
|
||||
* <p>Source : EF {@code PlayerPatch:82}.</p>
|
||||
*/
|
||||
protected static final float PLAYER_SCALE = 15.0F / 16.0F;
|
||||
|
||||
/**
|
||||
* Override — stub sans transition / sans vélocité.
|
||||
*
|
||||
* <p>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}).</p>
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* <p>Phase 2.4 : version procédurale ({@link TiedUpArmatures#BIPED}
|
||||
* construit from scratch). Phase 2.7 remplacera par un chargement JSON
|
||||
* avec offsets Blender-authored.</p>
|
||||
*
|
||||
* <p>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}).</p>
|
||||
*/
|
||||
@Override
|
||||
public HumanoidArmature getArmature() {
|
||||
return TiedUpArmatures.BIPED.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Override — tous les players passent par le renderer RIG patched.
|
||||
*
|
||||
* <p>{@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).</p>
|
||||
*/
|
||||
@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}.
|
||||
*
|
||||
* <p>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.).</p>
|
||||
*
|
||||
* <p>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).</p>
|
||||
*/
|
||||
@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.
|
||||
*
|
||||
* <p>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.</p>
|
||||
*/
|
||||
@Override
|
||||
protected void initAnimator(Animator animator) {
|
||||
super.initAnimator(animator);
|
||||
animator.addLivingAnimation(LivingMotions.IDLE, TiedUpRigRegistry.EMPTY_ANIMATION);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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}.
|
||||
*
|
||||
* <p>Garanties actuelles :</p>
|
||||
* <p><b>Pourquoi override render → false</b> : 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.</p>
|
||||
*
|
||||
* <p><b>Ce qui est dans PlayerPatch et hérité ici</b> :</p>
|
||||
* <ul>
|
||||
* <li>{@code overrideRender() = false} — serveur ne rend rien, pas de besoin
|
||||
* d'intercepter le render pipeline</li>
|
||||
* <li>{@code getArmature() = null} — le serveur n'a pas besoin de mesh data,
|
||||
* il joue des animations "blind" (calcule la pose pour syncer aux clients).
|
||||
* Sera fixé en Phase 2.4 avec un fallback vers {@code TiedUpRigRegistry.BIPED}.</li>
|
||||
* <li>{@code updateMotion} no-op — Phase 2.7 hook tick réel</li>
|
||||
* <li>{@code getArmature()} → {@link com.tiedup.remake.rig.TiedUpArmatures#BIPED}</li>
|
||||
* <li>{@code getModelMatrix(partialTick)} — inutile côté serveur mais pas de
|
||||
* coût à le garder (pas appelé)</li>
|
||||
* <li>{@code updateMotion(boolean)} no-op Phase 2.4</li>
|
||||
* <li>{@code initAnimator} bind IDLE → EMPTY_ANIMATION</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>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.</p>
|
||||
*/
|
||||
public class ServerPlayerPatch extends PlayerPatch<ServerPlayer> {
|
||||
|
||||
@Override
|
||||
public void updateMotion(boolean considerInaction) {
|
||||
// no-op stub — Phase 2.7
|
||||
}
|
||||
|
||||
@Override
|
||||
public Armature getArmature() {
|
||||
// TODO Phase 2.4 — retourner TiedUpRigRegistry.BIPED.get()
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean overrideRender() {
|
||||
// Serveur ne rend rien.
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenMatrix4f getModelMatrix(float partialTick) {
|
||||
return getMatrix(partialTick);
|
||||
}
|
||||
/**
|
||||
* Override à false — le serveur n'intercepte jamais le render (il ne rend
|
||||
* pas). Voir doc classe pour pourquoi c'est important malgré l'absence
|
||||
* de renderer serveur actuel.
|
||||
*/
|
||||
@Override
|
||||
public boolean overrideRender() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user