diff --git a/Runtime/CStateManager.cpp b/Runtime/CStateManager.cpp index bba5001e4..09622272e 100644 --- a/Runtime/CStateManager.cpp +++ b/Runtime/CStateManager.cpp @@ -1372,8 +1372,10 @@ void CStateManager::FreeScriptObjects(TAreaId aid) { } } + std::set freedObjects; for (auto it = x8a4_loadedScriptObjects.begin(); it != x8a4_loadedScriptObjects.end();) { if (it->first.AreaNum() == aid) { + freedObjects.emplace(it->first); it = x8a4_loadedScriptObjects.erase(it); continue; } @@ -1389,6 +1391,10 @@ void CStateManager::FreeScriptObjects(TAreaId aid) { } } } + + for (const auto& id : freedObjects) { + m_incomingConnections.erase(id); + } } void CStateManager::FreeScriptObject(TUniqueId id) { @@ -1451,7 +1457,6 @@ void CStateManager::LoadScriptObjects(TAreaId aid, CInputStream& in, std::vector const u32 objCount = in.readUint32Big(); idsOut.reserve(idsOut.size() + objCount); - for (u32 i = 0; i < objCount; ++i) { const auto objType = static_cast(in.readUByte()); const u32 objSize = in.readUint32Big(); @@ -1469,6 +1474,12 @@ void CStateManager::LoadScriptObjects(TAreaId aid, CInputStream& in, std::vector x8a4_loadedScriptObjects[id.first] = SScriptObjectStream{objType, pos, objSize}; idsOut.push_back(id.first); } + + for (const auto& pair : m_incomingConnections) { + if (auto* ent = ObjectById(GetIdForScript(pair.first))) { + ent->SetIncomingConnectionList(&pair.second); + } + } } std::pair CStateManager::LoadScriptObject(TAreaId aid, EScriptObjectType type, u32 length, @@ -1483,6 +1494,13 @@ std::pair CStateManager::LoadScriptObject(TAreaId aid, ESc const auto state = EScriptObjectState(in.readUint32Big()); const auto msg = EScriptObjectMessage(in.readUint32Big()); const TEditorId target = in.readUint32Big(); + // Metaforce Addition + if (m_incomingConnections.find(target) == m_incomingConnections.cend()) { + m_incomingConnections.emplace(target, std::set()); + } + SConnection inConn{state, msg, id}; + m_incomingConnections[target].emplace(inConn); + // End Metaforce Addition length -= 12; conns.push_back(SConnection{state, msg, target}); } @@ -1544,7 +1562,15 @@ std::pair CStateManager::GenerateObject(TEditorId eid) { if (area->IsPostConstructed()) { const std::pair buf = area->GetLayerScriptBuffer(build.second.LayerNum()); CMemoryInStream stream(buf.first + build.first->x4_position, build.first->x8_length); - return LoadScriptObject(build.second.AreaNum(), build.first->x0_type, build.first->x8_length, stream); + auto ret = LoadScriptObject(build.second.AreaNum(), build.first->x0_type, build.first->x8_length, stream); + // Metaforce Addition + if (m_incomingConnections.find(eid) != m_incomingConnections.end()) { + if (auto ent = ObjectById(ret.second)) { + ent->SetIncomingConnectionList(&m_incomingConnections[eid]); + } + } + // End Metaforce Addition + return ret; } } @@ -2874,9 +2900,9 @@ void CStateManager::sub_80044098(const CCollisionResponseData& colRespData, cons } const CGameArea* CStateManager::GetCurrentArea() const { - if (x850_world == nullptr || x850_world->GetCurrentAreaId() == kInvalidAreaId) { - return nullptr; + if (x850_world != nullptr && x850_world->GetCurrentAreaId() != kInvalidAreaId) { + return x850_world->GetAreaAlways(x850_world->GetCurrentAreaId()); } - return x850_world->GetAreaAlways(x850_world->GetCurrentAreaId()); + return nullptr; }; } // namespace metaforce diff --git a/Runtime/CStateManager.hpp b/Runtime/CStateManager.hpp index 8ce3f841c..51696462e 100644 --- a/Runtime/CStateManager.hpp +++ b/Runtime/CStateManager.hpp @@ -214,6 +214,7 @@ private: CColoredQuadFilter m_deathWhiteout{EFilterType::Add}; CColoredQuadFilter m_escapeWhiteout{EFilterType::Add}; bool m_warping = false; + std::map> m_incomingConnections; void UpdateThermalVisor(); static void RendererDrawCallback(void*, void*, int); diff --git a/Runtime/ImGuiEntitySupport.cpp b/Runtime/ImGuiEntitySupport.cpp index c972f6924..de8f42880 100644 --- a/Runtime/ImGuiEntitySupport.cpp +++ b/Runtime/ImGuiEntitySupport.cpp @@ -188,8 +188,8 @@ namespace metaforce { std::string_view CEntity::ImGuiType() { return "Entity"; } void CEntity::ImGuiInspect() { - if (!x20_conns.empty() && ImGui::CollapsingHeader("Connections")) { - if (ImGui::BeginTable("Connections", 6, + if (!x20_conns.empty() && ImGui::CollapsingHeader("Outgoing Connections")) { + if (ImGui::BeginTable("Outgoing Connections", 6, ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV)) { ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 0, 'id'); ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 0, 'type'); @@ -227,6 +227,44 @@ void CEntity::ImGuiInspect() { ImGui::EndTable(); } } + if (m_incomingConnections && ImGui::CollapsingHeader("Incoming Connections")) { + if (ImGui::BeginTable("Incoming Connections", 6, + ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV)) { + ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_WidthFixed, 0, 'id'); + ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 0, 'type'); + ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0, 'name'); + ImGui::TableSetupColumn("State", ImGuiTableColumnFlags_WidthFixed, 0, 'stat'); + ImGui::TableSetupColumn("Message", ImGuiTableColumnFlags_WidthFixed, 0, 'msg'); + ImGui::TableSetupColumn("", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupScrollFreeze(0, 1); + ImGui::TableHeadersRow(); + for (const auto& item : (*m_incomingConnections)) { + const auto uid = g_StateManager->GetIdForScript(item.x8_objId); + if (uid == kInvalidUniqueId) { + continue; + } + ImGuiEntityEntry& entry = ImGuiConsole::entities[uid.Value()]; + if (entry.uid == kInvalidUniqueId) { + continue; + } + ImGuiConsole::BeginEntityRow(entry); + if (ImGui::TableNextColumn()) { + ImGuiStringViewText(entry.type); + } + if (ImGui::TableNextColumn()) { + ImGuiStringViewText(entry.name); + } + if (ImGui::TableNextColumn()) { + ImGuiStringViewText(ScriptObjectStateToStr(item.x0_state)); + } + if (ImGui::TableNextColumn()) { + ImGuiStringViewText(ScriptObjectMessageToStr(item.x4_msg)); + } + ImGuiConsole::EndEntityRow(entry); + } + ImGui::EndTable(); + } + } if (ImGui::CollapsingHeader("Entity", ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::Text("ID: %x", x8_uid.Value()); ImGui::Text("Name: %s", x10_name.c_str()); diff --git a/Runtime/World/CEntity.hpp b/Runtime/World/CEntity.hpp index 68ed7aeda..6005aeb77 100644 --- a/Runtime/World/CEntity.hpp +++ b/Runtime/World/CEntity.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "Runtime/RetroTypes.hpp" #include "Runtime/World/CEntityInfo.hpp" @@ -44,7 +45,7 @@ protected: // Used in ImGuiConsole bool m_debugSelected = false; bool m_debugHovered = false; - + const std::set* m_incomingConnections = nullptr; public: static const std::vector NullConnectionList; virtual ~CEntity() = default; @@ -82,6 +83,9 @@ public: const std::vector& GetConnectionList() const { return x20_conns; } std::string_view GetName() const { return x10_name; } + void SetIncomingConnectionList(const std::set* conns) { + m_incomingConnections = conns; + } }; } // namespace metaforce diff --git a/Runtime/World/CEntityInfo.hpp b/Runtime/World/CEntityInfo.hpp index e9740bdf7..a3c51f1b6 100644 --- a/Runtime/World/CEntityInfo.hpp +++ b/Runtime/World/CEntityInfo.hpp @@ -7,9 +7,15 @@ namespace metaforce { struct SConnection { - EScriptObjectState x0_state; - EScriptObjectMessage x4_msg; - TEditorId x8_objId; + EScriptObjectState x0_state = EScriptObjectState::Any; + EScriptObjectMessage x4_msg = EScriptObjectMessage::None; + TEditorId x8_objId = kInvalidEditorId; + bool operator==(const SConnection& other) const { + return x0_state == other.x0_state && x4_msg == other.x4_msg && x8_objId == other.x8_objId; + } + bool operator<(const SConnection& other) const { + return x8_objId < other.x8_objId; + } }; class CEntityInfo {