runtime.h 20 KB

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