From e4ea4ca4b43a4637db3517d618e454d9cf6c7063 Mon Sep 17 00:00:00 2001 From: mlangkabel Date: Wed, 8 Jul 2026 20:45:41 +0200 Subject: [PATCH] Refresh selected-building panel when paused player commands drain --- src/lib/eventsystem/event/CMakeLists.txt | 1 + .../event/PlayerCommandsAppliedEvent.h | 13 +++++++++++++ src/ui/GameWorldView.cpp | 13 +++++++++++++ src/ui/SelectedBuildingPanel.cpp | 16 ++++++++++++++++ src/ui/SelectedBuildingPanel.h | 4 ++++ 5 files changed, 47 insertions(+) create mode 100644 src/lib/eventsystem/event/PlayerCommandsAppliedEvent.h diff --git a/src/lib/eventsystem/event/CMakeLists.txt b/src/lib/eventsystem/event/CMakeLists.txt index 5cef778..ab7f2ff 100644 --- a/src/lib/eventsystem/event/CMakeLists.txt +++ b/src/lib/eventsystem/event/CMakeLists.txt @@ -31,6 +31,7 @@ SET(HDRS ${CMAKE_CURRENT_SOURCE_DIR}/BeamFiredEvent.h ${CMAKE_CURRENT_SOURCE_DIR}/DebugDrawToggledEvent.h ${CMAKE_CURRENT_SOURCE_DIR}/CommandRequestedEvent.h + ${CMAKE_CURRENT_SOURCE_DIR}/PlayerCommandsAppliedEvent.h PARENT_SCOPE ) diff --git a/src/lib/eventsystem/event/PlayerCommandsAppliedEvent.h b/src/lib/eventsystem/event/PlayerCommandsAppliedEvent.h new file mode 100644 index 0000000..341441b --- /dev/null +++ b/src/lib/eventsystem/event/PlayerCommandsAppliedEvent.h @@ -0,0 +1,13 @@ +#pragma once + +#include "Event.h" + +// Emitted by GameWorldView once per frame after queued player commands have been +// drained and applied to the simulation. It lets presentation widgets refresh +// even while the game is paused (no tick advances, so no TickAdvancedEvent), for +// example so a shipyard's layout preview appears immediately after its schematic +// is chosen. It is a UI notification only and never feeds back into the command +// queue, so it has no effect on replay recording or determinism. +class PlayerCommandsAppliedEvent : public Event +{ +}; diff --git a/src/ui/GameWorldView.cpp b/src/ui/GameWorldView.cpp index 994de52..692b73f 100644 --- a/src/ui/GameWorldView.cpp +++ b/src/ui/GameWorldView.cpp @@ -62,6 +62,7 @@ #include "ExpansionCostChangedEvent.h" #include "GameSpeedChangedEvent.h" #include "SchematicChoicesAvailableEvent.h" +#include "PlayerCommandsAppliedEvent.h" #include "TickAdvancedEvent.h" namespace @@ -212,6 +213,7 @@ void GameWorldView::onFrame() // Drain queued player commands once per frame, before the tick batch. This // runs even at 0x so a paused player sees placed construction sites // immediately, while staying deterministic (see docs/replay_design.md). + const bool commandsApplied = m_commandManager.hasPending(); m_commandManager.drain(); // A drained Reset reinitialized the simulation; reset the view to match. @@ -221,6 +223,17 @@ void GameWorldView::onFrame() resetForNewGame(); } + // Notify presentation widgets that queued commands were applied, so a + // paused player still sees the effect (e.g. a shipyard's layout preview + // after picking a schematic) even though no tick advances. UI-only: this + // does not touch the command queue or simulation, so replay recording + // and determinism are unaffected. + if (commandsApplied) + { + EventManager::getInstance()->sendEventImmediately( + std::make_shared()); + } + const int ticks = m_tickDriver.advance( static_cast(elapsed), m_gameSpeedMultiplier); for (int i = 0; i < ticks; ++i) diff --git a/src/ui/SelectedBuildingPanel.cpp b/src/ui/SelectedBuildingPanel.cpp index 826ced3..bc28196 100644 --- a/src/ui/SelectedBuildingPanel.cpp +++ b/src/ui/SelectedBuildingPanel.cpp @@ -33,6 +33,7 @@ #include "ItemType.h" #include "LayoutDialogRequestedEvent.h" #include "ModulesConfig.h" +#include "PlayerCommandsAppliedEvent.h" #include "RecipeSelectionDialog.h" #include "RecipeSelectionRequestedEvent.h" #include "Rotation.h" @@ -560,6 +561,21 @@ const ShipDef* SelectedBuildingPanel::findShipDef(const std::string& id) const } void SelectedBuildingPanel::handleEvent(std::shared_ptr /*event*/) +{ + refreshSelectionDisplay(); +} + +void SelectedBuildingPanel::handleEvent( + std::shared_ptr /*event*/) +{ + // Player commands (e.g. choosing a shipyard schematic) are applied by a + // queued drain, not synchronously. When the game is paused no tick advances, + // so TickAdvancedEvent never fires; refresh here too, otherwise the panel + // would not reflect the change until the next tick or a re-selection. + refreshSelectionDisplay(); +} + +void SelectedBuildingPanel::refreshSelectionDisplay() { if (m_selectedEntity.has_value()) { diff --git a/src/ui/SelectedBuildingPanel.h b/src/ui/SelectedBuildingPanel.h index 11fb9c6..35f514d 100644 --- a/src/ui/SelectedBuildingPanel.h +++ b/src/ui/SelectedBuildingPanel.h @@ -16,6 +16,7 @@ #include "EntitySelectedEvent.h" #include "EventHandler.h" #include "GameConfig.h" +#include "PlayerCommandsAppliedEvent.h" #include "RecipesConfig.h" #include "SelectionChangedEvent.h" #include "ShipLayout.h" @@ -33,6 +34,7 @@ class QVBoxLayout; class SelectedBuildingPanel : public QWidget, public CombinedEventHandler @@ -46,6 +48,7 @@ public: private: void handleEvent(std::shared_ptr event) override; + void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; void handleEvent(std::shared_ptr event) override; @@ -57,6 +60,7 @@ private slots: private: void onSelectionChanged(const std::vector& ids); + void refreshSelectionDisplay(); void rebuild(); void hideAllWidgets(); void clearContent();