mirror of
https://github.com/brues-code/ClassicAPI.git
synced 2026-11-14 07:00:37 +00:00
Backport UpdateAddOnMemoryUsage / GetAddOnMemoryUsage and the script profiling family (scriptProfile, GetFunctionCPUUsage, UpdateAddOnCPUUsage, GetAddOnCPUUsage, GetFrameCPUUsage, GetEventCPUUsage, GetScriptCPUUsage, ResetCPUUsage), mirroring 3.3.5's engine mechanism. - Gc::Hooks owns the GC lifecycle hooks (luaC_link, newlstr, luaS_newudata, freeobj); Gc::Tag stamps each new object with the engine's context word (3.3.5's lua_tainted rule) and sums sizes with the engine's own free sizes. - lua_gctag pins: the addon load window (two call patches in FUN_ADDON_LOAD_ONE) and template application (engine single-name sites + Xml::Inherits lists). - Profile::Cpu keeps 3.3.5's per-closure Profile records through Lua's own call/return hook, installed only when scriptProfile is 1; tail calls, error unwinds and coroutines handled. - ScriptArgs observers time every handler run; signals counted at each dispatcher (call-site redirect inside FUN_FIRE_EVENT, not a MinHook). - Frame::ScriptSlots enumerates a frame's script slots without creating them, for GetFrameCPUUsage. - Add the unordered_dense submodule (v5.3.2); share ResolveRecord via addons/Registry; fix the AddOnEntry inline-name comments.
79 lines
2.7 KiB
C++
79 lines
2.7 KiB
C++
// This file is part of ClassicAPI.
|
|
//
|
|
// ClassicAPI is free software: you can redistribute it and/or modify it under the terms
|
|
// of the GNU General Public License as published by the Free Software Foundation, either
|
|
// version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// ClassicAPI is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
// PURPOSE. See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along with
|
|
// ClassicAPI. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#include "frame/ExtraScripts.h"
|
|
|
|
#include "Game.h"
|
|
#include "Offsets.h"
|
|
#include "baselib/Ascii.h"
|
|
#include "frame/ScriptSlots.h"
|
|
|
|
namespace Frame::ExtraScripts {
|
|
|
|
namespace {
|
|
|
|
// Zero-initialized before any Script's dynamic initializer runs.
|
|
Script *g_head = nullptr;
|
|
|
|
// The engine's __thiscall(frame, name) -> slot, modelled as __fastcall with a
|
|
// dummy edx so `name` lands on the first stack slot.
|
|
using Resolver_t = int(__fastcall *)(void *frame, void *edx, const char *name);
|
|
Resolver_t g_origResolver = nullptr;
|
|
|
|
int __fastcall Resolver_h(void *frame, void *edx, const char *name) {
|
|
const int slot = g_origResolver(frame, edx, name);
|
|
if (slot != 0) // a script the engine knows - leave it
|
|
return slot;
|
|
for (const Script *s = g_head; s != nullptr; s = s->next) {
|
|
if (!Ascii::EqualCI(name, s->nameLower))
|
|
continue;
|
|
if (!Game::Lua::IsA(frame, s->typeIdVar)) // another class may have the name
|
|
continue;
|
|
Script::Cell &cell = s->cells[frame];
|
|
return reinterpret_cast<int>(cell.v);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
const Game::HookAutoRegister _hook{Offsets::FUN_FRAME_SCRIPT_RESOLVER, reinterpret_cast<void *>(&Resolver_h),
|
|
reinterpret_cast<void **>(&g_origResolver)};
|
|
|
|
void PrepareForReload() {
|
|
for (Script *s = g_head; s != nullptr; s = s->next)
|
|
s->cells.clear();
|
|
}
|
|
|
|
const Game::ReloadAutoRegister _reload{&PrepareForReload};
|
|
|
|
void ForEachSlot(const void *frame, Frame::ScriptSlots::Visit visit, void *ctx) {
|
|
for (const Script *s = g_head; s != nullptr; s = s->next)
|
|
if (const uint32_t *slot = s->Slot(frame))
|
|
visit(slot, ctx);
|
|
}
|
|
|
|
const Frame::ScriptSlots::AutoRegister _slots{&ForEachSlot};
|
|
|
|
} // namespace
|
|
|
|
Script::Script(const char *nameLower, uintptr_t typeIdVar)
|
|
: nameLower(nameLower), typeIdVar(typeIdVar), next(g_head) {
|
|
g_head = this;
|
|
}
|
|
|
|
uint32_t *Script::Slot(const void *frame) const {
|
|
const auto it = cells.find(frame);
|
|
return it != cells.end() ? it->second.v : nullptr;
|
|
}
|
|
|
|
} // namespace Frame::ExtraScripts
|