Refresh selected-building panel when paused player commands drain
Option A made the per-tick refresh authoritative for the shipyard layout preview and Configure Layout button, but that path is driven by TickAdvancedEvent, which only fires while the game is running. Choosing a schematic while paused therefore still left the widgets hidden until the game was unpaused or the building re-selected, because the queued SetRecipeCommand drains on the next frame but no tick advances. Emit a new PlayerCommandsAppliedEvent from GameWorldView::onFrame once per frame when queued commands were drained, and have SelectedBuildingPanel refresh its selection display in response. This is a presentation-only notification: it is emitted only on the live path (not during replay playback), touches neither the command queue nor the simulation, and its only handler never enqueues commands -- so replay recording and determinism are unaffected. Factor the former TickAdvancedEvent handler body into refreshSelectionDisplay() and call it from both handlers to avoid duplication. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DyCu8vwChKMbLJQ3xosYEN
This commit is contained in:
@@ -31,6 +31,7 @@ SET(HDRS
|
|||||||
${CMAKE_CURRENT_SOURCE_DIR}/BeamFiredEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/BeamFiredEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/DebugDrawToggledEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/DebugDrawToggledEvent.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/CommandRequestedEvent.h
|
${CMAKE_CURRENT_SOURCE_DIR}/CommandRequestedEvent.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/PlayerCommandsAppliedEvent.h
|
||||||
PARENT_SCOPE
|
PARENT_SCOPE
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
13
src/lib/eventsystem/event/PlayerCommandsAppliedEvent.h
Normal file
13
src/lib/eventsystem/event/PlayerCommandsAppliedEvent.h
Normal file
@@ -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
|
||||||
|
{
|
||||||
|
};
|
||||||
@@ -62,6 +62,7 @@
|
|||||||
#include "ExpansionCostChangedEvent.h"
|
#include "ExpansionCostChangedEvent.h"
|
||||||
#include "GameSpeedChangedEvent.h"
|
#include "GameSpeedChangedEvent.h"
|
||||||
#include "SchematicChoicesAvailableEvent.h"
|
#include "SchematicChoicesAvailableEvent.h"
|
||||||
|
#include "PlayerCommandsAppliedEvent.h"
|
||||||
#include "TickAdvancedEvent.h"
|
#include "TickAdvancedEvent.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -212,6 +213,7 @@ void GameWorldView::onFrame()
|
|||||||
// Drain queued player commands once per frame, before the tick batch. This
|
// Drain queued player commands once per frame, before the tick batch. This
|
||||||
// runs even at 0x so a paused player sees placed construction sites
|
// runs even at 0x so a paused player sees placed construction sites
|
||||||
// immediately, while staying deterministic (see docs/replay_design.md).
|
// immediately, while staying deterministic (see docs/replay_design.md).
|
||||||
|
const bool commandsApplied = m_commandManager.hasPending();
|
||||||
m_commandManager.drain();
|
m_commandManager.drain();
|
||||||
|
|
||||||
// A drained Reset reinitialized the simulation; reset the view to match.
|
// A drained Reset reinitialized the simulation; reset the view to match.
|
||||||
@@ -221,6 +223,17 @@ void GameWorldView::onFrame()
|
|||||||
resetForNewGame();
|
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<PlayerCommandsAppliedEvent>());
|
||||||
|
}
|
||||||
|
|
||||||
const int ticks = m_tickDriver.advance(
|
const int ticks = m_tickDriver.advance(
|
||||||
static_cast<double>(elapsed), m_gameSpeedMultiplier);
|
static_cast<double>(elapsed), m_gameSpeedMultiplier);
|
||||||
for (int i = 0; i < ticks; ++i)
|
for (int i = 0; i < ticks; ++i)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
#include "ItemType.h"
|
#include "ItemType.h"
|
||||||
#include "LayoutDialogRequestedEvent.h"
|
#include "LayoutDialogRequestedEvent.h"
|
||||||
#include "ModulesConfig.h"
|
#include "ModulesConfig.h"
|
||||||
|
#include "PlayerCommandsAppliedEvent.h"
|
||||||
#include "RecipeSelectionDialog.h"
|
#include "RecipeSelectionDialog.h"
|
||||||
#include "RecipeSelectionRequestedEvent.h"
|
#include "RecipeSelectionRequestedEvent.h"
|
||||||
#include "Rotation.h"
|
#include "Rotation.h"
|
||||||
@@ -560,6 +561,21 @@ const ShipDef* SelectedBuildingPanel::findShipDef(const std::string& id) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SelectedBuildingPanel::handleEvent(std::shared_ptr<const TickAdvancedEvent> /*event*/)
|
void SelectedBuildingPanel::handleEvent(std::shared_ptr<const TickAdvancedEvent> /*event*/)
|
||||||
|
{
|
||||||
|
refreshSelectionDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SelectedBuildingPanel::handleEvent(
|
||||||
|
std::shared_ptr<const PlayerCommandsAppliedEvent> /*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())
|
if (m_selectedEntity.has_value())
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
#include "EntitySelectedEvent.h"
|
#include "EntitySelectedEvent.h"
|
||||||
#include "EventHandler.h"
|
#include "EventHandler.h"
|
||||||
#include "GameConfig.h"
|
#include "GameConfig.h"
|
||||||
|
#include "PlayerCommandsAppliedEvent.h"
|
||||||
#include "RecipesConfig.h"
|
#include "RecipesConfig.h"
|
||||||
#include "SelectionChangedEvent.h"
|
#include "SelectionChangedEvent.h"
|
||||||
#include "ShipLayout.h"
|
#include "ShipLayout.h"
|
||||||
@@ -33,6 +34,7 @@ class QVBoxLayout;
|
|||||||
|
|
||||||
class SelectedBuildingPanel : public QWidget,
|
class SelectedBuildingPanel : public QWidget,
|
||||||
public CombinedEventHandler<TickAdvancedEvent,
|
public CombinedEventHandler<TickAdvancedEvent,
|
||||||
|
PlayerCommandsAppliedEvent,
|
||||||
EntitySelectedEvent,
|
EntitySelectedEvent,
|
||||||
SelectionChangedEvent,
|
SelectionChangedEvent,
|
||||||
DebugDrawToggledEvent>
|
DebugDrawToggledEvent>
|
||||||
@@ -46,6 +48,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
|
void handleEvent(std::shared_ptr<const TickAdvancedEvent> event) override;
|
||||||
|
void handleEvent(std::shared_ptr<const PlayerCommandsAppliedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const EntitySelectedEvent> event) override;
|
void handleEvent(std::shared_ptr<const EntitySelectedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
|
void handleEvent(std::shared_ptr<const SelectionChangedEvent> event) override;
|
||||||
void handleEvent(std::shared_ptr<const DebugDrawToggledEvent> event) override;
|
void handleEvent(std::shared_ptr<const DebugDrawToggledEvent> event) override;
|
||||||
@@ -57,6 +60,7 @@ private slots:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
void onSelectionChanged(const std::vector<BuildingId>& ids);
|
||||||
|
void refreshSelectionDisplay();
|
||||||
void rebuild();
|
void rebuild();
|
||||||
void hideAllWidgets();
|
void hideAllWidgets();
|
||||||
void clearContent();
|
void clearContent();
|
||||||
|
|||||||
Reference in New Issue
Block a user