diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 284c8eb99e..9178f9e39d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1190,6 +1190,7 @@ set (PCH_SOURCES common/scripting/dap/IdProvider.cpp common/scripting/dap/Nodes/ArrayStateNode.cpp common/scripting/dap/Nodes/LocalScopeStateNode.cpp + common/scripting/dap/Nodes/GlobalScopeStateNode.cpp common/scripting/dap/Nodes/ObjectStateNode.cpp common/scripting/dap/Nodes/StackFrameStateNode.cpp common/scripting/dap/Nodes/StackStateNode.cpp diff --git a/src/common/scripting/dap/Nodes/GlobalScopeStateNode.cpp b/src/common/scripting/dap/Nodes/GlobalScopeStateNode.cpp new file mode 100644 index 0000000000..1e16270482 --- /dev/null +++ b/src/common/scripting/dap/Nodes/GlobalScopeStateNode.cpp @@ -0,0 +1,141 @@ +#include "GlobalScopeStateNode.h" +#include +#include + +namespace DebugServer +{ +// TODO: Do this dynamically? +static const char *const GlobalNames[] = { + "NotifyFontScale", + "ConsoleState", + "menuactive", + "BackbuttonTime", + "BackbuttonAlpha", + "GameTicRate", + "menuDelegate", + "WP_NOCHANGE", + "SmallFont", + "SmallFont2", + "BigFont", + "ConFont", + "NewConsoleFont", + "NewSmallFont", + "AlternativeSmallFont", + "AlternativeBigFont", + "OriginalSmallFont", + "OriginalBigFont", + "IntermissionFont", + "CleanXfac", + "CleanYfac", + "CleanWidth", + "CleanHeight", + "CleanXfac_1", + "CleanYfac_1", + "CleanWidth_1", + "CleanHeight_1", + "AllServices", + "Bindings", + "AutomapBindings", + "generic_ui", + "deh", + "gameinfo", + "Teams", + "LocalViewPitch", + "StatusBar", + "players", + "playeringame", + "PlayerClasses", + "consoleplayer", + "validcount", + "multiplayer", + "gameaction", + "gamestate", + "skyflatnum", + "globalfreeze", + "gametic", + "demoplayback", + "automapactive", + "viewactive", + "Net_Arbitrator", + "netgame", + "paused", + "Terrains", + "OptionMenuSettings", + "musplaying", + "AllClasses", + "Level", + // "level", technically its own global, but only the VM one is accessible by the VM + "AllActorClasses", + + nullptr}; + +GlobalScopeStateNode::GlobalScopeStateNode() { } + +bool GlobalScopeStateNode::SerializeToProtocol(dap::Scope &scope) +{ + scope.name = "Global"; + scope.expensive = false; + scope.presentationHint = "globals"; + scope.variablesReference = GetId(); + + std::vector childNames; + GetChildNames(childNames); + + scope.namedVariables = childNames.size(); + scope.indexedVariables = 0; + + return true; +} + +bool GlobalScopeStateNode::GetChildNames(std::vector &names) +{ + for (int i = 0; GlobalNames[i] != nullptr; i++) + { + names.push_back(GlobalNames[i]); + } + return true; +} + +bool GlobalScopeStateNode::GetChildNode(std::string name, std::shared_ptr &node) +{ + if (m_children.empty()) + { + std::vector childNames; + GetChildNames(childNames); + caseless_path_set childSet {childNames.begin(), childNames.end()}; + for (auto ns : Namespaces.AllNamespaces) + { + auto symbolIter = ns->Symbols.GetIterator(); + PSymbolTable::MapType::Pair *pair; + while (symbolIter.NextPair(pair)) + { + if (childSet.find(pair->Key.GetChars()) != childSet.end()) + { + std::string symname = pair->Key.GetChars(); + PSymbol *val = pair->Value; + if (val->SymbolName == NAME_None) + { + continue; + } + PField *field = dyn_cast(val); + if (field) + { + field->Type; + // the offset is the address of the field + void *addr = (void *)(field->Offset); + VMValue val = GetVMValue(addr, field->Type); + m_children[symname] = RuntimeState::CreateNodeForVariable(symname, val, field->Type); + } + } + } + } + } + if (m_children.find(name) != m_children.end()) + { + node = m_children[name]; + return true; + } + return false; +} + +} \ No newline at end of file diff --git a/src/common/scripting/dap/Nodes/GlobalScopeStateNode.h b/src/common/scripting/dap/Nodes/GlobalScopeStateNode.h new file mode 100644 index 0000000000..94544000aa --- /dev/null +++ b/src/common/scripting/dap/Nodes/GlobalScopeStateNode.h @@ -0,0 +1,20 @@ +#pragma once + +#include +#include + +#include "StateNodeBase.h" + +namespace DebugServer +{ +class GlobalScopeStateNode : public StateNodeBase, public IProtocolScopeSerializable, public IStructuredState +{ + caseless_path_map> m_children; + public: + GlobalScopeStateNode(); + + bool SerializeToProtocol(dap::Scope &scope) override; + bool GetChildNames(std::vector &names) override; + bool GetChildNode(std::string name, std::shared_ptr &node) override; +}; +} diff --git a/src/common/scripting/dap/Nodes/StackFrameStateNode.cpp b/src/common/scripting/dap/Nodes/StackFrameStateNode.cpp index 65ed12ab86..b793c012ef 100644 --- a/src/common/scripting/dap/Nodes/StackFrameStateNode.cpp +++ b/src/common/scripting/dap/Nodes/StackFrameStateNode.cpp @@ -1,10 +1,12 @@ #include "StackFrameStateNode.h" + #include #include #include "LocalScopeStateNode.h" #include "RegistersScopeStateNode.h" +#include "GlobalScopeStateNode.h" namespace DebugServer { @@ -20,6 +22,7 @@ StackFrameStateNode::StackFrameStateNode(VMFunction *nativeFunction, VMFrame *pa m_fakeStackFrame.MaxParam = 0; m_fakeStackFrame.NumParam = 0; m_stackFrame = &m_fakeStackFrame; + m_globalsScope = std::make_shared(); } StackFrameStateNode::StackFrameStateNode(VMFrame *stackFrame) : m_stackFrame(stackFrame), m_fakeStackFrame() @@ -33,6 +36,7 @@ StackFrameStateNode::StackFrameStateNode(VMFrame *stackFrame) : m_stackFrame(sta } m_registersScope = std::make_shared(m_stackFrame); } + m_globalsScope = std::make_shared(); } bool StackFrameStateNode::SerializeToProtocol(dap::StackFrame &stackFrame, PexCache *pexCache) const @@ -86,10 +90,14 @@ bool StackFrameStateNode::SerializeToProtocol(dap::StackFrame &stackFrame, PexCa bool StackFrameStateNode::GetChildNames(std::vector &names) { - auto scriptFunction = dynamic_cast(m_stackFrame->Func); + auto scriptFunction = GetVMScriptFunction(m_stackFrame->Func); if (scriptFunction) { names.push_back("Local"); + } + names.push_back("Globals"); + if (scriptFunction) + { names.push_back("Registers"); } return true; @@ -101,6 +109,11 @@ bool StackFrameStateNode::GetChildNode(std::string name, std::shared_ptr m_localScope = nullptr; std::shared_ptr m_registersScope = nullptr; + std::shared_ptr m_globalsScope = nullptr; public: StackFrameStateNode(VMFunction *nativeFunction, VMFrame *parentStackFrame); explicit StackFrameStateNode(VMFrame *stackFrame);