runtime.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <span>
  6. #include "state.h"
  7. namespace sunrise::state {
  8. /**
  9. * Assigns runtime SOIDs only to installed profile mod/shader rows which are socket action sources.
  10. * Currency, material, and consumable profile rows remain canonically non-instanced.
  11. */
  12. [[nodiscard]] bool ensure_profile_item_identities() noexcept;
  13. /**
  14. * Grants each character the other 2 subclasses of its equipped subclass's class, placing missing
  15. * ones into unequipped inventory with native socket defaults. Idempotent: one already equipped or
  16. * already in inventory is left alone.
  17. * @return True when every such character holds its whole class, or there was nothing to check.
  18. */
  19. [[nodiscard]] bool ensure_character_subclasses() noexcept;
  20. /** Prepared subclass socket-entry selection for the equipped selected-character subclass. */
  21. struct PendingSubclassSelection {
  22. /** Exact prepare-time character view used as the commit staleness guard. */
  23. CharacterState beforeCharacter{};
  24. /** Canonical after-image. Only one authored ability-entry field differs. */
  25. CharacterState afterCharacter{};
  26. std::uint64_t accountSoid{};
  27. std::uint64_t characterSoid{};
  28. std::uint64_t subclassInstanceSoid{};
  29. std::uint32_t subclassDefinitionHash{};
  30. std::size_t characterIndex{};
  31. std::uint16_t subclassDefinitionIndex{};
  32. std::uint16_t socketEntryListIndex{};
  33. /** Exact entry named by opcode 801. */
  34. std::uint8_t requestedEntry{};
  35. bool prepared{};
  36. };
  37. /**
  38. * Prepares one opcode-801 selection against the selected character's exact equipped subclass.
  39. * The installed socket-entry table maps the request to whichever of the character's 5 authored
  40. * picks competes in the same group; no class-specific node indices are authored in State.
  41. */
  42. [[nodiscard]] bool prepare_subclass_selection(std::uint64_t subclassInstanceSoid,
  43. std::uint8_t requestedEntry,
  44. PendingSubclassSelection& mutation) noexcept;
  45. /** Produces the complete uncommitted account after-image for a prepared subclass selection. */
  46. [[nodiscard]] bool preview_subclass_selection(const PendingSubclassSelection& mutation,
  47. AccountState& after) noexcept;
  48. /** Commits a prepared subclass selection behind the exact full-character staleness guard. */
  49. [[nodiscard]] bool commit_subclass_selection(PendingSubclassSelection& mutation) noexcept;
  50. /** Direction of one checked character equipment mutation. */
  51. enum class EquipmentMutationKind : std::uint8_t {
  52. none,
  53. equip,
  54. unequip,
  55. };
  56. /** Prepared character-inventory mutation kept private until its response and update both fit. */
  57. struct PendingEquipmentSwap {
  58. /** Exact prepare-time character view used as the commit staleness guard. */
  59. CharacterState beforeCharacter{};
  60. /** Canonical after-image, including every row-change mutation generation. */
  61. CharacterState afterCharacter{};
  62. std::uint64_t characterSoid{};
  63. std::uint64_t requestedInstanceSoid{};
  64. std::uint64_t previousInstanceSoid{};
  65. std::size_t characterIndex{};
  66. std::size_t equipmentSlotIndex{};
  67. std::size_t inventoryIndex{};
  68. std::size_t movedItemCount{};
  69. std::uint8_t nativeEquipmentSlot{};
  70. EquipmentMutationKind kind{};
  71. bool prepared{};
  72. };
  73. /** Prepared selected-character inventory insertion kept private until its reply and push fit. */
  74. struct PendingItemAcquisition {
  75. CharacterState beforeCharacter{};
  76. CharacterState afterCharacter{};
  77. /** Exact profile material view observed before and after charging the native requirement set.
  78. */
  79. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  80. beforeProfileItems{};
  81. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  82. afterProfileItems{};
  83. std::uint64_t accountSoid{};
  84. std::uint64_t characterSoid{};
  85. std::uint64_t acquiredInstanceSoid{};
  86. std::uint32_t acquiredDefinitionHash{};
  87. std::uint32_t materialRequirementSetHash{};
  88. std::uint32_t expectedNextInventorySerial{};
  89. std::size_t characterIndex{};
  90. std::size_t expectedInventoryCount{};
  91. std::size_t expectedProfileItemCount{};
  92. std::size_t afterProfileItemCount{};
  93. std::size_t inventoryIndex{};
  94. std::uint16_t collectibleIndex{};
  95. std::uint16_t inventoryRow{};
  96. std::uint8_t equipmentSlot{};
  97. std::uint8_t materialRequirementCount{};
  98. bool profileChanged{};
  99. bool prepared{};
  100. };
  101. /** Prepared account-profile stack insertion kept private until its reply and account upsert fit. */
  102. struct PendingProfileItemAcquisition {
  103. /** Exact profile inventory observed while preparing the mutation. */
  104. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  105. beforeItems{};
  106. /** Canonical profile inventory after incrementing or appending one stack. */
  107. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  108. afterItems{};
  109. std::uint64_t accountSoid{};
  110. /** Stable profile-row source identity, preserved for increments and allocated for appends. */
  111. std::uint64_t acquiredInstanceSoid{};
  112. std::uint32_t acquiredDefinitionHash{};
  113. std::uint32_t materialRequirementSetHash{};
  114. std::size_t expectedItemCount{};
  115. std::size_t afterItemCount{};
  116. std::size_t profileIndex{};
  117. std::int32_t previousQuantity{};
  118. std::int32_t acquiredQuantity{};
  119. std::int32_t previousMutationSerial{};
  120. std::int32_t acquiredMutationSerial{};
  121. std::uint16_t collectibleIndex{};
  122. std::uint8_t bucketId{};
  123. std::uint8_t materialRequirementCount{};
  124. /** True only for installed profile mod/shader rows materialized as Family-4 residents. */
  125. bool actionSource{};
  126. bool appended{};
  127. bool prepared{};
  128. };
  129. /** One profile material actually credited by a prepared dismantle. */
  130. struct DismantleReward {
  131. std::uint32_t definitionHash{};
  132. std::size_t profileIndex{};
  133. std::int32_t quantity{};
  134. std::int32_t afterQuantity{};
  135. std::int32_t mutationSerial{};
  136. };
  137. /** Dismantle feedback can publish every bounded server-authored policy row. */
  138. inline constexpr std::size_t kDismantleRewardCapacity = kDismantleRewardPolicyCapacity;
  139. /** Prepared selected-character inventory removal kept private until its reply and push fit. */
  140. struct PendingItemDismantle {
  141. /** Exact prepare-time character view used as the commit staleness guard. */
  142. CharacterState beforeCharacter{};
  143. /** Canonical dense inventory after-image, including row-change mutation generations. */
  144. CharacterState afterCharacter{};
  145. /** Exact profile material view observed before and after applying the dismantle payout. */
  146. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  147. beforeProfileItems{};
  148. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  149. afterProfileItems{};
  150. std::array<DismantleReward, kDismantleRewardCapacity> rewards{};
  151. account::inventory::Item dismantledItem{};
  152. std::uint64_t accountSoid{};
  153. std::uint64_t characterSoid{};
  154. std::uint64_t dismantledInstanceSoid{};
  155. std::size_t characterIndex{};
  156. std::size_t expectedInventoryCount{};
  157. std::size_t expectedProfileItemCount{};
  158. std::size_t afterProfileItemCount{};
  159. std::size_t inventoryIndex{};
  160. std::size_t movedInventoryItemCount{};
  161. std::size_t rewardCount{};
  162. std::uint16_t inventoryRow{};
  163. std::uint8_t equipmentSlot{};
  164. bool profileChanged{};
  165. bool prepared{};
  166. };
  167. /** Prepared ordinary-socket selection for one selected-character item instance. */
  168. struct PendingSocketPlug {
  169. /** Exact prepare-time character view used as the commit staleness guard. */
  170. CharacterState beforeCharacter{};
  171. /** Canonical after-image. Only the target item's authored socket block differs. */
  172. CharacterState afterCharacter{};
  173. /** Exact account-wide material balances observed before applying the installed cost set. */
  174. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  175. beforeProfileItems{};
  176. /** Canonical material balances after every consuming row in the installed cost set. */
  177. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  178. afterProfileItems{};
  179. std::uint64_t accountSoid{};
  180. std::uint64_t characterSoid{};
  181. std::uint64_t targetInstanceSoid{};
  182. std::uint32_t targetDefinitionHash{};
  183. std::uint32_t plugDefinitionHash{};
  184. std::uint32_t materialRequirementSetHash{};
  185. std::size_t characterIndex{};
  186. std::size_t expectedProfileItemCount{};
  187. std::size_t afterProfileItemCount{};
  188. /** Equipment semantic index or dense inventory index, selected by `targetEquipped`. */
  189. std::size_t itemIndex{};
  190. std::uint16_t targetDefinitionIndex{};
  191. /** Plug that lands in the lane. Differs from the request only for a rolled socket. */
  192. std::uint16_t plugDefinitionIndex{};
  193. /** Plug the Client asked for, which decides the pool check and the material charge. */
  194. std::uint16_t requestedPlugDefinitionIndex{};
  195. std::uint16_t materialRequirementSetIndex{0xFFFFU};
  196. std::uint8_t socketLane{};
  197. std::uint8_t targetBucketId{};
  198. std::uint8_t plugBucketId{};
  199. std::uint8_t materialRequirementCount{};
  200. bool profileChanged{};
  201. bool targetEquipped{};
  202. bool prepared{};
  203. };
  204. /** Prepared accumulated item-state change for one selected-character item instance. */
  205. struct PendingItemState {
  206. CharacterState beforeCharacter{};
  207. CharacterState afterCharacter{};
  208. std::uint64_t characterSoid{};
  209. std::uint64_t targetInstanceSoid{};
  210. std::size_t characterIndex{};
  211. /** Equipment semantic index or dense inventory index, selected by `targetEquipped`. */
  212. std::size_t itemIndex{};
  213. std::uint16_t targetDefinitionIndex{};
  214. std::uint32_t beforeFlags{};
  215. std::uint32_t afterFlags{};
  216. bool targetEquipped{};
  217. bool prepared{};
  218. };
  219. /**
  220. * Loads cached build data and generates secrets with Sunrise's authored activity defaults.
  221. * @param module Loaded Sunrise module, or null to disable disk persistence.
  222. * @param initialAccount Empty State, or a complete checked account from Core settings.
  223. * @return True when the cached data passes its checks and every secret is generated.
  224. */
  225. [[nodiscard]] bool initialize(void* module = nullptr,
  226. const AccountState& initialAccount = {}) noexcept;
  227. /**
  228. * Loads cached build data and publishes fixed activity defaults in one step.
  229. * @param module Loaded Sunrise module, or null to disable disk persistence.
  230. * @param initialAccount Empty State, or a complete checked account from Core settings.
  231. * @param activityDefaults Complete local fallback policy from immutable Core settings.
  232. * @return True when account, defaults, cached data, and generated secrets are valid.
  233. */
  234. [[nodiscard]] bool
  235. initialize(void* module,
  236. const AccountState& initialAccount,
  237. const activity::defaults::ActivityDefaults& activityDefaults) noexcept;
  238. /** Securely clears State, including activity destinations and matchmaking descriptors. */
  239. void shutdown() noexcept;
  240. /** @return Immutable generated SignOn session fields. */
  241. [[nodiscard]] const SignOnState& sign_on() noexcept;
  242. [[nodiscard]] bool publish_bootstrap_token(std::span<const std::byte> token) noexcept;
  243. /** @return Immutable generated BAP session fields. */
  244. [[nodiscard]] const BapState& bap() noexcept;
  245. /**
  246. * Stores the active nonzero account key when the account remains complete.
  247. * @param primarySoid Account key selected by the local Client.
  248. * @return False when the key or resulting account State is invalid.
  249. */
  250. [[nodiscard]] bool set_primary_soid(std::uint64_t primarySoid) noexcept;
  251. /**
  252. * Moves the selection to one authored character.
  253. * The Client names its pick only in the select-character request, so this is where a player's
  254. * choice enters State.
  255. * @param characterSoid Picked character key, which must name an authored character.
  256. * @param changed Receives whether the selection moved to a different character.
  257. * @return False when no authored character carries that key.
  258. */
  259. [[nodiscard]] bool set_selected_character(std::uint64_t characterSoid, bool& changed) noexcept;
  260. /**
  261. * Prepares an equip operation for one unequipped instance on the selected character.
  262. * An occupied slot is swapped; an empty semantic slot receives the requested item directly.
  263. * @param requestedInstanceSoid Unequipped item instance selected by the Client.
  264. * @param mutation Gets the checked after-image without changing account State.
  265. * @return True when the instance is owned, unequipped, and maps to one native equipment slot.
  266. */
  267. [[nodiscard]] bool prepare_equipment_swap(std::uint64_t requestedInstanceSoid,
  268. PendingEquipmentSwap& mutation) noexcept;
  269. /**
  270. * Prepares an unequip operation for one equipped selected-character instance.
  271. * The item is inserted before existing inventory items in its native bucket so their published
  272. * rows remain stable. Native slots without a proven semantic State mapping are rejected.
  273. *
  274. * @param requestedInstanceSoid Equipped item instance selected by the Client.
  275. * @param mutation Gets the checked after-image without changing account State.
  276. * @return True when the instance is equipped and the dense character inventory has room.
  277. */
  278. [[nodiscard]] bool prepare_equipment_unequip(std::uint64_t requestedInstanceSoid,
  279. PendingEquipmentSwap& mutation) noexcept;
  280. /**
  281. * Commits a prepared equipment mutation only while the full captured character still matches.
  282. *
  283. * @param mutation Prepared mutation, always cleared before this function returns.
  284. * @return True
  285. * when the equip or unequip commits atomically and leaves the whole account valid.
  286. */
  287. [[nodiscard]] bool commit_equipment_swap(PendingEquipmentSwap& mutation) noexcept;
  288. /**
  289. * Prepares one installed equippable definition as a new selected-character inventory instance.
  290. *
  291. * Native-default sockets, a unique runtime SOID, and the selected character's current item level
  292. * are used. Full loadout resolution is the authoritative bucket-capacity check.
  293. *
  294. * @param collectibleIndex Collections row the Client pulled from.
  295. * @param definitionHash Installed item definition requested by the Client.
  296. * @param mutation Gets a checked after-image without changing account State.
  297. * @return True when the item and every existing loadout row resolve with one free native row.
  298. */
  299. [[nodiscard]] bool prepare_item_acquisition(std::uint16_t collectibleIndex,
  300. std::uint32_t definitionHash,
  301. PendingItemAcquisition& mutation) noexcept;
  302. /** Builds the exact full-account after-image while a prepared item pull remains current. */
  303. [[nodiscard]] bool preview_item_acquisition(const PendingItemAcquisition& mutation,
  304. AccountState& after) noexcept;
  305. /**
  306. * Commits a prepared inventory insertion only while its selected character, existing loadout,
  307. * and next inventory serial still match the prepare-time view.
  308. *
  309. * @param mutation Prepared mutation, always cleared before this function returns.
  310. * @return True when the insertion commits atomically and leaves the whole account valid.
  311. */
  312. [[nodiscard]] bool commit_item_acquisition(PendingItemAcquisition& mutation) noexcept;
  313. /**
  314. * Prepares one installed profile-owned stackable definition for a Collections pull.
  315. *
  316. * An existing non-full stack is incremented. Otherwise a new dense State entry is appended only
  317. * when the installed profile bucket still owns a free native row.
  318. *
  319. * @param collectibleIndex Collections row the Client pulled from.
  320. * @param definitionHash Installed stackable definition requested by the Client.
  321. * @param mutation Gets the checked profile before/after images without changing account State.
  322. * @return True when the definition belongs to the main profile array and one unit fits.
  323. */
  324. [[nodiscard]] bool
  325. prepare_profile_item_acquisition(std::uint16_t collectibleIndex,
  326. std::uint32_t definitionHash,
  327. PendingProfileItemAcquisition& mutation) noexcept;
  328. /**
  329. * Materializes a prepared profile acquisition over the current account only while its complete
  330. * profile-inventory view is unchanged. This is the account object encoded before commit.
  331. *
  332. * @param mutation Prepared mutation that remains owned by the transaction.
  333. * @param after Gets the exact full-account after-image used by the Family-4 upsert.
  334. * @return True when the mutation is whole and its prepare-time profile remains current.
  335. */
  336. [[nodiscard]] bool preview_profile_item_acquisition(const PendingProfileItemAcquisition& mutation,
  337. AccountState& after) noexcept;
  338. /**
  339. * Commits a prepared profile stack insertion only while its prepare-time profile remains current.
  340. *
  341. * @param mutation Prepared mutation, always cleared before this function returns.
  342. * @return True when the stack update commits atomically and leaves the whole account valid.
  343. */
  344. [[nodiscard]] bool
  345. commit_profile_item_acquisition(PendingProfileItemAcquisition& mutation) noexcept;
  346. /**
  347. * Prepares removal of one unequipped instance from the selected character.
  348. * The authored inventory prefix is compacted. Any surviving item whose installed native row
  349. * changes receives a fresh mutation generation. Equipped items are never accepted.
  350. * @param instanceSoid Unequipped item-instance key selected by the Client.
  351. * @param mutation Gets checked before/after images without changing account State.
  352. * @return True when the selected character uniquely owns it and both loadouts resolve.
  353. */
  354. [[nodiscard]] bool prepare_item_dismantle(std::uint64_t instanceSoid,
  355. PendingItemDismantle& mutation) noexcept;
  356. /** Builds the exact account after-image while a prepared dismantle remains current. */
  357. [[nodiscard]] bool preview_item_dismantle(const PendingItemDismantle& mutation,
  358. AccountState& after) noexcept;
  359. /**
  360. * Commits a prepared inventory removal only while the complete prepare-time character view is
  361. * unchanged.
  362. *
  363. * @param mutation Prepared mutation, always cleared before this function returns.
  364. * @return True when the removal commits atomically and leaves the whole account valid.
  365. */
  366. [[nodiscard]] bool commit_item_dismantle(PendingItemDismantle& mutation) noexcept;
  367. /**
  368. * Prepares one exact opcode-903 ordinary-socket selection on a selected-character item.
  369. * The target may be equipped or unequipped. Native defaults are materialized into a complete
  370. * authored socket block, then only the requested lane changes; everything else stays byte-stable.
  371. * @param targetInstanceSoid Selected-character item-instance key named by the Client.
  372. * @param socketLane Zero-based ordinary socket lane.
  373. * @param plugDefinitionIndex Installed plug-definition row selected by the Client.
  374. * @param mutation Gets the checked before/after images without changing account State.
  375. * @return True when ownership, item detail, lane, plug compatibility, and both loadouts validate.
  376. */
  377. [[nodiscard]] bool prepare_socket_plug(std::uint64_t targetInstanceSoid,
  378. std::uint8_t socketLane,
  379. std::uint16_t plugDefinitionIndex,
  380. PendingSocketPlug& mutation) noexcept;
  381. /**
  382. * Prepares one ordinary-socket selection for an exact character-screen item selector.
  383. * The resolved instance runs through the same checked transition as an instance-addressed action,
  384. * so acquired and unequipped items do not depend on a coincidental menu-row ordinal.
  385. * @param instanceIdentityToken Item-instance identity decoded from the opcode-1901 selector.
  386. * @param requestedSocketLane Native socket action lane; compatibility resolves the physical lane.
  387. * @param plugDefinitionIndex Installed plug-definition row selected by the Client.
  388. * @param mutation Gets the checked before/after images without changing account State.
  389. * @return True when one item matches, the plug resolves to that lane, and the transition is valid.
  390. */
  391. [[nodiscard]] bool prepare_character_selector_socket_plug(std::uint64_t instanceIdentityToken,
  392. std::uint8_t requestedSocketLane,
  393. std::uint16_t plugDefinitionIndex,
  394. PendingSocketPlug& mutation) noexcept;
  395. /** Produces the complete uncommitted account after-image for a prepared socket transaction. */
  396. [[nodiscard]] bool preview_socket_plug(const PendingSocketPlug& mutation,
  397. AccountState& after) noexcept;
  398. /**
  399. * Commits a prepared socket selection only while the complete prepare-time character is unchanged.
  400. * @param mutation Prepared mutation, always cleared before this function returns.
  401. * @return True when the exact canonical transition commits atomically.
  402. */
  403. [[nodiscard]] bool commit_socket_plug(PendingSocketPlug& mutation) noexcept;
  404. /** Prepares one complete native item-state value for an owned selected-character instance. */
  405. [[nodiscard]] bool prepare_item_state(std::uint64_t targetInstanceSoid,
  406. std::uint16_t targetDefinitionIndex,
  407. std::uint32_t flags,
  408. PendingItemState& mutation) noexcept;
  409. /** Commits one prepared item-state change behind an exact full-character staleness guard. */
  410. [[nodiscard]] bool commit_item_state(PendingItemState& mutation) noexcept;
  411. /** @return A copy of the active account state, read under the lock. */
  412. [[nodiscard]] AccountState account_snapshot() noexcept;
  413. /** @return A copy of the evaluated content state, read under the lock. */
  414. [[nodiscard]] InvestmentState investment_snapshot() noexcept;
  415. } // namespace sunrise::state