Preprocess ailists to convert goto-labels to goto-offsets

This commit is contained in:
Ryan Dwyer
2022-10-23 12:28:07 +10:00
parent 0c948fdce9
commit bef9668e68
11 changed files with 928 additions and 521 deletions
-30
View File
@@ -650,24 +650,6 @@ s32 chraiGetListIdByList(u8 *ailist, bool *is_global)
return -1;
}
u8 *chraiGoToLabel(u8 *ailist, u8 *aioffset, u8 label)
{
do {
u8 *cmd = aioffset;
u32 type = (cmd[0] << 8) + cmd[1];
if (type == CMD_LABEL) {
if (label == cmd[2]) {
return aioffset;
}
} else if (type == CMD_END) {
return 0;
}
aioffset += g_CommandLengths[type];
} while (true);
}
void chraiExecute(void *entity, s32 proptype)
{
g_Vars.chrdata = NULL;
@@ -785,15 +767,3 @@ void chraiExecute(void *entity, s32 proptype)
}
}
}
u32 chraiGetCommandLength(u8 *ailist, u8 *aioffset)
{
u8 *cmd = aioffset;
s32 type = (cmd[0] << 8) + cmd[1];
if (type >= 0 && type < ARRAYCOUNT(g_CommandLengths)) {
return g_CommandLengths[type];
}
return 1;
}
+442 -442
View File
File diff suppressed because it is too large Load Diff
-46
View File
@@ -127,52 +127,6 @@ void stageAllocateBgChrs(void)
g_SquadronList = mempAlloc(0x220, MEMPOOL_STAGE);
}
void stageLoadAllAilistModels(void)
{
u8 *cmd = g_StageSetup.ailists[0].list;
s32 i = 0;
u16 id;
if (!cmd) {
return;
}
do {
while (true) {
if (cmd[0] == AICMD_END) {
break;
}
switch (cmd[0]) {
case AICMD_DROPITEM:
id = cmd[3] | (cmd[2] << 8);
if (setupLoadModeldef(id));
break;
case AICMD_SPAWNCHRATPAD:
bodyLoad(cmd[2]);
if ((s8)cmd[3] >= 0 && bodyLoad((s8)cmd[3]));
break;
case AICMD_SPAWNCHRATCHR:
bodyLoad(cmd[2]);
if ((s8)cmd[3] >= 0 && bodyLoad((s8)cmd[3]));
break;
case AICMD_EQUIPWEAPON:
setupLoadModeldef(cmd[3] | (cmd[2] << 8));
if (modelmgrLoadProjectileModeldefs(cmd[4]));
break;
case AICMD_EQUIPHAT:
setupLoadModeldef(cmd[3] | (cmd[2] << 8));
break;
}
cmd += chraiGetCommandLength(cmd, cmd);
}
i++;
cmd = g_StageSetup.ailists[i].list;
} while (cmd);
}
void func0f00c230(void)
{
// empty
+2 -1
View File
@@ -36,7 +36,7 @@ bool ai0176(void)
aibot = g_Vars.chrdata->aibot;
if (aibot->unk059 == 1) {
g_Vars.aioffset = chraiGoToLabel(g_Vars.ailist, g_Vars.aioffset, cmd[2]);
g_Vars.aioffset = AILABEL(g_Vars.ailist, cmd[2], cmd[3]);
aibot->unk059 = 0;
} else {
g_Vars.aioffset += 3;
@@ -44,3 +44,4 @@ bool ai0176(void)
return false;
}
+2
View File
@@ -1379,6 +1379,8 @@ void setupLoadFiles(s32 stagenum)
for (g_NumGlobalAilists = 0; g_GlobalAilists[g_NumGlobalAilists].list != NULL; g_NumGlobalAilists++);
for (g_NumLvAilists = 0; g_StageSetup.ailists[g_NumLvAilists].list != NULL; g_NumLvAilists++);
ailistPreprocessFile(g_StageSetup.ailists, MEMPOOL_STAGE);
// Convert path pad pointers from file-local to proper pointers
// and calculate the path lengths
if (g_StageSetup.paths) {
+3
View File
@@ -20,9 +20,12 @@
#define MINFLOAT ((float)-3.40282346638528860e+38)
#define MAXFLOAT ((float)3.40282346638528860e+38)
#define AILABEL(ailist, upper, lower) ((ailist) + ((upper) << 8 | (lower)))
#define ABS(val) ((val) > 0 ? (val) : -(val))
#define ABSF(val) ((val) > 0.0f ? (val) : -(val))
#define ALIGN2(val) (((val) | 1) ^ 0x1)
#define ALIGN4(val) ((((val) + 0x3) | 0x3) ^ 0x3)
#define ALIGN8(val) ((((val) + 0x7) | 0x7) ^ 0x7)
#define ALIGN16(val) ((((val) + 0xf) | 0xf) ^ 0xf)
#define ALIGN64(val) (((((u32)(val)) + 0x3f) | 0x3f) ^ 0x3f)
-2
View File
@@ -5,8 +5,6 @@
#include "types.h"
s32 chraiGetListIdByList(u8 *ailist, bool *is_global);
u8 *chraiGoToLabel(u8 *ailist, u8 *aioffset, u8 label);
void chraiExecute(void *entity, s32 proptype);
u32 chraiGetCommandLength(u8 *ailist, u8 *aioffset);
#endif
+1
View File
@@ -5,5 +5,6 @@
#include "types.h"
u8 *ailistFindById(s32 ailistid);
void ailistPreprocessFile(struct ailist *ailist, s32 mempool);
#endif
+1
View File
@@ -5575,6 +5575,7 @@ struct bytelist {
u8 b10;
u8 b11;
u8 b12;
u8 b13;
};
struct stageallocation {
+473
View File
@@ -2,6 +2,7 @@
#include "constants.h"
#include "bss.h"
#include "lib/ailist.h"
#include "lib/memp.h"
#include "data.h"
#include "types.h"
@@ -56,3 +57,475 @@ u8 *ailistFindById(s32 ailistid)
return NULL;
}
bool ailistIsGoto(s32 type)
{
switch (type) {
case 0x0000:
case 0x0001:
case 0x000c:
case 0x000f:
case 0x0010:
case 0x0011:
case 0x0012:
case 0x0013:
case 0x0014:
case 0x0015:
case 0x0016:
case 0x0017:
case 0x0018:
case 0x001b:
case 0x001c:
case 0x0023:
case 0x0027:
case 0x002a:
case 0x002b:
case 0x002c:
case 0x002d:
case 0x002e:
case 0x002f:
case 0x0030:
case 0x0031:
case 0x0032:
case 0x0033:
case 0x0034:
case 0x0035:
case 0x0037:
case 0x0038:
case 0x0039:
case 0x003a:
case 0x003b:
case 0x003c:
case 0x003d:
case 0x003e:
case 0x003f:
case 0x0040:
case 0x0041:
case 0x0042:
case 0x0043:
case 0x0044:
case 0x0045:
case 0x0046:
case 0x0047:
case 0x0048:
case 0x0049:
case 0x004a:
case 0x004b:
case 0x004c:
case 0x004d:
case 0x004e:
case 0x004f:
case 0x0050:
case 0x0051:
case 0x0052:
case 0x0053:
case 0x0054:
case 0x0055:
case 0x0056:
case 0x0057:
case 0x0058:
case 0x0059:
case 0x005a:
case 0x005b:
case 0x005c:
case 0x005d:
case 0x005e:
case 0x005f:
case 0x0060:
case 0x0061:
case 0x0062:
case 0x0063:
case 0x006e:
case 0x006f:
case 0x0072:
case 0x0073:
case 0x0074:
case 0x0075:
case 0x0076:
case 0x0077:
case 0x0078:
case 0x0079:
case 0x007a:
case 0x007b:
case 0x007c:
case 0x007d:
case 0x007e:
case 0x007f:
case 0x0080:
case 0x0081:
case 0x0082:
case 0x0083:
case 0x0088:
case 0x0089:
case 0x008e:
case 0x008f:
case 0x0090:
case 0x009d:
case 0x00a0:
case 0x00a3:
case 0x00a6:
case 0x00a9:
case 0x00ac:
case 0x00af:
case 0x00ba:
case 0x00bb:
case 0x00bd:
case 0x00bc:
case 0x00c3:
case 0x00c4:
case 0x00c5:
case 0x00c6:
case 0x00c7:
case 0x00c8:
case 0x00c9:
case 0x00ca:
case 0x00d4:
case 0x00e2:
case 0x00e5:
case 0x00ea:
case 0x00eb:
case 0x00ef:
case 0x00f0:
case 0x00f1:
case 0x00f6:
case 0x00f7:
case 0x00f8:
case 0x00fc:
case 0x00fd:
case 0x0103:
case 0x0105:
case 0x0107:
case 0x0108:
case 0x0109:
case 0x010a:
case 0x010c:
case 0x010f:
case 0x0110:
case 0x0113:
case 0x011a:
case 0x011d:
case 0x011e:
case 0x011f:
case 0x0120:
case 0x0121:
case 0x0122:
case 0x0123:
case 0x0125:
case 0x0126:
case 0x0127:
case 0x0128:
case 0x0129:
case 0x012a:
case 0x012b:
case 0x012c:
case 0x0133:
case 0x0134:
case 0x0135:
case 0x0137:
case 0x0138:
case 0x013a:
case 0x013c:
case 0x013d:
case 0x013f:
case 0x0140:
case 0x0147:
case 0x0149:
case 0x014a:
case 0x014b:
case 0x0152:
case 0x0165:
case 0x0166:
case 0x0168:
case 0x0169:
case 0x016a:
case 0x016f:
case 0x0170:
case 0x0171:
case 0x0172:
case 0x0173:
case 0x0174:
case 0x0176:
case 0x0178:
case 0x017a:
case 0x017b:
case 0x0181:
case 0x0182:
case 0x0183:
case 0x0186:
case 0x0187:
case 0x0188:
case 0x018a:
case 0x018e:
case 0x018f:
case 0x0192:
case 0x0193:
case 0x019e:
case 0x01a5:
case 0x01a6:
case 0x01a7:
case 0x01aa:
case 0x01ab:
case 0x01b4:
case 0x01ba:
case 0x01bc:
case 0x01bd:
case 0x01be:
case 0x01c0:
case 0x01c9:
case 0x01cc:
case 0x01d7:
case 0x01d8:
case 0x01dd:
case 0x01df:
case 0x01de:
return true;
}
return false;
}
extern u16 g_CommandLengths[];
void ailistAnalyse(u8 *ailist, s32 *numcmdsptr, s32 *numlabelsptr, s32 *numgotosptr, s32 *oldsizeptr)
{
s32 numcmds = 0;
s32 numlabels = 0;
s32 numgotos = 0;
u8 *ptr = ailist;
s32 type;
do {
type = ptr[0] << 8 | ptr[1];
if (type == 0x0002) {
numlabels++;
} else if (ailistIsGoto(type)) {
numgotos++;
}
numcmds++;
ptr += g_CommandLengths[type];
} while (type != CMD_END);
*numcmdsptr = numcmds;
*numlabelsptr = numlabels;
*numgotosptr = numgotos;
*oldsizeptr = ptr - ailist;
}
struct tmpcmd {
u16 type;
u16 oldoffset;
u16 newoffset;
u8 len;
u8 labelnum; // if label
u8 gotolabelnum; // if goto
struct tmpcmd *target;
};
void ailistConvert(u8 *src, u8 *dst, struct tmpcmd *cmds, s32 numcmds)
{
s32 i = 0;
s32 j;
u8 *ptr = src;
s32 newoffset = 0;
s32 type;
// Start by building the tmpcmd list, but keeping the target pointers NULL
do {
type = ptr[0] << 8 | ptr[1];
cmds[i].type = type;
cmds[i].oldoffset = ptr - src;
cmds[i].newoffset = newoffset;
cmds[i].labelnum = 0xff;
cmds[i].gotolabelnum = 0xff;
cmds[i].target = NULL;
cmds[i].len = g_CommandLengths[type];
if (type == 0x0002) {
cmds[i].labelnum = ptr[2];
} else if (ailistIsGoto(type)) {
if (type == 0x01c0) {
cmds[i].gotolabelnum = ptr[2];
} else {
cmds[i].gotolabelnum = ptr[cmds[i].len - 1];
}
newoffset += cmds[i].len + 1;
} else {
newoffset += cmds[i].len;
}
ptr += cmds[i].len;
i++;
} while (type != CMD_END);
// Iterate again and populate the target pointers
for (i = 0; i < numcmds; i++) {
if (cmds[i].gotolabelnum != 0xff) {
j = cmds[i].type == 0x0001 ? 0 : i + 1;
while (j < numcmds) {
if (cmds[j].labelnum == cmds[i].gotolabelnum) {
cmds[i].target = &cmds[j];
break;
}
j++;
}
if (j == numcmds) {
// Label wasn't found
cmds[i].target = &cmds[0];
}
}
}
// Write the new data
ptr = dst;
for (i = 0; i < numcmds; i++) {
if (cmds[i].labelnum != 0xff) {
// Label - don't write it
} else if (cmds[i].type == 0x01c0) {
// Special goto with label as first param instead of last
ptr[0] = 0x01;
ptr[1] = 0xc0;
ptr[2] = cmds[i].target->newoffset >> 8;
ptr[3] = cmds[i].target->newoffset & 0xff;
ptr[4] = src[cmds[i].oldoffset + 3];
ptr += 5;
} else if (cmds[i].gotolabelnum != 0xff) {
// Goto - write it and replace the label with the offset
for (j = 0; j < cmds[i].len - 1; j++) {
ptr[j] = src[cmds[i].oldoffset + j];
}
ptr += cmds[i].len + 1;
ptr[-2] = cmds[i].target->newoffset >> 8;
ptr[-1] = cmds[i].target->newoffset & 0xff;
} else {
// Other command - copy it verbatim
for (j = 0; j < cmds[i].len; j++) {
ptr[j] = src[cmds[i].oldoffset + j];
}
ptr += cmds[i].len;
}
}
}
/**
* Preprocess a single ailist.
*/
u8 *ailistPreprocessList(u8 *ailist, s32 mempool)
{
s32 numcmds;
s32 numlabels;
s32 numgotos;
s32 oldsize;
s32 newsize;
s32 newsizealigned;
u8 *ptr;
u8 *scratch;
struct tmpcmd *tmpcmds;
// Do the initial pass over the function, counting the number of commands,
// labels, gotos and also totalling out the byte size of the list.
ailistAnalyse(ailist, &numcmds, &numlabels, &numgotos, &oldsize);
// All goto instructions are having one byte added,
// and all labels (3 bytes each) are being removed.
newsize = oldsize + numgotos - numlabels * 3;
newsizealigned = ALIGN4(newsize);
// Allocate some scratch space where the new list will be built,
// and some space for a temporary command list.
ptr = mempAlloc(newsizealigned + numcmds * sizeof(struct tmpcmd), mempool);
scratch = ptr;
ptr += newsizealigned;
tmpcmds = (void *) ptr;
// Build the new list
ailistConvert(ailist, scratch, tmpcmds, numcmds);
if (newsize > oldsize) {
// It's too big to copy back to its original spot,
// so the scratch space is now becoming permanent.
// Free the tmpcmds part by resizing the allocation
// to the size of the scratch.
mempRealloc(scratch, newsize, mempool);
return scratch;
}
// Copy it back into its original spot
bcopy(scratch, ailist, newsize);
// Free the scratch space and cmds
mempRealloc(scratch, 0, mempool);
return NULL;
}
/**
* What we're doing here is preprocessing ailists to remove all label commands,
* and replace "goto label"-like statements with "goto offset".
*
* This allows the engine to jump directly to an offset in the ailist without
* having to iterate the commands in the list to find the label.
*
* In most cases the converted ailist is smaller than the original and can
* just overwrite the original data. In a few cases the new ailist is bigger
* so it must be relocated.
*
* This function in particular is processing all ailists in the file
* (file meaning gailists.c or a stage setup file). The ailist argument is a
* pointer to the start of the ailist table, usually found near the bottom of
* the file.
*
* Some ailists have multiple entries in the table, so we have to track which
* ones have been done to prevent doing them twice.
*/
void ailistPreprocessFile(struct ailist *ailist, s32 mempool)
{
u8 *done[150];
s32 donelen = 0;
s32 i;
// Iterate the ailists in the table
while (ailist->list) {
// Check it's not done already
for (i = 0; i < donelen; i++) {
if (done[i] == ailist->list) {
break;
}
}
if (i == donelen) {
// Convert the list, which might require relocating it in memory
u8 *newaddr = ailistPreprocessList(ailist->list, mempool);
if (newaddr) {
// Update this ailist's pointer to its commands
// and any future ailists that point to the same commands
struct ailist *tmp = ailist;
while (tmp->list) {
if (tmp->list == ailist->list) {
tmp->list = newaddr;
}
tmp++;
}
}
done[donelen] = ailist->list;
donelen++;
}
ailist++;
}
}
+4
View File
@@ -1,5 +1,6 @@
#include <ultra64.h>
#include <sched.h>
#include "lib/ailist.h"
#include "lib/sched.h"
#include "lib/vars.h"
#include "constants.h"
@@ -464,6 +465,9 @@ void mainInit(void)
mempResetPool(MEMPOOL_8);
mempResetPool(MEMPOOL_PERMANENT);
ailistPreprocessFile(g_GlobalAilists, MEMPOOL_PERMANENT);
crashReset();
challengesInit();
utilsInit();