Tutte le pagine dei formati ↓
Tutorial e riferimenti

Insidie comuni nel modding e nell'analisi dei file

Fonte: coreprime/kbot @ 0ab97bf · Modifica su GitHub

Un promemoria di una sola pagina con le insidie in cui si cade più spesso, sparse nei documenti sui formati di kbot. Se ti trovi davanti a un bug che non ha alcun senso, comincia da qui. Ogni voce rimanda alla spiegazione approfondita nella pagina del formato corrispondente.

Tip

Cerchi "la mia mod non si carica"? La regola del punto e virgola dei TDF (#tdf--fbi--ota, prima voce) è all'origine di più segnalazioni di "rotture silenziose" di tutte le altre insidie messe insieme.


HPI / UFO / CCX / GP3

  • I file sciolti nella radice dell'installazione hanno la precedenza su qualsiasi archivio. Metti units/MYUNIT.fbi su disco e il motore lo preferirà a qualunque cosa ci sia in totala1.hpi. Il diagramma della stratificazione in hpi.md mostra l'intera pila delle priorità.
  • Tra gli archivi vince il primo montato, e si montano solo dieci *.hpi. TA 3.1c monta rev31.gp3, poi *.ccx, *.ufo e i primi dieci *.hpi che riesce ad aprire, ogni gruppo in ordine di nome ASCII maiuscolo. Una mod distribuita come zz_mod.hpi viene dopo ogni archivio originale e, in un'installazione che ha già dieci *.hpi che la precedono nell'ordinamento, si monta solo tramite la scansione del CD, sotto tutto il resto. Distribuisci le mod come .ufo.
  • I puntatori di HPI v1 sono assoluti rispetto all'inizio del file, non all'inizio della directory. Non sottrarre niente. Il trucco del parser canonico è allocare un buffer di DirectorySize byte e decifrarci dentro la directory all'offset Start, così i puntatori indicizzano direttamente il buffer. Vedi Albero delle directory.
  • Il seme della cifratura di HPI v1 avanza con la posizione nel file. Non puoi decifrare un buffer preso da solo: devi sapere da quale offset assoluto del file proviene. Vedi Ricavare la chiave di cifratura.
  • Se DecryptKey == 0, non applicare affatto la cifratura XOR. Alcuni archivi personalizzati sono distribuiti in chiaro; applicare comunque la cifratura rimescola ciò che era già leggibile.
  • Il checksum dei chunk SQSH è calcolato sui byte cifrati. Verificalo prima di decifrare. Vedi Chunk compressi (SQSH).
  • TA: Kingdoms usa HPI v2 (Version == 0x00020000) con una struttura diversa: niente XOR, un solo chunk SQSH per file. Leggi la sezione HPI v2 di TA: Kingdoms prima di provare il parser v1 su un archivio di TAK.
  • I salvataggi con il marcatore BANK sono un'altra cosa: riusano l'involucro HPI, ma il contenuto è lo stato di gioco serializzato, non un filesystem. kbot non li decodifica.
  • Un .gp3 richiede la patch rev3.1. Dentro è ancora un HPI, ma TA senza patch si rifiuta di montarlo.

TDF / FBI / OTA

  • Ogni valore deve terminare con ;. I punti e virgola mancanti uniscono silenziosamente i valori di più righe e producono statistiche completamente sbagliate. È la causa n. 1 dei casi "la mia unità ha punti ferita strani / non ha descrizione / ha il costo sbagliato".
  • Le chiavi non distinguono tra maiuscole e minuscole, i valori sì. Side=arm funziona per la maggior parte delle ricerche, ma rompe il codice di qualsiasi mod che confronti Side per uguaglianza di stringhe.
  • I valori delle liste sono separati da spazi (Category=COMMANDER MOBILE WEAPON), non da virgole. L'eccezione è numplayers=2,4,6,8,10 degli OTA, che usa le virgole.
  • I booleani sono interi 1/0, non true/false. Il motore accetta solo le forme intere.
  • Nelle mod, non modificare mai sidedata.tdf per aggiungere unità. Usa invece una registrazione [MENUENTRY] in download/<UNITNAME>.tdf: lo stesso meccanismo usato da Core Contingency. Vedi TDF: [MENUENTRY] e il tutorial sul modding.
  • Bmcode=0 nasconde un'unità dal menu di costruzione anche se tutto il resto è valido. Quasi sempre vuoi Bmcode=1.
  • Un'unità che non compare sotto alcun costruttore non si può costruire, anche se per il resto il suo FBI è valido. È il bug più comune del tipo "la mia nuova unità esiste ma non si può costruire". Vedi il passo 5 del tutorial sul modding.
  • La profondità delle sezioni annidate è una convenzione, non una specifica. Alcuni strumenti presuppongono 2 livelli; i TDF delle armi arrivano a 3 ([WEAPON][DAMAGE][category]).

TNT / SCT — terreno delle mappe

  • Width e Height del TNT sono celle degli attributi da 16 px, non tile e non pixel. Dividi per 2 per il numero di tile; moltiplica per 16 per le dimensioni in pixel. Vedi l'intestazione TNT.
  • SeaLevel == 0 NON significa "niente acqua": significa che il valore più piccolo possibile sta sulla soglia, quindi niente è sott'acqua. Usa SeaLevel = 1 per le mappe davvero asciutte.
  • Le parole degli elementi nel TNT piazzano un elemento solo se sono inferiori al numero di voci della tabella degli elementi. 0xFFFC è una cella vuota (void); 0xFFFE (Lava Run, AC02), 0xFFFD e qualsiasi altra parola pari o superiore alla dimensione della tabella non piazzano nulla, e la cella resta edificabile.
  • Il riempimento della minimappa TNT usa l'indice della palette 0x64, e la regione della mappa è dimensionata a partire dalla mappa (lato lungo 252, proporzioni della mappa visibile), non trovata cercando il riempimento. Il gioco legge la minimappa memorizzata solo quando è impostato il bit 0 della parola dell'intestazione a 0x2c. Vedi TNT.
  • I .tnt di TA: Kingdoms usano IDVersion == 0x4000 invece del 0x2000 di TA (TA legge anche una struttura più vecchia, 0x1020). kbot tnt image produce immagini senza senso sui TNT di TAK; il decodificatore dei tile è specifico di TA. Vedi Mappe TA:K.
  • Le sezioni SCT devono avere entrambe le dimensioni multiple di 4 per essere caricate in TAE. Il formato su disco ammette altre dimensioni, ma l'editor le rifiuta con "section misaligned".
  • SCT V2 ha celle delle altezze da 8 byte, V3 da 4 byte. kbot accetta entrambe; le mod costruite con l'editor vedono solo V3.

3DO — modelli

  • L'asse verso l'alto è Y, non Z. Importare un 3DO in un motore con Z verso l'alto (Blender, Unreal moderno) senza scambiare gli assi lascia ogni unità sdraiata su un fianco.
  • Le primitive senza texture sono invisibili a meno che IsColored != 0: lo pseudocodice visible = (texture != "") || (IsColored != 0) copre entrambi i casi. È il bug di rendering dei 3DO più comune.
  • OffsetToSelectionPrim ha senso solo sull'oggetto radice; gli oggetti figli devono impostarlo a -1 (0xFFFFFFFF).
  • La scala in virgola fissa è 1 / 65536. Un vertice scritto come 0x00010000 vale 1,0 unità del mondo; i 16 bit bassi sono la parte frazionaria.
  • I vertici sono locali all'oggetto, non globali. Due oggetti possono avere array di vertici identici: si tratta di geometria speculare, non di dati condivisi.

COB / BOS — script

  • L'opcode di call-script è 0x10062000, NON 0x10063000 come sostengono alcuni documenti precedenti alla 3.1. I vecchi decompilatori che usano 0x10063000 producono risultati senza senso: vedi il riferimento degli opcode.
  • I numeri dei pezzi negli opcode sono indici nella tabella dei nomi dei pezzi, non stringhe. Il COB contiene i nomi come pool di stringhe; il runtime usa gli indici per ragioni di velocità.
  • SET_SIGNAL_MASK registra solo un interesse: non uccide niente. È l'invio di signal X a fermare gli script la cui maschera ha X impostato. La regola di lint signal-never-signalled individua gli script che impostano una maschera che nessuno segnala mai.
  • Lo Scriptor di Cavedog sostituisce inline CURRENT_SPEED con il letterale 29, rompendo gli script in stile MoveWatcher dopo un round-trip. Il decompilatore di kbot ripristina il nome simbolico; se devi per forza fare un round-trip con Scriptor, metti le parentesi: (get CURRENT_SPEED) > 5.
  • Gli offset dei salti sono offset in byte relativi a OffsetToScriptCode, non all'istruzione corrente. JUMP 0x4C significa "salta a OffsetToScriptCode + 0x4C".
  • I numeri di porta di GET_UNIT_VALUE cambiano tra TA e TA:K. Il catalogo di TA (il decompilatore di kbot etichetta le porte 1–20) è documentato nell'Appendice B.

GAF — animazioni di sprite

  • Una sequenza va in loop solo quando il byte basso della sua parola +2 è impostato; con 0 viene riprodotta una volta e si ferma. Tutte le sequenze originali contengono 1, quindi uno strumento che scrive zero congela gli elementi animati.
  • I frame in textures/*.gaf e anims/vismasks.gaf devono essere grezzi. Il gioco li legge come semplici array di pixel.
  • Alcune sequenze sono distribuite con durate dei frame pari a 0; il gioco mostra un frame del genere per un tick. Non "correggerle" con un valore predefinito.
  • L'indice 0 della palette non è trasparente di per sé. Lo sono solo la chiave di un frame grezzo e i run saltati di un frame compresso.
  • Le righe di pixel compresse possono essere più corte di Width. Il gioco continua a leggere i byte successivi; kbot completa la riga con pixel trasparenti e lo segnala. Nessun file originale ha righe del genere.
  • Le origini dei livelli sono hotspot: ogni livello di un frame composto viene posizionato in modo che la sua origine cada sull'origine del frame.
  • anims/terrain.gaf e anims/vismasks.gaf hanno Version == 0 nell'intestazione. Il gioco ignora la parola di versione.
  • Il .taf di TA: Kingdoms esiste in due varianti. Un .taf con palette È un GAF: stesso formato su disco, salvo che TAK prende la palette da un .pcx per fazione invece che dalla palette globale di TA. Un .taf truecolor riusa lo stesso contenitore ma memorizza pixel ARGB a 16 bit e non ha bisogno di una palette. A fare fede è il byte del formato del frame (0/1 = con palette, 4/5 = truecolor), non l'estensione: vedi TAF / TSF.

TAF / TSF — animazioni truecolor

  • .taf ha più significati: con palette (da leggere come GAF) oppure truecolor (da leggere con kbot taf). Controlla sempre il byte del formato del frame, mai il nome del file, anche se per convenzione la maggior parte dei file truecolor di TAK porta un suffisso _4444 / _1555.
  • L'esportazione in GIF perde informazioni. Una GIF contiene solo un ritaglio a 1 bit e 255 colori, quindi l'alfa sfumato di ARGB4444 si trasforma in bordi netti. Usa APNG (kbot taf export --format apng) per conservare il vero canale alfa.
  • Il campo del nome del frame e il byte di flag 0x0B possono contenere spazzatura. Conservali tali e quali per un round-trip esatto byte per byte; non normalizzarli.
  • Un Delay / Duration pari a 0 è valido: come nel GAF, un frame da zero tick è guidato dagli eventi (lo usano gli sfondi statici dei menu). Non "correggerlo".

PCX — immagini

  • TA ignora BytesPerLine. I lettori standard scartano il riempimento quando BytesPerLine > Width; TA 3.1c decodifica esattamente Width byte per riga, quindi nel gioco i file con riempimento risultano sfalsati. Scrivi BytesPerLine == Width e verifica con kbot pcx describe.
  • TA carica solo la versione 5, e decodifica ogni file come dati a 8 bit su un solo piano.
  • I byte letterali con i due bit alti impostati vanno codificati come run RLE. Un byte isolato di valore 0xC0–0xFF non è valido come letterale; scrivilo come run di lunghezza 1 (0xC1, 0xFF per un singolo 0xFF). Se lo si gestisce male, la decodifica perde la sincronia dopo una riga.
  • Il gioco prende gli ultimi 768 byte come palette, con o senza il marcatore 0x0C; i lettori standard hanno bisogno del marcatore.

PAL / ALP / LHT / SHD — palette e tabelle di ricerca

  • Il 4° byte di ogni voce NON è l'alfa. È un byte di riempimento inutilizzato che Cavedog ha sempre impostato a 0x00. Gli strumenti open source per le palette che lo trattano come alfa non riescono a disegnare la palette (alfa=0 → tutto trasparente).
  • L'indice 0 è nero, non trasparente. Terreno, minimappe e fondali lo disegnano opaco; gli sprite scelgono la propria chiave di trasparenza.
  • Un palette.pal vuoto o mancante viene sostituito da palette.pcx (i suoi ultimi 768 byte); un .pal più lungo di 1.024 byte viene letto fino al byte 1.024.
  • .alp / .lht / .shd NON sono palette RGB: .alp è una tabella 256×256 e .shd / .lht sono tabelle 32×256 di indici della palette, e il gioco ignora (e ricostruisce) una tabella di qualsiasi altra dimensione. Disegnarle con kbot pal describe mostra immagini senza senso; usa invece kbot pal lookup.
  • La palette di TA contiene 13 terne RGB duplicate. Se il tuo editor elimina i duplicati all'importazione (alcuni lo fanno), perdi delle voci e la palette diventa silenziosamente di 243 voci.

FNT — font bitmap

  • Offsets[c] == 0 significa "nessun glifo", non "glifo all'offset 0". L'offset 0 cade a metà dell'intestazione: Cavedog riusa lo zero come valore sentinella.
  • L'ordine dei bit è MSB-first all'interno di ciascun byte. Nei font bitmap moderni è più comune LSB-first; non darlo per scontato.
  • Il flusso di bit è continuo tra una riga e l'altra: nessun riempimento alla fine di ogni riga di scansione.

Profili IA

  • I file IA di TA: Kingdoms non hanno direttive plan: solo righe weight/limit isolate. Il parser di kbot apre un plan default implicito; i lettori dovrebbero tollerare il blocco mancante. Vedi TA:K — profili senza plan.
  • Nessuna validazione, da nessuna parte. Nomi di unità scritti male, valori di peso sbagliati, righe fuori da un plan: tutto viene ignorato in silenzio. Il primo segno di un profilo rotto è "l'IA si comporta in modo strano", senza alcun messaggio di log.
  • Gli alias di categoria (PLANT, LEVEL3) "esistono" solo se almeno un'unità li dichiara in Category=. Scrivi per errore LEVL3 e la direttiva non fa nulla, in silenzio.

Suoni

  • Un WAV mancante produce silenzio, non un errore. Scrivi male select1=cmsdel1 (lettere invertite) e il motore non riproduce nulla: nessun log, nessun ripiego.
  • L'estensione .wav è implicita nei valori dei TDF: non scriverla mai. select1=cmdsel1.wav diventa sounds/cmdsel1.wav.wav e non trova nulla.

Particolarità di TA: Kingdoms

  • TAK richiede -disablecavedogverification come argomento della riga di comando per caricare la maggior parte dei file modificati. Senza questa opzione il motore rifiuta qualsiasi file il cui hash non compaia nel suo elenco di quelli ammessi.
  • Nei dati di TAK ci sono 8 codici di fazione, non 4: ARA / TAR / VER / ZON per le quattro fazioni giocabili, più CRE (Creon, Iron Plague), MON (mostri), LIF (fauna selvatica), NPC (personaggi della campagna). Il filtraggio degli elenchi di unità deve gestirli tutti.
  • In TAK le armi stanno inline in ogni FBI come sottosezioni [WEAPON1]–[WEAPON3], non in una directory separata weapons/*.tdf.
  • I menu di costruzione di TAK sono lineari, non 2×3. Ogni costruttore ha una directory canbuild/<builder>/<unit>.tdf con un singolo blocco [Menu] { Priority = N; }.

Vedi anche

  • Tutorial sul modding: una mod di un'unità di TA, dall'inizio alla fine.
  • Glossario: le definizioni di tutti i termini comuni ai vari formati citati qui sopra.
  • Guida rapida: cinque comandi kbot da provare subito.