Reshapes every UI-driven sim mutation to flow through one path so it can be recorded and replayed later, with behaviour unchanged. - Command model (lib): Command base + derived types (PlaceBuilding, Demolish, RotateInPlace, SetRecipe, SetShipLayout, Set[Site]SplitterFilters, ClearBeltTiles, ApplySchematicChoice, Reset), each with a playerId for the future-multiplayer shape. PlaceBuilding is atomic (carries optional recipe/layout/filters) because deferred commands never return the new BuildingId to the caller. - CommandManager (lib): FIFO queue holding a Simulation&; enqueue + drain. - Simulation::apply(const Command&): the single chokepoint, dispatching by kind to the existing mutators. Mutators stay public (enforced by convention, not compile-time, so the test suite keeps driving the sim directly). - Timing: GameWorldView owns the CommandManager and drains it once per frame in onFrame, before the tick batch (runs at 0x too, so build-while-paused is preserved). A drained Reset triggers the view reset. - UI fan-in: GameWorldView enqueues its own input directly; MainWindow and SelectedBuildingPanel emit CommandRequestedEvent, which GameWorldView subscribes to and enqueues. No UI site mutates the sim directly anymore. - CommandTest: asserts apply(...) yields byte-identical state to the direct mutator path, and that CommandManager drains FIFO through apply. Full suite green (338 cases / 3353 assertions); determinism double-run still passes. Design doc updated with the atomic-PlaceBuilding and convention- enforcement decisions. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DUsFgd2Ga6pmLz8giS8WUn
24 lines
686 B
C++
24 lines
686 B
C++
#pragma once
|
|
|
|
#include <memory>
|
|
|
|
#include "Event.h"
|
|
|
|
struct Command;
|
|
|
|
// UI fan-in for the command path: widgets emit this with a built command, and a
|
|
// single subscriber (GameWorldView) enqueues it onto the CommandManager. This
|
|
// keeps widgets decoupled (consistent with the rest of the UI), while the
|
|
// sim-mutating command itself is routed through the dedicated CommandManager
|
|
// queue rather than the EventManager bus (see docs/replay_design.md).
|
|
class CommandRequestedEvent : public Event
|
|
{
|
|
public:
|
|
explicit CommandRequestedEvent(std::shared_ptr<const Command> command)
|
|
: command(std::move(command))
|
|
{
|
|
}
|
|
|
|
const std::shared_ptr<const Command> command;
|
|
};
|