runtime.h 28 KB

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