sm64coopdx/data/dynos_mgr_bhv.cpp
Isaac0-dev 5303357146
Some checks are pending
Build coop / build-linux (push) Waiting to run
Build coop / build-steamos (push) Waiting to run
Build coop / build-windows (push) Waiting to run
Build coop / build-macos-arm (push) Waiting to run
Build coop / build-macos-intel (push) Waiting to run
fix custom level data memory leak (#1256)
this fixes the giant memory leak that happens due to not freeing custom level data when closing a lobby.
`DynOS_Lvl_ModShutdown` was not freeing the data nodes for the level data, it was only freeing the surface data.
To fix this, I have made it use `DynOS_Gfx_Free` to free the `GfxData` correctly. I found that the level script VM will still be trying to warp from the custom level after `DynOS_Lvl_ModShutdown` is executed, so I added a schedule to simply free it the next frame.
I've made it force the level script to change to a vanilla level during mod shutdown. This is critical to ensure the VM doesn't continue to read from a freed level script.

Removed the explicit deletion of data nodes in `DynOS_MovtexQC_ModShutdown` because `DynOS_Gfx_Free` already frees that, and it's actually data owned by the data node, so it's more appropriate in `DynOS_Gfx_Free`
2026-06-15 11:22:03 +10:00

106 lines
3.2 KiB
C++

#include "dynos.cpp.h"
extern "C" {
#include "engine/behavior_script.h"
#include "pc/network/packets/packet.h"
#include "pc/lua/smlua_hooks.h"
}
std::vector<std::pair<std::string, GfxData *>> &DynOS_Bhv_GetArray() {
static std::vector<std::pair<std::string, GfxData *>> sDynosCustomBehaviorScripts;
return sDynosCustomBehaviorScripts;
}
void DynOS_Bhv_Activate(s32 modIndex, const SysPath &aFilename, const char *aBehaviorName) {
auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray();
// check for duplicates
for (auto &behavior : _CustomBehaviorScripts) {
if (behavior.first == aBehaviorName) {
return;
}
}
std::string behaviorName = aBehaviorName;
GfxData *_Node = DynOS_Bhv_LoadFromBinary(aFilename, behaviorName.c_str());
if (!_Node) { return; }
// Remember index
_Node->mModIndex = modIndex;
// Add to behaviors
_CustomBehaviorScripts.emplace_back(behaviorName, _Node);
}
void DynOS_Bhv_ModShutdown() {
auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray();
for (auto &pair : _CustomBehaviorScripts) {
DynOS_Gfx_Free(pair.second);
}
_CustomBehaviorScripts.clear();
}
GfxData *DynOS_Bhv_GetActiveGfx(BehaviorScript *bhvScript) {
auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray();
for (auto &behavior : _CustomBehaviorScripts) {
auto &gfxData = behavior.second;
auto &scripts = gfxData->mBehaviorScripts;
if (scripts.Count() == 0) { continue; }
if (bhvScript == scripts[scripts.Count() - 1]->mData) {
return gfxData;
}
}
return NULL;
}
bool DynOS_Bhv_GetActiveModIndex(BehaviorScript *bhvScript, s32 *modIndex, s32 *modFileIndex) {
auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray();
for (auto &behavior : _CustomBehaviorScripts) {
auto &gfxData = behavior.second;
auto &scripts = gfxData->mBehaviorScripts;
if (scripts.Count() == 0) { continue; }
if (bhvScript == scripts[scripts.Count() - 1]->mData) {
*modIndex = gfxData->mModIndex;
*modFileIndex = gfxData->mModFileIndex;
return true;
}
}
return false;
}
const char *DynOS_Bhv_GetToken(BehaviorScript *bhvScript, u32 index) {
GfxData *gfxData = DynOS_Bhv_GetActiveGfx(bhvScript);
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();
}
void DynOS_Bhv_HookAllCustomBehaviors() {
auto &_CustomBehaviorScripts = DynOS_Bhv_GetArray();
for (auto &behavior : _CustomBehaviorScripts) {
auto &scriptName = behavior.first;
auto &aGfxData = behavior.second;
if (aGfxData->mBehaviorScripts.Count() == 0) { continue; }
auto *node = aGfxData->mBehaviorScripts[aGfxData->mBehaviorScripts.Count() - 1];
if (node == nullptr) { continue; }
auto &script = node->mData;
// Theres currently no better place but to do this here.
if (smlua_hook_custom_bhv(script, scriptName.c_str()) == 0) {
PrintDataError(" ERROR: Failed to add custom behavior '%s'!", scriptName.c_str());
}
}
}