diff --git a/src/lib/eventsystem/event/CMakeLists.txt b/src/lib/eventsystem/event/CMakeLists.txt index 1125058..5b579c7 100644 --- a/src/lib/eventsystem/event/CMakeLists.txt +++ b/src/lib/eventsystem/event/CMakeLists.txt @@ -30,6 +30,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 0849a03..2e52e1a 100644 --- a/src/ui/GameWorldView.cpp +++ b/src/ui/GameWorldView.cpp @@ -61,6 +61,7 @@ #include "BuildingBlocksChangedEvent.h" #include "GameSpeedChangedEvent.h" #include "SchematicChoicesAvailableEvent.h" +#include "PlayerCommandsAppliedEvent.h" #include "TickAdvancedEvent.h" namespace @@ -211,6 +212,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. @@ -220,6 +222,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();