feat(D-01/D): V1 cleanup — delete 28 files, ~5400 lines removed
D1: ThreadLocal alert suppression moved from ItemCollar to CollarHelper.
onCollarRemoved() logic (kidnapper alert) moved to CollarHelper.
D2+D3: Deleted 17 V1 item classes + 4 V1-only interfaces:
ItemBind, ItemGag, ItemBlindfold, ItemCollar, ItemEarplugs, ItemMittens,
ItemColor, ItemClassicCollar, ItemShockCollar, ItemShockCollarAuto,
ItemGpsCollar, ItemChokeCollar, ItemHood, ItemMedicalGag,
IBondageItem, IHasGaggingEffect, IHasBlindingEffect, IAdjustable
D4: KidnapperTheme/KidnapperItemSelector/DispenserBehaviors migrated
from variant enums to string-based DataDrivenItemRegistry IDs.
D5: Deleted 11 variant enums + Generic* factories + ItemBallGag3D:
BindVariant, GagVariant, BlindfoldVariant, EarplugsVariant, MittensVariant,
GenericBind, GenericGag, GenericBlindfold, GenericEarplugs, GenericMittens
D6: ModItems cleaned — all V1 bondage registrations removed.
D7: ModCreativeTabs rewritten — iterates DataDrivenItemRegistry.
D8+D9: All V2 helpers cleaned (V1 fallbacks removed), orphan imports removed.
Zero V1 bondage code references remain (only Javadoc comments).
All bondage items are now data-driven via 47 JSON definitions.
This commit is contained in:
413
docs/AUDIT.md
Normal file
413
docs/AUDIT.md
Normal file
@@ -0,0 +1,413 @@
|
||||
# TiedUp! — Codebase Audit
|
||||
|
||||
> Audit complet du mod, systeme par systeme, pour consolider la base et la coherence du code.
|
||||
|
||||
---
|
||||
|
||||
## Objectif
|
||||
|
||||
Passer en revue **chaque systeme** du mod en profondeur pour :
|
||||
1. **Consolider** — identifier et corriger les incohérences, le code mort, la duplication
|
||||
2. **Améliorer** — proposer des refactors ciblés là où l'architecture freine le développement
|
||||
3. **Documenter** — laisser une trace des décisions et de l'état de chaque système
|
||||
|
||||
Ce n'est pas un rewrite. On stabilise ce qui existe.
|
||||
|
||||
---
|
||||
|
||||
## Règles de l'audit
|
||||
|
||||
- **Système par système**, dans l'ordre de dépendance (fondations d'abord)
|
||||
- **Deep dive** — on remonte les sources, les dépendants, les call chains via le MCP
|
||||
- **Pas de changement sans discussion** — on constate, on discute, puis on corrige
|
||||
- **Pas de sur-ingénierie** — on fixe les vrais problèmes, on ne refactor pas pour le plaisir
|
||||
- **Reindex MCP** après chaque batch de corrections significatives
|
||||
|
||||
### Processus par système
|
||||
|
||||
Chaque audit suit ce cycle :
|
||||
|
||||
```
|
||||
1. EXPLORATION — Lire le code, tracer les dépendances (MCP)
|
||||
2. CONSTATS — Documenter les problèmes trouvés (dans ce fichier)
|
||||
3. VÉRIFICATION — Relire, confirmer, pas de faux positifs
|
||||
4. PROPOSITIONS — Pour chaque constat :
|
||||
→ Fix direct (bug, incohérence simple)
|
||||
→ Amélioration architecturale (refactor ciblé, avec justification)
|
||||
5. DISCUSSION — Valider avec l'utilisateur avant d'implémenter
|
||||
6. CORRECTION — Appliquer les changements validés
|
||||
7. REINDEX — MCP reindex après corrections
|
||||
```
|
||||
|
||||
On ne passe au système suivant qu'une fois le cycle terminé.
|
||||
|
||||
---
|
||||
|
||||
## Ordre d'audit
|
||||
|
||||
| # | Système | Packages | Status |
|
||||
|---|---------|----------|--------|
|
||||
| 1 | Core + Registries | `core`, `ModItems`, `ModEntities`, `ModNetwork`, `ModGameRules` | Done |
|
||||
| 2 | State | `state`, `state/components`, `state/hosts`, `state/struggle` | Done |
|
||||
| 3 | Items (v1) + V2 Bondage | `items/**`, `v2/bondage/**` | Done |
|
||||
| 4 | Network | `network/**` | Done |
|
||||
| 5 | Client Animation + GLTF | `client/animation/**`, `client/gltf` | Done |
|
||||
| 6 | Furniture | `v2/furniture/**` | Done |
|
||||
| 7 | Entities + AI | `entities/**` | Done |
|
||||
| 8 | Events | `events/**` | Done |
|
||||
| 9 | Dialogue + Personality | `dialogue/**`, `personality` | Done |
|
||||
| 10 | Cells / Prison / Blocks | `cells`, `prison/**`, `blocks/**` | Done |
|
||||
| 11 | Compat | `compat/mca/**`, `compat/wildfire/**` | Done |
|
||||
| 12 | Util + Commands + Worldgen + Resources | `util/**`, `commands/**`, `worldgen`, resources | Done |
|
||||
|
||||
---
|
||||
|
||||
## Échelle de sévérité
|
||||
|
||||
| Niveau | Signification | Action |
|
||||
|--------|--------------|--------|
|
||||
| **Haute** | Bug actif, bloquant, ou dette qui empêche une feature majeure | Corriger avant de continuer |
|
||||
| **Moyenne** | Incohérence ou fragilité qui va poser problème à terme | Planifier la correction |
|
||||
| **Basse** | Code smell, naming, organisation — pas urgent | Corriger si on touche le fichier |
|
||||
| **Cosmétique** | Style, formatting, commentaires | Optionnel |
|
||||
|
||||
---
|
||||
|
||||
## Constats
|
||||
|
||||
### #1 — Core + Registries
|
||||
|
||||
**Positif :**
|
||||
- DeferredRegister correct partout
|
||||
- Factory pattern propre pour les variant items
|
||||
- SettingsAccessor bridge solide (safeGet, BUG-003 fix)
|
||||
- Séparation client/server correcte
|
||||
- Data-driven reload listeners bien câblés
|
||||
|
||||
**Problèmes :** (tous vérifiés ✓)
|
||||
|
||||
| ID | Sévérité | Constat | Fichier(s) | Proposition |
|
||||
|----|----------|---------|------------|-------------|
|
||||
| C-01 | Haute | SystemMessageManager : 80+ messages hardcodés en anglais, zero `Component.translatable()` | `core/SystemMessageManager.java` | **Fix** : Remplacer `Component.literal()` par `Component.translatable()` avec clés dans `en_us.json`. Garder l'enum + les couleurs, changer uniquement le transport du texte. |
|
||||
| C-02 | Moyenne | 25 settings triplés entre ModConfig + ModGameRules + SettingsAccessor. Historique de bug (BUG-001 : defaults désyncés) | `core/ModConfig.java`, `core/ModGameRules.java`, `core/SettingsAccessor.java` | **Archi** : Évaluer si les GameRules sont vraiment utiles (ils dupliquent la config serveur). Si oui, centraliser les defaults dans une seule source. Si non, supprimer les GameRules doublons et garder ModConfig + SettingsAccessor. |
|
||||
| C-03 | Moyenne | ModNetwork : 74 IDs séquentiels. Pattern standard Forge mais fragile à l'insertion. `PROTOCOL_VERSION` protège partiellement. | `network/ModNetwork.java` | **Pas d'action immédiate** : pattern idiomatique Forge 1.20.1. Bumper `PROTOCOL_VERSION` à chaque ajout/suppression de packet. Documenter cette règle. |
|
||||
| C-04 | Basse | ChokeEffect importe EntityMaster (core → entities) pour check "non-lethal when master-owned" | `core/ChokeEffect.java` | **Fix** : Extraire le check via un tag NBT ou capability sur le Player, consultable sans dépendre d'EntityMaster. |
|
||||
| C-05 | Basse | 10 types d'entités NPC utilisent DamselRenderer — nom spécifique pour un usage générique | `core/TiedUpMod.java`, `client/renderer/DamselRenderer.java` | **Fix** : Renommer `DamselRenderer` → `NpcRenderer` ou `HumanoidNpcRenderer`. |
|
||||
| C-06 | Cosmétique | 47+ FQCNs dans le corps de TiedUpMod au lieu d'imports | `core/TiedUpMod.java` | **Fix** : Remplacer par des imports. Faire quand on touche le fichier. |
|
||||
| C-07 | Basse | ModConfig.ServerConfig : 127 valeurs configurables, 628 lignes, 20+ catégories dans une classe | `core/ModConfig.java` | **Archi** : Découper en sous-classes par domaine (StruggleConfig, NpcConfig, EconomyConfig, etc.) au prochain refactor config. Pas urgent. |
|
||||
|
||||
### #2 — State
|
||||
|
||||
**Positif :**
|
||||
- Hiérarchie d'interfaces bien conçue (ISP) : `IRestrainableEntity` → `ICapturable` → `IBondageState` → `IRestrainable` (union)
|
||||
- Décomposition en 11 components (PlayerEquipment, PlayerStateQuery, etc.) — bonne intention
|
||||
- `IBondageState` n'expose que l'API V2 region-based — l'interface publique est propre
|
||||
- `CollarRegistry` et `SocialData` : implémentations `SavedData` propres avec persistence correcte
|
||||
- `IPlayerLeashAccess` : séparation mixin clean pour le système de laisse
|
||||
- `PlayerCaptorManager` : thread-safe avec `CopyOnWriteArrayList` et `synchronized`
|
||||
|
||||
**Problèmes :** (tous vérifiés ✓)
|
||||
|
||||
| ID | Sévérité | Constat | Fichier(s) | Proposition |
|
||||
|----|----------|---------|------------|-------------|
|
||||
| S-01 | Moyenne | PlayerBindState : god class de façade, 1237 lignes, ~80 méthodes de pure délégation vers 11 components | `state/PlayerBindState.java` | **Archi** : Évaluer si les consommateurs peuvent utiliser les components directement via des accesseurs typés (`state.equipment().putBindOn()`) au lieu de passer par la façade. Réduirait la surface de ~80 méthodes de boilerplate. Risque : gros refactor, beaucoup de call sites. |
|
||||
| S-02 | Moyenne | 8 champs de mouvement publics (`hopCooldown`, `lastX`, etc.) directement mutés par MovementStyleManager (33 accès directs) | `state/PlayerBindState.java`, `v2/bondage/movement/MovementStyleManager.java` | **Fix** : Extraire dans un `MovementState` component avec getters/setters. MovementStyleManager opère via ce component. |
|
||||
| S-03 | Basse | API V1 slot-based (`putBindOn`, `takeGagOff`) coexiste avec V2 region-based sur la classe concrète PlayerBindState. L'interface `IBondageState` est propre (V2 only). | `state/PlayerBindState.java` | **Archi** : Marquer les méthodes V1 `@Deprecated` pour guider la migration. Les call sites (commands, etc.) devraient migrer vers `equip(BodyRegionV2)`. Pas urgent car l'interface est déjà propre. |
|
||||
| S-04 | Basse | `hasLegsBound()` lit le slot ARMS (pas LEGS) — design V1 intentionnel : un seul item "bind" couvre bras+jambes via NBT mode. Pas un bug. | `state/IBondageState.java` | **Pas d'action immédiate** : cohérent avec le système actuel. Documenter le design dans un commentaire. Deviendra un vrai problème quand des items LEGS dédiés seront ajoutés en V2. |
|
||||
| S-05 | Moyenne | Thread safety incohérente : `volatile` (3 champs), `synchronized` (5 méthodes), rien (le reste). La paire `isStruggling`/`struggleStartTick` peut être observée dans un état inconsistant. | `state/PlayerBindState.java` | **Fix** : Définir une stratégie claire. Les champs accédés cross-thread (mouvement, struggle, captor) doivent être soit volatile soit synchronized. Auditer chaque champ. |
|
||||
| S-06 | Basse | `HumanChairHelper` dans `state/` mais c'est un utilitaire pur sans lien avec le state. Utilisé par AI, animation, mixins. | `state/HumanChairHelper.java` | **Fix** : Déplacer dans `items/base/` (à côté de `PoseType` dont il dépend) ou `util/`. Faire quand on touche le fichier. |
|
||||
|
||||
### #3 — Items (V1) + V2 Bondage
|
||||
|
||||
**Positif :**
|
||||
- `IV2BondageItem` bien conçu : multi-region, stack-aware, pose priority, blocked regions
|
||||
- `V2EquipmentManager` : conflict resolution solide (swap single, supersede global)
|
||||
- `V2EquipmentHelper` : facade propre pour read/write/sync
|
||||
- `DataDrivenBondageItem` : singleton + NBT registry pattern intelligent pour items data-driven
|
||||
- `ILockable` : système lock/jam/key complet et cohérent
|
||||
- `IHasResistance` : résistance NBT avec migration legacy, bien documentée
|
||||
- `BodyRegionV2` enum complet (15 régions, global flag)
|
||||
- Variant enums + factory pattern (BindVariant, GagVariant, etc.) propres
|
||||
|
||||
**Problèmes :** (tous vérifiés ✓)
|
||||
|
||||
| ID | Sévérité | Constat | Fichier(s) | Proposition |
|
||||
|----|----------|---------|------------|-------------|
|
||||
| I-01 | ~~Haute~~ | ~~Deux hiérarchies d'interfaces parallèles~~ | | **RÉSOLU** : suppression V1 (voir Décision D-01) |
|
||||
| I-02 | ~~Haute~~ | ~~V1 items bypassent la conflict resolution V2~~ | | **RÉSOLU** : suppression V1 (voir Décision D-01) |
|
||||
| I-03 | Moyenne | `DataDrivenBondageItem.getBaseResistance()` scanne tous items équipés et retourne MAX difficulty car `IHasResistance` n'a pas de paramètre ItemStack. Workaround documenté mais approximatif — peut surestimer la résistance. | `v2/bondage/datadriven/DataDrivenBondageItem.java` | **Archi** : Ajouter `getBaseResistance(ItemStack, LivingEntity)` à `IHasResistance` avec default qui délègue à l'ancienne méthode. DataDrivenBondageItem override la version stack-aware. |
|
||||
| I-04 | ~~Basse~~ | ~~IBondageItem.getBodyRegion() single-region~~ | | **RÉSOLU** : suppression V1 (voir Décision D-01) |
|
||||
| I-05 | ~~Moyenne~~ | ~~V1 items pas @Deprecated~~ | | **RÉSOLU** : suppression V1 (voir Décision D-01) |
|
||||
|
||||
### Décision D-01 — Suppression totale du système V1 + Composants data-driven
|
||||
|
||||
**Décision :** Le système V1 items est supprimé entièrement. Tous les items deviennent data-driven V2. La logique complexe (shock, GPS, lock, gagging, blinding, resistance, etc.) est extraite en **composants réutilisables** déclarables dans le JSON.
|
||||
|
||||
**Périmètre de suppression :**
|
||||
- `IBondageItem` (interface)
|
||||
- `ItemBind`, `ItemGag`, `ItemBlindfold`, `ItemCollar`, `ItemEarplugs`, `ItemMittens` (abstracts)
|
||||
- `GenericBind`, `GenericGag`, `GenericBlindfold`, `GenericEarplugs`, `GenericMittens` (concrets)
|
||||
- `BindVariant`, `GagVariant`, `BlindfoldVariant`, `EarplugsVariant`, `MittensVariant` (enums)
|
||||
- `ItemClassicCollar`, `ItemShockCollar`, `ItemShockCollarAuto`, `ItemGpsCollar`, `ItemChokeCollar` (collars)
|
||||
- `ItemHood`, `ItemMedicalGag`, `ItemBallGag3D` (combos/special)
|
||||
- Registrations V1 dans `ModItems`
|
||||
- `PlayerEquipment.equipInRegion()` → remplacé par `V2EquipmentManager.tryEquip()`
|
||||
|
||||
**Interfaces à conserver / migrer :**
|
||||
- `ILockable` — conservé, utilisé par V2 items
|
||||
- `IHasResistance` — conservé, refactoré avec paramètre ItemStack (I-03)
|
||||
- `IKnife` — conservé (outils, pas des bondage items)
|
||||
- `IAdjustable` — à évaluer (potentiellement composant)
|
||||
- `IHasBlindingEffect`, `IHasGaggingEffect` — deviennent des composants
|
||||
|
||||
**Système de composants envisagé :**
|
||||
|
||||
Chaque composant est une logique serveur réutilisable qu'un item data-driven peut déclarer :
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "tiedup:bondage_item",
|
||||
"display_name": "Shock Collar",
|
||||
"model": "tiedup:models/gltf/shock_collar.glb",
|
||||
"regions": ["NECK"],
|
||||
"components": {
|
||||
"lockable": true,
|
||||
"shock": { "auto_interval": 200, "damage": 2.0 },
|
||||
"gps": { "safe_zone_radius": 50 },
|
||||
"gagging": { "comprehension": 0.2, "range": 10.0 },
|
||||
"blinding": { "overlay": "tiedup:textures/overlay/blindfold.png" },
|
||||
"resistance": { "base": 150 }
|
||||
},
|
||||
"escape_difficulty": 5,
|
||||
"pose_priority": 10
|
||||
}
|
||||
```
|
||||
|
||||
Exemples de composants à extraire de la logique V1 existante :
|
||||
| Composant | Source V1 | Comportement |
|
||||
|-----------|-----------|-------------|
|
||||
| `lockable` | `ILockable` | Lock/unlock, padlock, key matching, jam, lock resistance |
|
||||
| `resistance` | `IHasResistance` | Struggle resistance, configurable base value |
|
||||
| `shock` | `ItemShockCollar` | Auto-shock intervals, manual shock, damage |
|
||||
| `gps` | `ItemGpsCollar` | Safe zone, zone violation detection, owner alerts |
|
||||
| `gagging` | `IHasGaggingEffect` | Muffled speech, comprehension %, range limit |
|
||||
| `blinding` | `IHasBlindingEffect` | Blindfold overlay, hardcore mode |
|
||||
| `choking` | `ItemChokeCollar` | Air drain, darkness, slowness, non-lethal master mode |
|
||||
| `adjustable` | `IAdjustable` | Tightness level, visual adjustment |
|
||||
|
||||
**Ce refactor est le plus gros chantier identifié par l'audit.** Il fera l'objet d'un plan d'implémentation dédié après la fin de l'audit.
|
||||
|
||||
### #4 — Network
|
||||
|
||||
**Positif :**
|
||||
- `AbstractClientPacket` / `AbstractPlayerSyncPacket` — bon pattern de base, handle enqueue sur main thread, retry queue pour les players pas encore loaded
|
||||
- `PacketRateLimiter` — token bucket complet avec catégories (struggle, minigame, action, selfbondage, ui). Thread-safe. Bon anti-spam.
|
||||
- `SyncManager` — facade centralisée pour sync inventory/state/enslavement/struggle/clothes. Pattern `sendSync()` générique propre.
|
||||
- `NetworkEventHandler` — gère correctement login sync, start-tracking sync, furniture reconnection, et fix MC-262715 (stale riding state)
|
||||
- `PacketSlaveAction` — bonnes validations serveur : dimension check, distance check, collar ownership check, GPS permission check
|
||||
- `PacketSelfBondage` — rate limited, route correctement V2 via `handleV2SelfBondage()` avec conflict check (`isRegionOccupied` + `isRegionBlocked`)
|
||||
|
||||
**Problèmes :**
|
||||
|
||||
| ID | Sévérité | Constat | Fichier(s) | Proposition |
|
||||
|----|----------|---------|------------|-------------|
|
||||
| N-01 | Moyenne | `PacketSelfBondage.handle()` contient 5 branches V1 (`instanceof ItemBind/ItemGag/ItemBlindfold/ItemMittens/ItemEarplugs`) qui devront être supprimées avec D-01. La branche V2 (`instanceof IV2BondageItem`) restera seule. | `network/selfbondage/PacketSelfBondage.java` | **Fix D-01** : Supprimer les branches V1, ne garder que la route V2. Simplifie massivement le fichier. |
|
||||
| N-02 | Moyenne | 4 packets dépendent de `ItemCollar` (V1 class) : `PacketSlaveAction`, `PacketMasterEquip`, `PacketAssignCellToCollar`, `PacketNpcCommand`. La logique collar (ownership, canShock, hasGPS) est couplée à la classe Java. | `network/slave/PacketSlaveAction.java`, `network/slave/PacketMasterEquip.java`, `network/cell/PacketAssignCellToCollar.java`, `network/personality/PacketNpcCommand.java` | **Fix D-01** : Quand ItemCollar migre vers le système composants, ces packets devront checker les composants (ex: `hasComponent("shock")`) au lieu de `instanceof ItemCollar`. |
|
||||
| N-03 | Basse | `PacketSyncBindState` sync des flags d'état V1 (isTiedUp, isGagged, isBlindfolded, etc.) séparément de `PacketSyncV2Equipment` qui sync le V2 capability. Potentiellement redondant post-suppression V1 — l'état peut être dérivé du V2 equipment. | `network/sync/PacketSyncBindState.java`, `v2/bondage/network/PacketSyncV2Equipment.java` | **Archi post-D-01** : Évaluer si `PacketSyncBindState` peut être supprimé et ses flags dérivés côté client depuis V2 equipment. Réduirait le nombre de packets sync. |
|
||||
| N-04 | Basse | `SyncManager.syncAllPlayersTo()` envoie 4 packets distincts par joueur (V2Equipment, BindState, Enslavement, Struggle, + Clothes si applicable). Pour un serveur avec N joueurs, un login génère ~4N packets. | `network/sync/SyncManager.java` | **Archi** : Considérer un packet bulk `PacketSyncFullState` qui combine tout en un seul envoi. Pas urgent — 4N packets est acceptable pour les tailles de serveur visées. |
|
||||
| N-05 | Cosmétique | Pas de `MCABondageManager` dans le package network, mais `PacketSyncMCABondage` existe — la logique MCA bondage sync est split entre `network/sync/` et `compat/mca/`. | `network/sync/PacketSyncMCABondage.java`, `compat/mca/` | **Pas d'action** : Acceptable pour un module de compatibilité. |
|
||||
|
||||
### #5 — Client Animation + GLTF
|
||||
|
||||
**Positif :**
|
||||
- **Architecture 3 couches propre** : Context layer (pri 40) → Item layer (pri 42) → Furniture layer (pri 43). Priorités claires, bon découplage.
|
||||
- **BondageAnimationManager** : API unifiée `playAnimation/playDirect/playContext/playFurniture` pour players et NPCs. Gestion des remote players (fallback stack), pending queue pour retry, furniture grace ticks pour éviter les stuck poses.
|
||||
- **GlbAnimationResolver** : Fallback chain fidèle au ARTIST_GUIDE (FullSitStruggle → SitStruggle → FullStruggle → Struggle → FullIdle → Idle). Support variants (.1, .2) avec random selection.
|
||||
- **GltfAnimationApplier** : Multi-item composite animation propre. Cache par state key, skip si unchanged. `applyMultiItemV2Animation()` merge les bones de plusieurs items dans un seul AnimationBuilder.
|
||||
- **ContextGlbRegistry** : Hot-reload des GLB de contexte depuis resource packs. Atomic swap pour thread safety render.
|
||||
- **AnimationContextResolver** : Résolution claire de contexte (sitting → struggling → movement style → sneaking → walking → idle). Version NPC séparée.
|
||||
- **GLTF pipeline (12 fichiers)** : Zéro dépendance V1. Parser, cache, skinning engine, mesh renderer, bone mapper, pose converter — tout est V2 natif.
|
||||
|
||||
**Problèmes :**
|
||||
|
||||
| ID | Sévérité | Constat | Fichier(s) | Proposition |
|
||||
|----|----------|---------|------------|-------------|
|
||||
| A-01 | Moyenne | 6 fichiers animation dépendent de `ItemBind` et `PoseType` (V1) pour déterminer le type de pose (STANDARD, DOG, HUMAN_CHAIR) et le bind mode (arms/legs/full). | `tick/AnimationTickHandler.java`, `tick/NpcAnimationTickHandler.java`, `render/PlayerArmHideEventHandler.java`, `render/PetBedRenderHandler.java`, `render/DogPoseRenderHandler.java`, `util/AnimationIdBuilder.java` | **Fix D-01** : Quand les items V1 sont supprimés, la pose type et le bind mode doivent venir du système V2 (data-driven definition ou composant). `PoseType` peut être conservé comme enum mais lu depuis `DataDrivenItemDefinition` au lieu de `ItemBind.getPoseType()`. |
|
||||
| A-02 | Basse | `StaticPoseApplier` dépend de `PoseType` — applique des rotations hardcodées par pose type (V1 fallback pour quand le GLTF n'est pas disponible). | `animation/StaticPoseApplier.java` | **Évaluer D-01** : Si tous les items ont un GLB, le static pose applier devient un fallback pur. Peut être conservé comme sécurité ou supprimé. |
|
||||
| A-03 | Basse | `GltfAnimationApplier` a un toggle debug F9 hardcodé qui charge un GLB spécifique (`cuffs_prototype.glb`). | `client/gltf/GltfAnimationApplier.java` (l.~350) | **Fix** : Supprimer ou mettre derrière un flag dev. Mineur. |
|
||||
| A-04 | Cosmétique | Le fallback animation dans `BondageAnimationManager.tryFallbackAnimation()` contient des patterns V1 spécifiques (`_arms_`, `sit_dog_`, `kneel_dog_`). Post-D-01, ces patterns n'existeront plus. | `animation/BondageAnimationManager.java` | **Fix D-01** : Nettoyer les fallbacks V1 obsolètes. Le système GLB a sa propre fallback chain (GlbAnimationResolver). |
|
||||
|
||||
### #6 — Furniture
|
||||
|
||||
**Positif :**
|
||||
- **Architecture data-driven exemplaire** : `FurnitureDefinition` (record immuable) + `FurnitureRegistry` (volatile atomic swap) + `FurnitureParser` + `FurnitureServerReloadListener`. Exactement le même pattern que les bondage items V2 data-driven.
|
||||
- **`ISeatProvider`** : interface propre et générique — conçue pour être implémentée par des monstres aussi (ARTIST_GUIDE: "monster seat system"). Bonne anticipation.
|
||||
- **`SeatDefinition`** : record immuable avec tous les champs du guide artiste (blocked regions, lockable, locked difficulty, item difficulty bonus).
|
||||
- **`EntityFurniture`** : Entity simple (pas LivingEntity), synced via `IEntityAdditionalSpawnData`. Dimensions variables depuis la definition. Animation state machine (IDLE → OCCUPIED → LOCKING → STRUGGLE → UNLOCKING). Seat assignments persistés en NBT.
|
||||
- **`FurniturePlacerItem`** : singleton item avec NBT ID, snap-to-wall, floor-only. Même pattern que `DataDrivenBondageItem`.
|
||||
- **`FurnitureAnimationContext`** : Conversion GLB → KeyframeAnimation avec bones sélectifs (blocked regions only). S'intègre proprement avec la furniture layer (pri 43) de BondageAnimationManager.
|
||||
- **`FurnitureGltfData`** : Parsing dédié qui sépare furniture armature des Player_* seat skeletons dans un seul GLB. Fidèle à l'ARTIST_GUIDE.
|
||||
- **Packets** : Rate limited, distance checks, permission checks (collar ownership pour forcemount).
|
||||
- **Reconnection robuste** : `NetworkEventHandler.handleFurnitureReconnection()` restaure les joueurs locked dans un seat après déconnexion, avec teleport si le meuble n'existe plus.
|
||||
|
||||
**Problèmes :**
|
||||
|
||||
| ID | Sévérité | Constat | Fichier(s) | Proposition |
|
||||
|----|----------|---------|------------|-------------|
|
||||
| F-01 | Moyenne | `EntityFurniture` et `PacketFurnitureForcemount` dépendent de `ItemCollar` (V1) pour vérifier collar ownership avant forcemount. | `v2/furniture/EntityFurniture.java`, `v2/furniture/network/PacketFurnitureForcemount.java` | **Fix D-01** : Quand ItemCollar migre vers composants, le check ownership doit utiliser le composant `lockable` ou `collar` au lieu de `instanceof ItemCollar`. |
|
||||
| F-02 | Basse | `FurnitureAnimationContext.create()` log "V1: skeleton parsing not yet implemented" quand `seatSkeleton` est null. Si le GLB n'a pas de skeleton data parsé, l'animation silencieusement ne se joue pas. | `v2/furniture/client/FurnitureAnimationContext.java` | **Évaluer** : Vérifier que le parser GLB furniture extrait toujours le skeleton. Si oui, le fallback est juste un safety net. Sinon, c'est un bug silencieux. |
|
||||
|
||||
**Verdict : Le système furniture est le plus propre du mod.** Zéro dette architecturale, fidèle au guide artiste, extensible (monster seats prêts). Les deux constats sont mineurs — un couplage V1 qui part avec D-01 et un fallback debug à vérifier.
|
||||
|
||||
### #7 — Entities + AI
|
||||
|
||||
**Hiérarchie d'héritage :**
|
||||
|
||||
```
|
||||
PathfinderMob
|
||||
└─ AbstractTiedUpNpc (1281 lignes, ~100 méthodes) — implements IRestrainable, IAnimatedPlayer, IV2EquipmentHolder
|
||||
├─ EntityDamsel (834 lignes) — capturable NPC, personality, dialogue, inventory
|
||||
│ ├─ EntityDamselShiny — variante rare
|
||||
│ └─ EntityLaborGuard — garde de prison
|
||||
└─ EntityKidnapper (2039 lignes, ~170 méthodes) — implements ICaptor, IDialogueSpeaker
|
||||
└─ EntityKidnapperElite
|
||||
├─ EntityKidnapperMerchant — marchand neutre/hostile
|
||||
├─ EntityKidnapperArcher — attaque à distance
|
||||
├─ EntitySlaveTrader — boss de camp
|
||||
├─ EntityMaid — servante du trader
|
||||
└─ EntityMaster (1192 lignes) — pet play system
|
||||
```
|
||||
|
||||
**Positif :**
|
||||
- **Composant-based decomposition pour Damsel** : `DamselBondageManager`, `DamselPersonalitySystem`, `DamselInventoryManager`, `DamselAIController`, `DamselAnimationController`, `DamselAppearance`, `NpcEquipmentManager`, `NpcCaptivityManager` — 8 components avec interfaces host (`IBondageHost`, `IAIHost`, `IAnimationHost`, etc.). Bonne intention.
|
||||
- **Composant-based pour Kidnapper** : `KidnapperAggressionSystem`, `KidnapperAlertManager`, `KidnapperAppearance`, `KidnapperCaptiveManager`, `KidnapperCellManager`, `KidnapperCampManager`, `KidnapperStateManager`, `KidnapperSaleManager`, `KidnapperTargetSelector`, `KidnapperDataSerializer` — 10 components avec interfaces host. Très granulaire.
|
||||
- **AI goals bien séparés** : 80+ goals dédiés par type de NPC. Chaque goal est une classe autonome avec une seule responsabilité (KidnapperCaptureGoal, MasterDogwalkGoal, NpcFarmCommandGoal, etc.).
|
||||
- **V2 equipment intégré** : `AbstractTiedUpNpc` implémente `IV2EquipmentHolder`, utilise `V2BondageEquipment` directement. Les NPCs sont déjà sur le système V2.
|
||||
- **State machines Kidnapper** : `KidnapperState` enum avec états clairs (IDLE, HUNTING, CAPTURING, FLEEING, etc.).
|
||||
- **Master NPC complet** : pet play system avec task manager, state machine, punishment, dogwalk, furniture interaction — complexe mais fonctionnel.
|
||||
|
||||
**Problèmes :**
|
||||
|
||||
| ID | Sévérité | Constat | Fichier(s) | Proposition |
|
||||
|----|----------|---------|------------|-------------|
|
||||
| E-01 | Haute | **EntityKidnapper = 2039 lignes**, la plus grosse classe du mod. Malgré la décomposition en 10 components, la classe reste un god class. Elle mélange : ICaptor impl, targeting, capture equipment, sale system, job system, camp system, cell integration, alert system, NBT serialization, display name, dialogue, et des dizaines de getters/helpers. | `entities/EntityKidnapper.java` | **Archi** : Continuer la décomposition. Candidates : extraire le système de vente (`startSale`/`completeSale`/`cancelSale`/`abandonCaptive`) dans un component dédié, extraire le dialogue, extraire le ciblage. Objectif : ramener la classe sous 800 lignes. |
|
||||
| E-02 | Haute | **AbstractTiedUpNpc = 1281 lignes** avec ~100 méthodes. Même pattern que PlayerBindState (S-01) — c'est une façade de délégation vers les components, mais doit aussi implémenter IRestrainable (30+ méthodes) directement. | `entities/AbstractTiedUpNpc.java` | **Archi** : La taille vient surtout de l'implémentation de IRestrainable. Évaluer si les méthodes bondage peuvent être déléguées à `DamselBondageManager` via un pattern `default` sur IRestrainable (mais IRestrainable est une interface, pas une classe — limité). Ou accepter la taille comme coût de l'implémentation multi-interface. |
|
||||
| E-03 | Moyenne | **24 fichiers entities** dépendent de V1 item classes (`ItemBind`, `ItemCollar`, `PoseType`, `BindVariant`, etc.). C'est le package le plus impacté par D-01. | 24 fichiers (voir liste grep) | **Fix D-01** : Migration bulk. Les `instanceof ItemBind` deviennent `instanceof IV2BondageItem`, les `ItemCollar` checks deviennent des component checks. `PoseType` et `BindVariant` sont remplacés par des propriétés data-driven. |
|
||||
| E-04 | Moyenne | **Héritage profond** : EntityMaid → EntityKidnapperElite → EntityKidnapper → AbstractTiedUpNpc → PathfinderMob. 5 niveaux. EntityMaid et EntitySlaveTrader héritent de toute la logique kidnapper (capture, targeting, sale) alors qu'ils n'utilisent pas tout. | `entities/EntityMaid.java`, `entities/EntitySlaveTrader.java` | **Archi** : Envisager une refactorisation vers composition plutôt qu'héritage. La Maid n'est PAS un kidnapper — elle ne devrait pas hériter de `canCapture()`, `getCaptureBindTime()`, etc. Long terme : AbstractTiedUpNpc → EntityDamsel (passive) / EntityKidnapper (hostile), et les autres types composent leurs comportements. Pas urgent mais dette croissante. |
|
||||
| E-05 | Basse | `EntityDamsel` et `EntityKidnapper` ont des hiérarchies de host interfaces parallèles : `damsel/components/IBondageHost`, `damsel/components/IAIHost` vs `kidnapper/components/IAIHost`, `kidnapper/components/ICaptiveHost`, etc. Certaines pourraient être unifiées. | `entities/damsel/components/*.java`, `entities/kidnapper/components/*.java` | **Pas d'action immédiate** : Les interfaces host sont des contrats internes de chaque sous-arbre. Les unifier créerait un couplage horizontal. Acceptable tel quel. |
|
||||
| E-06 | Basse | `EntityMaster` (1192 lignes) contient le pet play system complet. Components `MasterPetManager`, `MasterTaskManager`, `MasterStateManager` existent mais la classe orchestre encore beaucoup de logique. | `entities/EntityMaster.java` | **Archi** : Même recommandation que E-01 — continuer la décomposition. Moins urgent car le système est plus cohérent (une seule responsabilité : pet play). |
|
||||
|
||||
### #8 — Events
|
||||
|
||||
**27 handlers, 5722 lignes, 8 domaines** (camp, captivity, combat, interaction, lifecycle, restriction, system).
|
||||
|
||||
**Positif :** Bonne séparation par domaine. La plupart des handlers sont focalisés (85-200 lignes).
|
||||
|
||||
| ID | Sévérité | Constat | Proposition |
|
||||
|----|----------|---------|-------------|
|
||||
| EV-01 | Moyenne | `RestraintTaskTickHandler` (675 lignes, 12 @SubscribeEvent) — consolide tous les ticks restraint. | Découper par type de tâche (tying, untying, force-feeding, shock checks). |
|
||||
| EV-02 | Moyenne | `BondageItemRestrictionHandler` (544 lignes, 12 @SubscribeEvent) — consolide toutes les restrictions. | Découper par type de restriction (legs, arms, gags, etc.). |
|
||||
| EV-03 | Moyenne | 7/27 handlers importent des classes V1 (`ItemBind`, `ItemCollar`, `ItemGag`, `IKnife`, `ILockable`). | **Fix D-01** : Migrer vers V2 checks (composants). |
|
||||
|
||||
### #9 — Dialogue + Personality
|
||||
|
||||
**31 fichiers, 7625 lignes.** Dialogue 100% data-driven (JSON par personality × speaker type). Personality enum-based (11 types) avec state machine (needs, mood, commands).
|
||||
|
||||
**Positif :** Pipeline de chargement JSON propre (default → personality override → speaker-type). 18 catégories de dialogue. Dépendance unidirectionnelle (dialogue → personality, pas l'inverse). Seulement 3 fichiers importent du V1.
|
||||
|
||||
| ID | Sévérité | Constat | Proposition |
|
||||
|----|----------|---------|-------------|
|
||||
| DI-01 | Moyenne | 6 god classes dans dialogue/ (EntityDialogueManager 622l, ConversationManager 564l, GagTalkManager 557l, DialogueLoader 469l, DialogueBridge 463l, DialogueManager 428l). | Acceptable pour la complexité du système. `DialogueBridge` (mapping legacy → new) peut être supprimé après D-01. |
|
||||
| DI-02 | Basse | `PersonalityState` (709 lignes) — god class conteneur d'état NPC (needs, mood, commands, jobs, home). | Continuer la décomposition si ça grossit. OK pour l'instant. |
|
||||
| DI-03 | Basse | 3 fichiers importent V1 (`GagTalkManager` → ItemGag, `ToolMode` → ItemBind, `PetRequestManager` → BindVariant). | **Fix D-01** : Migrer. |
|
||||
|
||||
### #10 — Cells / Prison / Blocks
|
||||
|
||||
**41 fichiers, 13329 lignes.** Système SavedData massif (CellRegistryV2, PrisonerManager, CampOwnership, ConfiscatedInventoryRegistry).
|
||||
|
||||
**Positif :** Architecture SavedData correcte. Spatial indexing dans CellRegistryV2. Séparation services (PrisonerService, ItemService, BondageService).
|
||||
|
||||
| ID | Sévérité | Constat | Proposition |
|
||||
|----|----------|---------|-------------|
|
||||
| CP-01 | Haute | `PrisonerService` (1058 lignes) — plus grosse classe du package, gère tout le lifecycle prisonnier. | Décomposer : labor, ransom, confiscation pourraient être des services séparés. |
|
||||
| CP-02 | Moyenne | `MarkerBlockEntity` (1146 lignes) — god class block entity, gère spawning + teleportation + cell deletion. | Extraire la logique spawning et teleportation dans des helpers. |
|
||||
| CP-03 | Moyenne | `BondageItemBlockEntity` utilise 6 imports V1 (ItemBind, ItemGag, ItemBlindfold, ItemCollar, ItemEarplugs, GenericClothes) pour valider les items dans les trap blocks. | **Fix D-01** : Remplacer par `instanceof IV2BondageItem` + component checks. |
|
||||
| CP-04 | Basse | `CellRegistryV2` (903 lignes) — gros mais justifié par les index spatiaux. | Acceptable. |
|
||||
|
||||
### #11 — Compat (MCA + Wildfire)
|
||||
|
||||
**24 fichiers, 6536 lignes.** MCA très couplé (21 fichiers, 5 sous-systèmes). Wildfire léger (3 fichiers, rendu only).
|
||||
|
||||
| ID | Sévérité | Constat | Proposition |
|
||||
|----|----------|---------|-------------|
|
||||
| CO-01 | Haute | `MCAKidnappedAdapter` (907 lignes) — implémente IRestrainable complet pour les villagers MCA. God class + dépend de V1 items. | **Fix D-01** : Migrer V1 → V2. Décomposer en components comme AbstractTiedUpNpc. |
|
||||
| CO-02 | Moyenne | `WildfireDamselLayer` (988 lignes) — rendu physique très complexe. | Acceptable pour un système de rendu physique. Pas urgent. |
|
||||
| CO-03 | Basse | MCA compat utilise WeakHashMap et reflection pour détection — bon pattern de découplage. | Pas d'action. |
|
||||
|
||||
### #12 — Util + Commands + Worldgen
|
||||
|
||||
**55 fichiers, 15475 lignes.**
|
||||
|
||||
| ID | Sévérité | Constat | Proposition |
|
||||
|----|----------|---------|-------------|
|
||||
| UC-01 | Haute | `BondageSubCommand` (1232 lignes) — monolithique, contient 16 sous-commandes (tie, untie, gag, collar, etc.) dans un seul fichier. | Découper : TieCommands, GagCommands, CollarCommands, etc. |
|
||||
| UC-02 | Haute | `RoomTheme` (1368 lignes) — config hardcodée de palettes de blocs pour worldgen. | **Archi** : Externaliser en data-driven (JSON). C'est exactement le type de contenu qui devrait être configurable. |
|
||||
| UC-03 | Moyenne | 7 fichiers importent V1 items (commands + RestraintApplicator + MCA adapter + HangingCagePiece). | **Fix D-01** : Migrer. |
|
||||
| UC-04 | Basse | `NPCCommand` (764 lignes) — gros mais focalisé sur le spawning/state NPC. | Acceptable, pourrait split par entity type. |
|
||||
|
||||
---
|
||||
|
||||
## Bilan Final
|
||||
|
||||
### Statistiques
|
||||
|
||||
- **12/12 systèmes audités**
|
||||
- **744 classes, 233k lignes** analysées
|
||||
- **38 constats** documentés (+ 4 résolus par D-01)
|
||||
- **1 décision architecturale majeure** (D-01 : suppression V1 + composants data-driven)
|
||||
|
||||
### Classement par santé
|
||||
|
||||
| Rang | Système | Verdict | Problèmes |
|
||||
|------|---------|---------|-----------|
|
||||
| 1 | Furniture | Exemplaire | 2 mineurs |
|
||||
| 2 | Animation + GLTF | Excellent | Résidus V1 seulement |
|
||||
| 3 | Network | Solide | Résidus V1 seulement |
|
||||
| 4 | Dialogue + Personality | Bon | God classes acceptables |
|
||||
| 5 | Events | Bon | 2 handlers trop gros |
|
||||
| 6 | Core | Dette technique | i18n, config triple |
|
||||
| 7 | State | Croissance organique | God class, thread safety |
|
||||
| 8 | Cells / Prison | Fonctionnel mais lourd | 11 god classes |
|
||||
| 9 | Compat | Fonctionnel mais couplé | MCA adapter 907l |
|
||||
| 10 | Util / Commands / Worldgen | Fonctionnel | BondageSubCmd 1232l, RoomTheme 1368l |
|
||||
| 11 | Entities + AI | Riche mais massif | 2039l god class, héritage 5 niveaux |
|
||||
| 12 | Items V1/V2 | **Point critique** | **D-01 : suppression totale V1** |
|
||||
|
||||
### Priorités de correction
|
||||
|
||||
| Priorité | Chantier | Impact |
|
||||
|----------|----------|--------|
|
||||
| **P0** | **D-01 : Suppression V1 + composants data-driven** | Élimine la dette #1 du mod. Impacte ~60 fichiers. Requiert un plan dédié. |
|
||||
| **P1** | C-01 : i18n SystemMessageManager | Requis pour toute traduction du mod. |
|
||||
| **P1** | UC-02 : RoomTheme → data-driven | 1368 lignes hardcodées de config worldgen. |
|
||||
| **P2** | E-01/E-02 : Décomposition EntityKidnapper/AbstractTiedUpNpc | 2039 + 1281 lignes. Améliore la maintenabilité entities. |
|
||||
| **P2** | CP-01 : Décomposition PrisonerService | 1058 lignes. |
|
||||
| **P2** | UC-01 : Split BondageSubCommand | 1232 lignes en 1 fichier. |
|
||||
| **P3** | S-02 : Encapsuler MovementState | 8 champs publics mutés directement. |
|
||||
| **P3** | S-05 : Thread safety cohérente | 3 stratégies sans cohérence dans PlayerBindState. |
|
||||
| **P3** | C-02 : Unifier Config/GameRules | 25 settings triplés. |
|
||||
| **P4** | Renommages (C-05 DamselRenderer, C-06 FQCNs) et cleanups cosmétiques. |
|
||||
|
||||
### D-01 Phase 1 — Suivi implémentation
|
||||
|
||||
**Branche :** `feature/d01-component-system` (17 commits, build clean)
|
||||
|
||||
**Review adversariale :** 3 critiques + 5 hauts trouvés et corrigés.
|
||||
|
||||
**Problèmes notés (non bloquants, à traiter lors de la migration Phase 2) :**
|
||||
|
||||
| ID | Constat | Action |
|
||||
|----|---------|--------|
|
||||
| SMELL-002 | `GaggingComponent` n'a aucun consommateur — `GagTalkManager` lit `GagMaterial.getComprehension()`, pas le composant. | Lors de la migration Phase 2, faire pointer `GagTalkManager` vers le composant pour les items data-driven. |
|
||||
| SMELL-003 | Duplication sémantique entre le champ top-level `lockable` (boolean) et le composant `LockableComponent`. Un item doit configurer les deux pour un lock complet. | Lors de la migration Phase 2, le champ `lockable` devrait être dérivé de la présence du composant `lockable`. |
|
||||
| NOTE-003 | `test_component_gag.json` est dans les resources de production — visible par les joueurs. | Supprimer ou déplacer avant release. OK pour le dev. |
|
||||
Reference in New Issue
Block a user