#ifndef ANGELSCRIPTDEBUGGER_ANGELSCRIPTDEBUGGER_HPP #define ANGELSCRIPTDEBUGGER_ANGELSCRIPTDEBUGGER_HPP #include #include #include #include #include "asio.hpp" #include "Breakpoint.hpp" #include "DebugAdapterProtocol/BaseProtocol.hpp" class AngelscriptDebugger { public: ~AngelscriptDebugger() { _server->close(); delete _server; } void Run(uint16_t port); void Stop() { _server->close(); } void RegisterContext(asIScriptContext* ctx); void Continue() { std::cout << "Continuing from suspension" << std::endl; _storedVariableReferences.clear(); while (!_pausedContexts.empty()) { auto* ctx = _pausedContexts[_pausedContexts.size() - 1]; _pausedContexts.pop_back(); std::thread([](asIScriptContext* ctx) { ctx->Execute(); }, ctx).detach(); } } bool HasDebuggerAttached() const { for (const auto& c : _connections) { if (c->is_open()) { return true; } } return false; } size_t StoreVariable(void* address, int typeId, const std::optional>& release) { _storedVariableReferences.emplace_back(std::make_unique(address, typeId, release)); return _storedVariableReferences.size(); } private: static void on_line_callback(asIScriptContext* ctx, AngelscriptDebugger* dbg); static void on_exception_callback(asIScriptContext* ctx, AngelscriptDebugger* d); void EnterBreakpoint(asIScriptContext* ctx, const std::string& section, size_t line); [[noreturn]] void AcceptLoop(); void ClientLoop(asio::ip::tcp::socket&); void Send(DebugAdapterProtocol::ProtocolMessage* msg); void Send(asio::ip::tcp::socket* client, DebugAdapterProtocol::ProtocolMessage* msg); void OnMessage(asio::ip::tcp::socket* client, DebugAdapterProtocol::ProtocolMessage* msg); void OnRequest(asio::ip::tcp::socket* client, DebugAdapterProtocol::Request* msg); std::string GetResolvedScriptPath(const char* scriptSection); void Next(asIScriptContext* ctx); void StepInto(asIScriptContext* ctx); void StepOut(asIScriptContext* ctx); asio::io_context _ioContext; asio::ip::tcp::acceptor* _server; std::unordered_set _connections; std::unordered_map> _breakpoints; std::vector _pausedContexts; std::optional _scriptPath; asIScriptContext* _nextContext; bool _next; size_t _nextDepth; bool _stepInto; bool _stepOut; struct StackScope { size_t StackLevel; uint8_t Type; StackScope(size_t stackLevel, uint8_t type) : StackLevel(stackLevel), Type(type) {} }; struct PointerVariable { void* Address; int TypeID; std::optional> Release; PointerVariable(void* address, int typeId, std::optional> release) : Address(address), TypeID(typeId), Release(release) {} ~PointerVariable() { if (Release.has_value()) { Release.value()(Address); } } }; std::vector, std::unique_ptr>> _storedVariableReferences; }; #endif // ANGELSCRIPTDEBUGGER_ANGELSCRIPTDEBUGGER_HPP