From 224ad2c2c07311475875d1d243354f8647112b45 Mon Sep 17 00:00:00 2001 From: Kae <80987908+Novaenia@users.noreply.github.com> Date: Sat, 29 Jul 2023 02:12:03 +1000 Subject: [PATCH] Reset script panes on character swap --- source/client/StarClientApplication.cpp | 21 ++++++-- source/frontend/StarBaseScriptPane.cpp | 5 +- source/frontend/StarBaseScriptPane.hpp | 4 ++ source/frontend/StarMainInterface.cpp | 67 +++++++++++++++++++------ source/frontend/StarMainInterface.hpp | 12 +++++ source/frontend/StarScriptPane.cpp | 4 ++ source/frontend/StarScriptPane.hpp | 2 + source/game/StarUniverseClient.cpp | 12 ++--- source/game/StarUniverseClient.hpp | 11 ++-- source/windowing/StarPaneManager.cpp | 17 +++++++ source/windowing/StarPaneManager.hpp | 2 + source/windowing/StarWidget.cpp | 4 ++ source/windowing/StarWidget.hpp | 1 + 13 files changed, 131 insertions(+), 31 deletions(-) diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp index ab620b4..efbdcad 100644 --- a/source/client/StarClientApplication.cpp +++ b/source/client/StarClientApplication.cpp @@ -510,10 +510,23 @@ void ClientApplication::changeState(MainAppState newState) { m_universeClient->setLuaCallbacks("input", LuaBindings::makeInputCallbacks()); m_universeClient->setLuaCallbacks("voice", LuaBindings::makeVoiceCallbacks()); - m_universeClient->playerReloadCallback() = [&]() { - if (auto paneManager = m_mainInterface->paneManager()) { - if (auto inventory = paneManager->registeredPane(MainInterfacePanes::Inventory)) - inventory->clearChangedSlots(); + auto heldScriptPanes = make_shared>(); + + m_universeClient->playerReloadPreCallback() = [&, heldScriptPanes](bool resetInterface) { + if (!resetInterface) + return; + + m_mainInterface->takeScriptPanes(*heldScriptPanes); + }; + + m_universeClient->playerReloadCallback() = [&, heldScriptPanes](bool resetInterface) { + auto paneManager = m_mainInterface->paneManager(); + if (auto inventory = paneManager->registeredPane(MainInterfacePanes::Inventory)) + inventory->clearChangedSlots(); + + if (resetInterface) { + m_mainInterface->reviveScriptPanes(*heldScriptPanes); + heldScriptPanes->clear(); } }; diff --git a/source/frontend/StarBaseScriptPane.cpp b/source/frontend/StarBaseScriptPane.cpp index 90d253c..4164d9e 100644 --- a/source/frontend/StarBaseScriptPane.cpp +++ b/source/frontend/StarBaseScriptPane.cpp @@ -14,7 +14,7 @@ namespace Star { -BaseScriptPane::BaseScriptPane(Json config) : Pane() { +BaseScriptPane::BaseScriptPane(Json config) : Pane(), m_rawConfig(config) { auto& root = Root::singleton(); auto assets = root.assets(); @@ -97,6 +97,9 @@ bool BaseScriptPane::sendEvent(InputEvent const& event) { return Pane::sendEvent(event); } +Json const& BaseScriptPane::config() const { return m_config; } +Json const& BaseScriptPane::rawConfig() const { return m_rawConfig; } + PanePtr BaseScriptPane::createTooltip(Vec2I const& screenPosition) { auto result = m_script.invoke("createTooltip", screenPosition); if (result && !result.value().isNull()) { diff --git a/source/frontend/StarBaseScriptPane.hpp b/source/frontend/StarBaseScriptPane.hpp index 4a47a4a..df2d4c5 100644 --- a/source/frontend/StarBaseScriptPane.hpp +++ b/source/frontend/StarBaseScriptPane.hpp @@ -25,12 +25,16 @@ public: void tick(float dt) override; bool sendEvent(InputEvent const& event) override; + + Json const& config() const; + Json const& rawConfig() const; PanePtr createTooltip(Vec2I const& screenPosition) override; Maybe cursorOverride(Vec2I const& screenPosition) override; protected: virtual GuiReaderPtr reader(); Json m_config; + Json m_rawConfig; GuiReaderPtr m_reader; diff --git a/source/frontend/StarMainInterface.cpp b/source/frontend/StarMainInterface.cpp index 526ab99..1497b8b 100644 --- a/source/frontend/StarMainInterface.cpp +++ b/source/frontend/StarMainInterface.cpp @@ -498,22 +498,8 @@ void MainInterface::handleInteractAction(InteractAction interactAction) { m_paneManager.dismissPane(m_interactionScriptPanes[sourceEntity]); ScriptPanePtr scriptPane = make_shared(m_client, interactAction.data, sourceEntity); - // keep any number of script panes open with null source entities - if (sourceEntity != NullEntityId) - m_interactionScriptPanes[sourceEntity] = scriptPane; + displayScriptPane(scriptPane, sourceEntity); - if (scriptPane->openWithInventory()) { - m_paneManager.displayPane(PaneLayer::Window, scriptPane, [this](PanePtr const&) { - if (auto player = m_client->mainPlayer()) - player->clearSwap(); - m_paneManager.dismissRegisteredPane(MainInterfacePanes::Inventory); - }); - m_paneManager.displayRegisteredPane(MainInterfacePanes::Inventory); - m_paneManager.bringPaneAdjacent(m_paneManager.registeredPane(MainInterfacePanes::Inventory), - scriptPane, Root::singleton().assets()->json("/interface.config:bringAdjacentWindowGap").toFloat()); - } else { - m_paneManager.displayPane(PaneLayer::Window, scriptPane); - } } else if (interactAction.type == InteractActionType::Message) { m_client->mainPlayer()->receiveMessage(connectionForEntity(interactAction.entityId), interactAction.data.getString("messageType"), interactAction.data.getArray("messageArgs")); @@ -952,6 +938,38 @@ CanvasWidgetPtr MainInterface::fetchCanvas(String const& canvasName, bool ignore return canvas; } +// For when the player swaps characters. We need to completely reload ScriptPanes, +// because a lot of ScriptPanes do not expect the character to suddenly change and may break or spill data over. +void MainInterface::takeScriptPanes(List& out) { + m_paneManager.dismissWhere([&](PanePtr const& pane) { + if (auto scriptPane = as(pane)) { + if (scriptPane->isDismissed()) + return false; + auto sourceEntityId = scriptPane->sourceEntityId(); + m_interactionScriptPanes.remove(sourceEntityId); + auto& info = out.emplaceAppend(); + info.scriptPane = scriptPane; + info.config = scriptPane->rawConfig(); + info.sourceEntityId = sourceEntityId; + info.visible = scriptPane->visibility(); + info.position = scriptPane->relativePosition(); + + return true; + } + return false; + }); +} + +void MainInterface::reviveScriptPanes(List& panes) { + for (auto& info : panes) { // this is evil and stupid + info.scriptPane->~ScriptPane(); + new(info.scriptPane.get()) ScriptPane(m_client, info.config, info.sourceEntityId); + info.scriptPane->setVisibility(info.visible); + displayScriptPane(info.scriptPane, info.sourceEntityId); + info.scriptPane->setPosition(info.position); + } +} + PanePtr MainInterface::createEscapeDialog() { auto assets = Root::singleton().assets(); @@ -1542,4 +1560,23 @@ bool MainInterface::overlayClick(Vec2I const& mousePos, MouseButton mouseButton) return false; } +void MainInterface::displayScriptPane(ScriptPanePtr& scriptPane, EntityId sourceEntity) { + // keep any number of script panes open with null source entities + if (sourceEntity != NullEntityId) + m_interactionScriptPanes[sourceEntity] = scriptPane; + + if (scriptPane->openWithInventory()) { + m_paneManager.displayPane(PaneLayer::Window, scriptPane, [this](PanePtr const&) { + if (auto player = m_client->mainPlayer()) + player->clearSwap(); + m_paneManager.dismissRegisteredPane(MainInterfacePanes::Inventory); + }); + m_paneManager.displayRegisteredPane(MainInterfacePanes::Inventory); + m_paneManager.bringPaneAdjacent(m_paneManager.registeredPane(MainInterfacePanes::Inventory), + scriptPane, Root::singleton().assets()->json("/interface.config:bringAdjacentWindowGap").toFloat()); + } else { + m_paneManager.displayPane(PaneLayer::Window, scriptPane); + } +} + } \ No newline at end of file diff --git a/source/frontend/StarMainInterface.hpp b/source/frontend/StarMainInterface.hpp index ddc4d3d..adba4e6 100644 --- a/source/frontend/StarMainInterface.hpp +++ b/source/frontend/StarMainInterface.hpp @@ -119,6 +119,16 @@ public: CanvasWidgetPtr fetchCanvas(String const& canvasName, bool ignoreInterfaceScale = false); + struct ScriptPaneInfo { + ScriptPanePtr scriptPane; + Json config; + EntityId sourceEntityId; + bool visible; + Vec2I position; + }; + + void takeScriptPanes(List& out); + void reviveScriptPanes(List& panes); private: PanePtr createEscapeDialog(); @@ -142,6 +152,8 @@ private: bool overlayClick(Vec2I const& mousePos, MouseButton mouseButton); + void displayScriptPane(ScriptPanePtr& scriptPane, EntityId sourceEntity); + GuiContext* m_guiContext; MainInterfaceConfigConstPtr m_config; InterfaceCursor m_cursor; diff --git a/source/frontend/StarScriptPane.cpp b/source/frontend/StarScriptPane.cpp index 2cd74a5..2105680 100644 --- a/source/frontend/StarScriptPane.cpp +++ b/source/frontend/StarScriptPane.cpp @@ -88,4 +88,8 @@ bool ScriptPane::openWithInventory() const { return m_config.getBool("openWithInventory", false); } +EntityId ScriptPane::sourceEntityId() const { + return m_sourceEntityId; +} + } diff --git a/source/frontend/StarScriptPane.hpp b/source/frontend/StarScriptPane.hpp index e7ed2ae..298d7c0 100644 --- a/source/frontend/StarScriptPane.hpp +++ b/source/frontend/StarScriptPane.hpp @@ -22,6 +22,8 @@ public: bool openWithInventory() const; + EntityId sourceEntityId() const; + LuaCallbacks makePaneCallbacks() override; private: UniverseClientPtr m_client; diff --git a/source/game/StarUniverseClient.cpp b/source/game/StarUniverseClient.cpp index f12ae28..c17f8bc 100644 --- a/source/game/StarUniverseClient.cpp +++ b/source/game/StarUniverseClient.cpp @@ -477,7 +477,7 @@ void UniverseClient::stopLua() { m_scriptContexts.clear(); } -bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid) { +bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid, bool resetInterfaces) { auto player = mainPlayer(); bool playerInWorld = player->inWorld(); auto world = as(player->world()); @@ -487,7 +487,7 @@ bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid) { : connectionEntitySpace(world->connection()).first; if (m_playerReloadPreCallback) - m_playerReloadPreCallback(); + m_playerReloadPreCallback(resetInterfaces); if (playerInWorld) { world->removeEntity(player->entityId(), false); @@ -515,7 +515,7 @@ bool UniverseClient::reloadPlayer(Json const& data, Uuid const& uuid) { player->universeMap()->filterMappedObjects(coordinate, m_systemWorldClient->objectKeys()); if (m_playerReloadCallback) - m_playerReloadCallback(); + m_playerReloadCallback(resetInterfaces); if (exception) std::rethrow_exception(exception); @@ -527,7 +527,7 @@ bool UniverseClient::switchPlayer(Uuid const& uuid) { if (uuid == mainPlayer()->uuid()) return false; else if (auto data = m_playerStorage->maybeGetPlayerData(uuid)) - return reloadPlayer(*data, uuid); + return reloadPlayer(*data, uuid, true); else return false; } @@ -546,11 +546,11 @@ bool UniverseClient::switchPlayer(String const& name) { return false; } -UniverseClient::Callback& UniverseClient::playerReloadPreCallback() { +UniverseClient::ReloadPlayerCallback& UniverseClient::playerReloadPreCallback() { return m_playerReloadPreCallback; } -UniverseClient::Callback& UniverseClient::playerReloadCallback() { +UniverseClient::ReloadPlayerCallback& UniverseClient::playerReloadCallback() { return m_playerReloadCallback; } diff --git a/source/game/StarUniverseClient.hpp b/source/game/StarUniverseClient.hpp index 911061c..89c9c39 100644 --- a/source/game/StarUniverseClient.hpp +++ b/source/game/StarUniverseClient.hpp @@ -91,14 +91,15 @@ public: void startLua(); void stopLua(); - bool reloadPlayer(Json const& data, Uuid const& uuid); + bool reloadPlayer(Json const& data, Uuid const& uuid, bool resetInterfaces = false); bool switchPlayer(Uuid const& uuid); bool switchPlayer(size_t index); bool switchPlayer(String const& name); typedef std::function Callback; - Callback& playerReloadPreCallback(); - Callback& playerReloadCallback(); + typedef std::function ReloadPlayerCallback; + ReloadPlayerCallback& playerReloadPreCallback(); + ReloadPlayerCallback& playerReloadCallback(); ClockConstPtr universeClock() const; CelestialLogConstPtr celestialLog() const; @@ -161,8 +162,8 @@ private: typedef shared_ptr ScriptComponentPtr; StringMap m_scriptContexts; - Callback m_playerReloadPreCallback; - Callback m_playerReloadCallback; + ReloadPlayerCallback m_playerReloadPreCallback; + ReloadPlayerCallback m_playerReloadCallback; }; } diff --git a/source/windowing/StarPaneManager.cpp b/source/windowing/StarPaneManager.cpp index f34c786..9dd7737 100644 --- a/source/windowing/StarPaneManager.cpp +++ b/source/windowing/StarPaneManager.cpp @@ -128,6 +128,23 @@ void PaneManager::setBackgroundWidget(WidgetPtr bg) { m_backgroundWidget = bg; } +void PaneManager::dismissWhere(function func) { + if (!func) + return; + + for (auto& layerPair : m_displayedPanes) { + eraseWhere(layerPair.second, [&](auto& panePair) { + if (func(panePair.first)) { + panePair.first->dismissed(); + if (panePair.second) + panePair.second(panePair.first); + return true; + } + return false; + }); + } +} + PanePtr PaneManager::keyboardCapturedPane() const { for (auto const& layerPair : m_displayedPanes) { for (auto const& panePair : layerPair.second) { diff --git a/source/windowing/StarPaneManager.hpp b/source/windowing/StarPaneManager.hpp index 8adf772..e69f699 100644 --- a/source/windowing/StarPaneManager.hpp +++ b/source/windowing/StarPaneManager.hpp @@ -63,6 +63,8 @@ public: void setBackgroundWidget(WidgetPtr bg); + void dismissWhere(function func); + // Returns the pane that has captured the keyboard, if any. PanePtr keyboardCapturedPane() const; // Returns true if the current pane that has captured the keyboard is diff --git a/source/windowing/StarWidget.cpp b/source/windowing/StarWidget.cpp index 48b945f..0287288 100644 --- a/source/windowing/StarWidget.cpp +++ b/source/windowing/StarWidget.cpp @@ -219,6 +219,10 @@ void Widget::hide() { m_visible = false; } +bool Widget::visibility() const { + return m_visible; +} + void Widget::toggleVisibility() { m_visible = !m_visible; } diff --git a/source/windowing/StarWidget.hpp b/source/windowing/StarWidget.hpp index f6e9928..1e78d74 100644 --- a/source/windowing/StarWidget.hpp +++ b/source/windowing/StarWidget.hpp @@ -58,6 +58,7 @@ public: virtual void show(); virtual void hide(); + virtual bool visibility() const; virtual void toggleVisibility(); virtual void setVisibility(bool visibility);