From 688cd3b3991d219a26cfffe4f81aa54e2103832a Mon Sep 17 00:00:00 2001 From: MysterD Date: Mon, 15 May 2023 20:45:04 -0700 Subject: [PATCH] Rewrite how models are loaded and retrieved... yet again --- data/dynos.c.h | 8 +- data/dynos.cpp.h | 8 +- data/dynos_c.cpp | 24 ++- data/dynos_mgr_actor.cpp | 6 +- data/dynos_mgr_models.cpp | 174 +++++++++++++--- data/dynos_mgr_pack.cpp | 3 +- developer/debug.sh | 4 +- src/engine/level_script.c | 69 ++----- src/game/area.c | 2 - src/game/area.h | 5 - src/game/behaviors/koopa.inc.c | 4 +- src/game/object_helpers.c | 13 +- src/menu/file_select.c | 12 +- src/pc/lua/smlua.c | 2 +- src/pc/lua/utils/smlua_model_utils.c | 191 +++--------------- src/pc/lua/utils/smlua_model_utils.h | 5 +- src/pc/lua/utils/smlua_obj_utils.c | 12 +- src/pc/network/packets/packet_area.c | 8 +- src/pc/network/packets/packet_spawn_objects.c | 4 +- 19 files changed, 255 insertions(+), 299 deletions(-) diff --git a/data/dynos.c.h b/data/dynos.c.h index c24f762d..75011a7a 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -72,8 +72,12 @@ const char *dynos_behavior_get_token(BehaviorScript *bhvScript, u32 index); void dynos_behavior_hook_all_custom_behaviors(void); // -- models -- // -struct GraphNode* dynos_model_load_geo(enum ModelPool aModelPool, void* aAsset); -struct GraphNode* dynos_model_load_dl(enum ModelPool aModelPool, u8 aLayer, void* aAsset); +struct GraphNode* dynos_model_load_geo(u32* aId, enum ModelPool aModelPool, void* aAsset); +struct GraphNode* dynos_model_load_dl(u32* aId, enum ModelPool aModelPool, u8 aLayer, void* aAsset); +struct GraphNode* dynos_model_store_geo(u32* aId, enum ModelPool aModelPool, void* aAsset, struct GraphNode* aGraphNode); +struct GraphNode* dynos_model_get_geo(u32 aId); +void dynos_model_overwrite_slot(u32 srcSlot, u32 dstSlot); +u32 dynos_model_get_id_from_asset(void* asset); void dynos_model_clear_pool(enum ModelPool aModelPool); // -- other -- // diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index 2d2c1726..6fc7f7ed 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -963,8 +963,12 @@ void DynOS_MovtexQC_ModShutdown(); // Model Manager // -struct GraphNode* DynOS_Model_LoadGeo(enum ModelPool aModelPool, void* aAsset); -struct GraphNode* DynOS_Model_LoadDl(enum ModelPool aModelPool, u8 aLayer, void* aAsset); +struct GraphNode* DynOS_Model_LoadGeo(u32* aId, enum ModelPool aModelPool, void* aAsset); +struct GraphNode* DynOS_Model_LoadDl(u32* aId, enum ModelPool aModelPool, u8 aLayer, void* aAsset); +struct GraphNode* DynOS_Model_StoreGeo(u32* aId, enum ModelPool aModelPool, void* aAsset, struct GraphNode* aGraphNode); +struct GraphNode* DynOS_Model_GetGeo(u32 aId); +u32 DynOS_Model_GetIdFromAsset(void* asset); +void DynOS_Model_OverwriteSlot(u32 srcSlot, u32 dstSlot); void DynOS_Model_ClearPool(enum ModelPool aModelPool); void DynOS_Model_Update(); diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index 5aad0f45..4a13d61f 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -225,18 +225,34 @@ void dynos_behavior_hook_all_custom_behaviors(void) { // -- models -- // -struct GraphNode* dynos_model_load_geo(enum ModelPool aModelPool, void* aAsset) { - return DynOS_Model_LoadGeo(aModelPool, aAsset); +struct GraphNode* dynos_model_load_geo(u32* aId, enum ModelPool aModelPool, void* aAsset) { + return DynOS_Model_LoadGeo(aId, aModelPool, aAsset); } -struct GraphNode* dynos_model_load_dl(enum ModelPool aModelPool, u8 aLayer, void* aAsset) { - return DynOS_Model_LoadDl(aModelPool, aLayer, aAsset); +struct GraphNode* dynos_model_load_dl(u32* aId, enum ModelPool aModelPool, u8 aLayer, void* aAsset) { + return DynOS_Model_LoadDl(aId, aModelPool, aLayer, aAsset); +} + +struct GraphNode* dynos_model_store_geo(u32* aId, enum ModelPool aModelPool, void* aAsset, struct GraphNode* aGraphNode) { + return DynOS_Model_StoreGeo(aId, aModelPool, aAsset, aGraphNode); +} + +u32 dynos_model_get_id_from_asset(void* asset) { + return DynOS_Model_GetIdFromAsset(asset); } void dynos_model_clear_pool(enum ModelPool aModelPool) { DynOS_Model_ClearPool(aModelPool); } +struct GraphNode* dynos_model_get_geo(u32 aId) { + return DynOS_Model_GetGeo(aId); +} + +void dynos_model_overwrite_slot(u32 srcSlot, u32 dstSlot) { + DynOS_Model_OverwriteSlot(srcSlot, dstSlot); +} + // -- other -- // void dynos_mod_shutdown(void) { diff --git a/data/dynos_mgr_actor.cpp b/data/dynos_mgr_actor.cpp index f54b16ec..890e5b06 100644 --- a/data/dynos_mgr_actor.cpp +++ b/data/dynos_mgr_actor.cpp @@ -46,10 +46,11 @@ void DynOS_Actor_AddCustom(const SysPath &aFilename, const char *aActorName) { } // Alloc and init the actors gfx list + u32 id = 0; ActorGfx actorGfx = { }; actorGfx.mGfxData = _GfxData; actorGfx.mPackIndex = MOD_PACK_INDEX; - actorGfx.mGraphNode = (GraphNode *) DynOS_Model_LoadGeo(MODEL_POOL_SESSION, geoLayout); + actorGfx.mGraphNode = (GraphNode *) DynOS_Model_LoadGeo(&id, MODEL_POOL_SESSION, geoLayout); if (!actorGfx.mGraphNode) { Print(" ERROR: Couldn't load graph node for \"%s\"", actorName); free(actorName); @@ -168,7 +169,8 @@ void DynOS_Actor_Override_All(void) { for (struct Object *_Object = (struct Object *) _Head->header.next; _Object != _Head; _Object = (struct Object *) _Object->header.next) { if (_Object->header.gfx.sharedChild != NULL && _Object->header.gfx.sharedChild->georef != NULL) { GraphNode* georef = (GraphNode*)_Object->header.gfx.sharedChild->georef; - _Object->header.gfx.sharedChild = DynOS_Model_LoadGeo(MODEL_POOL_PERMANENT, georef); + u32 id = 0; + _Object->header.gfx.sharedChild = DynOS_Model_LoadGeo(&id, MODEL_POOL_PERMANENT, georef); } DynOS_Actor_Override((void**)&_Object->header.gfx.sharedChild); } diff --git a/data/dynos_mgr_models.cpp b/data/dynos_mgr_models.cpp index afba8951..8ab15c19 100644 --- a/data/dynos_mgr_models.cpp +++ b/data/dynos_mgr_models.cpp @@ -5,19 +5,62 @@ extern "C" { #include "engine/geo_layout.h" #include "engine/graph_node.h" +#include "model_ids.h" } +enum ModelLoadType { + MLT_GEO, + MLT_DL, + MLT_STORE, +}; + +struct ModelInfo { + u32 id; + void* asset; + struct GraphNode* graphNode; + enum ModelPool modelPool; +}; + struct ScheduledFreePool { struct DynamicPool* pool; u32 timeout; }; static struct DynamicPool* sModelPools[MODEL_POOL_MAX] = { 0 }; -static std::map sGraphNodeMap[MODEL_POOL_MAX]; -static std::map sModelIdMap; + +static std::map sAssetMap[MODEL_POOL_MAX]; +static std::map> sIdMap; +static std::map sOverwriteMap; + static std::vector sPoolsToFree; -struct GraphNode* DynOS_Model_LoadGeo(enum ModelPool aModelPool, void* aAsset) { +static u32 find_empty_id() { + u32 id = 256; + while (true) { + if (sIdMap.count(id) == 0) { return id; } + if (sIdMap[id].size() == 0) { return id; } + id++; + } +} + +void DynOS_Model_Dump() { + for (auto& it : sIdMap) { + if (it.second.size() == 0 || it.second.empty()) { continue; } + printf(">> [%03x] ", it.first); + for (auto& it2 : it.second) { + switch (it2.modelPool) { + case MODEL_POOL_PERMANENT: printf("P "); break; + case MODEL_POOL_SESSION: printf("S "); break; + case MODEL_POOL_LEVEL: printf("L "); break; + case MODEL_POOL_MAX: printf("M "); break; + } + printf("%p ", it2.graphNode); + } + printf("\n"); + } +} + +struct GraphNode* DynOS_Model_LoadCommon(u32* aId, enum ModelPool aModelPool, void* aAsset, u8 aLayer, struct GraphNode* aGraphNode, enum ModelLoadType mlt) { // sanity check pool if (aModelPool >= MODEL_POOL_MAX) { return NULL; } @@ -27,40 +70,99 @@ struct GraphNode* DynOS_Model_LoadGeo(enum ModelPool aModelPool, void* aAsset) { } // check map - auto& map = sGraphNodeMap[aModelPool]; + auto& map = sAssetMap[aModelPool]; if (map.count(aAsset)) { - return map[aAsset]; + auto& found = map[aAsset]; + if (*aId && *aId != found.id) { + sOverwriteMap[*aId] = found.id; + } + *aId = found.id; + return found.graphNode; } // load geo - struct GraphNode* node = process_geo_layout(sModelPools[aModelPool], aAsset); + struct GraphNode* node = NULL; + switch (mlt) { + case MLT_GEO: + node = process_geo_layout(sModelPools[aModelPool], aAsset); + break; + case MLT_DL: + node = (struct GraphNode *) init_graph_node_display_list(sModelPools[aModelPool], NULL, aLayer, aAsset); + break; + case MLT_STORE: + node = aGraphNode; + break; + } + if (!node) { return NULL; } + + // figure out id + if (!*aId) { *aId = find_empty_id(); } + + // create model info + struct ModelInfo info = { + .id = *aId, + .asset = aAsset, + .graphNode = node, + .modelPool = aModelPool + }; + + // store in maps + sIdMap[*aId].push_back(info); + map[aAsset] = info; - // store and return geo - map[aAsset] = node; return node; } -struct GraphNode* DynOS_Model_LoadDl(enum ModelPool aModelPool, u8 aLayer, void* aAsset) { - // sanity check pool - if (aModelPool >= MODEL_POOL_MAX) { return NULL; } +struct GraphNode* DynOS_Model_LoadGeo(u32* aId, enum ModelPool aModelPool, void* aAsset) { + return DynOS_Model_LoadCommon(aId, aModelPool, aAsset, 0, NULL, MLT_GEO); +} - // allocate pool - if (!sModelPools[aModelPool]) { - sModelPools[aModelPool] = dynamic_pool_init(); +struct GraphNode* DynOS_Model_LoadDl(u32* aId, enum ModelPool aModelPool, u8 aLayer, void* aAsset) { + return DynOS_Model_LoadCommon(aId, aModelPool, aAsset, aLayer, NULL, MLT_DL); +} + +struct GraphNode* DynOS_Model_StoreGeo(u32* aId, enum ModelPool aModelPool, void* aAsset, struct GraphNode* aGraphNode) { + return DynOS_Model_LoadCommon(aId, aModelPool, aAsset, 0, aGraphNode, MLT_STORE); +} + +struct GraphNode* DynOS_Model_GetErrorGeo() { + if (!sIdMap.count(MODEL_ERROR_MODEL)) { return NULL; } + auto& vec = sIdMap[MODEL_ERROR_MODEL]; + if (vec.size() == 0 || vec.empty()) { + return NULL; + } + return vec.back().graphNode; +} + +struct GraphNode* DynOS_Model_GetGeo(u32 aId) { + if (!aId) { return NULL; } + + if (sOverwriteMap.count(aId)) { aId = sOverwriteMap[aId]; } + + if (sIdMap.count(aId) == 0) { + return DynOS_Model_GetErrorGeo(); } - // check map - auto& map = sGraphNodeMap[aModelPool]; - if (map.count(aAsset)) { - return map[aAsset]; + auto& vec = sIdMap[aId]; + if (vec.size() == 0 || vec.empty()) { + return DynOS_Model_GetErrorGeo(); } - // load geo - struct GraphNode* node = (struct GraphNode *) init_graph_node_display_list(sModelPools[aModelPool], NULL, aLayer, aAsset); + return vec.back().graphNode; +} - // store and return geo - map[aAsset] = node; - return node; +u32 DynOS_Model_GetIdFromAsset(void* asset) { + if (!asset) { return MODEL_NONE; } + for (int i = 0; i < MODEL_POOL_MAX; i++) { + if (sAssetMap[i].count(asset)) { + return sAssetMap[i][asset].id; + } + } + return MODEL_ERROR_MODEL; +} + +void DynOS_Model_OverwriteSlot(u32 srcSlot, u32 dstSlot) { + sOverwriteMap[srcSlot] = dstSlot; } void DynOS_Model_ClearPool(enum ModelPool aModelPool) { @@ -75,9 +177,29 @@ void DynOS_Model_ClearPool(enum ModelPool aModelPool) { // clear pointer sModelPools[aModelPool] = NULL; - // clear map - auto& map = sGraphNodeMap[aModelPool]; - map.clear(); + // clear overwrite + if (aModelPool == MODEL_POOL_LEVEL) { + sOverwriteMap.clear(); + } + + // clear maps + auto& assetMap = sAssetMap[aModelPool]; + for (auto& asset : assetMap) { + auto& info = asset.second; + if (sIdMap.count(info.id) == 0) { continue; } + + // erase from id map + auto& idMap = sIdMap[info.id]; + for (auto info2 = idMap.begin(); info2 != idMap.end(); ) { + if (info.id == info2->id && info2->modelPool == aModelPool) { + info2 = idMap.erase(info2); + } else { + info2++; + } + } + } + + assetMap.clear(); } void DynOS_Model_Update() { diff --git a/data/dynos_mgr_pack.cpp b/data/dynos_mgr_pack.cpp index 664c9883..fa30be75 100644 --- a/data/dynos_mgr_pack.cpp +++ b/data/dynos_mgr_pack.cpp @@ -42,7 +42,8 @@ static void DynOS_Pack_ActivateActor(s32 aPackIndex, PairmGeoLayouts.end() - 1); - GraphNode* graphNode = DynOS_Model_LoadGeo(MODEL_POOL_PERMANENT, geoNode->mData); + u32 id = 0; + GraphNode* graphNode = DynOS_Model_LoadGeo(&id, MODEL_POOL_PERMANENT, geoNode->mData); if (graphNode == NULL) { return; } const void* georef = DynOS_Builtin_Actor_GetFromName(aActorName); diff --git a/developer/debug.sh b/developer/debug.sh index 532f4140..2bf3dc9a 100755 --- a/developer/debug.sh +++ b/developer/debug.sh @@ -2,9 +2,9 @@ set -e if [ $# -eq 0 ]; then - make DEBUG=1 DEVELOPMENT=1 STRICT=1 ASAN=1 -j + make DEBUG=1 DEVELOPMENT=1 STRICT=1 ASAN=1 COMPILER=clang -j else - make DEBUG=1 DEVELOPMENT=1 ASAN=1 -j + make DEBUG=1 DEVELOPMENT=1 ASAN=1 COMPILER=clang -j fi # find file diff --git a/src/engine/level_script.c b/src/engine/level_script.c index 47bd8d31..3ac827f2 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -64,7 +64,6 @@ static s16 sScriptStatus; static s32 sRegister; static struct LevelCommand *sCurrentCmd; -static u8 sLevelOwnedGraphNodes[MAX_LOADED_GRAPH_NODES] = { 0 }; static u8 sFinishedLoadingPerm = false; static s32 eval_script_area(s32 arg) { @@ -350,7 +349,6 @@ static void level_cmd_init_level(void) { init_graph_node_start(NULL, (struct GraphNodeStart *) &gObjParentGraphNode); clear_objects(); clear_areas(); - smlua_model_util_clear(); gSkipInterpolationTitleScreen = false; sCurrentCmd = CMD_NEXT; @@ -361,14 +359,6 @@ static void level_cmd_clear_level(void) { clear_area_graph_nodes(); clear_areas(); - // reset the level's graph nodes to NULL - for (s32 i = 0; i < MAX_LOADED_GRAPH_NODES; i++) { - if (sLevelOwnedGraphNodes[i]) { - gLoadedGraphNodes[i] = NULL; - sLevelOwnedGraphNodes[i] = false; - } - } - sCurrentCmd = CMD_NEXT; } @@ -388,15 +378,6 @@ static void level_reset_globals(void) { } static void level_cmd_alloc_level_pool(void) { - - // reset level graph node ownership - for (s32 i = 0; i < MAX_LOADED_GRAPH_NODES; i++) { - if (sLevelOwnedGraphNodes[i]) { - gLoadedGraphNodes[i] = NULL; - sLevelOwnedGraphNodes[i] = false; - } - } - // reset all globals level_reset_globals(); @@ -432,7 +413,8 @@ static void level_cmd_begin_area(void) { void *geoLayoutAddr = CMD_GET(void *, 4); if (areaIndex < 8) { - struct GraphNodeRoot *screenArea = (struct GraphNodeRoot *) dynos_model_load_geo(MODEL_POOL_LEVEL, geoLayoutAddr); + u32 id = 0; + struct GraphNodeRoot *screenArea = (struct GraphNodeRoot *) dynos_model_load_geo(&id, MODEL_POOL_LEVEL, geoLayoutAddr); struct GraphNodeCamera *node = (struct GraphNodeCamera *) screenArea->views[0]; sCurrAreaIndex = areaIndex; @@ -462,11 +444,8 @@ static void level_cmd_load_model_from_dl(void) { s16 val2 = ((u16)CMD_GET(s16, 2)) >> 12; void *val3 = CMD_GET(void *, 4); - if (val1 < MAX_LOADED_GRAPH_NODES) { - gLoadedGraphNodes[val1] = dynos_model_load_dl(sFinishedLoadingPerm ? MODEL_POOL_LEVEL : MODEL_POOL_PERMANENT, val2, val3); - if (sFinishedLoadingPerm) { sLevelOwnedGraphNodes[val1] = true; } - smlua_model_util_remember(val1, val2, val3, 1); - } + u32 id = val1; + dynos_model_load_dl(&id, sFinishedLoadingPerm ? MODEL_POOL_LEVEL : MODEL_POOL_PERMANENT, val2, val3); sCurrentCmd = CMD_NEXT; } @@ -475,11 +454,8 @@ static void level_cmd_load_model_from_geo(void) { s16 arg0 = CMD_GET(s16, 2); void *arg1 = CMD_GET(void *, 4); - if (arg0 < MAX_LOADED_GRAPH_NODES) { - gLoadedGraphNodes[arg0] = dynos_model_load_geo(sFinishedLoadingPerm ? MODEL_POOL_LEVEL : MODEL_POOL_PERMANENT, arg1); - if (sFinishedLoadingPerm) { sLevelOwnedGraphNodes[arg0] = true; } - smlua_model_util_remember(arg0, LAYER_OPAQUE, arg1, 0); - } + u32 id = arg0; + dynos_model_load_geo(&id, sFinishedLoadingPerm ? MODEL_POOL_LEVEL : MODEL_POOL_PERMANENT, arg1); sCurrentCmd = CMD_NEXT; } @@ -496,13 +472,10 @@ static void level_cmd_23(void) { // load an f32, but using an integer load instruction for some reason (hence the union) arg2.i = CMD_GET(s32, 8); - if (model < MAX_LOADED_GRAPH_NODES) { - // GraphNodeScale has a GraphNode at the top. This - // is being stored to the array, so cast the pointer. - gLoadedGraphNodes[model] = (struct GraphNode *) init_graph_node_scale(gLevelPool, 0, arg0H, arg1, arg2.f); - if (sFinishedLoadingPerm) { sLevelOwnedGraphNodes[model] = true; } - smlua_model_util_remember(model, arg0H, arg1, 1); - } + // GraphNodeScale has a GraphNode at the top. This + // is being stored to the array, so cast the pointer. + u32 id = model; + dynos_model_store_geo(&id, MODEL_POOL_LEVEL, arg1, (struct GraphNode*)init_graph_node_scale(gLevelPool, 0, arg0H, arg1, arg2.f)); sCurrentCmd = CMD_NEXT; } @@ -512,8 +485,7 @@ static void level_cmd_init_mario(void) { behaviorArg = behaviorArg; void* behaviorScript = CMD_GET(void*, 8); u16 slot = CMD_GET(u8, 3); - if (slot >= MAX_LOADED_GRAPH_NODES) { slot = MODEL_NONE; } - struct GraphNode* unk18 = gLoadedGraphNodes[slot]; + struct GraphNode* unk18 = dynos_model_get_geo(slot); struct SpawnInfo* lastSpawnInfo = NULL; for (s32 i = 0; i < MAX_PLAYERS; i++) { @@ -545,7 +517,6 @@ static void level_cmd_place_object(void) { if (sCurrAreaIndex != -1 && (gLevelValues.disableActs || (CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) { model = CMD_GET(u8, 3); - if (model >= MAX_LOADED_GRAPH_NODES) { model = MODEL_NONE; } spawnInfo = dynamic_pool_alloc(gLevelPool, sizeof(struct SpawnInfo)); spawnInfo->startPos[0] = CMD_GET(s16, 4); @@ -561,7 +532,7 @@ static void level_cmd_place_object(void) { spawnInfo->behaviorArg = CMD_GET(u32, 16); spawnInfo->behaviorScript = CMD_GET(void *, 20); - spawnInfo->unk18 = gLoadedGraphNodes[model]; + spawnInfo->unk18 = dynos_model_get_geo(model); spawnInfo->next = gAreas[sCurrAreaIndex].objectSpawnInfos; spawnInfo->syncID = gAreas[sCurrAreaIndex].nextSyncID; @@ -944,7 +915,6 @@ static void level_cmd_place_object_ext(void) { if (sCurrAreaIndex != -1 && (gLevelValues.disableActs || (CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) { u16 model = CMD_GET(u8, 3); - if (model >= MAX_LOADED_GRAPH_NODES) { model = MODEL_NONE; } spawnInfo = dynamic_pool_alloc(gLevelPool, sizeof(struct SpawnInfo)); spawnInfo->startPos[0] = CMD_GET(s16, 4); @@ -961,7 +931,7 @@ static void level_cmd_place_object_ext(void) { spawnInfo->behaviorArg = CMD_GET(u32, 16); spawnInfo->behaviorScript = (BehaviorScript*)get_behavior_from_id(behId); - spawnInfo->unk18 = gLoadedGraphNodes[model]; + spawnInfo->unk18 = dynos_model_get_geo(model); spawnInfo->next = gAreas[sCurrAreaIndex].objectSpawnInfos; spawnInfo->syncID = spawnInfo->next @@ -1031,9 +1001,8 @@ static void level_cmd_place_object_ext2(void) { spawnInfo->behaviorArg = CMD_GET(u32, 16); spawnInfo->behaviorScript = (BehaviorScript*)get_behavior_from_id(behId); - u16 slot = smlua_model_util_load_with_pool(modelId, MODEL_POOL_LEVEL); - if (slot >= MAX_LOADED_GRAPH_NODES) { slot = MODEL_NONE; } - spawnInfo->unk18 = gLoadedGraphNodes[slot]; + u16 slot = smlua_model_util_load(modelId); + spawnInfo->unk18 = dynos_model_get_geo(slot); spawnInfo->next = gAreas[sCurrAreaIndex].objectSpawnInfos; spawnInfo->syncID = spawnInfo->next @@ -1049,13 +1018,11 @@ static void level_cmd_place_object_ext2(void) { 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); + smlua_model_util_store_in_slot(modelSlot, geoName); - if (modelSlot < MAX_LOADED_GRAPH_NODES) { - smlua_model_util_load_with_pool_and_cache_id(modelId, MODEL_POOL_LEVEL, modelSlot); - } + // DO NOT COMMIT, this is broken + // it's supposed to load our custom model into a vanilla slot (ugh why) sCurrentCmd = CMD_NEXT; } diff --git a/src/game/area.c b/src/game/area.c index 3d82ef9a..eb3c92be 100644 --- a/src/game/area.c +++ b/src/game/area.c @@ -29,7 +29,6 @@ #include "pc/djui/djui_panel_pause.h" struct SpawnInfo gPlayerSpawnInfos[MAX_PLAYERS]; -struct GraphNode *D_8033A160[MAX_LOADED_GRAPH_NODES]; struct Area gAreaData[8]; struct WarpTransition gWarpTransition; @@ -43,7 +42,6 @@ s16 gPauseScreenMode; s16 gSaveOptSelectIndex; struct SpawnInfo *gMarioSpawnInfo = &gPlayerSpawnInfos[0]; -struct GraphNode **gLoadedGraphNodes = D_8033A160; struct Area *gAreas = gAreaData; struct Area *gCurrentArea = NULL; struct CreditsEntry *gCurrCreditsEntry = NULL; diff --git a/src/game/area.h b/src/game/area.h index 19f0b5af..1b855a8e 100644 --- a/src/game/area.h +++ b/src/game/area.h @@ -7,10 +7,6 @@ #include "camera.h" #include "engine/graph_node.h" -#define LOADED_GRAPH_NODES_VANILLA 256 -#define LOADED_GRAPH_NODES_EXTENDED 512 -#define MAX_LOADED_GRAPH_NODES (LOADED_GRAPH_NODES_VANILLA + LOADED_GRAPH_NODES_EXTENDED) - struct WarpNode { /*00*/ u8 id; @@ -128,7 +124,6 @@ struct WarpTransition /*0x04*/ struct WarpTransitionData data; }; -extern struct GraphNode **gLoadedGraphNodes; extern struct SpawnInfo gPlayerSpawnInfos[]; extern struct GraphNode *D_8033A160[]; extern struct Area gAreaData[]; diff --git a/src/game/behaviors/koopa.inc.c b/src/game/behaviors/koopa.inc.c index c0590db8..273ce5f1 100644 --- a/src/game/behaviors/koopa.inc.c +++ b/src/game/behaviors/koopa.inc.c @@ -379,7 +379,7 @@ void shelled_koopa_attack_handler(s32 attackType) { * Update function for both regular and tiny shelled koopa. */ static void koopa_shelled_update(void) { - u8 modelId = smlua_model_util_load(E_MODEL_KOOPA_WITH_SHELL); + u16 modelId = smlua_model_util_load(E_MODEL_KOOPA_WITH_SHELL); if (!cur_obj_has_model(modelId)) { cur_obj_set_model(modelId); } @@ -548,7 +548,7 @@ static void koopa_unshelled_act_unused3(void) { * Update function for koopa after losing his shell. */ static void koopa_unshelled_update(void) { - u8 modelId = smlua_model_util_load(E_MODEL_KOOPA_WITHOUT_SHELL); + u16 modelId = smlua_model_util_load(E_MODEL_KOOPA_WITHOUT_SHELL); if (!cur_obj_has_model(modelId)) { cur_obj_set_model(modelId); } diff --git a/src/game/object_helpers.c b/src/game/object_helpers.c index c26527ce..f6e9682b 100644 --- a/src/game/object_helpers.c +++ b/src/game/object_helpers.c @@ -680,9 +680,7 @@ struct Object *spawn_object_at_origin(struct Object *parent, UNUSED s32 unusedAr } obj->globalPlayerIndex = 0; - if (model >= MAX_LOADED_GRAPH_NODES) { model = MODEL_ERROR_MODEL; } - geo_obj_init((struct GraphNodeObject *) &obj->header.gfx, gLoadedGraphNodes[model], gVec3fZero, - gVec3sZero); + geo_obj_init((struct GraphNodeObject *) &obj->header.gfx, dynos_model_get_geo(model), gVec3fZero, gVec3sZero); smlua_call_event_hooks_object_model_param(HOOK_OBJECT_SET_MODEL, obj, model); return obj; @@ -1436,8 +1434,7 @@ void cur_obj_set_model(s32 modelID) { } void obj_set_model(struct Object* obj, s32 modelID) { - if (modelID >= MAX_LOADED_GRAPH_NODES) { modelID = MODEL_ERROR_MODEL; } - obj->header.gfx.sharedChild = gLoadedGraphNodes[modelID]; + obj->header.gfx.sharedChild = dynos_model_get_geo(modelID); dynos_actor_override((void*)&obj->header.gfx.sharedChild); smlua_call_event_hooks_object_model_param(HOOK_OBJECT_SET_MODEL, obj, modelID); } @@ -3267,10 +3264,10 @@ s32 cur_obj_update_dialog_with_cutscene(struct MarioState* m, s32 actionArg, s32 s32 cur_obj_has_model(u16 modelID) { if (!o) { return 0; } - if (modelID >= MAX_LOADED_GRAPH_NODES) { return FALSE; } - if (o->header.gfx.sharedChild == gLoadedGraphNodes[modelID]) { + struct GraphNode* node = dynos_model_get_geo(modelID); + if (o->header.gfx.sharedChild == node) { return TRUE; - } else if (o->header.gfx.sharedChild && gLoadedGraphNodes[modelID] && o->header.gfx.sharedChild->georef == gLoadedGraphNodes[modelID]->georef) { + } else if (o->header.gfx.sharedChild && node && o->header.gfx.sharedChild->georef == node->georef) { return TRUE; } else { return FALSE; diff --git a/src/menu/file_select.c b/src/menu/file_select.c index b4d68097..45a51658 100644 --- a/src/menu/file_select.c +++ b/src/menu/file_select.c @@ -792,10 +792,8 @@ void copy_action_file_button(struct Object *copyButton, s32 copyFileButtonID) { sFadeOutText = TRUE; sMainMenuTimer = 0; save_file_copy(sSelectedFileIndex, copyFileButtonID - MENU_BUTTON_COPY_MIN); - sMainMenuButtons[copyFileButtonID]->header.gfx.sharedChild = - gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE]; - sMainMenuButtons[copyFileButtonID - MENU_BUTTON_COPY_MIN]->header.gfx.sharedChild = - gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE]; + sMainMenuButtons[copyFileButtonID]->header.gfx.sharedChild = dynos_model_get_geo(MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE); + sMainMenuButtons[copyFileButtonID - MENU_BUTTON_COPY_MIN]->header.gfx.sharedChild = dynos_model_get_geo(MODEL_MAIN_MENU_MARIO_SAVE_BUTTON_FADE); } else { // If clicked in a existing save file, play buzz sound if (MENU_BUTTON_COPY_FILE_A + sSelectedFileIndex == copyFileButtonID) { @@ -2258,10 +2256,8 @@ void print_erase_menu_prompt(s16 x, s16 y) { sFadeOutText = TRUE; sMainMenuTimer = 0; save_file_erase(sSelectedFileIndex); - sMainMenuButtons[MENU_BUTTON_ERASE_MIN + sSelectedFileIndex]->header.gfx.sharedChild = - gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE]; - sMainMenuButtons[sSelectedFileIndex]->header.gfx.sharedChild = - gLoadedGraphNodes[MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE]; + sMainMenuButtons[MENU_BUTTON_ERASE_MIN + sSelectedFileIndex]->header.gfx.sharedChild = dynos_model_get_geo(MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE); + sMainMenuButtons[sSelectedFileIndex]->header.gfx.sharedChild = dynos_model_get_geo(MODEL_MAIN_MENU_MARIO_NEW_BUTTON_FADE); sEraseYesNoHoverState = MENU_ERASE_HOVER_NONE; // ..and is hovering "NO", return back to main phase } else if (sEraseYesNoHoverState == MENU_ERASE_HOVER_NO) { diff --git a/src/pc/lua/smlua.c b/src/pc/lua/smlua.c index 2e0bd462..a557f778 100644 --- a/src/pc/lua/smlua.c +++ b/src/pc/lua/smlua.c @@ -197,7 +197,7 @@ void smlua_shutdown(void) { smlua_cobject_allowlist_shutdown(); smlua_cpointer_allowlist_shutdown(); smlua_clear_hooks(); - smlua_model_util_reset(); + smlua_model_util_clear(); smlua_level_util_reset(); smlua_anim_util_reset(); lua_State* L = gLuaState; diff --git a/src/pc/lua/utils/smlua_model_utils.c b/src/pc/lua/utils/smlua_model_utils.c index fde9e25b..03be005b 100644 --- a/src/pc/lua/utils/smlua_model_utils.c +++ b/src/pc/lua/utils/smlua_model_utils.c @@ -59,21 +59,19 @@ struct ModelUtilsInfo { enum ModelExtendedId extId; u8 layer; u16 loadedId; - bool permanent; bool isDisplayList; const void* asset; - u8 shouldFreeAsset; }; -#define UNLOADED_ID 0xFFFF +#define UNLOADED_ID 0 -#define MODEL_UTIL_GEO(x, y) [x] = { .extId = x, .asset = y, .layer = LAYER_OPAQUE, .isDisplayList = false, .loadedId = UNLOADED_ID, .permanent = false } -#define MODEL_UTIL_DL(x, y, z) [x] = { .extId = x, .asset = y, .layer = z, .isDisplayList = true, .loadedId = UNLOADED_ID, .permanent = false } -#define MODEL_UTIL_GEO_PERM(x, y, w) [x] = { .extId = x, .asset = y, .layer = LAYER_OPAQUE, .isDisplayList = false, .loadedId = w, .permanent = true } -#define MODEL_UTIL_DL_PERM(x, y, z, w) [x] = { .extId = x, .asset = y, .layer = z, .isDisplayList = true, .loadedId = w, .permanent = true } +#define MODEL_UTIL_GEO(x, y) [x] = { .extId = x, .asset = y, .layer = LAYER_OPAQUE, .isDisplayList = false, .loadedId = UNLOADED_ID, } +#define MODEL_UTIL_DL(x, y, z) [x] = { .extId = x, .asset = y, .layer = z, .isDisplayList = true, .loadedId = UNLOADED_ID, } +#define MODEL_UTIL_GEO_PERM(x, y, w) [x] = { .extId = x, .asset = y, .layer = LAYER_OPAQUE, .isDisplayList = false, .loadedId = w, } +#define MODEL_UTIL_DL_PERM(x, y, z, w) [x] = { .extId = x, .asset = y, .layer = z, .isDisplayList = true, .loadedId = w, } struct ModelUtilsInfo sModels[E_MODEL_MAX] = { - MODEL_UTIL_GEO(E_MODEL_NONE, NULL), + MODEL_UTIL_GEO(E_MODEL_NONE, NULL), // actors MODEL_UTIL_GEO_PERM(E_MODEL_MARIO, mario_geo, MODEL_MARIO), @@ -468,172 +466,53 @@ struct ModelUtilsInfo sModels[E_MODEL_MAX] = { struct ModelUtilsInfo sCustomModels[MAX_CUSTOM_MODELS] = { 0 }; static u16 sCustomModelsCount = 0; -struct ModelUtilsInfo* sCachedAssets[MAX_LOADED_GRAPH_NODES] = { 0 }; -bool sCachedAssetTaken[MAX_LOADED_GRAPH_NODES] = { 0 }; - -void smlua_model_util_remember(u16 loadedId, UNUSED u8 layer, const void* asset, UNUSED u8 isDisplayList) { - struct ModelUtilsInfo* found = NULL; - - // find in sModels - for (s32 i = 0; i < E_MODEL_MAX; i++) { - struct ModelUtilsInfo* m = &sModels[i]; - if (m->asset != asset) { continue; } - found = m; - break; - } - - // find in sCustomModels - if (!found) { - for (s32 i = 0; i < sCustomModelsCount; i++) { - struct ModelUtilsInfo* m = &sCustomModels[i]; - if (m->asset != asset) { continue; } - found = m; - break; - } - } - - // sanity check - if (found == NULL) { - LOG_ERROR("Could not find asset to remember!"); - return; - } - - // remember - if (sCachedAssetTaken[loadedId] && sCachedAssets[loadedId] != found) { - if (sCachedAssets[loadedId]->permanent) { - LOG_ERROR("Tried to override permanent model: %u -> %u", sCachedAssets[loadedId]->loadedId, loadedId); - return; - } else { - //LOG_INFO("Overriding model: loadedId %u was extId %u, now extId %u", loadedId, sCachedAssets[loadedId]->extId, found->extId); - } - sCachedAssets[loadedId]->loadedId = UNLOADED_ID; - } - found->loadedId = loadedId; - sCachedAssets[loadedId] = found; - sCachedAssetTaken[loadedId] = true; - //LOG_INFO("Remember model: %u -> %u", found->extId, loadedId); -} - -void smlua_model_util_reset(void) { - smlua_model_util_clear(); - for (u32 i = 0; i < sCustomModelsCount; i++) { - struct ModelUtilsInfo* m = &sCustomModels[i]; - m->loadedId = UNLOADED_ID; - if (m->asset && m->shouldFreeAsset) { - free((void*)m->asset); - m->asset = NULL; - } - m->shouldFreeAsset = false; - } +void smlua_model_util_clear(void) { sCustomModelsCount = 0; } -void smlua_model_util_clear(void) { - for (int i = 0; i < MAX_LOADED_GRAPH_NODES; i++) { - struct ModelUtilsInfo* m = sCachedAssets[i]; - if (m == NULL) { continue; } - //LOG_INFO("Forget: %u -> %u", m->extId, m->loadedId); - if (!m->permanent) { - m->loadedId = UNLOADED_ID; - if (m->asset && m->shouldFreeAsset) { - free((void*)m->asset); - m->asset = NULL; - } - } - m->shouldFreeAsset = false; - sCachedAssets[i] = NULL; - sCachedAssetTaken[i] = false; - } - - //LOG_INFO("Cleared runtime model cache."); -} - -u16 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId extId, enum ModelPool pool, u16 loadedId) { - if (extId == E_MODEL_NONE) { return MODEL_NONE; } - if (extId >= (u16)(E_MODEL_MAX + sCustomModelsCount)) { - LOG_ERROR("Tried to load invalid extId: %u >= %u (%u)", extId, (E_MODEL_MAX + sCustomModelsCount), sCustomModelsCount); - extId = E_MODEL_ERROR_MODEL; - } - - struct ModelUtilsInfo* info = (extId >= E_MODEL_MAX) - ? &sCustomModels[extId - E_MODEL_MAX] - : &sModels[extId]; - - // check cache - if (info->loadedId != UNLOADED_ID) { - //LOG_INFO("Found in cache - %u -> %u", extId, info->loadedId); - return info->loadedId; - } - - // find cached asset - u16 pickLoadedId = loadedId; - if (loadedId == UNLOADED_ID) { - for (s32 i = 0; i < (MAX_LOADED_GRAPH_NODES-1); i++) { - struct ModelUtilsInfo* m = sCachedAssets[i]; - if (m == info) { - //LOG_INFO("Found in cache (but late, confused?) - %u -> %u", extId, i); - info->loadedId = m->loadedId; - return info->loadedId; - } else if (i >= LOADED_GRAPH_NODES_VANILLA && !sCachedAssetTaken[i]) { - pickLoadedId = i; - } - } - - if (pickLoadedId == UNLOADED_ID) { - LOG_ERROR("Could not find slot for extId - %u", extId); - return UNLOADED_ID; - } - } - - if (pickLoadedId >= MAX_LOADED_GRAPH_NODES) { - LOG_ERROR("Could not find slot for extId - %u", extId); - return UNLOADED_ID; - } - - // load - struct GraphNode* node = NULL; - node = (info->isDisplayList) - ? dynos_model_load_dl(pool, info->layer, (void*)info->asset) - : dynos_model_load_geo(pool, (void*) info->asset); - gLoadedGraphNodes[pickLoadedId] = node; - - // remember - if (node) { - smlua_model_util_remember(pickLoadedId, info->layer, info->asset, info->isDisplayList); - } - //LOG_INFO("Loaded custom model - %u -> %u", extId, pickLoadedId); - - return pickLoadedId; -} - -u16 smlua_model_util_load_with_pool(enum ModelExtendedId extId, enum ModelPool pool) { - return smlua_model_util_load_with_pool_and_cache_id(extId, pool, UNLOADED_ID); +void smlua_model_util_store_in_slot(u32 slot, const char* name) { + u32 extId = smlua_model_util_get_id(name); + if (extId == E_MODEL_ERROR_MODEL) { return; } + u32 loadedId = smlua_model_util_load(extId); + dynos_model_overwrite_slot(slot, loadedId); } u16 smlua_model_util_load(enum ModelExtendedId extId) { - return smlua_model_util_load_with_pool(extId, MODEL_POOL_SESSION); + if (extId >= E_MODEL_MAX + sCustomModelsCount) { extId = E_MODEL_ERROR_MODEL; } + + struct ModelUtilsInfo* info = (extId < E_MODEL_MAX) + ? &sModels[extId] + : &sCustomModels[extId - E_MODEL_MAX]; + + u32 id = info->loadedId; + if (info->isDisplayList) { + dynos_model_load_dl(&id, MODEL_POOL_SESSION, info->layer, (void*)info->asset); + } else { + dynos_model_load_geo(&id, MODEL_POOL_SESSION, (void*)info->asset); + } + return (u16)id; } u32 smlua_model_util_get_id(const char* name) { // find geolayout - const void* layout = dynos_geolayout_get(name); - if (layout == NULL) { + const void* asset = dynos_geolayout_get(name); + if (asset == NULL) { LOG_ERROR("Failed to find model: %s - %u", name, E_MODEL_ERROR_MODEL); return E_MODEL_ERROR_MODEL; } - // find existing model + // find existing built-in model for (u32 i = 0; i < E_MODEL_MAX; i++) { struct ModelUtilsInfo* m = &sModels[i]; - if (m->asset == layout) { - //LOG_INFO("Found existing model: %s :: %u -> %u", name, m->extId, m->loadedId); + if (m->asset == asset) { return m->extId; } } + + // find existing custom model for (u32 i = 0; i < sCustomModelsCount; i++) { struct ModelUtilsInfo* m = &sCustomModels[i]; - if (m->asset == layout) { - //LOG_INFO("Found existing custom model: %s :: %u -> %u", name, m->extId, m->loadedId); + if (m->asset == asset) { return m->extId; } } @@ -641,15 +520,11 @@ u32 smlua_model_util_get_id(const char* name) { // allocate custom model u16 customIndex = sCustomModelsCount++; struct ModelUtilsInfo* info = &sCustomModels[customIndex]; - info->asset = layout; - info->shouldFreeAsset = false; + info->asset = asset; info->loadedId = UNLOADED_ID; info->extId = E_MODEL_MAX + customIndex; info->isDisplayList = false; info->layer = LAYER_OPAQUE; - //LOG_INFO("Allocated model: %s :: %u -> %u", name, info->extId, info->loadedId); return info->extId; } - - diff --git a/src/pc/lua/utils/smlua_model_utils.h b/src/pc/lua/utils/smlua_model_utils.h index f004050a..c0243170 100644 --- a/src/pc/lua/utils/smlua_model_utils.h +++ b/src/pc/lua/utils/smlua_model_utils.h @@ -395,11 +395,8 @@ enum ModelExtendedId { E_MODEL_MAX }; -void smlua_model_util_remember(u16 loadedId, u8 layer, const void* asset, u8 isDisplayList); -void smlua_model_util_reset(void); void smlua_model_util_clear(void); -u16 smlua_model_util_load_with_pool_and_cache_id(enum ModelExtendedId extId, enum ModelPool pool, u16 loadedId); -u16 smlua_model_util_load_with_pool(enum ModelExtendedId extId, enum ModelPool pool); +void smlua_model_util_store_in_slot(u32 slot, const char* name); u16 smlua_model_util_load(enum ModelExtendedId extId); u32 smlua_model_util_get_id(const char* name); diff --git a/src/pc/lua/utils/smlua_obj_utils.c b/src/pc/lua/utils/smlua_obj_utils.c index 385ec14f..f87752a4 100644 --- a/src/pc/lua/utils/smlua_obj_utils.c +++ b/src/pc/lua/utils/smlua_obj_utils.c @@ -23,11 +23,6 @@ static struct Object* spawn_object_internal(enum BehaviorId behaviorId, enum Mod } u16 loadedModelId = smlua_model_util_load(modelId); - if (loadedModelId >= MAX_LOADED_GRAPH_NODES) { - LOG_ERROR("failed to load model %u", modelId); - return NULL; - } - struct Object* obj = spawn_object(gMarioStates[0].marioObj, loadedModelId, behavior); if (obj == NULL) { @@ -95,8 +90,7 @@ s32 obj_has_behavior_id(struct Object *o, enum BehaviorId behaviorId) { s32 obj_has_model_extended(struct Object *o, enum ModelExtendedId modelId) { if (!o) { return 0; } u16 slot = smlua_model_util_load(modelId); - if (slot >= MAX_LOADED_GRAPH_NODES) { return false; } - struct GraphNode *model = gLoadedGraphNodes[slot]; + struct GraphNode *model = dynos_model_get_geo(slot); return o->header.gfx.sharedChild == model; } @@ -267,10 +261,6 @@ struct SpawnParticlesInfo* obj_get_temp_spawn_particles_info(enum ModelExtendedI memset(&sTmpSpi, 0, sizeof(struct SpawnParticlesInfo)); u16 loadedModelId = smlua_model_util_load(modelId); - if (loadedModelId >= MAX_LOADED_GRAPH_NODES) { - LOG_ERROR("failed to load model %u", modelId); - return NULL; - } sTmpSpi.model = loadedModelId; return &sTmpSpi; diff --git a/src/pc/network/packets/packet_area.c b/src/pc/network/packets/packet_area.c index 3fa466af..5c7a9d05 100644 --- a/src/pc/network/packets/packet_area.c +++ b/src/pc/network/packets/packet_area.c @@ -102,13 +102,7 @@ void network_send_area(struct NetworkPlayer* toNp) { // TODO: move find model to a utility file/function // find model - u32 model = 0; - for (s32 j = 0; j < MAX_LOADED_GRAPH_NODES; j++) { - if (so->o->header.gfx.sharedChild == gLoadedGraphNodes[j]) { - model = j; - break; - } - } + u32 model = dynos_model_get_id_from_asset(so->o->header.gfx.sharedChild); u32 models[] = { model }; network_send_spawn_objects_to(toNp->localIndex, spawn_objects, models, 1); diff --git a/src/pc/network/packets/packet_spawn_objects.c b/src/pc/network/packets/packet_spawn_objects.c index 728876a9..781de92b 100644 --- a/src/pc/network/packets/packet_spawn_objects.c +++ b/src/pc/network/packets/packet_spawn_objects.c @@ -189,9 +189,7 @@ void network_receive_spawn_objects(struct Packet* p) { // load extended model if (data.extendedModelId != 0xFFFF) { u16 loadedModelId = smlua_model_util_load(data.extendedModelId); - if (loadedModelId < MAX_LOADED_GRAPH_NODES) { - data.model = loadedModelId; - } + data.model = loadedModelId; } void* behavior = (void*)get_behavior_from_id(data.behaviorId);