XPlor/definitions/asura/asura_archive.xscript
njohnson 8f07bf0b72 Update Asura XScript definitions with new syntax
- Migrate from bracket attributes to ui() function calls
- Enhance chunk parsing with improved structure definitions
- Add additional metadata fields to chunk handlers
- Update Xbox 360 texture and archive definitions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 12:10:29 -05:00

170 lines
6.4 KiB
Plaintext

// Asura Engine archive format
// Used by Rebellion games: Sniper Elite series, AVP 2010, etc.
// Archives contain chunks like FCSR (resources), TSXT (textures), LFSR (lists), etc.
type asura_archive [display="Asura Archive"] byteorder BE
{
criteria {
// Match "Asura " signature (8 bytes with trailing spaces)
require ascii(bytesat(0, 8)) == "Asura ";
}
// Store base name for chunk naming (use full filename, not basename)
base_name = _name;
// Set display name for this archive
set_name(base_name + ".asr");
// Asura signature
signature = ascii(read(8));
signature = signature;
ui("signature", "Signature");
// Track chunk indices (separate counter per type for naming)
chunk_index = 0;
ctx_set("_fcsr_idx", 0);
ctx_set("_tsxt_idx", 0);
ctx_set("_lfsr_idx", 0);
ctx_set("_stsa_idx", 0);
ctx_set("_txet_idx", 0);
ctx_set("_gsms_idx", 0);
ctx_set("_itne_idx", 0);
ctx_set("_stuc_idx", 0);
ctx_set("_catc_idx", 0);
ctx_set("_rttc_idx", 0);
ctx_set("_vetc_idx", 0);
ctx_set("_pose_idx", 0);
ctx_set("_pvet_idx", 0);
ctx_set("_tatc_idx", 0);
ctx_set("_ttat_idx", 0);
ctx_set("_tvet_idx", 0);
ctx_set("_ucat_idx", 0);
ctx_set("_uvet_idx", 0);
ctx_set("_unk_idx", 0);
// Parse chunks until end of file (need at least 16 bytes for header)
while (pos() + 16 <= size()) {
// Save chunk start position
chunk_start = pos();
// Peek at chunk header to get ID and size
peek_id = ascii(read(4));
u32 peek_size;
// Seek back to chunk start for proper parsing
seek(chunk_start);
// Validate chunk - if peek_size is 0 or invalid, stop parsing
if (peek_size == 0 || peek_size > size() - chunk_start) {
remaining = size() - pos();
if (remaining > 0) {
raw_tail = read(remaining);
ui("raw_tail", "Raw Tail Data");
}
break;
}
// Set chunk name before parsing (child will inherit this)
set_name(base_name + ".chunk" + chunk_index);
// Dispatch to appropriate chunk type based on ID and push to arrays
// Note: increment index AFTER parse so chunk can read current value
if (peek_id == "FCSR" || peek_id == "RSCF") {
chunk = parse_here("fcsr_chunk");
push("fcsr_chunks", chunk);
ctx_set("_fcsr_idx", ctx_get("_fcsr_idx") + 1);
} else if (peek_id == "TSXT" || peek_id == "TXST") {
chunk = parse_here("tsxt_chunk");
push("tsxt_chunks", chunk);
ctx_set("_tsxt_idx", ctx_get("_tsxt_idx") + 1);
} else if (peek_id == "LFSR" || peek_id == "RSFL") {
chunk = parse_here("lfsr_chunk");
push("lfsr_chunks", chunk);
ctx_set("_lfsr_idx", ctx_get("_lfsr_idx") + 1);
} else if (peek_id == "STSA" || peek_id == "ASTS") {
chunk = parse_here("stsa_chunk");
push("stsa_chunks", chunk);
ctx_set("_stsa_idx", ctx_get("_stsa_idx") + 1);
} else if (peek_id == "TXET" || peek_id == "TEXT") {
chunk = parse_here("txet_chunk");
push("txet_chunks", chunk);
ctx_set("_txet_idx", ctx_get("_txet_idx") + 1);
} else if (peek_id == "GSMS" || peek_id == "SMSG") {
chunk = parse_here("gsms_chunk");
push("gsms_chunks", chunk);
ctx_set("_gsms_idx", ctx_get("_gsms_idx") + 1);
} else if (peek_id == "ITNE" || peek_id == "ENTI") {
chunk = parse_here("itne_chunk");
push("itne_chunks", chunk);
ctx_set("_itne_idx", ctx_get("_itne_idx") + 1);
} else if (peek_id == "STUC" || peek_id == "CUTS") {
chunk = parse_here("stuc_chunk");
push("stuc_chunks", chunk);
ctx_set("_stuc_idx", ctx_get("_stuc_idx") + 1);
} else if (peek_id == "CATC") {
chunk = parse_here("catc_chunk");
push("catc_chunks", chunk);
ctx_set("_catc_idx", ctx_get("_catc_idx") + 1);
} else if (peek_id == "RTTC") {
chunk = parse_here("rttc_chunk");
push("rttc_chunks", chunk);
ctx_set("_rttc_idx", ctx_get("_rttc_idx") + 1);
} else if (peek_id == "VETC") {
chunk = parse_here("vetc_chunk");
push("vetc_chunks", chunk);
ctx_set("_vetc_idx", ctx_get("_vetc_idx") + 1);
} else if (peek_id == "POSE") {
chunk = parse_here("pose_chunk");
push("pose_chunks", chunk);
ctx_set("_pose_idx", ctx_get("_pose_idx") + 1);
} else if (peek_id == "PVET") {
chunk = parse_here("pvet_chunk");
push("pvet_chunks", chunk);
ctx_set("_pvet_idx", ctx_get("_pvet_idx") + 1);
} else if (peek_id == "TATC") {
chunk = parse_here("tatc_chunk");
push("tatc_chunks", chunk);
ctx_set("_tatc_idx", ctx_get("_tatc_idx") + 1);
} else if (peek_id == "TTAT") {
chunk = parse_here("ttat_chunk");
push("ttat_chunks", chunk);
ctx_set("_ttat_idx", ctx_get("_ttat_idx") + 1);
} else if (peek_id == "TVET") {
chunk = parse_here("tvet_chunk");
push("tvet_chunks", chunk);
ctx_set("_tvet_idx", ctx_get("_tvet_idx") + 1);
} else if (peek_id == "UCAT") {
chunk = parse_here("ucat_chunk");
push("ucat_chunks", chunk);
ctx_set("_ucat_idx", ctx_get("_ucat_idx") + 1);
} else if (peek_id == "UVET") {
chunk = parse_here("uvet_chunk");
push("uvet_chunks", chunk);
ctx_set("_uvet_idx", ctx_get("_uvet_idx") + 1);
} else {
// Unknown chunk type - parse as generic chunk
chunk = parse_here("asura_chunk");
push("unknown_chunks", chunk);
ctx_set("_unk_idx", ctx_get("_unk_idx") + 1);
}
// Increment chunk index
chunk_index = chunk_index + 1;
// Seek to next chunk (chunk_start + peek_size)
next_chunk = chunk_start + peek_size;
if (next_chunk > size()) {
break;
}
seek(next_chunk);
}
// Restore archive name and show total count
set_name(base_name + ".asr");
chunk_count = chunk_index;
chunk_count = chunk_count;
ui("chunk_count", "Total Chunks");
}