From 4956f0dd9581e1ea8ac6d9428aa9c25e73c0a834 Mon Sep 17 00:00:00 2001 From: MysterD Date: Thu, 7 Apr 2022 08:21:19 -0700 Subject: [PATCH] Fixed token corruption in DynOS, added support for runtime LOAD_MODEL_FROM_GEO --- data/dynos.c.h | 1 + data/dynos.cpp.h | 1 + data/dynos_bin_lvl.cpp | 21 +++++++++++- data/dynos_bin_pointer.cpp | 7 +++- data/dynos_c.cpp | 4 +++ data/dynos_misc.cpp | 48 ++++++++++++++++++++++------ data/dynos_warps.cpp | 1 + include/level_commands.h | 4 +++ src/engine/level_script.c | 21 ++++++++++-- src/engine/level_script.h | 1 + src/game/object_helpers.c | 18 ++++++++--- src/pc/lua/smlua_utils.c | 4 +-- src/pc/lua/smlua_utils.h | 2 +- src/pc/lua/utils/smlua_model_utils.c | 34 ++++++++++++-------- src/pc/lua/utils/smlua_model_utils.h | 1 + 15 files changed, 133 insertions(+), 35 deletions(-) diff --git a/data/dynos.c.h b/data/dynos.c.h index 8981b83b..cac6ea37 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -37,6 +37,7 @@ Collision* dynos_collision_get(const char* collisionName); // -- levels -- // void dynos_add_level(s32 modIndex, const char *modPath, const char* levelName); LevelScript* dynos_level_get(const char* levelName); +const char* dynos_level_get_token(u32 index); struct MovtexQuadCollection *dynos_level_movtexqc_getfromindex(s32 index); void dynos_level_load_background(void *ptr); diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index 519e4c59..2d3c2fe1 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -717,6 +717,7 @@ s16 *DynOS_Level_GetWarpDeath(s32 aLevel, s32 aArea); void DynOS_Lvl_Add(s32 modIndex, const SysPath &aPackFolder, const char *aLevelName); LevelScript* DynOS_Lvl_Get(const char* levelName); s32 DynOS_Lvl_GetModIndex(void* levelScript); +const char* DynOS_Lvl_Get_Token(u32 index); DataNode *DynOS_Lvl_Texture_Get(void *aPtr); DataNode *DynOS_Lvl_MovtexQuadCollection_GetFromIndex(s32 index); void DynOS_Lvl_Load_Background(void *aPtr); diff --git a/data/dynos_bin_lvl.cpp b/data/dynos_bin_lvl.cpp index 37de1cb1..9f0a3398 100644 --- a/data/dynos_bin_lvl.cpp +++ b/data/dynos_bin_lvl.cpp @@ -1665,7 +1665,6 @@ static void ParseLevelScriptSymbol(GfxData* aGfxData, DataNode* aNo // models lvl_symbol_3(LOAD_MODEL_FROM_DL, 1, 0, 0); - lvl_symbol_2(LOAD_MODEL_FROM_GEO, 1, 0); lvl_symbol_3(CMD23, 1, 0, 0); // objects @@ -1779,6 +1778,26 @@ static void ParseLevelScriptSymbol(GfxData* aGfxData, DataNode* aNo return; } + // LOAD_MODEL_FROM_GEO + if (_Symbol == "LOAD_MODEL_FROM_GEO") { + u64 topTokenIndex = aTokenIndex; + bool foundGeo = true; + LevelScript model = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript geo = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundGeo); + if (foundGeo) { + aGfxData->mPointerList.Add(aHead + 1); + LevelScript _Ls[] = { LOAD_MODEL_FROM_GEO(model, geo) }; + memcpy(aHead, _Ls, sizeof(_Ls)); + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); + } else { + u32 geoIndex = DynOS_Lua_RememberVariable(aGfxData, aHead + 1, aNode->mTokens[topTokenIndex + 1]); + LevelScript _Ls[] = { LOAD_MODEL_FROM_GEO_EXT(model, geo) }; + memcpy(aHead, _Ls, sizeof(_Ls)); + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); + } + return; + } + // Unknown PrintError(" ERROR: Unknown lvl symbol: %s", _Symbol.begin()); } diff --git a/data/dynos_bin_pointer.cpp b/data/dynos_bin_pointer.cpp index 39c2d2e3..32c16173 100644 --- a/data/dynos_bin_pointer.cpp +++ b/data/dynos_bin_pointer.cpp @@ -393,9 +393,14 @@ void *DynOS_Pointer_Load(FILE *aFile, GfxData *aGfxData, u32 aValue, bool isLvl) // LUAV if (aValue == LUA_VAR_CODE) { String token; token.Read(aFile); + for (s32 i = 0; i < aGfxData->mLuaTokenList.Count(); i++) { + if (token == aGfxData->mLuaTokenList[i]) { + return (void*)(uintptr_t)(i+1); + } + } u32 index = aGfxData->mLuaTokenList.Count(); aGfxData->mLuaTokenList.Add(token); - return aGfxData->mLuaTokenList[index].begin(); + return (void*)(uintptr_t)(index+1); } // FUNC diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index 6fdc2cdc..c9eb72d0 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -108,6 +108,10 @@ LevelScript* dynos_level_get(const char* levelName) { return DynOS_Lvl_Get(levelName); } +const char* dynos_level_get_token(u32 index) { + return DynOS_Lvl_Get_Token(index); +} + struct MovtexQuadCollection *dynos_level_movtexqc_getfromindex(s32 index) { DataNode *node = DynOS_Lvl_MovtexQuadCollection_GetFromIndex(index); if (node == NULL) { return NULL; } diff --git a/data/dynos_misc.cpp b/data/dynos_misc.cpp index 59872b79..0e889308 100644 --- a/data/dynos_misc.cpp +++ b/data/dynos_misc.cpp @@ -404,6 +404,8 @@ const void *DynOS_Geo_GetActorLayout(s32 aIndex) { } const void *DynOS_Geo_GetActorLayoutFromName(const char *aActorName) { + if (aActorName == NULL) { return NULL; } + // check levels for (auto& lvl : sDynosCustomLevelScripts) { for (auto& geo : lvl.second->mGeoLayouts) { @@ -698,19 +700,47 @@ DataNode *DynOS_Lvl_Texture_Get(void *aPtr) { return NULL; } +static GfxData* DynOS_Lvl_Get_Active_Gfx(void) { + for (s32 i = 0; i < sDynosCustomLevelScripts.Count(); ++i) { + auto& gfxData = sDynosCustomLevelScripts[i].second; + auto& scripts = gfxData->mLevelScripts; + if (gLevelScriptActive == scripts[scripts.Count() - 1]->mData) { + return gfxData; + } + } + return NULL; +} + +const char* DynOS_Lvl_Get_Token(u32 index) { + GfxData* gfxData = DynOS_Lvl_Get_Active_Gfx(); + if (gfxData == NULL) { + return NULL; + } + + // have to 1-index due to to pointer read code + index = index - 1; + + if (index >= gfxData->mLuaTokenList.Count()) { + return NULL; + } + + return gfxData->mLuaTokenList[index].begin(); +} + DataNode *DynOS_Lvl_MovtexQuadCollection_GetFromIndex(s32 index) { - s32 modIndex = gLevelScriptModIndex - 1; - // Sanity check our currently loaded mod. - if (modIndex < 0 || modIndex >= sDynosCustomLevelScripts.Count()) { return NULL; } - - auto &mMovtexQCs = sDynosCustomLevelScripts[modIndex].second->mMovtexQCs; + GfxData* gfxData = DynOS_Lvl_Get_Active_Gfx(); + if (gfxData == NULL) { + return NULL; + } + + auto &mMovtexQCs = gfxData->mMovtexQCs; // Sanity check the index we passed. - if (index < 0 || index >= mMovtexQCs.Count()) { return NULL; } + if (index < 0 || index >= mMovtexQCs.Count()) { + return NULL; + } - auto &movetexQC = mMovtexQCs[index]; - - return movetexQC; + return mMovtexQCs[index]; } void DynOS_Lvl_Load_Background(void *aPtr) { diff --git a/data/dynos_warps.cpp b/data/dynos_warps.cpp index cd1deeff..76a5af5b 100644 --- a/data/dynos_warps.cpp +++ b/data/dynos_warps.cpp @@ -251,6 +251,7 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) { sWarpDest.arg = 0; void* levelScript = (void *) DynOS_Level_GetScript(gCurrLevelNum); gLevelScriptModIndex = DynOS_Lvl_GetModIndex(levelScript); + gLevelScriptActive = (LevelScript*)levelScript; return levelScript; } else { diff --git a/include/level_commands.h b/include/level_commands.h index 823522b4..e2c2e677 100644 --- a/include/level_commands.h +++ b/include/level_commands.h @@ -303,4 +303,8 @@ #define OBJECT_EXT2(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh) \ OBJECT_WITH_ACTS_EXT2(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh, 0x1F) +#define LOAD_MODEL_FROM_GEO_EXT(model, geo) \ + CMD_BBH(0x41, 0x08, model), \ + CMD_PTR(geo) + #endif // LEVEL_COMMANDS_H diff --git a/src/engine/level_script.c b/src/engine/level_script.c index e178c09b..578c8bde 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -41,6 +41,7 @@ struct LevelCommand { enum ScriptStatus { SCRIPT_RUNNING = 1, SCRIPT_PAUSED = 0, SCRIPT_PAUSED2 = -1 }; s32 gLevelScriptModIndex = -1; +LevelScript* gLevelScriptActive = NULL; static uintptr_t sStack[32]; @@ -829,7 +830,7 @@ static void level_cmd_place_object_ext(void) { struct SpawnInfo *spawnInfo; u16 modIndex = gLevelScriptModIndex; - char* behStr = CMD_GET(char*, 20); + const char* behStr = dynos_level_get_token(CMD_GET(u32, 20)); gSmLuaConvertSuccess = true; enum BehaviorId behId = smlua_get_mod_variable(modIndex, behStr); @@ -872,8 +873,8 @@ static void level_cmd_place_object_ext2(void) { struct SpawnInfo *spawnInfo; u16 modIndex = gLevelScriptModIndex; - char* modelStr = CMD_GET(char*, 20); - char* behStr = CMD_GET(char*, 24); + const char* modelStr = dynos_level_get_token(CMD_GET(u32, 20)); + const char* behStr = dynos_level_get_token(CMD_GET(u32, 24)); gSmLuaConvertSuccess = true; enum ModelExtendedId modelId = smlua_get_mod_variable(modIndex, modelStr); @@ -911,6 +912,19 @@ static void level_cmd_place_object_ext2(void) { sCurrentCmd = CMD_NEXT; } +static void level_cmd_load_model_from_geo_ext(void) { + s16 modelSlot = CMD_GET(s16, 2); + + const char* geoName = dynos_level_get_token(CMD_GET(u32, 4)); + u32 modelId = smlua_model_util_get_id(geoName); + + if (modelSlot < 256) { + smlua_model_util_load_with_pool_and_cache_id(modelId, sLevelPool, modelSlot); + } + + sCurrentCmd = CMD_NEXT; +} + static void (*LevelScriptJumpTable[])(void) = { /*00*/ level_cmd_load_and_execute, /*01*/ level_cmd_exit_and_execute, @@ -979,6 +993,7 @@ static void (*LevelScriptJumpTable[])(void) = { // coop /*3F*/ level_cmd_place_object_ext, /*40*/ level_cmd_place_object_ext2, + /*41*/ level_cmd_load_model_from_geo_ext, }; struct LevelCommand *level_script_execute(struct LevelCommand *cmd) { diff --git a/src/engine/level_script.h b/src/engine/level_script.h index 27b8f7cc..280394f5 100644 --- a/src/engine/level_script.h +++ b/src/engine/level_script.h @@ -6,6 +6,7 @@ struct LevelCommand; extern s32 gLevelScriptModIndex; +extern LevelScript* gLevelScriptActive; extern u8 level_script_entry[]; diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index 4f556466..da8fc54a 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -798,26 +798,34 @@ void cur_obj_scale(f32 scale) { void cur_obj_init_animation(s32 animIndex) { struct Animation **anims = o->oAnimations; - geo_obj_init_animation(&o->header.gfx, &anims[animIndex]); + if (anims != NULL) { + geo_obj_init_animation(&o->header.gfx, &anims[animIndex]); + } } void cur_obj_init_animation_with_sound(s32 animIndex) { struct Animation **anims = o->oAnimations; - geo_obj_init_animation(&o->header.gfx, &anims[animIndex]); + if (anims != NULL) { + geo_obj_init_animation(&o->header.gfx, &anims[animIndex]); + } o->oSoundStateID = animIndex; } void cur_obj_init_animation_with_accel_and_sound(s32 animIndex, f32 accel) { struct Animation **anims = o->oAnimations; - s32 animAccel = (s32)(accel * 65536.0f); - geo_obj_init_animation_accel(&o->header.gfx, &anims[animIndex], animAccel); + if (anims != NULL) { + s32 animAccel = (s32)(accel * 65536.0f); + geo_obj_init_animation_accel(&o->header.gfx, &anims[animIndex], animAccel); + } o->oSoundStateID = animIndex; } void obj_init_animation_with_sound(struct Object *obj, const struct Animation * const* animations, s32 animIndex) { struct Animation **anims = (struct Animation **)animations; obj->oAnimations = (struct Animation **)animations; - geo_obj_init_animation(&obj->header.gfx, &anims[animIndex]); + if (anims != NULL) { + geo_obj_init_animation(&obj->header.gfx, &anims[animIndex]); + } obj->oSoundStateID = animIndex; } diff --git a/src/pc/lua/smlua_utils.c b/src/pc/lua/smlua_utils.c index ed2fb587..9c4b50a5 100644 --- a/src/pc/lua/smlua_utils.c +++ b/src/pc/lua/smlua_utils.c @@ -372,7 +372,7 @@ lua_Number smlua_get_number_field(int index, char* name) { /////////////////////////////////////////////////////////////////////////////////////////// -s64 smlua_get_mod_variable(u16 modIndex, char* variable) { +s64 smlua_get_mod_variable(u16 modIndex, const char* variable) { lua_State* L = gLuaState; // figure out entry @@ -385,7 +385,7 @@ s64 smlua_get_mod_variable(u16 modIndex, char* variable) { int prevTop = lua_gettop(L); lua_getglobal(L, "_G"); // get global table lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); // get the file's "global" table - s64 value = smlua_get_integer_field(-1, variable); + s64 value = smlua_get_integer_field(-1, (char*)variable); lua_settop(L, prevTop); // return variable diff --git a/src/pc/lua/smlua_utils.h b/src/pc/lua/smlua_utils.h index 1fe99dc3..80259a28 100644 --- a/src/pc/lua/smlua_utils.h +++ b/src/pc/lua/smlua_utils.h @@ -34,7 +34,7 @@ lua_Number smlua_get_number_field(int index, char* name); char* smlua_lnt_to_str(struct LSTNetworkType* lnt); -s64 smlua_get_mod_variable(u16 modIndex, char* variable) ; +s64 smlua_get_mod_variable(u16 modIndex, const char* variable) ; void smlua_logline(void); void smlua_dump_stack(void); diff --git a/src/pc/lua/utils/smlua_model_utils.c b/src/pc/lua/utils/smlua_model_utils.c index 4b242db9..b868f44f 100644 --- a/src/pc/lua/utils/smlua_model_utils.c +++ b/src/pc/lua/utils/smlua_model_utils.c @@ -480,7 +480,7 @@ void smlua_model_util_clear(void) { } } -u8 smlua_model_util_load_with_pool(enum ModelExtendedId id, struct AllocOnlyPool* pool) { +u8 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId id, struct AllocOnlyPool* pool, u8 cacheId) { if (id == E_MODEL_NONE) { return MODEL_NONE; } if (id == E_MODEL_MAX) { LOG_ERROR("id invalid"); return MODEL_NONE; } if (id > E_MODEL_MAX + sCustomModelsCount) { LOG_ERROR("id invalid"); return MODEL_NONE; } @@ -496,21 +496,25 @@ u8 smlua_model_util_load_with_pool(enum ModelExtendedId id, struct AllocOnlyPool } // find cached asset - bool foundEmptyCacheId = false; u8 emptyCacheId = 0; - for (int i = 0; i < 255; i++) { - if (sCachedAssets[i].asset == info->asset) { - //LOG_INFO("Found in cached assets"); - return sCachedAssets[i].id; + if (cacheId == 0) { + bool foundEmptyCacheId = false; + for (int i = 0; i < 255; i++) { + if (sCachedAssets[i].asset == info->asset) { + //LOG_INFO("Found in cached assets"); + return sCachedAssets[i].id; + } + if (sCachedAssets[i].asset == NULL) { + foundEmptyCacheId = true; + emptyCacheId = i; + } } - if (sCachedAssets[i].asset == NULL) { - foundEmptyCacheId = true; - emptyCacheId = i; + if (!foundEmptyCacheId) { + LOG_ERROR("No empty cache"); + return 0xFF; } - } - if (!foundEmptyCacheId) { - LOG_ERROR("No empty cache"); - return 0xFF; + } else { + emptyCacheId = cacheId; } // load @@ -537,6 +541,10 @@ u8 smlua_model_util_load_with_pool(enum ModelExtendedId id, struct AllocOnlyPool return emptyCacheId; } +u8 smlua_model_util_load_with_pool(enum ModelExtendedId id, struct AllocOnlyPool* pool) { + return smlua_model_util_load_with_pool_and_cache_id(id, pool, 0); +} + u8 smlua_model_util_load(enum ModelExtendedId id) { return smlua_model_util_load_with_pool(id, NULL); } diff --git a/src/pc/lua/utils/smlua_model_utils.h b/src/pc/lua/utils/smlua_model_utils.h index 4128098e..c8974294 100644 --- a/src/pc/lua/utils/smlua_model_utils.h +++ b/src/pc/lua/utils/smlua_model_utils.h @@ -392,6 +392,7 @@ enum ModelExtendedId { void smlua_model_util_remember(u8 modelId, u8 layer, const void* asset, u8 isDisplayList); void smlua_model_util_clear(void); +u8 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId id, struct AllocOnlyPool* pool, u8 cacheId); u8 smlua_model_util_load_with_pool(enum ModelExtendedId id, struct AllocOnlyPool* pool); u8 smlua_model_util_load(enum ModelExtendedId id); u32 smlua_model_util_get_id(const char* name);