Files
dota_factory/src/lib/eventsystem/event/CommandRequestedEvent.h
Malte Langkabel 82ca9080a5 replay: route player input through a command chokepoint (Phase 1)
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
2026-06-30 19:44:50 +02:00

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;
};