state_account_transaction_helpers.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <memory>
  6. #include <string_view>
  7. #include <type_traits>
  8. #include "../../middleware/datagen/family4/loadout/loadout_resolver.h"
  9. #include "../build_data/runtime.h"
  10. #include "runtime.h"
  11. namespace sunrise::state::runtime::detail {
  12. /** Clears a consumed mutation on every commit exit without copying its full snapshot. */
  13. template <typename Pending> class PendingConsumption final {
  14. public:
  15. static_assert(std::is_nothrow_default_constructible_v<Pending>);
  16. static_assert(std::is_nothrow_destructible_v<Pending>);
  17. explicit PendingConsumption(Pending& pending) noexcept : pending_(pending) {}
  18. PendingConsumption(const PendingConsumption&) = delete;
  19. PendingConsumption(PendingConsumption&&) = delete;
  20. PendingConsumption& operator=(const PendingConsumption&) = delete;
  21. PendingConsumption& operator=(PendingConsumption&&) = delete;
  22. ~PendingConsumption() noexcept {
  23. std::destroy_at(std::addressof(pending_));
  24. std::construct_at(std::addressof(pending_));
  25. }
  26. private:
  27. Pending& pending_;
  28. };
  29. /** Where one resolved loadout places an instance, and the serial it published there. */
  30. struct ResolvedPosition {
  31. std::uint16_t inventoryRow{};
  32. std::uint8_t equipmentSlot{};
  33. bool equipped{};
  34. std::int32_t mutationSerial{};
  35. };
  36. /** Stable location of one character-owned item inside authored State. */
  37. struct CharacterItemLocation {
  38. std::size_t index{};
  39. bool equipped{};
  40. };
  41. void report_dismantle(std::string_view stage,
  42. std::string_view result,
  43. std::string_view reason,
  44. std::uint32_t definitionHash,
  45. std::uint64_t characterSoid,
  46. std::uint64_t instanceSoid,
  47. std::size_t inventoryIndex,
  48. std::uint16_t inventoryRow,
  49. std::uint8_t equipmentSlot,
  50. std::size_t movedItemCount,
  51. std::uint32_t nextInventorySerial) noexcept;
  52. void report_socket_plug(std::string_view stage,
  53. std::string_view result,
  54. std::string_view reason,
  55. std::uint64_t characterSoid,
  56. std::uint64_t targetInstanceSoid,
  57. std::uint16_t targetDefinitionIndex,
  58. std::uint8_t socketLane,
  59. std::uint16_t plugDefinitionIndex,
  60. std::uint8_t targetBucketId,
  61. std::uint8_t plugBucketId,
  62. bool targetEquipped,
  63. std::size_t itemIndex) noexcept;
  64. void report_item_state(std::string_view stage,
  65. std::string_view result,
  66. std::string_view reason,
  67. std::uint64_t characterSoid,
  68. std::uint64_t instanceSoid,
  69. std::uint16_t definitionIndex,
  70. std::uint32_t beforeFlags,
  71. std::uint32_t afterFlags,
  72. bool equipped,
  73. std::size_t itemIndex) noexcept;
  74. [[nodiscard]] bool
  75. same_profile_inventory(const AccountState& account,
  76. const std::array<account::inventory::ProfileItem,
  77. account::inventory::kProfileItemCapacity>& expected,
  78. std::size_t expectedCount) noexcept;
  79. [[nodiscard]] bool same_profile_views(
  80. const std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>&
  81. left,
  82. std::size_t leftCount,
  83. const std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>&
  84. right,
  85. std::size_t rightCount) noexcept;
  86. [[nodiscard]] bool valid_profile_inventory(const AccountState& account) noexcept;
  87. [[nodiscard]] bool
  88. apply_collection_materials(const AccountState& before,
  89. const build_data::collectibles::Definition& collectible,
  90. AccountState& after,
  91. bool& changed) noexcept;
  92. [[nodiscard]] bool
  93. valid_profile_mutation_shape(const PendingProfileItemAcquisition& mutation) noexcept;
  94. [[nodiscard]] bool materialize_profile_acquisition(const AccountState& current,
  95. const PendingProfileItemAcquisition& mutation,
  96. AccountState& after) noexcept;
  97. /** What paid for one grant: a Collections row with its material cost, or nothing. */
  98. struct GrantSource {
  99. std::uint32_t materialRequirementSetHash{};
  100. std::uint16_t collectibleIndex{};
  101. std::uint8_t materialRequirementCount{};
  102. bool direct{};
  103. };
  104. /** @return The selected character's index, or the character count when none is selected. */
  105. [[nodiscard]] std::size_t selected_character_index(const AccountState& account) noexcept;
  106. /**
  107. * Hold investment::store::g_mutex while capturing inventory and quest state together.
  108. * @param account State before any acquisition charge.
  109. * @param chargedAccount State after the prepared material charge.
  110. * @param definitionHash Item definition to grant.
  111. * @param profileChanged Whether the charge changed profile inventory.
  112. * @param source Grant identity and material requirements for commit checks.
  113. * @param mutation Receives a pending grant; use only on success.
  114. * @return False when the item, inventory, mapping, or saved quest state is invalid.
  115. */
  116. [[nodiscard]] bool finalize_item_acquisition(const AccountState& account,
  117. const AccountState& chargedAccount,
  118. std::uint32_t definitionHash,
  119. bool profileChanged,
  120. const GrantSource& source,
  121. PendingItemAcquisition& mutation) noexcept;
  122. /**
  123. * Stages the common profile-stack insertion path.
  124. * @param chargedAccount Account after any material cost, or account itself when nothing is charged.
  125. * @param actionSource True when the stack carries a resident instance soid.
  126. * @return False when the quantity does not fit the stack or the after-image is not canonical.
  127. */
  128. [[nodiscard]] bool
  129. finalize_profile_item_acquisition(const AccountState& account,
  130. const AccountState& chargedAccount,
  131. std::uint32_t definitionHash,
  132. const build_data::items::details::Definition& detail,
  133. bool actionSource,
  134. std::int32_t quantity,
  135. const GrantSource& source,
  136. PendingProfileItemAcquisition& mutation) noexcept;
  137. /**
  138. * Hold investment::store::g_mutex; the selected character and saved state must still match.
  139. * @param current Current account from the locked save view.
  140. * @param mutation Prepared inventory insertion and prior quest state.
  141. * @param after Receives the candidate account; use only on success.
  142. * @return False for stale state or an invalid resulting inventory.
  143. */
  144. [[nodiscard]] bool materialize_item_acquisition(const AccountState& current,
  145. const PendingItemAcquisition& mutation,
  146. AccountState& after) noexcept;
  147. /**
  148. * Rebuilds one package from installed policy and rejects any altered after-image.
  149. * @return False when the account moved or the rebuilt character differs from the mutation.
  150. */
  151. [[nodiscard]] bool materialize_direct_item_bundle(const AccountState& current,
  152. const PendingDirectItemBundle& mutation,
  153. AccountState& after) noexcept;
  154. [[nodiscard]] bool native_equipment_slot(const account::inventory::Item& item,
  155. std::uint8_t& slot) noexcept;
  156. [[nodiscard]] bool semantic_equipment_slot(std::uint8_t nativeSlot,
  157. std::size_t& semanticIndex) noexcept;
  158. [[nodiscard]] bool
  159. find_resolved_position(const middleware::datagen::family4::loadout::ResolvedLoadout& loadout,
  160. std::uint64_t instanceSoid,
  161. ResolvedPosition& position) noexcept;
  162. [[nodiscard]] bool finalize_equipment_transition(
  163. const AccountState& account,
  164. std::size_t characterIndex,
  165. std::uint64_t requestedInstanceSoid,
  166. EquipmentMutationKind kind,
  167. std::uint8_t expectedNativeSlot,
  168. const middleware::datagen::family4::loadout::ResolvedLoadout& beforeLoadout,
  169. CharacterState& after,
  170. std::size_t& movedItemCount) noexcept;
  171. [[nodiscard]] bool same_character(const CharacterState& left, const CharacterState& right) noexcept;
  172. /**
  173. * @param pinnedPlugHash For a rolled socket's apply or re-roll, the result plug an earlier
  174. * staging rolled, so a re-staging reproduces the same after-image; 0 rolls afresh.
  175. */
  176. [[nodiscard]] bool stage_socket_plug(const AccountState& snapshot,
  177. std::size_t characterIndex,
  178. std::uint64_t targetInstanceSoid,
  179. std::uint8_t socketLane,
  180. std::uint16_t plugDefinitionIndex,
  181. PendingSocketPlug& mutation,
  182. std::uint32_t pinnedPlugHash = 0) noexcept;
  183. [[nodiscard]] bool stage_item_state(const AccountState& snapshot,
  184. std::size_t characterIndex,
  185. std::uint64_t targetInstanceSoid,
  186. std::uint16_t targetDefinitionIndex,
  187. std::uint32_t flags,
  188. PendingItemState& mutation) noexcept;
  189. [[nodiscard]] bool stage_subclass_selection(const AccountState& snapshot,
  190. std::size_t characterIndex,
  191. std::uint64_t subclassInstanceSoid,
  192. std::uint8_t requestedEntry,
  193. PendingSubclassSelection& mutation) noexcept;
  194. [[nodiscard]] bool next_item_instance_soid(const AccountState& account,
  195. std::uint64_t& output) noexcept;
  196. [[nodiscard]] bool next_profile_item_instance_soid(const AccountState& account,
  197. std::uint64_t& output) noexcept;
  198. [[nodiscard]] bool account_owns_soid(const AccountState& account, std::uint64_t soid) noexcept;
  199. [[nodiscard]] std::int32_t acquisition_level(const CharacterState& character) noexcept;
  200. [[nodiscard]] bool stage_item_dismantle(const AccountState& account,
  201. std::size_t characterIndex,
  202. std::uint64_t instanceSoid,
  203. PendingItemDismantle& mutation) noexcept;
  204. [[nodiscard]] bool same_dismantle_transition(const PendingItemDismantle& left,
  205. const PendingItemDismantle& right) noexcept;
  206. [[nodiscard]] bool materialize_item_dismantle(const AccountState& current,
  207. const PendingItemDismantle& mutation,
  208. AccountState& after) noexcept;
  209. [[nodiscard]] bool identity_uses_soid(const AccountState& account, std::uint64_t soid) noexcept;
  210. [[nodiscard]] bool holds_plug_source(const AccountState& account,
  211. std::uint32_t definitionHash) noexcept;
  212. [[nodiscard]] bool spend_plug_source(AccountState& account, std::uint32_t definitionHash) noexcept;
  213. [[nodiscard]] bool
  214. apply_action_materials(const AccountState& before,
  215. const build_data::material_requirements::Definition& definition,
  216. AccountState& after,
  217. bool& changed) noexcept;
  218. [[nodiscard]] bool inventory_bucket_id(const account::inventory::Item& item,
  219. std::uint8_t& bucketId) noexcept;
  220. [[nodiscard]] bool same_position(const ResolvedPosition& left,
  221. const ResolvedPosition& right) noexcept;
  222. [[nodiscard]] bool same_stationary_item(const account::inventory::Item& left,
  223. const account::inventory::Item& right) noexcept;
  224. [[nodiscard]] bool find_character_item_location(const CharacterState& character,
  225. std::uint64_t instanceSoid,
  226. CharacterItemLocation& location) noexcept;
  227. [[nodiscard]] const account::inventory::Item*
  228. character_item_at(const CharacterState& character, const CharacterItemLocation& location) noexcept;
  229. [[nodiscard]] account::inventory::Item*
  230. character_item_at(CharacterState& character, const CharacterItemLocation& location) noexcept;
  231. [[nodiscard]] bool
  232. find_unequipped_row(const middleware::datagen::family4::loadout::ResolvedLoadout& loadout,
  233. std::uint64_t instanceSoid,
  234. std::uint16_t& inventoryRow,
  235. std::uint8_t& equipmentSlot) noexcept;
  236. [[nodiscard]] bool
  237. loadout_contains(const middleware::datagen::family4::loadout::ResolvedLoadout& loadout,
  238. std::uint64_t instanceSoid) noexcept;
  239. } // namespace sunrise::state::runtime::detail