From 95f30da49b6bee2cf4a0e1f98051d8b236a93290 Mon Sep 17 00:00:00 2001 From: MihailRis Date: Tue, 7 Oct 2025 18:02:06 +0300 Subject: [PATCH] add engine pause mode --- src/devtools/DebuggingServer.cpp | 9 ++ src/engine/Engine.cpp | 24 ++++ src/engine/Engine.hpp | 1 + src/logic/scripting/lua/lua_extensions.cpp | 157 +++++++++++---------- 4 files changed, 114 insertions(+), 77 deletions(-) diff --git a/src/devtools/DebuggingServer.cpp b/src/devtools/DebuggingServer.cpp index 26a2ecfa..88466dd3 100644 --- a/src/devtools/DebuggingServer.cpp +++ b/src/devtools/DebuggingServer.cpp @@ -168,6 +168,15 @@ bool DebuggingServer::performCommand( void DebuggingServer::onHitBreakpoint(dv::value&& stackTrace) { logger.info() << "hit breakpoint:\n" << json::stringify(stackTrace, true, " "); + if (connection == nullptr) { + return; + } + connection->send(dv::object({ + {"type", std::string("hit-breakpoint")}, + {"stack", std::move(stackTrace)} + })); + + engine.startPauseLoop(); } void DebuggingServer::setClient(u64id_t client) { diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 65a0be87..64a89fb5 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -309,6 +309,30 @@ void Engine::nextFrame() { input->pollEvents(); } +void Engine::startPauseLoop() { + bool initialCursorLocked = false; + if (!isHeadless()) { + initialCursorLocked = input->isCursorLocked(); + if (initialCursorLocked) { + input->toggleCursor(); + } + } + while (!isQuitSignal()) { + if (!debuggingServer->update()) { + debuggingServer.reset(); + break; + } + if (isHeadless()) { + platform::sleep(1.0 / params.tps * 1000); + } else { + nextFrame(); + } + } + if (initialCursorLocked) { + input->toggleCursor(); + } +} + void Engine::renderFrame() { screen->draw(time.getDelta()); diff --git a/src/engine/Engine.hpp b/src/engine/Engine.hpp index 6d04da5c..a9fb62ea 100644 --- a/src/engine/Engine.hpp +++ b/src/engine/Engine.hpp @@ -108,6 +108,7 @@ public: void updateFrontend(); void renderFrame(); void nextFrame(); + void startPauseLoop(); /// @brief Set screen (scene). /// nullptr may be used to delete previous screen before creating new one, diff --git a/src/logic/scripting/lua/lua_extensions.cpp b/src/logic/scripting/lua/lua_extensions.cpp index 74be96de..15749b47 100644 --- a/src/logic/scripting/lua/lua_extensions.cpp +++ b/src/logic/scripting/lua/lua_extensions.cpp @@ -164,7 +164,85 @@ static int l_math_normal_random(lua::State* L) { constexpr inline int MAX_SHORT_STRING_LEN = 50; -static dv::value create_stack_trace(lua_State* L, int initFrame = 2) { +static dv::value collect_locals(lua::State* L, lua_Debug& frame) { + auto locals = dv::object(); + + int localIndex = 1; + const char* name; + while ((name = lua_getlocal(L, &frame, localIndex++))) { + if (name[0] == '(') { + lua::pop(L); + continue; + } + auto local = dv::object(); + + int type = lua::type(L, -1); + switch (type) { + case LUA_TNIL: + local["short"] = "nil"; + local["type"] = "nil"; + break; + case LUA_TBOOLEAN: + local["short"] = lua::toboolean(L, -1) ? "true" : "false"; + local["type"] = "boolean"; + break; + case LUA_TNUMBER: { + std::stringstream ss; + ss << lua::tonumber(L, -1); + local["short"] = ss.str(); + local["type"] = "number"; + break; + } + case LUA_TSTRING: { + const char* str = lua::tostring(L, -1); + if (strlen(str) > MAX_SHORT_STRING_LEN) { + local["short"] = std::string(str, MAX_SHORT_STRING_LEN); + } else { + local["short"] = str; + } + local["type"] = "string"; + break; + } + case LUA_TTABLE: + local["short"] = "{...}"; + local["type"] = "table"; + break; + case LUA_TFUNCTION: { + std::stringstream ss; + ss << "function: 0x" << std::hex << lua::topointer(L, -1); + local["short"] = ss.str(); + local["type"] = "function"; + break; + } + case LUA_TUSERDATA: { + std::stringstream ss; + ss << "userdata: 0x" << std::hex << lua::topointer(L, -1); + local["short"] = ss.str(); + local["type"] = "userdata"; + break; + } + case LUA_TTHREAD: { + std::stringstream ss; + ss << "thread: 0x" << std::hex << lua::topointer(L, -1); + local["short"] = ss.str(); + local["type"] = "thread"; + break; + } + default: { + std::stringstream ss; + ss << "cdata: 0x" << std::hex << lua::topointer(L, -1); + local["short"] = ss.str(); + local["type"] = "cdata"; + break; + } + } + locals[name] = std::move(local); + lua::pop(L); + } + return locals; +} + +static dv::value create_stack_trace(lua::State* L, int initFrame = 2) { auto entriesList = dv::list(); lua_Debug frame; @@ -187,82 +265,7 @@ static dv::value create_stack_trace(lua_State* L, int initFrame = 2) { entry["line"] = frame.currentline; } entry["what"] = frame.what; - - auto locals = dv::object(); - - int localIndex = 1; - const char* name; - while ((name = lua_getlocal(L, &frame, localIndex++))) { - if (name[0] == '(') { - lua::pop(L); - continue; - } - auto local = dv::object(); - - int type = lua::type(L, -1); - switch (type) { - case LUA_TNIL: - local["short"] = "nil"; - local["type"] = "nil"; - break; - case LUA_TBOOLEAN: - local["short"] = lua::toboolean(L, -1) ? "true" : "false"; - local["type"] = "boolean"; - break; - case LUA_TNUMBER: { - std::stringstream ss; - ss << lua::tonumber(L, -1); - local["short"] = ss.str(); - local["type"] = "number"; - break; - } - case LUA_TSTRING: { - const char* str = lua::tostring(L, -1); - if (strlen(str) > MAX_SHORT_STRING_LEN) { - local["short"] = std::string(str, MAX_SHORT_STRING_LEN); - } else { - local["short"] = str; - } - local["type"] = "string"; - break; - } - case LUA_TTABLE: - local["short"] = "{...}"; - local["type"] = "table"; - break; - case LUA_TFUNCTION: { - std::stringstream ss; - ss << "function: 0x" << std::hex << lua::topointer(L, -1); - local["short"] = ss.str(); - local["type"] = "function"; - break; - } - case LUA_TUSERDATA: { - std::stringstream ss; - ss << "userdata: 0x" << std::hex << lua::topointer(L, -1); - local["short"] = ss.str(); - local["type"] = "userdata"; - break; - } - case LUA_TTHREAD: { - std::stringstream ss; - ss << "thread: 0x" << std::hex << lua::topointer(L, -1); - local["short"] = ss.str(); - local["type"] = "thread"; - break; - } - default: { - std::stringstream ss; - ss << "cdata: 0x" << std::hex << lua::topointer(L, -1); - local["short"] = ss.str(); - local["type"] = "cdata"; - break; - } - } - locals[name] = std::move(local); - lua::pop(L); - } - entry["locals"] = std::move(locals); + entry["locals"] = collect_locals(L, frame); entriesList.add(std::move(entry)); level++; }