From abce3b3afd4eddf6a4f5f77f3ebc0be18eaadf88 Mon Sep 17 00:00:00 2001 From: MysterD Date: Mon, 4 Apr 2022 18:16:36 -0700 Subject: [PATCH] Added ability for DynOS levels to call into lua for custom objects --- data/dynos.c.h | 2 +- data/dynos.cpp.h | 6 +- data/dynos_bin_actor.cpp | 1 + data/dynos_bin_col.cpp | 8 +- data/dynos_bin_lvl.cpp | 201 +++++++++++++++++---------- data/dynos_bin_pointer.cpp | 18 +++ data/dynos_bin_read.cpp | 4 +- data/dynos_c.cpp | 4 +- data/dynos_misc.cpp | 16 ++- data/dynos_warps.cpp | 5 +- include/level_commands.h | 12 ++ src/engine/level_script.c | 51 +++++++ src/engine/level_script.h | 2 + src/pc/lua/smlua_utils.c | 22 +++ src/pc/lua/smlua_utils.h | 3 + src/pc/lua/utils/smlua_model_utils.c | 19 ++- src/pc/lua/utils/smlua_model_utils.h | 3 + src/pc/mods/mod.c | 2 +- src/pc/mods/mod.h | 1 + src/pc/mods/mods.c | 1 + 20 files changed, 289 insertions(+), 92 deletions(-) diff --git a/data/dynos.c.h b/data/dynos.c.h index 0732a02e..3f48ace5 100644 --- a/data/dynos.c.h +++ b/data/dynos.c.h @@ -35,7 +35,7 @@ Collision* dynos_collision_get(const char* collisionName); // -- levels -- // -void dynos_add_level(const char *modPath, const char* levelName); +void dynos_add_level(s32 modIndex, const char *modPath, const char* levelName); LevelScript* dynos_level_get(const char* levelName); #endif diff --git a/data/dynos.cpp.h b/data/dynos.cpp.h index 2b20ec0d..c545b09c 100644 --- a/data/dynos.cpp.h +++ b/data/dynos.cpp.h @@ -10,6 +10,7 @@ extern "C" { #define FUNCTION_CODE (u32) 0x434E5546 #define POINTER_CODE (u32) 0x52544E50 +#define LUA_VAR_CODE (u32) 0x5641554C // // Enums @@ -450,8 +451,10 @@ struct GfxData : NoCopy { u64 mLoadIndex = 0; s32 mErrorCount = 0; u32 mModelIdentifier = 0; + s32 mModIndex = 0; SysPath mPackFolder; Array mPointerList; + Array mPointerTokenList; GfxContext mGfxContext; Array mGeoNodeStack; }; @@ -703,8 +706,9 @@ s16 *DynOS_Level_GetWarp(s32 aLevel, s32 aArea, u8 aWarpId); s16 *DynOS_Level_GetWarpEntry(s32 aLevel, s32 aArea); s16 *DynOS_Level_GetWarpDeath(s32 aLevel, s32 aArea); -void DynOS_Lvl_Add(const SysPath &aPackFolder, const char *aLevelName); +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); DataNode *DynOS_Lvl_Texture_Get(void *aPtr); // diff --git a/data/dynos_bin_actor.cpp b/data/dynos_bin_actor.cpp index 046f5846..1d513f35 100644 --- a/data/dynos_bin_actor.cpp +++ b/data/dynos_bin_actor.cpp @@ -142,6 +142,7 @@ static void DynOS_Actor_Generate(const SysPath &aPackFolder, ArraymModelIdentifier = _GeoNode->mModelIdentifier; _GfxData->mPackFolder = aPackFolder; _GfxData->mPointerList = { NULL }; // The NULL pointer is needed, so we add it here + _GfxData->mPointerTokenList = { }; _GfxData->mGfxContext.mCurrentTexture = NULL; _GfxData->mGfxContext.mCurrentPalette = NULL; _GfxData->mGeoNodeStack.Clear(); diff --git a/data/dynos_bin_col.cpp b/data/dynos_bin_col.cpp index 57e39d83..c8ee4b16 100644 --- a/data/dynos_bin_col.cpp +++ b/data/dynos_bin_col.cpp @@ -463,10 +463,12 @@ DataNode* DynOS_Col_LoadFromBinary(const SysPath &aPackFolder, const SysPath _Filename = fstring("%s/%s.col", aPackFolder.begin(), aCollisionName); FILE *_File = fopen(_Filename.c_str(), "rb"); if (_File) { + // backwards compatibility + long prevPos = ftell(_File); u8 type = ReadBytes(_File); - if (type == DATA_TYPE_COLLISION) { - collisionNode = DynOS_Col_Load(_File, NULL); - } + if (type != DATA_TYPE_COLLISION) { fseek(_File, prevPos, SEEK_SET); } + + collisionNode = DynOS_Col_Load(_File, NULL); fclose(_File); } diff --git a/data/dynos_bin_lvl.cpp b/data/dynos_bin_lvl.cpp index 72448f1a..f84161cb 100644 --- a/data/dynos_bin_lvl.cpp +++ b/data/dynos_bin_lvl.cpp @@ -1404,7 +1404,7 @@ s64 DynOS_Lvl_ParseLevelScriptConstants(const String& _Arg, bool* found) { return 0; } -static LevelScript ParseLevelScriptSymbolArg(GfxData* aGfxData, DataNode* aNode, u64& aTokenIndex) { +static LevelScript ParseLevelScriptSymbolArgInternal(GfxData* aGfxData, DataNode* aNode, u64& aTokenIndex, bool* found) { const String& _Arg = aNode->mTokens[aTokenIndex++]; // Lvl functions @@ -1492,11 +1492,20 @@ static LevelScript ParseLevelScriptSymbolArg(GfxData* aGfxData, DataNode* aNode, u64& aTokenIndex) { + bool found = true; + LevelScript value = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &found); + if (!found) { + const String& _Arg = aNode->mTokens[aTokenIndex - 1]; + PrintError(" ERROR: Unknown lvl arg: %s", _Arg.begin()); + } + return value; +} + #define lvl_symbol_0(symb) \ if (_Symbol == #symb) { \ LevelScript _Ls[] = { symb() }; \ @@ -1541,95 +1550,52 @@ static LevelScript ParseLevelScriptSymbolArg(GfxData* aGfxData, DataNodemPointerList.Add(aHead + n1); } \ - if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ - if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ - LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3) }; \ - memcpy(aHead, _Ls, sizeof(_Ls)); \ - aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ - return; \ + if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \ + if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ + if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ + LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3) }; \ + memcpy(aHead, _Ls, sizeof(_Ls)); \ + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ + return; \ } -#define lvl_symbol_5(symb, n1, n2, n3) \ - if (_Symbol == #symb) { \ +#define lvl_symbol_5(symb, n1, n2, n3) \ + if (_Symbol == #symb) { \ LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg3 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg4 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \ - if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ - if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ - LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4) }; \ - memcpy(aHead, _Ls, sizeof(_Ls)); \ - aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ - return; \ + if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \ + if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ + if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ + LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4) }; \ + memcpy(aHead, _Ls, sizeof(_Ls)); \ + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ + return; \ } -#define lvl_symbol_6(symb, n1, n2, n3) \ - if (_Symbol == #symb) { \ - LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg3 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg4 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg5 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \ - if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ - if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ - LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5) }; \ - memcpy(aHead, _Ls, sizeof(_Ls)); \ - aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ - return; \ - } - -#define lvl_symbol_9(symb, n1, n2, n3) \ - if (_Symbol == #symb) { \ +#define lvl_symbol_6(symb, n1, n2, n3) \ + if (_Symbol == #symb) { \ LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg3 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg4 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ LevelScript _Arg5 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg6 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg7 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg8 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \ - if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ - if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ - LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5, \ - _Arg6, _Arg7, _Arg8) }; \ - memcpy(aHead, _Ls, sizeof(_Ls)); \ - aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ - return; \ - } - -#define lvl_symbol_10(symb, n1, n2, n3) \ - if (_Symbol == #symb) { \ - LevelScript _Arg0 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg1 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg2 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg3 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg4 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg5 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg6 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg7 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg8 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - LevelScript _Arg9 = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); \ - if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \ - if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ - if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ - LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5, \ - _Arg6, _Arg7, _Arg8, _Arg9) }; \ - memcpy(aHead, _Ls, sizeof(_Ls)); \ - aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ - return; \ + if (n1 != 0) { aGfxData->mPointerList.Add(aHead + n1); } \ + if (n2 != 0) { aGfxData->mPointerList.Add(aHead + n2); } \ + if (n3 != 0) { aGfxData->mPointerList.Add(aHead + n3); } \ + LevelScript _Ls[] = { symb(_Arg0, _Arg1, _Arg2, _Arg3, _Arg4, _Arg5) }; \ + memcpy(aHead, _Ls, sizeof(_Ls)); \ + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); \ + return; \ } #define lvl_symbol_noop(symb, skipCount) \ @@ -1693,8 +1659,6 @@ static void ParseLevelScriptSymbol(GfxData* aGfxData, DataNode* aNo lvl_symbol_3(CMD23, 1, 0, 0); // objects - lvl_symbol_10(OBJECT_WITH_ACTS, 5, 0, 0); - lvl_symbol_9(OBJECT, 5, 0, 0); lvl_symbol_3(MARIO, 2, 0, 0); // warps @@ -1732,6 +1696,91 @@ static void ParseLevelScriptSymbol(GfxData* aGfxData, DataNode* aNo lvl_symbol_0(ADV_DEMO); lvl_symbol_0(CLEAR_DEMO_PTR); + // object + if (_Symbol == "OBJECT") { + u64 topTokenIndex = aTokenIndex; + + bool foundModel = true; + bool foundBeh = true; + LevelScript model = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundModel); + LevelScript posX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript posY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript posZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript angleX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript angleY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript angleZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript behParam = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript beh = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundBeh); + + if (foundModel && foundBeh) { + aGfxData->mPointerList.Add(aHead + 5); + LevelScript _Ls[] = { OBJECT(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh) }; + memcpy(aHead, _Ls, sizeof(_Ls)); + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); + } else { + // remember model/beh as pointer + aGfxData->mPointerList.Add(aHead + 5); + aGfxData->mPointerList.Add(aHead + 6); + + // add model/beh tokens + u32 tokenListIndex = aGfxData->mPointerTokenList.Count(); + aGfxData->mPointerTokenList.Add(aNode->mTokens[topTokenIndex + 0]); + aGfxData->mPointerTokenList.Add(aNode->mTokens[topTokenIndex + 8]); + + // get model/beh tokens + String& modelToken = aGfxData->mPointerTokenList[tokenListIndex + 0]; + String& behToken = aGfxData->mPointerTokenList[tokenListIndex + 1]; + + LevelScript _Ls[] = { OBJECT_EXT(modelToken.begin(), posX, posY, posZ, angleX, angleY, angleZ, behParam, behToken.begin()) }; + memcpy(aHead, _Ls, sizeof(_Ls)); + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); + } + return; + } + + // object with acts + if (_Symbol == "OBJECT_WITH_ACTS") { + u64 topTokenIndex = aTokenIndex; + + bool foundModel = true; + bool foundBeh = true; + LevelScript model = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundModel); + LevelScript posX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript posY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript posZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript angleX = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript angleY = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript angleZ = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript behParam = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + LevelScript beh = ParseLevelScriptSymbolArgInternal(aGfxData, aNode, aTokenIndex, &foundBeh); + LevelScript acts = ParseLevelScriptSymbolArg(aGfxData, aNode, aTokenIndex); + + if (foundModel && foundBeh) { + aGfxData->mPointerList.Add(aHead + 5); + LevelScript _Ls[] = { OBJECT_WITH_ACTS(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh, acts) }; + memcpy(aHead, _Ls, sizeof(_Ls)); + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); + } else { + // remember model/beh as pointer + aGfxData->mPointerList.Add(aHead + 5); + aGfxData->mPointerList.Add(aHead + 6); + + // add model/beh tokens + u32 tokenListIndex = aGfxData->mPointerTokenList.Count(); + aGfxData->mPointerTokenList.Add(aNode->mTokens[topTokenIndex + 0]); + aGfxData->mPointerTokenList.Add(aNode->mTokens[topTokenIndex + 8]); + + // get model/beh tokens + String& modelToken = aGfxData->mPointerTokenList[tokenListIndex + 0]; + String& behToken = aGfxData->mPointerTokenList[tokenListIndex + 1]; + + LevelScript _Ls[] = { OBJECT_WITH_ACTS_EXT(modelToken.begin(), posX, posY, posZ, angleX, angleY, angleZ, behParam, behToken.begin(), acts) }; + memcpy(aHead, _Ls, sizeof(_Ls)); + aHead += (sizeof(_Ls) / sizeof(_Ls[0])); + } + return; + } + // Unknown PrintError(" ERROR: Unknown lvl symbol: %s", _Symbol.begin()); } @@ -2014,7 +2063,7 @@ void DynOS_Lvl_GeneratePack(const SysPath &aPackFolder) { if (!fs_sys_dir_exists(_Folder.c_str())) continue; // Only parse folders with a 'script.c' - if (!fs_sys_file_exists(fstring("%s/script.c", _Folder.c_str()).c_str())) continue; + if (!fs_sys_file_exists(fstring("%s/script.c", _Folder.c_str()).c_str()) && !fs_sys_file_exists(fstring("%s/custom.script.c", _Folder.c_str()).c_str())) continue; GfxData *_GfxData = New(); _GfxData->mModelIdentifier = 0; diff --git a/data/dynos_bin_pointer.cpp b/data/dynos_bin_pointer.cpp index eebbf884..3df0521c 100644 --- a/data/dynos_bin_pointer.cpp +++ b/data/dynos_bin_pointer.cpp @@ -178,6 +178,16 @@ void DynOS_Pointer_Write(FILE* aFile, const void* aPtr, GfxData* aGfxData) { return; } + // Lua variable + for (s32 i = 0; i < aGfxData->mPointerTokenList.Count(); i++) { + if (aPtr == aGfxData->mPointerTokenList[i].begin()) { + String& token = aGfxData->mPointerTokenList[i]; + WriteBytes(aFile, LUA_VAR_CODE); + token.Write(aFile); + return; + } + } + // Pointer PointerData _PtrData = GetDataFromPointer(aPtr, aGfxData); if (strlen(_PtrData.first.begin()) == 0) { @@ -324,6 +334,14 @@ void *DynOS_Pointer_Load(FILE *aFile, GfxData *aGfxData, u32 aValue, bool isLvl) : DynOS_Geo_GetFunctionPointerFromIndex(_FunctionIndex); } + // LUAV + if (aValue == LUA_VAR_CODE) { + String token; token.Read(aFile); + u32 index = aGfxData->mPointerTokenList.Count(); + aGfxData->mPointerTokenList.Add(token); + return aGfxData->mPointerTokenList[index].begin(); + } + // PNTR if (aValue == POINTER_CODE) { String _PtrName; _PtrName.Read(aFile); diff --git a/data/dynos_bin_read.cpp b/data/dynos_bin_read.cpp index 5fad16f3..5a6bbbab 100644 --- a/data/dynos_bin_read.cpp +++ b/data/dynos_bin_read.cpp @@ -140,8 +140,8 @@ void DynOS_Read_Source(GfxData *aGfxData, const SysPath &aFilename) { // Scanning data type if (_DataType == DATA_TYPE_NONE) { - // skip includes - if (!strncmp(c, "#include", 8)) { + // skip includes and externs + if (!strncmp(c, "#include", 8) || !strncmp(c, "extern ", 7)) { while (*c != '\n' && *c != '\0') { c++; } diff --git a/data/dynos_c.cpp b/data/dynos_c.cpp index fd6d0d63..b23ec32e 100644 --- a/data/dynos_c.cpp +++ b/data/dynos_c.cpp @@ -99,8 +99,8 @@ Collision* dynos_collision_get(const char* collisionName) { // -- levels -- // -void dynos_add_level(const char *modPath, const char* levelName) { - DynOS_Lvl_Add(modPath, levelName); +void dynos_add_level(s32 modIndex, const char *modPath, const char* levelName) { + DynOS_Lvl_Add(modIndex, modPath, levelName); } LevelScript* dynos_level_get(const char* levelName) { diff --git a/data/dynos_misc.cpp b/data/dynos_misc.cpp index d3dde864..d0728470 100644 --- a/data/dynos_misc.cpp +++ b/data/dynos_misc.cpp @@ -36,6 +36,7 @@ extern "C" { #include "actors/group17.h" #include "actors/custom0.h" #include "actors/zcustom0.h" +#include "levels/wf/header.h" } // @@ -607,7 +608,7 @@ Collision* DynOS_Col_Get(const char* collisionName) { static Array> sDynosCustomLevelScripts; -void DynOS_Lvl_Add(const SysPath &aPackFolder, const char *aLevelName) { +void DynOS_Lvl_Add(s32 modIndex, const SysPath &aPackFolder, const char *aLevelName) { // check for duplicates for (s32 i = 0; i < sDynosCustomLevelScripts.Count(); ++i) { if (!strcmp(sDynosCustomLevelScripts[i].first, aLevelName)) { @@ -625,6 +626,9 @@ void DynOS_Lvl_Add(const SysPath &aPackFolder, const char *aLevelName) { return; } + // remember index + _Node->mModIndex = modIndex; + // Add to levels sDynosCustomLevelScripts.Add({ levelName, _Node }); } @@ -644,6 +648,16 @@ LevelScript* DynOS_Lvl_Get(const char* levelName) { return NULL; } +s32 DynOS_Lvl_GetModIndex(void* levelScript) { + for (s32 i = 0; i < sDynosCustomLevelScripts.Count(); ++i) { + auto& scripts = sDynosCustomLevelScripts[i].second->mLevelScripts; + if (levelScript == scripts[scripts.Count() - 1]->mData) { + return sDynosCustomLevelScripts[i].second->mModIndex; + } + } + return -1; +} + DataNode *DynOS_Lvl_Texture_Get(void *aPtr) { for (s32 i = 0; i < sDynosCustomLevelScripts.Count(); ++i) { auto &mTextures = sDynosCustomLevelScripts[i].second->mTextures; diff --git a/data/dynos_warps.cpp b/data/dynos_warps.cpp index 4e595ae1..cd1deeff 100644 --- a/data/dynos_warps.cpp +++ b/data/dynos_warps.cpp @@ -11,6 +11,7 @@ extern "C" { #include "game/sound_init.h" #include "game/object_list_processor.h" #include "game/options_menu.h" +#include "engine/level_script.h" extern s8 gDialogBoxState; extern s16 gMenuMode; extern s32 gWdwWaterLevelSet; @@ -248,7 +249,9 @@ static void *DynOS_Warp_UpdateWarp(void *aCmd, bool aIsLevelInitDone) { sWarpDest.areaIdx = gCurrAreaIndex; sWarpDest.nodeId = 0; sWarpDest.arg = 0; - return (void *) DynOS_Level_GetScript(gCurrLevelNum); + void* levelScript = (void *) DynOS_Level_GetScript(gCurrLevelNum); + gLevelScriptModIndex = DynOS_Lvl_GetModIndex(levelScript); + return levelScript; } else { diff --git a/include/level_commands.h b/include/level_commands.h index aa4211a4..8a28a68f 100644 --- a/include/level_commands.h +++ b/include/level_commands.h @@ -282,4 +282,16 @@ #define CLEAR_DEMO_PTR() \ CMD_BBH(0x3E, 0x04, 0x0000) +// coop + +#define OBJECT_WITH_ACTS_EXT(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh, acts) \ + CMD_BBBB(0x3F, 0x1C, acts, 0), \ + CMD_HHHHHH(posX, posY, posZ, angleX, angleY, angleZ), \ + CMD_W(behParam), \ + CMD_PTR(model), \ + CMD_PTR(beh) + +#define OBJECT_EXT(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh) \ + OBJECT_WITH_ACTS_EXT(model, posX, posY, posZ, angleX, angleY, angleZ, behParam, beh, 0x1F) + #endif // LEVEL_COMMANDS_H diff --git a/src/engine/level_script.c b/src/engine/level_script.c index a371d0c0..78a006c0 100644 --- a/src/engine/level_script.c +++ b/src/engine/level_script.c @@ -24,6 +24,7 @@ #include "surface_load.h" #include "level_table.h" #include "src/pc/lua/utils/smlua_model_utils.h" +#include "src/pc/lua/smlua.h" #define CMD_GET(type, offset) (*(type *) (CMD_PROCESS_OFFSET(offset) + (u8 *) sCurrentCmd)) @@ -39,6 +40,8 @@ struct LevelCommand { enum ScriptStatus { SCRIPT_RUNNING = 1, SCRIPT_PAUSED = 0, SCRIPT_PAUSED2 = -1 }; +s32 gLevelScriptModIndex = -1; + static uintptr_t sStack[32]; static struct AllocOnlyPool *sLevelPool = NULL; @@ -820,6 +823,51 @@ static void level_cmd_cleardemoptr(void) sCurrentCmd = CMD_NEXT; } +// coop +static void level_cmd_place_object_ext(void) { + u8 val7 = 1 << (gCurrActNum - 1); + struct SpawnInfo *spawnInfo; + + u16 modIndex = gLevelScriptModIndex; + char* modelStr = CMD_GET(char*, 20); + char* behStr = CMD_GET(char*, 24); + + gSmLuaConvertSuccess = true; + enum ModelExtendedId modelId = smlua_get_mod_variable(modIndex, modelStr); + enum BehaviorId behId = smlua_get_mod_variable(modIndex, behStr); + + if ((gLevelScriptModIndex == -1) || !gSmLuaConvertSuccess) { + LOG_ERROR("Failed to place custom object: %u, %u", modelId, behId); + sCurrentCmd = CMD_NEXT; + return; + } + + if (sCurrAreaIndex != -1 && ((CMD_GET(u8, 2) & val7) || CMD_GET(u8, 2) == 0x1F)) { + spawnInfo = alloc_only_pool_alloc(sLevelPool, sizeof(struct SpawnInfo)); + + spawnInfo->startPos[0] = CMD_GET(s16, 4); + spawnInfo->startPos[1] = CMD_GET(s16, 6); + spawnInfo->startPos[2] = CMD_GET(s16, 8); + + spawnInfo->startAngle[0] = CMD_GET(s16, 10) * 0x8000 / 180; + spawnInfo->startAngle[1] = CMD_GET(s16, 12) * 0x8000 / 180; + spawnInfo->startAngle[2] = CMD_GET(s16, 14) * 0x8000 / 180; + + spawnInfo->areaIndex = sCurrAreaIndex; + spawnInfo->activeAreaIndex = sCurrAreaIndex; + + spawnInfo->behaviorArg = CMD_GET(u32, 16); + + spawnInfo->behaviorScript = (BehaviorScript*)get_behavior_from_id(behId); + spawnInfo->unk18 = gLoadedGraphNodes[smlua_model_util_load_with_pool(modelId, sLevelPool)]; + spawnInfo->next = gAreas[sCurrAreaIndex].objectSpawnInfos; + + gAreas[sCurrAreaIndex].objectSpawnInfos = spawnInfo; + } + + sCurrentCmd = CMD_NEXT; +} + static void (*LevelScriptJumpTable[])(void) = { /*00*/ level_cmd_load_and_execute, /*01*/ level_cmd_exit_and_execute, @@ -884,6 +932,9 @@ static void (*LevelScriptJumpTable[])(void) = { /*3C*/ level_cmd_get_or_set_var, /*3D*/ level_cmd_advdemo, /*3E*/ level_cmd_cleardemoptr, + + // coop + /*3F*/ level_cmd_place_object_ext, }; struct LevelCommand *level_script_execute(struct LevelCommand *cmd) { diff --git a/src/engine/level_script.h b/src/engine/level_script.h index d41a91c8..27b8f7cc 100644 --- a/src/engine/level_script.h +++ b/src/engine/level_script.h @@ -5,6 +5,8 @@ struct LevelCommand; +extern s32 gLevelScriptModIndex; + extern u8 level_script_entry[]; struct LevelCommand *level_script_execute(struct LevelCommand *cmd); diff --git a/src/pc/lua/smlua_utils.c b/src/pc/lua/smlua_utils.c index d6f02201..bc577710 100644 --- a/src/pc/lua/smlua_utils.c +++ b/src/pc/lua/smlua_utils.c @@ -1,4 +1,5 @@ #include "smlua.h" +#include "src/pc/mods/mods.h" u8 gSmLuaConvertSuccess = false; @@ -191,6 +192,7 @@ void* smlua_to_cpointer(lua_State* L, int index, u16 lvt) { gSmLuaConvertSuccess = true; return pointer; } + struct LSTNetworkType smlua_to_lnt(lua_State* L, int index) { struct LSTNetworkType lnt = { 0 }; int valueType = lua_type(L, index); @@ -366,6 +368,26 @@ lua_Number smlua_get_number_field(int index, char* name) { /////////////////////////////////////////////////////////////////////////////////////////// +s64 smlua_get_mod_variable(u16 modIndex, char* variable) { + lua_State* L = gLuaState; + + // figure out entry + struct Mod* mod = gActiveMods.entries[modIndex]; + if (mod == NULL) { + LOG_ERROR("Could not find mod list entry for modIndex: %u", modIndex); + return 0; + } + + lua_getglobal(L, "_G"); // get global table + lua_getfield(L, LUA_REGISTRYINDEX, mod->relativePath); // get the file's "global" table + lua_remove(L, -2); // remove global table + + // push variable + return smlua_get_integer_field(-1, variable); +} + +/////////////////////////////////////////////////////////////////////////////////////////// + char* smlua_lnt_to_str(struct LSTNetworkType* lnt) { static char sLntStr[32] = ""; switch (lnt->type) { diff --git a/src/pc/lua/smlua_utils.h b/src/pc/lua/smlua_utils.h index b8516d53..1fe99dc3 100644 --- a/src/pc/lua/smlua_utils.h +++ b/src/pc/lua/smlua_utils.h @@ -33,6 +33,9 @@ lua_Integer smlua_get_integer_field(int index, char* name); 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) ; + void smlua_logline(void); void smlua_dump_stack(void); void smlua_dump_globals(void); diff --git a/src/pc/lua/utils/smlua_model_utils.c b/src/pc/lua/utils/smlua_model_utils.c index 7f9a2061..4b242db9 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(enum ModelExtendedId id) { +u8 smlua_model_util_load_with_pool(enum ModelExtendedId id, struct AllocOnlyPool* pool) { 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; } @@ -514,14 +514,21 @@ u8 smlua_model_util_load(enum ModelExtendedId id) { } // load - struct AllocOnlyPool* pool = alloc_only_pool_init(main_pool_available() - sizeof(struct AllocOnlyPool), MEMORY_POOL_LEFT); + bool resizePool = false; + if (pool == NULL) { + pool = alloc_only_pool_init(main_pool_available() - sizeof(struct AllocOnlyPool), MEMORY_POOL_LEFT); + resizePool = true; + } + if (info->isDisplayList) { gLoadedGraphNodes[emptyCacheId] = (struct GraphNode *) init_graph_node_display_list(pool, NULL, info->layer, (void*)info->asset); } else { gLoadedGraphNodes[emptyCacheId] = process_geo_layout(pool, (void*)info->asset); } - alloc_only_pool_resize(pool, pool->usedSpace); - //LOG_INFO("Loaded at runtime"); + + if (resizePool) { + alloc_only_pool_resize(pool, pool->usedSpace); + } // remember smlua_model_util_remember(emptyCacheId, info->layer, info->asset, info->isDisplayList); @@ -530,6 +537,10 @@ u8 smlua_model_util_load(enum ModelExtendedId id) { return emptyCacheId; } +u8 smlua_model_util_load(enum ModelExtendedId id) { + return smlua_model_util_load_with_pool(id, NULL); +} + u32 smlua_model_util_get_id(const char* name) { // find geolayout const void* layout = dynos_geolayout_get(name); diff --git a/src/pc/lua/utils/smlua_model_utils.h b/src/pc/lua/utils/smlua_model_utils.h index 1c0a2753..4128098e 100644 --- a/src/pc/lua/utils/smlua_model_utils.h +++ b/src/pc/lua/utils/smlua_model_utils.h @@ -1,6 +1,8 @@ #ifndef SMLUA_MODEL_UTILS_H #define SMLUA_MODEL_UTILS_H +#include "src/game/memory.h" + enum ModelExtendedId { E_MODEL_NONE, @@ -390,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(enum ModelExtendedId id, struct AllocOnlyPool* pool); u8 smlua_model_util_load(enum ModelExtendedId id); u32 smlua_model_util_get_id(const char* name); diff --git a/src/pc/mods/mod.c b/src/pc/mods/mod.c index e95b34ab..e1a93b33 100644 --- a/src/pc/mods/mod.c +++ b/src/pc/mods/mod.c @@ -88,7 +88,7 @@ static void mod_activate_lvl(struct Mod* mod, struct ModFile* file) { } // Add to levels - dynos_add_level(dynosPath, lvlName); + dynos_add_level(mod->index, dynosPath, lvlName); LOG_INFO("Activating DynOS lvl: '%s', '%s'", dynosPath, lvlName); } diff --git a/src/pc/mods/mod.h b/src/pc/mods/mod.h index 3123b535..cf2690e8 100644 --- a/src/pc/mods/mod.h +++ b/src/pc/mods/mod.h @@ -23,6 +23,7 @@ struct Mod { char relativePath[SYS_MAX_PATH]; char basePath[SYS_MAX_PATH]; struct ModFile* files; + s32 index; u16 fileCount; bool isDirectory; bool enabled; diff --git a/src/pc/mods/mods.c b/src/pc/mods/mods.c index 38b9a560..44c9830c 100644 --- a/src/pc/mods/mods.c +++ b/src/pc/mods/mods.c @@ -64,6 +64,7 @@ void mods_activate(struct Mods* mods) { for (int i = 0; i < mods->entryCount; i++) { struct Mod* mod = mods->entries[i]; if (mod->enabled) { + mod->index = gActiveMods.entryCount; gActiveMods.entries[gActiveMods.entryCount++] = mod; mod_activate(mod); }