Phase 2.3 review fixes : P2-BUG-01/02/03 + RISK-02
Résout les findings P0 remontés par la review post-Phase 2.3 (@4780c96).
P2-BUG-01 — Pipeline RIG dormant au runtime
EntityPatchProvider.registerEntityPatches() et registerEntityPatchesClient()
étaient définis mais JAMAIS appelés depuis TiedUpMod setups → CAPABILITIES
map vide → aucun patch ne se crée, pipeline entier dormant.
Fix :
- commonSetup : event.enqueueWork(EntityPatchProvider::registerEntityPatches)
- ClientModEvents.onClientSetup : event.enqueueWork(
EntityPatchProvider::registerEntityPatchesClient) avant BondageAnimationManager.init
P2-BUG-02 — Memory leak LazyOptional non invalidée
EntityPatchProvider.optional jamais invalidated → chaque respawn/dim change
fuit patch + animator + armature.
Fix :
- EntityPatchProvider.invalidate() public méthode qui appelle optional.invalidate()
- TiedUpCapabilityEvents.attachEntityCapability : event.addListener(provider::invalidate)
après addCapability. Pattern aligné sur V2BondageEquipmentProvider existant.
P2-BUG-03 — NPE latent HumanoidModelBaker.bakeArmor
Ligne 88 retournait entityMesh.getHumanoidArmorModel(slot).get() mais le
getter retourne null (Phase 0 strip S-03 : Meshes.HELMET/CHESTPLATE/LEGGINS/BOOTS
strippés). Null-check + fallback null + commentaire pointant vers V3-REW-04.
P2-RISK-02 — @OnlyIn(Dist.CLIENT) sur transformers
VanillaModelTransformer, HumanoidModelTransformer, HumanoidModelBaker
importent HumanoidModel/PoseStack (client-only). Risque NoClassDefFoundError
si code serveur touche HumanoidModelBaker.VANILLA_TRANSFORMER static field.
Fix : @OnlyIn(Dist.CLIENT) sur les 3 classes.
P2-RISK-01/03 + SMELL-01/02/03 tracés dans docs/plans/rig/PHASE0_DEGRADATIONS.md
Phase 2.1-2.3 findings section.
Compile BUILD SUCCESSFUL + 11 tests bridge GREEN maintenus.
This commit is contained in:
@@ -137,6 +137,9 @@ public class TiedUpMod {
|
||||
|
||||
// Register dispenser behaviors (must be on main thread)
|
||||
event.enqueueWork(DispenserBehaviors::register);
|
||||
|
||||
// RIG Phase 2 — dispatcher EntityType → EntityPatch (PLAYER Phase 2, NPCs Phase 5)
|
||||
event.enqueueWork(com.tiedup.remake.rig.patch.EntityPatchProvider::registerEntityPatches);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,6 +188,9 @@ public class TiedUpMod {
|
||||
|
||||
// Initialize animation system
|
||||
event.enqueueWork(() -> {
|
||||
// RIG Phase 2 — override client dispatch PLAYER → Local/Client/ServerPlayerPatch
|
||||
com.tiedup.remake.rig.patch.EntityPatchProvider.registerEntityPatchesClient();
|
||||
|
||||
// Initialize unified BondageAnimationManager
|
||||
com.tiedup.remake.client.animation.BondageAnimationManager.init();
|
||||
LOGGER.info("BondageAnimationManager initialized");
|
||||
|
||||
@@ -32,11 +32,14 @@ import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ArmorItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.registries.ForgeRegistries;
|
||||
import com.tiedup.remake.rig.mesh.SkinnedMesh;
|
||||
import com.tiedup.remake.rig.mesh.HumanoidMesh;
|
||||
import com.tiedup.remake.rig.TiedUpRigConstants;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class HumanoidModelBaker {
|
||||
static final Map<ResourceLocation, SkinnedMesh> BAKED_MODELS = Maps.newHashMap();
|
||||
static final List<HumanoidModelTransformer> MODEL_TRANSFORMERS = Lists.newArrayList();
|
||||
@@ -85,7 +88,12 @@ public class HumanoidModelBaker {
|
||||
|
||||
if (!EXCEPTIONAL_MODELS.contains(armorItem)) {
|
||||
if (forgeModel == originalModel || !(forgeModel instanceof HumanoidModel humanoidModel)) {
|
||||
return entityMesh.getHumanoidArmorModel(slot).get();
|
||||
// RIG Phase 0 : Meshes.HELMET/CHESTPLATE/LEGGINS/BOOTS strippés →
|
||||
// HumanoidMesh.getHumanoidArmorModel(slot) retourne null.
|
||||
// Safe-guard ici pour éviter NPE si bakeArmor est appelé avant que
|
||||
// V3-REW-04 soit implémenté (armor rendering rework).
|
||||
var armorAccessor = entityMesh.getHumanoidArmorModel(slot);
|
||||
return armorAccessor != null ? armorAccessor.get() : null;
|
||||
}
|
||||
|
||||
for (HumanoidModelTransformer modelTransformer : MODEL_TRANSFORMERS) {
|
||||
|
||||
@@ -14,10 +14,14 @@ import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.client.model.HumanoidModel;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import com.tiedup.remake.rig.mesh.MeshPartDefinition;
|
||||
import com.tiedup.remake.rig.mesh.SingleGroupVertexBuilder;
|
||||
import com.tiedup.remake.rig.mesh.SkinnedMesh;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public abstract class HumanoidModelTransformer {
|
||||
public abstract SkinnedMesh transformArmorModel(HumanoidModel<?> humanoidModel);
|
||||
|
||||
|
||||
@@ -36,8 +36,12 @@ import com.tiedup.remake.rig.math.OpenMatrix4f;
|
||||
import com.tiedup.remake.rig.math.QuaternionUtils;
|
||||
import com.tiedup.remake.rig.math.Vec2f;
|
||||
import com.tiedup.remake.rig.math.Vec3f;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
|
||||
import com.tiedup.remake.rig.mixin.client.MixinAgeableListModel;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class VanillaModelTransformer extends HumanoidModelTransformer {
|
||||
public static final SimpleTransformer HEAD = new SimpleTransformer(AABB.ofSize(new Vec3(0.0D, -4.0D, 0.0D), 8.0D, 8.0D, 8.0D), 9);
|
||||
public static final SimpleTransformer LEFT_FEET = new SimpleTransformer(AABB.ofSize(new Vec3(0.0D, -4.0D, 0.0D), 8.0D, 8.0D, 8.0D), 5);
|
||||
|
||||
@@ -148,4 +148,14 @@ public class EntityPatchProvider implements ICapabilityProvider, NonNullSupplier
|
||||
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) {
|
||||
return cap == TiedUpCapabilities.CAPABILITY_ENTITY ? this.optional.cast() : LazyOptional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalide la {@link LazyOptional} portée par ce provider. À appeler depuis
|
||||
* {@code AttachCapabilitiesEvent.addListener} — sans ça les références vers
|
||||
* le patch, l'animator et l'armature persistent à chaque respawn / dimension
|
||||
* change → fuite mémoire.
|
||||
*/
|
||||
public void invalidate() {
|
||||
this.optional.invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,5 +69,10 @@ public class TiedUpCapabilityEvents {
|
||||
// l'entity commence son premier tick.
|
||||
patch.onConstructed(entity);
|
||||
event.addCapability(ENTITY_CAPABILITY_KEY, provider);
|
||||
|
||||
// CRITICAL : invalide la LazyOptional au respawn / dim change, sinon
|
||||
// chaque mort fuit patch + animator + armature. Pattern Forge standard
|
||||
// (cf. V2BondageEquipmentProvider.invalidate, CapabilityEventHandler:50).
|
||||
event.addListener(provider::invalidate);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user