Monopoly — Portage moderne 0.1.0
Portage moderne C/C++23 du Monopoly de 1999
Loading...
Searching...
No Matches
SequenceCommands.cpp
Go to the documentation of this file.
2
3#include <limits>
4#include <type_traits>
5#include <utility>
6
7namespace monopoly::sequence
8{
10 std::uint16_t priority, SequenceTransform transform, bool wholeTree) noexcept
11 { return {dataId, priority, std::move(transform), wholeTree}; }
12
14 std::uint16_t priority, std::int32_t x, std::int32_t y) noexcept
15 { return makeMoveTheWorks(dataId, priority, moveXYTransform(x, y)); }
16
18 std::uint16_t priority, float yaw, float scale,
19 float x, float z) noexcept
20 {
21 return makeMoveTheWorks(dataId, priority,
23 }
24
26 : runtime_(runtime)
27 {
28 }
29
30 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueueValidated(
31 SequenceCommand command)
32 {
33 if (pending_.size() >= Capacity)
34 return std::unexpected(CommandQueueError::QueueFull);
35 pending_.push_back(std::move(command));
36 return {};
37 }
38
39 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
41 {
42 if (!command.program || command.program->descriptions().empty())
43 return std::unexpected(CommandQueueError::InvalidProgram);
44 return enqueueValidated(std::move(command));
45 }
46
47 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
48 StopSequenceCommand command)
49 {
50 return enqueueValidated(command);
51 }
52
53 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
54 MoveSequenceCommand command)
55 {
56 return enqueueValidated(std::move(command));
57 }
58
59 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
61 {
62 if (command.action == 0 || command.action > 3)
63 return std::unexpected(CommandQueueError::InvalidEndingAction);
64 return enqueueValidated(command);
65 }
66
67 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
69 {
70 return enqueueValidated(command);
71 }
72
73 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
75 {
76 return enqueueValidated(command);
77 }
78
79 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
81 {
82 return enqueueValidated(command);
83 }
84
85 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
87 {
88 return enqueueValidated(command);
89 }
90
91 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
92 SetViewportCommand command)
93 {
95 return std::unexpected(CommandQueueError::InvalidRenderSlot);
96 return enqueueValidated(command);
97 }
98
99 std::expected<void, CommandQueueError> SequenceCommandQueue::enqueue(
100 SetCameraCommand command)
101 {
102 // Monopoly's C_ArtLib.h sets CE_ARTLIB_RendMaxRenderSlots to five.
103 // Preserve raw camera values here; the historical queue did not
104 // validate vectors/FOV/planes before dispatching to the render slot.
105 if (command.renderSlot >= MonopolyRenderSlotCount)
106 return std::unexpected(CommandQueueError::InvalidRenderSlot);
107 return enqueueValidated(command);
108 }
109
111 std::uint8_t renderSlot) const noexcept
112 {
113 if (renderSlot >= viewportStates_.size() || !viewportStates_[renderSlot])
114 return nullptr;
115 return &*viewportStates_[renderSlot];
116 }
117
119 std::uint8_t renderSlot) const noexcept
120 {
121 if (renderSlot >= cameraStates_.size() || !cameraStates_[renderSlot]) return nullptr;
122 return &*cameraStates_[renderSlot];
123 }
124
125 std::expected<int, CommandQueueError> SequenceCommandQueue::collect()
126 {
127 if (nestingLevel_ == std::numeric_limits<int>::max())
128 return std::unexpected(CommandQueueError::NestingOverflow);
129 return ++nestingLevel_;
130 }
131
132 std::expected<int, CommandQueueError> SequenceCommandQueue::execute()
133 {
134 cycleEvents_.clear();
135 cycleError_.reset();
136 if (nestingLevel_ == std::numeric_limits<int>::min())
137 return std::unexpected(CommandQueueError::NestingOverflow);
138 --nestingLevel_;
139 if (nestingLevel_ == 0 && !pending_.empty())
140 {
141 // LE_SEQNCR_ProcessUserCommands maps to DoUpdateCycle(0) in the
142 // single-tasking Monopoly build. Preserve the current parent time.
143 drain();
144 const auto updated = runtime_.update(parentClock_);
145 const auto events = runtime_.events();
146 cycleEvents_.assign(events.begin(), events.end());
147 cycleError_ = updated ? std::nullopt : std::optional<RuntimeError>(updated.error());
148 }
149 return nestingLevel_;
150 }
151
152 std::expected<void, RuntimeError>
154 {
155 // Monopoly is built with CE_ARTLIB_EnableMultitasking == 0, where
156 // LE_SEQNCR_ProcessUserCommands() is LE_SEQNCR_DoUpdateCycle(0).
157 // Preserve the modern absolute parent clock while forcing the queued
158 // command cycle immediately.
159 return updateCycle(parentClock_);
160 }
161
162 void SequenceCommandQueue::drain()
163 {
164 outcomes_.clear();
165 while (nestingLevel_ <= 0 && !pending_.empty())
166 {
167 auto command = std::move(pending_.front());
168 pending_.pop_front();
169 std::visit([this](auto&& value)
170 {
171 using Command = std::remove_cvref_t<decltype(value)>;
172 if constexpr (std::is_same_v<Command, StartSequenceCommand>)
173 {
174 const auto result = runtime_.start(
175 std::move(value.program), value.priority, value.options,
176 std::move(value.initialTransform), value.labelOverride);
178 result ? std::optional<SequenceNodeId>(*result) : std::nullopt,
179 result ? 1U : 0U, result ? std::nullopt : std::optional<RuntimeError>(result.error())});
180 }
181 else if constexpr (std::is_same_v<Command, StopSequenceCommand>)
182 {
183 const auto count = runtime_.stopMatching(
184 value.dataId, value.priority, value.wholeTree);
185 outcomes_.push_back(SequenceCommandOutcome{
187 }
188 else if constexpr (std::is_same_v<Command, MoveSequenceCommand>)
189 {
190 const auto count = runtime_.moveMatching(
191 value.dataId, value.priority, value.transform, value.wholeTree);
192 outcomes_.push_back(SequenceCommandOutcome{
194 }
195 else if constexpr (std::is_same_v<Command, SetSequenceEndingActionCommand>)
196 {
197 const auto result = runtime_.setEndingActionMatching(
198 value.dataId, value.priority, value.action, value.wholeTree);
199 outcomes_.push_back(SequenceCommandOutcome{SequenceCommandKind::SetEndingAction,
200 {}, result ? *result : 0U,
201 result ? std::nullopt : std::optional<RuntimeError>(result.error())});
202 }
203 else if constexpr (std::is_same_v<Command, SetSequenceVolumeCommand>)
204 {
205 const auto count = runtime_.setVolumeMatching(
206 value.dataId, value.priority, value.volume, value.wholeTree);
207 outcomes_.push_back(SequenceCommandOutcome{
209 }
210 else if constexpr (std::is_same_v<Command, SetSequencePitchCommand>)
211 {
212 const auto count = runtime_.setPitchMatching(
213 value.dataId, value.priority, value.pitch, value.wholeTree);
214 outcomes_.push_back(SequenceCommandOutcome{
216 }
217 else if constexpr (std::is_same_v<Command, SetSequencePanningCommand>)
218 {
219 const auto count = runtime_.setPanningMatching(
220 value.dataId, value.priority, value.panning, value.wholeTree);
221 outcomes_.push_back(SequenceCommandOutcome{
223 }
224 else if constexpr (std::is_same_v<Command, ForceRedrawSequenceCommand>)
225 {
226 const auto count = runtime_.forceRedrawMatching(
227 value.dataId, value.priority, value.wholeTree);
228 outcomes_.push_back(SequenceCommandOutcome{
230 }
231 else if constexpr (std::is_same_v<Command, SetViewportCommand>)
232 {
233 viewportStates_[value.renderSlot] = value;
234 outcomes_.push_back(SequenceCommandOutcome{
236 }
237 else
238 {
239 cameraStates_[value.renderSlot] = value;
240 outcomes_.push_back(SequenceCommandOutcome{
241 SequenceCommandKind::SetCamera, {}, 1U, {}});
242 }
243 }, std::move(command));
244
245 if (!outcomes_.empty() &&
246 outcomes_.back().kind != SequenceCommandKind::SetViewport &&
247 outcomes_.back().kind != SequenceCommandKind::SetCamera &&
248 !outcomes_.back().error)
249 {
250 const auto events = runtime_.events();
251 outcomes_.back().events.assign(events.begin(), events.end());
252 }
253 }
254 }
255
256 std::expected<void, RuntimeError> SequenceCommandQueue::updateCycle(std::int32_t parentClock)
257 {
258 outcomes_.clear();
259 cycleEvents_.clear();
260 cycleError_.reset();
261 parentClock_ = parentClock;
262 if (nestingLevel_ <= 0) drain();
263 auto updated = runtime_.update(parentClock);
264 const auto events = runtime_.events();
265 cycleEvents_.assign(events.begin(), events.end());
266 if (!updated) cycleError_ = updated.error();
267 return updated;
268 }
269
271 {
272 return static_cast<int>((100U * pending_.size()) / Capacity);
273 }
274}
std::size_t count
std::uint16_t priority
unsigned index
float yaw
int z
std::string error
std::uint16_t value
Definition Timers.cpp:16
SequenceCommandQueue(SequenceRuntime &runtime) noexcept
const SetCameraCommand * cameraState(std::uint8_t renderSlot) const noexcept
std::expected< int, CommandQueueError > execute()
std::expected< void, RuntimeError > updateCycle(std::int32_t parentClock)
std::expected< void, RuntimeError > processUserCommands()
const SetViewportCommand * viewportState(std::uint8_t renderSlot) const noexcept
std::expected< void, CommandQueueError > enqueue(StartSequenceCommand command)
std::expected< int, CommandQueueError > collect()
std::size_t setPitchMatching(data::DataId id, std::uint16_t priority, std::uint16_t pitch, bool wholeTree=false)
std::size_t forceRedrawMatching(data::DataId id, std::uint16_t priority, bool wholeTree=false)
std::expected< void, RuntimeError > update(std::int32_t parentClock)
std::size_t moveMatching(data::DataId id, std::uint16_t priority, const SequenceTransform &transform, bool wholeTree=false)
std::size_t setPanningMatching(data::DataId id, std::uint16_t priority, std::int8_t panning, bool wholeTree=false)
std::size_t stopMatching(data::DataId id, std::uint16_t priority, bool wholeTree=false)
std::expected< std::size_t, RuntimeError > setEndingActionMatching(data::DataId id, std::uint16_t priority, std::uint8_t action, bool wholeTree=false)
std::expected< SequenceNodeId, RuntimeError > start(std::shared_ptr< const SequenceProgram > program, std::uint16_t priority=0, ClockStartOptions options={}, std::optional< SequenceTransform > initialTransform=std::nullopt, std::uint8_t labelOverride=0)
std::size_t setVolumeMatching(data::DataId id, std::uint16_t priority, std::uint8_t volume, bool wholeTree=false)
std::span< const SequenceEvent > events() const noexcept
std::uint32_t DataId
Definition DataBanks.hpp:10
constexpr std::uint8_t MonopolyRenderSlotCount
MoveSequenceCommand makeMoveTheWorks(data::DataId dataId, std::uint16_t priority, SequenceTransform transform, bool wholeTree) noexcept
Matrix3D moveRySTxzTransform(float yaw, float scale, float x, float z) noexcept
std::variant< std::monostate, Matrix2D, Matrix3D > SequenceTransform
SequenceTransform moveXYTransform(std::int32_t x, std::int32_t y) noexcept
std::variant< StartSequenceCommand, StopSequenceCommand, MoveSequenceCommand, SetSequenceEndingActionCommand, SetSequenceVolumeCommand, SetSequencePitchCommand, SetSequencePanningCommand, ForceRedrawSequenceCommand, SetViewportCommand, SetCameraCommand > SequenceCommand
MoveSequenceCommand makeMoveXY(data::DataId dataId, std::uint16_t priority, std::int32_t x, std::int32_t y) noexcept
MoveSequenceCommand makeMoveRySTxz(data::DataId dataId, std::uint16_t priority, float yaw, float scale, float x, float z) noexcept
std::shared_ptr< const SequenceProgram > program