载入中...
搜索中...
未找到
Presentation.cpp
浏览该文件的文档.
1
7
8#include "common/Diagnostic.h"
9
10#include <utility>
11
12namespace eve::tactics {
13namespace {
14
16UnitVisualState restingFor(const PresentationFrame& frame, SubjectRef subject) {
17 const auto found = frame.restingState.find(subject.format());
18 return found == frame.restingState.end() ? UnitVisualState::Idle : found->second;
19}
20
21PresentationCommand revertible(const BattleEvent& event, const PresentationFrame& frame, SubjectRef subject,
23 PresentationCommand command;
24 command.intent.sequence = event.sequence;
25 command.intent.subject = subject;
26 command.intent.state = state;
27 command.intent.revision = frame.revision;
28 command.intent.tick = event.tick;
29 command.revert.restingState = restingFor(frame, subject);
30 command.revert.trigger = trigger;
31 command.revert.sequence = event.sequence;
33 command.intent.expiresAtTick = SimulationTick(event.tick.value() + frame.transientTicks);
34 return command;
35}
36
37PresentationCommand durable(const BattleEvent& event, const PresentationFrame& frame, SubjectRef subject,
38 UnitVisualState state) {
39 PresentationCommand command = revertible(event, frame, subject, state, PresentationRevertTrigger::Never);
40 // A durable intent never expires, so it must not advertise a deadline.
41 command.intent.expiresAtTick = SimulationTick::zero();
42 return command;
43}
44
45} // namespace
46
47std::string_view unitVisualStateName(UnitVisualState state) noexcept {
48 switch (state) {
49 case UnitVisualState::Idle: return "idle";
50 case UnitVisualState::Friendly: return "friendly";
51 case UnitVisualState::Selected: return "selected";
52 case UnitVisualState::Finished: return "finished";
53 case UnitVisualState::Targetable: return "targetable";
54 case UnitVisualState::Attacking: return "attacking";
55 case UnitVisualState::Defending: return "defending";
56 case UnitVisualState::Moving: return "moving";
57 case UnitVisualState::Destroyed: return "destroyed";
58 }
59 return "idle";
60}
61
62std::string_view presentationRevertTriggerName(PresentationRevertTrigger trigger) noexcept {
63 switch (trigger) {
64 case PresentationRevertTrigger::Never: return "never";
65 case PresentationRevertTrigger::OnExpiry: return "on_expiry";
66 case PresentationRevertTrigger::OnNextTurn: return "on_next_turn";
67 case PresentationRevertTrigger::OnRoundStart: return "on_round_start";
68 }
69 return "never";
70}
71
73 const BattleCommand* command,
74 const PresentationFrame& frame) const {
75 (void)transientTicks_;
76 std::vector<PresentationCommand> commands;
77 // The event type is the stable protocol spelling owned by the simulation; matching on it
78 // keeps presentation a pure function of the event stream instead of a second opinion.
79 if (event.type == "turn.pending") {
80 commands.push_back(revertible(event, frame, event.subject, UnitVisualState::Selected,
82 } else if (event.type == "turn.completed") {
83 // Finishing an activation lasts until the round boundary, which is exactly the kind
84 // of lifetime a view-object API cannot state.
85 commands.push_back(revertible(event, frame, event.subject, UnitVisualState::Finished,
87 } else if (event.type == "round.pending") {
88 // The round boundary clears every per-round marker, so it emits no new intent; the
89 // consumer reverts everything this trigger names.
90 return Result<std::vector<PresentationCommand>>::success(std::move(commands));
91 } else if (event.type == "unit.moved") {
92 PresentationCommand moved = revertible(event, frame, event.subject, UnitVisualState::Moving,
94 if (command != nullptr && command->kind == BattleCommandKind::Move) {
95 moved.intent.from = command->cell;
96 moved.intent.to = command->cell;
97 moved.intent.path = {command->cell};
98 }
99 commands.push_back(std::move(moved));
100 } else if (event.type == "action.declared") {
101 PresentationCommand declared = revertible(event, frame, event.subject, UnitVisualState::Attacking,
103 if (command != nullptr && command->kind == BattleCommandKind::UseAbility) {
104 declared.intent.to = command->cell;
105 declared.intent.other = command->targetUnit;
106 }
107 commands.push_back(std::move(declared));
108 } else if (event.type == "unit.defeated") {
109 // Terminal: a destroyed unit is not coming back, so the revert is refused by contract.
110 commands.push_back(durable(event, frame, event.subject, UnitVisualState::Destroyed));
111 }
112 return Result<std::vector<PresentationCommand>>::success(std::move(commands));
113}
114
116 const PresentationRevert& spec) const {
117 if (!spec.isRevertable())
119 DiagnosticCode::Unsupported, "durable presentation intent cannot be reverted", "presentation.revert"));
120 PresentationIntent inverse;
121 inverse.sequence = spec.sequence;
122 inverse.subject = intent.subject;
123 inverse.other = intent.other;
124 inverse.state = spec.restingState;
125 inverse.from = intent.to;
126 inverse.to = intent.from;
127 inverse.revision = intent.revision;
128 inverse.tick = intent.expiresAtTick;
129 // The inverse is itself a transient instruction, so it must expire too; otherwise the
130 // "undo" would become the next stale state.
131 inverse.expiresAtTick = intent.expiresAtTick;
132 return Result<PresentationIntent>::success(std::move(inverse));
133}
134
135} // namespace eve::tactics
int subject
Definition AnimSmr.cpp:163
Stable, structured diagnostics shared by engine modules.
Presentation intents derived from the battle event stream, with an explicit undo.
bool found
std::vector< VegetationPresetCommand > commands
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
static constexpr StrongUint64 zero() noexcept
Returns the zero value for this strong type.
Result< PresentationIntent > revert(const PresentationIntent &intent, const PresentationRevert &spec) const
Build the inverse intent that undoes intent.
Result< std::vector< PresentationCommand > > project(const BattleEvent &event, const BattleCommand *command, const PresentationFrame &frame) const
Project one authoritative event into presentation commands.
PresentationRevertTrigger
What makes a presentation intent stop being true.
@ OnExpiry
Clear when expiresAtTick has passed.
@ Never
Durable state (defeat, end of round): never taken back.
@ OnNextTurn
Clear when any unit's next turn starts.
@ OnRoundStart
Clear at the next round boundary.
std::string_view presentationRevertTriggerName(PresentationRevertTrigger trigger) noexcept
Human-readable stable spelling of a revert trigger (protocol text).
std::string_view unitVisualStateName(UnitVisualState state) noexcept
Human-readable stable spelling of a visual state (protocol text).
@ UseAbility
Declare a unit ability activation against a target cell.
UnitVisualState
How a consumer should draw one unit.
@ Friendly
Controlled by the viewing session.
@ Targetable
A legal target for the armed ability.
@ Attacking
Currently declaring an ability.
@ Finished
Already finished this round.
@ Selected
Currently selected or acting.
@ Destroyed
Defeated; terminal.
@ Moving
In transit between cells.
@ Idle
Resting, nothing special.
@ Defending
Reacting to an incoming effect.
detail::StrongUint64< detail::SimulationTickTag > SimulationTick
Deterministic simulation time step; it is not wall-clock time.
Definition Time.h:31
One accepted replay command using only persistent identities and values.
SubjectRef targetUnit
The unit this command targeted, when the command targets one.
One deterministic battle lifecycle event owned by Battle.
One intent together with the way to take it back.
What the projector knows about the battle beyond the event itself.
One presentation instruction: what to show, where, and until when.
SimulationTick tick
Battle tick this intent was projected from.
SimulationTick expiresAtTick
Tick after which the intent is stale.
Cell from
Origin cell, when the intent has geometry.
Cell to
Destination or target cell, when the intent has geometry.
std::vector< Cell > path
Traversal the consumer may animate; empty when not applicable.
Revision revision
Battle revision this intent was projected from.
SubjectRef subject
The unit the intent is about.
SubjectRef other
The other unit involved (ability target, attacker), when there is one.
std::uint64_t sequence
Battle event sequence this intent was projected from.
The explicit undo contract for one intent.
std::uint64_t sequence
Event sequence the revert belongs to, for correlation.
UnitVisualState restingState
The state to restore when the trigger fires.
constexpr bool isRevertable() const noexcept
Whether a consumer may undo the intent at all.