Contexte
Malgre les sessions 99 (audit donnees ignorees) et 118 (PointBrights +
ZoneBorderPoints), il restait un doute sur la fidelite COMPLETE de la conversion
twolev.bin / twolev.graph.bin -> JSON. Plusieurs structures du binaire ne sont
lues qu’en partie (champs marques TODO dans defs.i, hex dumps non interpretes
dans le parser actuel).
Objectif : ecrire un extracteur autonome qui lit absolument tous les bytes
de twolev.bin et twolev.graph.bin, et les expose en JSON, sans interpretation.
Les champs incompris sont conserves en raw word/byte ou hex dump. Permet :
- Audit visuel de la conversion (verifier que rien n’est perdu).
- Diagnostic des bugs subtils (un champ TODO peut etre la source d’un
comportement non reproduit). - Reference pour de futures sessions qui voudraient interpreter ces champs.
Choix d’architecture
Nouveau package com.ab3d2.core.level.full, completement autonome. Ne touche
pas aux parsers existants (LevelBinaryParser, GraphicsBinaryParser,
LevelJsonExporter). Sortie JSON distincte level_X_full.json (vs
level_X.json existant). L’utilisateur pourra integrer ce qu’il veut apres.
Fichiers crees
-
core/level/full/LevelFullExtractor.java(~640 lignes, ~30 KB) : parser
monolithique. Records nested (LvlTHeader,TLGTHeader,Vec2W,
ControlPoint,ZoneRecord21 champs,EdgeRecord9 champs incluant
word5/byte12/byte13/flagsTODO,PvsTuple,ObjectRecord29 champs
ObjT+EntT,ZLiftable18 champs,ZDoorWall,LiftableEntry,SwitchRecord,
ExtractedLevel). API :extract(String levelId, byte[] bin, byte[] graph). -
core/level/full/LevelFullJsonExporter.java(~330 lignes) : serialisation JSON
manuelle (StringBuilder + helpers), sans dependance externe. Tous les champs
systematiquement emis, indente. -
core/level/full/LevelFullExtractorMain.java(~100 lignes) : entry point qui
itere LEVEL_A..P, litsrc/main/resources/levels/LEVEL_X/twolev.binet
twolev.graph.bin, ecritassets/levels/level_X_full.json. Niveaux absents
listes dansassets/levels/MISSING.md. -
core/level/full/SmokeTest.java(~285 lignes) : test synthetique avec ~26
assertions. Fabrique des mini twolev.bin/graph.bin avec valeurs connues, parse,
verifie. Couvre header, messages, points, control points, zones, edges, doors
(avec ZLiftable signe :bottom=-32correct), switches, JSON valide. Toutes
les assertions passent.
Constantes confirmees via /mnt/project/defs.i + zone_liftable.h + newanims.s + hires.s
LVLT_MESSAGE_LENGTH = 160,LVLT_MESSAGE_COUNT = 10-> bloc messages = 1600 bytesLvlT/TLBT_SizeOf = 54bytes,TLGT_SizeOf = 20bytesZoneT_SizeOf = 50,EdgeT_SizeOf = 16,ObjT/EntT = 64,ODefT = 40,PVST = 8ZLiftable = 36 bytes(zone_liftable.h:33),ZDoorWall = 10 bytesSwitch = 14 bytes × 8 records fixes(newanims.s:1585 SwitchRoutine, deduit
viamove.w #7,d0)PointBrights = NumZones × 80 bytes(40 words/zone, hires.s:1502 muls #40)- Door/Lift stream :
[ZLiftable + ZDoorWall×2N + WORD -1]... terminee par
WORD 999 END_OF_DOOR_LIST = 999,END_OF_DOOR_WALL_LIST = -1numObjectsdeduit par(offsetToPlayerShot - offsetToObjects) / 64car le
champTLBT_NumObjects_w(offset 20) est en realite
Lvl_NumObjectPoints_w(confirme hires.s:413).- Convention
numZones = field + 1: le binaire stockeMaxZoneId, le parser
fait+1(LEVEL_A = 134 zones donc le binaire stocke 133). Aligne avec le
parser existant.
Tasks Gradle ajoutees
extractLevelsFull: lance l’extraction sur les 16 niveaux. Genere les JSONMISSING.mdlistant les niveaux absents.extractLevelsFullSmokeTest: lance le smoke test (assertions sur donnees
synthetiques).
Actions NetBeans : action.custom-43 et action.custom-44.
Validation locale (pre-deploiement)
En sandbox (avant integration projet) :
cd /home/claude/work
javac -d build -sourcepath src src/com/ab3d2/core/level/full/*.java
java -cp build com.ab3d2.core.level.full.SmokeTest
# Resultat : 26 assertions passees, JSON valide affiche
Reste a faire (post deploiement)
- Copier les niveaux depuis
ab3d2-tkg-original/media/levels/LEVEL_*/vers
ab3d2-tkg-jme/src/main/resources/levels/LEVEL_*/(au moinstwolev.binet
twolev.graph.bin) : actuellement les dossiers cibles sont vides. - Lancer
./gradlew extractLevelsFullSmokeTestpuis./gradlew extractLevelsFull
pour generer les JSON. - Valider sur LEVEL_A (134 zones, 635 edges) : verifier qu’aucun parsing ne
remonte d’erreur.
Limites connues / a verifier ensuite
- Format Control Points : assume 4 bytes/point (WORD X + WORD Z). A
verifier en croisant avecEntT_CurrentControlPoint_w. Le dump raw hex est
expose en parallele pour permettre une re-interpretation si necessaire. - Champs EdgeT TODO (
word5,byte12,byte13,flags) : conserves en raw
signed/unsigned, mais leur usage exact n’est pas decode. - Champs ZLiftable
word9..word12,word16: TODO dans defs.i, conserves
en raw. Probablement coordonnees XZ pour positionnement / animation texture. - Format Switch (14 bytes) : deduit de l’ASM SwitchRoutine, pas confirme
par defs.i. Champs+11..+13exposes en hex.
Pipeline pour tester apres deploiement
# 1. Verifier que la compilation passe
./gradlew compileJava
# 2. Lancer le smoke test (assertions deterministes)
./gradlew extractLevelsFullSmokeTest
# 3. Copier au moins LEVEL_A et LEVEL_B depuis original (si manquants) :
# src/main/resources/levels/LEVEL_A/twolev.bin
# src/main/resources/levels/LEVEL_A/twolev.graph.bin
# 4. Lancer l'extraction complete
./gradlew extractLevelsFull
# 5. Verifier le JSON genere
ls -lh assets/levels/level_*_full.json
head -100 assets/levels/level_A_full.json