Bug fix : 0 edges sur tous les niveaux
Après premier run de extractLevelsFull sur les 16 niveaux, on observe 0 edges
sur tous les niveaux, ce qui est impossible (les niveaux ont 50-220 zones).
Diagnostic : le calcul était
int numEdges = (offsetToObjects - offsetToFloorLines) / EDGE_SIZE;
basé sur le commentaire ; todo de hires.s:362-369. Mais sur LEVEL_A :
– offsetToFloorLines = 25494
– offsetToObjects = 3014
=> (3014 - 25494) < 0, donc numEdges = 0. Les edges sont en réalité à la fin
du fichier, pas entre les autres sections. Le commentaire ASM était un TODO non
résolu chez Team17 eux-mêmes.
Fix dans LevelFullExtractor.java :
int edgeStart = header.offsetToFloorLines;
int edgeEnd = header.offsetToObjects > edgeStart
? header.offsetToObjects // cas "theorique"
: bin.length; // cas reel observe
int numEdges = Math.max(0, (edgeEnd - edgeStart) / EDGE_SIZE);
// Sanity check : somme des ZoneT_Points_w (chaque zone est polygone N-edges)
int zoneEdgesSum = zones.stream().mapToInt(ZoneRecord::pointsCount).sum();
if (zoneEdgesSum > 0 && zoneEdgesSum < numEdges) numEdges = zoneEdgesSum;
Extension : intégration de twolev.clips/.map/.flymap
Deuxième phase de l’extracteur : lire les 3 fichiers de niveau qu’on n’utilisait
pas. Refactor minimal pour rester rétrocompatible.
Nouveaux records dans LevelFullExtractor :
– PvsClipData(totalBytes, totalWords, groups, tailHex) :
contenu de twolev.clips découpé en groupes de WORDs séparés par 0xFFFE,
avec la queue (probable Lvl_ConnectTable) en hex.
– LevelGrid(width, height, totalBytes, dataHex) :
grille 100×100 bytes pour twolev.map et twolev.flymap.
Nouveaux champs dans ExtractedLevel :
– PvsClipData clips (null si twolev.clips absent)
– LevelGrid map (null si twolev.map absent)
– LevelGrid flyMap (null si twolev.flymap absent)
API :
– extract(id, bin, graph) reste la signature historique (overload qui délègue
avec null/null/null) — SmokeTest continue à marcher sans modif.
– extract(id, bin, graph, clips, map, flyMap) est la nouvelle signature complète.
Main charge les 3 fichiers via Files.exists() (silencieux si absent).
L’output console affiche maintenant [CMF] indiquant la présence de chaque
fichier optionnel : [CMF] = tous trois présents, [--F] = juste flymap, etc.
JSON : les 3 nouveaux champs sont sérialisés en queue. Pour les fichiers
absents : "clips": null, "map": null, "flyMap": null. Pour les présents,
structure complète avec groups: [[...], [...], ...] pour les clips et dataHex
pour les grilles.
Format de twolev.clips reverse-engineeré
Depuis hires.s:418-475 :
– Tableau de WORDs signés 16-bit big-endian
– Séparateur 0xFFFE (-2) entre les groupes de clips
– Chaque groupe = liste d’indices vers les points (vertices) qui clippent un
edge dans le PVS d’une zone
– Après tous les groupes : Lvl_ConnectTable (table de connexions inter-zones,
format à reverser plus tard)
Notre parseur découpe naïvement sur tous les 0xFFFE et place le reste après le
dernier 0xFFFE dans tailHex. Plus tard, le cross-référencement avec les
PVST.clipId permettra d’identifier exactement où s’arrête la série de groupes
PVS et où commence la ConnectTable.
Format de twolev.map / twolev.flymap
Grilles 100×100 bytes (10000 = 100²). Chaque cellule = ID de tile :
– twolev.map : map top-down (sol/plafond visible au menu pause)
– twolev.flymap : pathfinding AI grid pour les flying aliens
Stocké en hex pour rester compact dans le JSON. Le décodage 2D se fait côté
consommateur (par exemple un futur LevelMapInspector).