mission_script_runtime_internal.h 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. #pragma once
  2. #include <algorithm>
  3. #include <array>
  4. #include <cstddef>
  5. #include <cstdint>
  6. #include <limits>
  7. #include <span>
  8. #include <string_view>
  9. #include <vector>
  10. #include "../../../core/logging/log.h"
  11. #include "../../../state/activity/mission/runtime.h"
  12. #include "../../../state/activity/runtime.h"
  13. #include "../../../state/activity_sdk/generated_world/runtime.h"
  14. #include "../../../state/activity_sdk/runtime.h"
  15. #include "../host_runtime.h"
  16. #include "mission_script_actor_path_sense.h"
  17. #include "mission_script_ghost_sense.h"
  18. #include "mission_script_object_sense.h"
  19. #include "mission_script_player_sense.h"
  20. #include "mission_script_runtime.h"
  21. #include "mission_script_squad_sense.h"
  22. #include "mission_script_vm.h"
  23. // What the seven mission-runtime translation units share: the instance table and service slice,
  24. // the attach pipeline, the two Host feeds and the VM callback, the panel rows, the delivery state
  25. // machine, the intent fan-out, and the Sense and host-state edges.
  26. namespace sunrise::server::activity::mission {
  27. namespace sdk = state::activity_sdk;
  28. namespace generated = state::activity_sdk::generated_world;
  29. namespace format = state::activity_sdk::format;
  30. namespace mission_state = state::activity::mission;
  31. enum class ProgramStatus : std::uint8_t {
  32. none,
  33. loaded,
  34. missing,
  35. fileError,
  36. sourceTooLarge,
  37. programError,
  38. };
  39. enum class DeliveryStage : std::uint8_t {
  40. idle,
  41. awaitingHostCommit,
  42. awaitingTransport,
  43. awaitingCancel,
  44. };
  45. /** Stable result classes bound repeated attach logs. */
  46. enum class AttachResult : std::uint8_t {
  47. none,
  48. catalogUnavailable,
  49. noActivityLink,
  50. sdkStatus,
  51. generatedWorldStatus,
  52. capacity,
  53. noScript,
  54. scriptFileError,
  55. sourceTooLarge,
  56. programError,
  57. ready,
  58. };
  59. /** Copies text into a fixed buffer, truncating it, and always leaves it terminated. */
  60. template <std::size_t Capacity>
  61. void copy_text(std::array<char, Capacity>& output, std::string_view value) noexcept {
  62. output = {};
  63. const std::size_t length = (std::min)(value.size(), output.size() - 1);
  64. std::copy_n(value.data(), length, output.data());
  65. }
  66. /** Watched trigger volumes retained per instance. */
  67. constexpr std::size_t kTriggerOccupancyCapacity = 32;
  68. /** Watched squads retained per instance. A social destination places well over a hundred. */
  69. constexpr std::size_t kSquadObservationCapacity = 160;
  70. /** Watched authored scenes retained per instance. */
  71. constexpr std::size_t kSceneObservationCapacity = 32;
  72. /** Watched objective sensors retained per instance. */
  73. constexpr std::size_t kObjectiveObservationCapacity = 32;
  74. static_assert(kSquadObjectiveGroupCount == host::kSquadObjectiveGroupCount);
  75. /** Watched Ghost links, damage monitors, interactable objects and named actors per instance. */
  76. constexpr std::size_t kGhostObservationCapacity = 8;
  77. constexpr std::size_t kDamageObservationCapacity = 8;
  78. constexpr std::size_t kObjectInteractionObservationCapacity = 64;
  79. constexpr std::size_t kActorPathObservationCapacity = 64;
  80. /** One objective sensor carries this many objective blocks. */
  81. constexpr std::size_t kObjectiveCapacity = 24;
  82. /** One objective block carries this many task counters. */
  83. constexpr std::size_t kObjectiveTaskCapacity = 24;
  84. /** How long a committed Host output may take to reach transport before the delivery faults. */
  85. constexpr std::uint64_t kTransportTimeoutMs = 15'000;
  86. /** How long an enqueued Host output may take to reach the reducer before the delivery retries. */
  87. constexpr std::uint64_t kHostCommitTimeoutMs = 2'000;
  88. /** Last occupancy seen for one watched volume, so only a change raises an event. */
  89. struct TriggerOccupancy final {
  90. std::uint32_t registryKey{};
  91. std::uint32_t objectTag{};
  92. std::uint16_t slotIndex{};
  93. bool occupied{};
  94. bool used{};
  95. };
  96. /** Last movement and delivery level seen for one named actor, so only a change raises an event. */
  97. struct ActorPathObservation final {
  98. ActorPathLevel level{};
  99. std::uint32_t registryKey{};
  100. std::uint32_t objectTag{};
  101. std::uint16_t slotIndex{};
  102. bool used{};
  103. };
  104. /** Last health, shield and revision seen for one damage monitor. */
  105. struct DamageObservation final {
  106. std::uint32_t registryKey{};
  107. std::uint32_t objectTag{};
  108. std::uint16_t slotIndex{};
  109. std::int32_t revision{};
  110. float health{-1.0F};
  111. float shield{-1.0F};
  112. bool used{};
  113. };
  114. /** Last object and interaction level seen for one interactable object. */
  115. struct ObjectInteractionObservation final {
  116. ObjectInteractionLevel level{};
  117. std::uint32_t registryKey{};
  118. std::uint32_t objectTag{};
  119. std::uint16_t slotIndex{};
  120. bool used{};
  121. };
  122. /** Last Ghost-link level seen for one sensor. */
  123. struct GhostObservation final {
  124. GhostLevel level{};
  125. std::uint32_t registryKey{};
  126. std::uint32_t objectTag{};
  127. std::uint16_t slotIndex{};
  128. bool used{};
  129. };
  130. /** Last squad counters seen for one watched object, so only a change raises an event. */
  131. struct SquadObservation final {
  132. SquadObjectiveCosts objectiveCosts{};
  133. std::array<std::int32_t, host::kSquadSlotCapacity> slotCounts{};
  134. std::uint32_t registryKey{};
  135. std::uint32_t objectTag{};
  136. std::int32_t aliveCount{};
  137. std::uint16_t slotIndex{};
  138. std::uint8_t slotCountLength{};
  139. bool removalFlag{};
  140. bool used{};
  141. };
  142. /** Last completion latch seen for one watched authored scene, so only the edge raises an event. */
  143. struct SceneObservation final {
  144. std::uint32_t registryKey{};
  145. std::uint32_t objectTag{};
  146. std::uint16_t slotIndex{};
  147. bool completed{};
  148. bool used{};
  149. };
  150. /** Last task counters seen for one watched objective sensor, so only a rise raises an event. */
  151. struct ObjectiveObservation final {
  152. std::array<std::array<std::uint8_t, kObjectiveTaskCapacity>, kObjectiveCapacity> counters{};
  153. std::uint32_t registryKey{};
  154. std::uint32_t objectTag{};
  155. std::uint16_t slotIndex{};
  156. bool used{};
  157. };
  158. /** Last peer session seen sharing this destination, so only a change raises an event. */
  159. struct SessionRosterWatch final {
  160. std::uint64_t sessionId{};
  161. std::uint64_t createdRevision{};
  162. std::uint64_t memberKey{};
  163. std::uint64_t joinIdentity{};
  164. bool used{};
  165. };
  166. /** Everything one bound mission program owns: its VM, views, delivery state and counters. */
  167. struct RuntimeInstance final {
  168. lua_vm::Vm vm{};
  169. sdk::BoundView view{};
  170. generated::GeneratedWorldView worldView{};
  171. lua_vm::ProgramIdentity identity{};
  172. mission_state::ProgramKey programKey{};
  173. std::array<char, 16> lastVmStage{};
  174. std::array<char, 32> lastVmStatus{};
  175. std::uint64_t eventsSeen{};
  176. std::uint64_t eventsCommitted{};
  177. std::uint64_t intentsTransportStaged{};
  178. std::uint64_t lastEventSequence{};
  179. std::uint64_t lastLoggedRevision{};
  180. std::uint64_t lastMissionSequence{};
  181. std::uint64_t missionStateRevision{};
  182. std::uint32_t missionPhase{};
  183. std::uint64_t activityStateRevision{};
  184. std::uint64_t durableIntentSequence{};
  185. std::uint64_t durableHostOutputRevision{};
  186. std::uint64_t expectedScriptableRevision{};
  187. std::uint64_t deliveryDeadline{};
  188. std::uint64_t firstIntentAttempt{};
  189. std::uint64_t nextIntentAttempt{};
  190. std::uint64_t firstStartAttempt{};
  191. std::uint64_t nextStartAttempt{};
  192. host::Event pendingTimerEvent{};
  193. std::uint64_t firstTimerAttempt{};
  194. std::uint64_t nextTimerAttempt{};
  195. std::array<TriggerOccupancy, kTriggerOccupancyCapacity> triggerOccupancy{};
  196. std::array<SquadObservation, kSquadObservationCapacity> squadObservations{};
  197. std::array<GhostObservation, kGhostObservationCapacity> ghostObservations{};
  198. std::array<DamageObservation, kDamageObservationCapacity> damageObservations{};
  199. std::array<ObjectInteractionObservation, kObjectInteractionObservationCapacity>
  200. objectInteractionObservations{};
  201. std::array<ActorPathObservation, kActorPathObservationCapacity> actorPathObservations{};
  202. std::array<SceneObservation, kSceneObservationCapacity> sceneObservations{};
  203. std::array<ObjectiveObservation, kObjectiveObservationCapacity> objectiveObservations{};
  204. // The table is exactly as large as the session table, so it can never overflow.
  205. std::array<SessionRosterWatch, state::activity::kSessionCapacity> sessionRoster{};
  206. /** Participation levels of the sixteen player slots, for the client generation below. */
  207. std::array<PlayerLifeObservation, kParticipationSlotCount> playerLife{};
  208. std::uint64_t playerLifeGeneration{};
  209. /** Last published party life counts. Published once, then only on a change. */
  210. FireteamLife lastFireteamLife{};
  211. bool fireteamLifePublished{};
  212. /** Dynamically sized host-state reports waiting for this script, in arrival order. */
  213. std::vector<host::Event> scriptEvents{};
  214. std::uint64_t firstScriptEventAttempt{};
  215. std::uint64_t nextScriptEventAttempt{};
  216. std::uint32_t intentAttempts{};
  217. std::uint32_t startAttempts{};
  218. std::uint32_t timerAttempts{};
  219. std::uint32_t scriptEventAttempts{};
  220. std::size_t durablePendingIntentCount{};
  221. std::size_t scriptEventRead{};
  222. std::uint16_t lastIntentStatus{(std::numeric_limits<std::uint16_t>::max)()};
  223. std::int32_t initialStateRegion{-1};
  224. /** Last client-reported activity region used to select state-local incoming references. */
  225. std::int32_t activeRegion{-1};
  226. ProgramStatus programStatus{ProgramStatus::none};
  227. DeliveryStage deliveryStage{DeliveryStage::idle};
  228. /** The player key the bound link's message 5 binds, read at attach. */
  229. std::uint64_t playerKey{};
  230. bool publicTarget{};
  231. bool missionStateBound{};
  232. bool missionStarted{};
  233. bool missionStateFaulted{};
  234. bool initialStateDeclared{};
  235. bool initialStateSelected{};
  236. bool startPending{};
  237. bool timerPending{};
  238. /** Set after the first roster read, so an attach never replays every existing peer. */
  239. bool sessionRosterObserved{};
  240. /** This VM reattached to its current session, so its entry is on_load, not on_start. */
  241. bool missionReattached{};
  242. bool occupied{};
  243. };
  244. /** Writes one bounded mission-script diagnostic line. Fields are key=value, error is free text. */
  245. void log_line(core::log::Level level,
  246. const RuntimeInstance* instance,
  247. std::string_view stage,
  248. std::string_view result,
  249. std::string_view fields = {},
  250. std::string_view error = {}) noexcept;
  251. /** Appends one host-state event for the script. */
  252. void push_script_event(RuntimeInstance& instance, const host::Event& event) noexcept;
  253. /** Raises a fireteam event on each private instance whose party life counts changed. */
  254. void publish_fireteam_life(std::uint64_t now) noexcept;
  255. /** Merges the type-13 participation records of one Sense snapshot into the instance. */
  256. void observe_player_life(RuntimeInstance& instance,
  257. const host::SenseObservationSnapshot& sense) noexcept;
  258. /** Raises one event per watched trigger volume whose occupancy changed. */
  259. void push_trigger_edges(RuntimeInstance& instance,
  260. const host::SenseObservationSnapshot& sense) noexcept;
  261. /** Raises one dedicated type-31 edge from a decoded schema-0x8080879F msg-19 payload. */
  262. void push_player_trigger(RuntimeInstance& instance, const host::Event& incident) noexcept;
  263. /** Raises one exact Type-6 start/finish edge from a decoded schema-0x808087BF msg-19 payload. */
  264. void push_cinematic(RuntimeInstance& instance, const host::Event& incident) noexcept;
  265. /** Raises one event per named actor whose movement or delivery level changed. */
  266. void push_actor_path_edges(RuntimeInstance& instance,
  267. const host::SenseObservationSnapshot& sense) noexcept;
  268. /** Raises one event per damage monitor whose health, shield or revision changed. */
  269. void push_damage_edges(RuntimeInstance& instance,
  270. const host::SenseObservationSnapshot& sense) noexcept;
  271. /** Raises object state and accepted interaction events per interactable object. */
  272. void push_object_interaction_edges(RuntimeInstance& instance,
  273. const host::SenseObservationSnapshot& sense) noexcept;
  274. /** Raises one event per Ghost link whose level changed. */
  275. void push_ghost_edges(RuntimeInstance& instance,
  276. const host::SenseObservationSnapshot& sense) noexcept;
  277. /** Raises the squad state, spawn and death events derived from one msg 6 body. */
  278. void push_squad_edges(RuntimeInstance& instance,
  279. const host::SenseObservationSnapshot& sense) noexcept;
  280. /** Raises one event per watched authored scene that latched complete. */
  281. void push_scene_edges(RuntimeInstance& instance,
  282. const host::SenseObservationSnapshot& sense) noexcept;
  283. /** Raises one event per watched objective task counter that rose. */
  284. void push_objective_edges(RuntimeInstance& instance,
  285. const host::SenseObservationSnapshot& sense) noexcept;
  286. /** Reports one committed phase change to the script. */
  287. void queue_phase_entered(RuntimeInstance& instance, std::uint32_t previousPhase) noexcept;
  288. /** @return The identity every host-state edge that is not a Sense edge carries. */
  289. [[nodiscard]] host::Event state_edge_event(const RuntimeInstance& instance) noexcept;
  290. /** Raises one event per peer session that appeared or left this instance's destination. */
  291. void push_session_roster_edges(RuntimeInstance& instance,
  292. std::span<const state::activity::SessionRosterRow> roster) noexcept;
  293. // The runtime unit owns these. The delivery state machine calls into them.
  294. /** Retires every queued mission event that belongs to one binding. */
  295. void clear_pending_events(const state::activity::SessionBinding& binding) noexcept;
  296. /** Copies one committed authoritative snapshot into the runtime's exact compare baseline. */
  297. void accept_mission_state(RuntimeInstance& instance,
  298. const mission_state::Snapshot& snapshot) noexcept;
  299. /** Marks the already-faulted VM in durable State when its exact compare still matches. */
  300. void persist_mission_fault(RuntimeInstance& instance) noexcept;
  301. /** Faults both the VM and the exact server-owned mission record. */
  302. void fault_instance(RuntimeInstance& instance, std::string_view reason) noexcept;
  303. // The delivery unit owns these. The runtime unit's service slice calls into them.
  304. /** @return now plus delay, saturated at the maximum instead of wrapping. */
  305. [[nodiscard]] std::uint64_t deadline_after(std::uint64_t now, std::uint64_t delay) noexcept;
  306. /** Retires the head event after its single delivery attempt. */
  307. void retire_script_event(RuntimeInstance& instance) noexcept;
  308. /** Advances the delivery stage from one Host delivery lifecycle event. */
  309. void observe_delivery_event(RuntimeInstance& instance,
  310. const host::Event& event,
  311. std::uint64_t now) noexcept;
  312. /** Reconciles an output assigned before a terminal program fault. */
  313. void reconcile_terminal_delivery(RuntimeInstance& instance) noexcept;
  314. // The delivery unit owns these too. The intent fan-out drives the state machine through them.
  315. /** Releases an exact unstaged Host revision while retaining the durable intent. */
  316. [[nodiscard]] bool release_delivery_state(RuntimeInstance& instance) noexcept;
  317. /** Returns the instance to the idle stage and clears delivery timing. */
  318. void clear_delivery(RuntimeInstance& instance) noexcept;
  319. /** Retires one successfully applied local effect without assigning a Host output revision. */
  320. [[nodiscard]] bool complete_local_effect(RuntimeInstance& instance,
  321. std::string_view result) noexcept;
  322. /** Faults the program and abandons the delivery. */
  323. void fault_delivery(RuntimeInstance& instance,
  324. std::string_view result,
  325. std::string_view reason) noexcept;
  326. /** Reports one refused request to the script and keeps the program running. */
  327. void refuse_delivery(RuntimeInstance& instance,
  328. std::string_view result,
  329. std::string_view reason,
  330. host::EffectOutcome outcome) noexcept;
  331. /** Dedup keys for report_intent_status. Each pending wait owns one value in its own range. */
  332. inline constexpr std::uint16_t kIntentStatusCancelPending = 0x2FF;
  333. inline constexpr std::uint16_t kIntentStatusSceneOutputBusy = 0x301;
  334. inline constexpr std::uint16_t kIntentStatusStateTransitionPending = 0x302;
  335. inline constexpr std::uint16_t kIntentStatusSceneLeasePending = 0x303;
  336. /** Logs one adapter status, and only when it differs from the last one logged. */
  337. void report_intent_status(RuntimeInstance& instance,
  338. std::uint16_t status,
  339. std::string_view name) noexcept;
  340. /** @return Whether the intent has been in delivery longer than its lifetime allows. */
  341. [[nodiscard]] bool intent_lifetime_expired(const RuntimeInstance& instance,
  342. std::uint64_t now) noexcept;
  343. /** @return Whether an exact transport stage was found, so the delivery completed here. */
  344. [[nodiscard]] bool reconcile_transport_stage(RuntimeInstance& instance) noexcept;
  345. /** @return Whether an expired delivery was completed or left owned, so the caller must stop. */
  346. [[nodiscard]] bool reconcile_expired_delivery(RuntimeInstance& instance) noexcept;
  347. /** @return Whether a stage deadline fired, so no further delivery work is owed this tick. */
  348. [[nodiscard]] bool service_delivery_timeout(RuntimeInstance& instance, std::uint64_t now) noexcept;
  349. // The dispatch unit owns this. The runtime unit's service slice calls it.
  350. /** Raises one queued intent, or advances the delivery already in flight. */
  351. void dispatch_intent(RuntimeInstance& instance, std::uint64_t now) noexcept;
  352. // The runtime unit owns the instance table too. Every other unit reaches it through these.
  353. extern std::array<RuntimeInstance, host::kInstanceCapacity> g_instances;
  354. /** @return The open slot for one exact binding, or null. */
  355. [[nodiscard]] RuntimeInstance*
  356. find_instance(const state::activity::SessionBinding& binding) noexcept;
  357. /** @return One unused slot, or null when every slot is open. */
  358. [[nodiscard]] RuntimeInstance* free_instance() noexcept;
  359. /** Frees one slot; its queued events are retired unless the caller keeps them for a reattach. */
  360. void clear_instance(RuntimeInstance& instance, bool clearPending = true) noexcept;
  361. /** Retains the last VM stage and status shown on the panel. */
  362. void note_vm_status(RuntimeInstance& instance,
  363. std::string_view stage,
  364. std::string_view status) noexcept;
  365. /** Commits the VM's phase/revision/start transaction into exact server-owned State. */
  366. [[nodiscard]] bool commit_mission_state(RuntimeInstance& instance,
  367. bool started,
  368. std::uint64_t nextInputSequence) noexcept;
  369. // The attach unit owns these. The service slice and the lifecycle entry points call into them.
  370. /** Resolves the script root and the SDK Lua search path. Logs its own refusal. */
  371. [[nodiscard]] bool resolve_script_paths() noexcept;
  372. /** Clears the script buffer, both paths and every reload authorization. */
  373. void clear_script_paths() noexcept;
  374. /** @return False when no authorization slot is free, so the reload cannot replace this program. */
  375. [[nodiscard]] bool authorize_reload(const RuntimeInstance& instance) noexcept;
  376. /** Drops slots that no longer match, publishes the roster, and attaches active host instances. */
  377. void synchronize_instances(std::uint64_t now) noexcept;
  378. /** Advances fresh programs only when their declared state roster has reached transport output. */
  379. void service_pending_starts(std::uint64_t now) noexcept;
  380. // The diagnostics unit owns these. The attach unit and the panel snapshot call into them.
  381. /** @return Stable panel-facing class for one retained attach result. */
  382. [[nodiscard]] const char* attach_result_name(AttachResult value) noexcept;
  383. /**
  384. * Reports an attach result when it changes for the binding.
  385. * @param name Stable result token written to the log.
  386. * @param activityRow Zero-based SDK row, or the absent sentinel before one resolves.
  387. */
  388. void report_attach_result(
  389. const state::activity::SessionBinding& binding,
  390. AttachResult result,
  391. std::string_view name,
  392. std::uint32_t activityRow = format::kAbsentIndex,
  393. sdk::Status sdkStatus = sdk::Status::notReady,
  394. generated::BindStatus generatedWorldStatus = generated::BindStatus::invalidBoundView) noexcept;
  395. /** @return True when the Host still reports this binding as active. */
  396. [[nodiscard]] bool is_active(const host::DiagnosticsSnapshot& diagnostics,
  397. const state::activity::SessionBinding& binding) noexcept;
  398. /** Drops results after their exact bindings leave the active Host set. */
  399. void retire_attach_diagnostics(const host::DiagnosticsSnapshot& diagnostics) noexcept;
  400. /** Clears every retained attach result. */
  401. void clear_attach_diagnostics() noexcept;
  402. /** Copies one instance and its VM counters into the panel-facing diagnostics row. */
  403. void copy_diagnostics(const RuntimeInstance& instance, InstanceDiagnostics& output) noexcept;
  404. /** Copies every retained attach result into the panel-facing snapshot. */
  405. void snapshot_attach_diagnostics(DiagnosticsSnapshot& output) noexcept;
  406. // The feed unit owns these. The service slice and the lifecycle entry points call into them.
  407. /** Retires every queued mission event that belongs to one binding. */
  408. void clear_all_pending_events() noexcept;
  409. /** Keeps accepted values but removes every VM- and ActivityClient-generation-local decision. */
  410. void reset_pending_events_for_reattach(const state::activity::SessionBinding& binding) noexcept;
  411. /** Retires rows as soon as authoritative State no longer owns their exact binding. */
  412. void retire_unbound_pending_events() noexcept;
  413. /** @return Queued rows still owed to one exact binding. */
  414. [[nodiscard]] std::size_t
  415. pending_event_count(const state::activity::SessionBinding& binding) noexcept;
  416. /** @return True when one queued accepted row is still owed to this instance. */
  417. [[nodiscard]] bool has_pending_host_input(const RuntimeInstance& instance) noexcept;
  418. /** Points both Host cursors at the current feed heads and replays retained accepted inputs. */
  419. void reset_feed_cursors() noexcept;
  420. /** Clears both Host cursors. */
  421. void clear_feed_cursors() noexcept;
  422. /** Reads new host events, advances delivery, and queues only the lifecycle rows for scripts. */
  423. void consume_delivery_events(std::uint64_t now) noexcept;
  424. /** Reads the ordered mission-input feed and drains the queue. */
  425. void consume_mission_inputs(std::uint64_t now) noexcept;
  426. /**
  427. * Runs one event through the VM, commits what it changed, and faults on a script failure.
  428. * @param sense Values owned by a Sense row, or null.
  429. * @param clientMessage Envelope snapshot owned by a client-message row, or null.
  430. * @param firstAttempt True on the first delivery attempt, which is the one that counts it.
  431. * @return The VM call status; `inactive` when no callback could take the event.
  432. */
  433. [[nodiscard]] lua_vm::CallStatus dispatch_event(RuntimeInstance& instance,
  434. const host::Event& event,
  435. const host::SenseObservationSnapshot* sense,
  436. const host::ClientMessageSnapshot* clientMessage,
  437. bool firstAttempt,
  438. std::uint64_t now) noexcept;
  439. } // namespace sunrise::server::activity::mission