Script directory: Difference between revisions
(Created page with "The script directory (contained in the master file table) contains both bytecode scripts and strings used in the game. It's layout is different than the other directories in the MFT: <syntaxhighlight lang="c"> struct script_directory { u32 unknown; // 0x3ea8eae6 in Boktai 1 (U) script_entry script_entries[]; directory_offsets offsets; // string_index contains the start index (in string_data) for each string // NOTE: offsets.string_i...") |
No edit summary |
||
Line 10: | Line 10: | ||
// string_index contains the start index (in string_data) for each string | // string_index contains the start index (in string_data) for each string | ||
// NOTE: offsets.string_index points here | // NOTE: offsets.string_index points here | ||
u32 string_index[ | u32 string_index[]; | ||
// NOTE: offsets.string_data points here | // NOTE: offsets.string_data points here | ||
char string_data[]; | char string_data[]; | ||
Line 21: | Line 21: | ||
// Unknown data, including the "special script" | // Unknown data, including the "special script" | ||
u8[?] | u8 unknown[?]; | ||
}; | }; | ||
// Use one of these two structs for script_entry, depending on the game: | // Use one of these two structs for script_entry, depending on the game: | ||
// script_entries[] array is null-terminated (ends when all fields are 0) | // script_entries[] array is null-terminated (ends when all fields are 0) | ||
struct script_entry_boktai_1 { | struct script_entry_boktai_1 { | ||
u32 id; | u32 id; // script id | ||
u32 offset; // top 8 bits unknown (not part of offset) | |||
u32 offset | |||
}; | }; | ||
// script_entries[] array is -1 terminated (ends when | // script_entries[] array is -1 terminated (ends when all fields are -1) | ||
struct script_entry_boktai_2_and_3 { | struct script_entry_boktai_2_and_3 { | ||
// id is implied (id = array index + 1) | // id is implied (id = array index + 1), meaning the 1st script has ID 1, not ID 0! | ||
u32 offset; // top 8 bits unknown (not part of offset) | |||
u32 offset | |||
}; | }; | ||
Line 49: | Line 45: | ||
u32 unknown; // offset to unknown data | u32 unknown; // offset to unknown data | ||
}; | }; | ||
</syntaxhighlight> | |||
= Example code (Boktai 1) = | |||
<syntaxhighlight lang="c"> | |||
script_entry_boktai_1* script_index; | |||
int script_count; | |||
u8* script_data; | |||
char* string_data; | |||
u32* string_index; | |||
// ptr = pointer to script_directory | |||
void open_script_directory(u8* ptr) { | |||
// skip "unknown" field | |||
ptr += 4; | |||
script_index = (script_entry_boktai_1*) ptr; | |||
// skip over script index | |||
while (true) { | |||
script_entry_boktai_1* entry = (script_entry_boktai_1*) ptr; | |||
ptr += 8; | |||
if (entry->id == 0 && entry->offset == 0) { | |||
break; | |||
} | |||
script_count++; | |||
} | |||
script_data = (u8*)(ptr + *(uint32_t*)ptr); | |||
string_index = (u32*)(ptr + *(uint32_t*)(ptr + 4)); | |||
string_data = (char*)(ptr + *(uint32_t*)(ptr + 8)); | |||
} | |||
char* get_string(int id) { | |||
// top bit is unknown, always seems to be 1? | |||
u32 offset = string_index[id] & 0x7fffffff; | |||
return string_data + offset; | |||
} | |||
u8* get_script(int id) { | |||
// NOTE: you should use a binary search (script_index is sorted by id) | |||
for (int i=0; i<script_count; i++) { | |||
script_entry_boktai_1* entry = script_index + i; | |||
if (entry->id == id) { | |||
// +4 to skip over the "special_script_offset" field | |||
return script_data + 4 + (entry->offset & 0x00ffffff); | |||
} | |||
} | |||
return NULL; | |||
} | |||
</syntaxhighlight> | |||
= Example code (Boktai 2 & 3) = | |||
<syntaxhighlight lang="c"> | |||
u32* script_index; | |||
char* string_data; | |||
u8* script_data; | |||
int script_count; | |||
u32* string_index; | |||
// ptr = pointer to script_directory | |||
void open_script_directory(u8* ptr) { | |||
// skip "unknown" field | |||
ptr += 4; | |||
script_index = (u32*) ptr; | |||
// skip over script index | |||
while (true) { | |||
u32 script_offset = *(u32*)ptr; | |||
ptr += 4; | |||
if (script_offset == 0xffffffff) { | |||
break; | |||
} | |||
script_count++; | |||
} | |||
script_data = (u8*)(ptr + *(uint32_t*)ptr); | |||
string_index = (u32*)(ptr + *(uint32_t*)(ptr + 4)); | |||
string_data = (char*)(ptr + *(uint32_t*)(ptr + 8)); | |||
} | |||
char* get_string(int id) { | |||
// top bit is unknown, always seems to be 1? | |||
u32 offset = string_index[id] & 0x7fffffff; | |||
return string_data + offset; | |||
} | |||
u8* get_script(int id) { | |||
if (id <= 0 || id > script_count) { | |||
return NULL; | |||
} | |||
u32 offset = script_index[id - 1]; | |||
return script_data + 4 + (offset & 0x00ffffff); | |||
} | |||
</syntaxhighlight> | </syntaxhighlight> |
Revision as of 07:56, 7 August 2024
The script directory (contained in the master file table) contains both bytecode scripts and strings used in the game. It's layout is different than the other directories in the MFT:
struct script_directory {
u32 unknown; // 0x3ea8eae6 in Boktai 1 (U)
script_entry script_entries[];
directory_offsets offsets;
// string_index contains the start index (in string_data) for each string
// NOTE: offsets.string_index points here
u32 string_index[];
// NOTE: offsets.string_data points here
char string_data[];
// NOTE: offsets.script_data points here
u32 special_script_offset; // unknown...
// NOTE: script_entry.offset is relative to here
u8 bytecode[];
// Unknown data, including the "special script"
u8 unknown[?];
};
// Use one of these two structs for script_entry, depending on the game:
// script_entries[] array is null-terminated (ends when all fields are 0)
struct script_entry_boktai_1 {
u32 id; // script id
u32 offset; // top 8 bits unknown (not part of offset)
};
// script_entries[] array is -1 terminated (ends when all fields are -1)
struct script_entry_boktai_2_and_3 {
// id is implied (id = array index + 1), meaning the 1st script has ID 1, not ID 0!
u32 offset; // top 8 bits unknown (not part of offset)
};
struct directory_offsets {
// all offsets here are relative to the start of this struct
u32 script_data;
u32 string_index;
u32 string_data;
u32 unknown; // offset to unknown data
};
Example code (Boktai 1)
script_entry_boktai_1* script_index;
int script_count;
u8* script_data;
char* string_data;
u32* string_index;
// ptr = pointer to script_directory
void open_script_directory(u8* ptr) {
// skip "unknown" field
ptr += 4;
script_index = (script_entry_boktai_1*) ptr;
// skip over script index
while (true) {
script_entry_boktai_1* entry = (script_entry_boktai_1*) ptr;
ptr += 8;
if (entry->id == 0 && entry->offset == 0) {
break;
}
script_count++;
}
script_data = (u8*)(ptr + *(uint32_t*)ptr);
string_index = (u32*)(ptr + *(uint32_t*)(ptr + 4));
string_data = (char*)(ptr + *(uint32_t*)(ptr + 8));
}
char* get_string(int id) {
// top bit is unknown, always seems to be 1?
u32 offset = string_index[id] & 0x7fffffff;
return string_data + offset;
}
u8* get_script(int id) {
// NOTE: you should use a binary search (script_index is sorted by id)
for (int i=0; i<script_count; i++) {
script_entry_boktai_1* entry = script_index + i;
if (entry->id == id) {
// +4 to skip over the "special_script_offset" field
return script_data + 4 + (entry->offset & 0x00ffffff);
}
}
return NULL;
}
Example code (Boktai 2 & 3)
u32* script_index;
char* string_data;
u8* script_data;
int script_count;
u32* string_index;
// ptr = pointer to script_directory
void open_script_directory(u8* ptr) {
// skip "unknown" field
ptr += 4;
script_index = (u32*) ptr;
// skip over script index
while (true) {
u32 script_offset = *(u32*)ptr;
ptr += 4;
if (script_offset == 0xffffffff) {
break;
}
script_count++;
}
script_data = (u8*)(ptr + *(uint32_t*)ptr);
string_index = (u32*)(ptr + *(uint32_t*)(ptr + 4));
string_data = (char*)(ptr + *(uint32_t*)(ptr + 8));
}
char* get_string(int id) {
// top bit is unknown, always seems to be 1?
u32 offset = string_index[id] & 0x7fffffff;
return string_data + offset;
}
u8* get_script(int id) {
if (id <= 0 || id > script_count) {
return NULL;
}
u32 offset = script_index[id - 1];
return script_data + 4 + (offset & 0x00ffffff);
}