account_state.h 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include "inventory/inventory_state.h"
  6. #include "settings/settings_state.h"
  7. namespace sunrise::state {
  8. /** One account can own at most the 3 playable character slots. */
  9. inline constexpr std::size_t kCharacterCapacity = 3;
  10. /** A server-authored dismantle policy: a few rows per rarity and gear class. */
  11. inline constexpr std::size_t kDismantleRewardPolicyCapacity = 32;
  12. /** Maximum authored Triumph reward overrides. */
  13. inline constexpr std::size_t kRecordRewardPolicyCapacity = 256;
  14. /** Native sentinel used when a character has no title equipped. */
  15. inline constexpr std::uint16_t kUnequippedTitleRecordIndex = 0xFFFFU;
  16. /** Gear classes a dismantle payout row can be limited to. */
  17. enum class DismantleGearClass : std::uint8_t {
  18. weapon = 1U << 0U,
  19. armor = 1U << 1U,
  20. };
  21. /** Whether a payout row wants the dismantled item masterworked. */
  22. enum class DismantleMasterworkFilter : std::uint8_t {
  23. any = 0,
  24. masterworked = 1,
  25. notMasterworked = 2,
  26. };
  27. /**
  28. * One profile material credited when ordinary character gear is dismantled. Every filter left at
  29. * its "any" value matches every item; the payout is the sum of the matching rows.
  30. */
  31. struct DismantleRewardPolicy {
  32. std::uint32_t definitionHash{};
  33. std::int32_t quantity{};
  34. /** Bit (1 << tier) per native tier 1-5 the row pays for; 0 pays for every tier. */
  35. std::uint8_t tierMask{};
  36. /** DismantleGearClass bits the row pays for; 0 pays for both. */
  37. std::uint8_t classMask{};
  38. DismantleMasterworkFilter masterwork{DismantleMasterworkFilter::any};
  39. };
  40. /** @return True when both rows are the same row: same material under the same filters. */
  41. [[nodiscard]] constexpr bool
  42. same_dismantle_policy_key(const DismantleRewardPolicy& left,
  43. const DismantleRewardPolicy& right) noexcept {
  44. return left.definitionHash == right.definitionHash && left.tierMask == right.tierMask
  45. && left.classMask == right.classMask && left.masterwork == right.masterwork;
  46. }
  47. /** Settings override for one Triumph claim reward. */
  48. struct RecordRewardPolicy {
  49. std::uint16_t recordIndex{};
  50. std::uint16_t itemIndex{};
  51. std::int32_t quantity{};
  52. };
  53. [[nodiscard]] constexpr bool same_record_reward_key(const RecordRewardPolicy& left,
  54. const RecordRewardPolicy& right) noexcept {
  55. return left.recordIndex == right.recordIndex;
  56. }
  57. /** Stable character race values authored independently of package definition mappings. */
  58. enum class CharacterRace : std::uint8_t {
  59. /** Wire value 0 is a Human character. */
  60. human = 0,
  61. /** Wire value 1 is an Awoken character. */
  62. awoken = 1,
  63. /** Wire value 2 is an Exo character. */
  64. exo = 2,
  65. };
  66. /** Stable character gender values authored independently of package definition mappings. */
  67. enum class CharacterGender : std::uint8_t {
  68. /** Wire value 0 is a male character. */
  69. male = 0,
  70. /** Wire value 1 is a female character. */
  71. female = 1,
  72. };
  73. /** Stable character class values authored independently of package definition mappings. */
  74. enum class CharacterClass : std::uint8_t {
  75. /** Wire value 0 is a Titan character. */
  76. titan = 0,
  77. /** Wire value 1 is a Hunter character. */
  78. hunter = 1,
  79. /** Wire value 2 is a Warlock character. */
  80. warlock = 2,
  81. };
  82. /** Default movement entry. Each subclass offers 3, as entries 4, 5 and 6 of its group. */
  83. inline constexpr std::uint8_t kDefaultMovementAbilityEntry = 4;
  84. /**
  85. * Socket entries of the other abilities a subclass lets the player choose. Each names one entry
  86. * of that ability's group. The subclass offers several and the character picks one. These
  87. * defaults are the first option of each group, where every shipped subclass starts.
  88. */
  89. inline constexpr std::uint8_t kDefaultGrenadeAbilityEntry = 7;
  90. /** Default super entry. It is the lane that carries no plug source and kind 34. */
  91. inline constexpr std::uint8_t kDefaultSuperAbilityEntry = 10;
  92. /** Default melee entry. */
  93. inline constexpr std::uint8_t kDefaultMeleeAbilityEntry = 11;
  94. /** Default class-ability entry. Which bucket it publishes into follows the character class. */
  95. inline constexpr std::uint8_t kDefaultClassAbilityEntry = 2;
  96. /**
  97. * Semantic ability-bucket destinations shared by the wire encoder and the selection logic that
  98. * routes a clicked socket entry to a character field. A subclass entry's authored selector chain,
  99. * not its table position, decides which it reaches; a bundled pick can mix members across them.
  100. */
  101. inline constexpr std::uint8_t kGrenadeAbilityBucket = 0;
  102. inline constexpr std::uint8_t kSuperAbilityBucket = 1;
  103. inline constexpr std::uint8_t kMeleeAbilityBucket = 2;
  104. inline constexpr std::uint8_t kMovementAbilityBucket = 3;
  105. inline constexpr std::uint8_t kSprintAbilityBucket = 4;
  106. /**
  107. * Widest node bundle one summary pick can publish together.
  108. * Some groups (an Attunement pick, for example) hold several consecutive entries that all
  109. * activate, and contribute their hashes, as one unit rather than a single alternative per group.
  110. */
  111. inline constexpr std::size_t kMaxAttunementBundleSize = 4;
  112. /** @param characterClass Authored class. @return The bucket its class ability publishes into. */
  113. [[nodiscard]] inline constexpr std::uint8_t
  114. class_ability_bucket(CharacterClass characterClass) noexcept {
  115. switch (characterClass) {
  116. case CharacterClass::hunter:
  117. return 9;
  118. case CharacterClass::warlock:
  119. return 11;
  120. case CharacterClass::titan:
  121. default:
  122. return 6;
  123. }
  124. }
  125. /** Authored state for one playable character slot. */
  126. struct CharacterState {
  127. std::uint64_t soid{};
  128. /** Runtime selection, moved only by the character pick. No character is selected at boot. */
  129. bool selected{};
  130. CharacterRace race{CharacterRace::human};
  131. CharacterGender gender{CharacterGender::male};
  132. CharacterClass characterClass{CharacterClass::titan};
  133. std::uint8_t level{};
  134. bool accepted{};
  135. bool previewAvailable{};
  136. /** Authored scalar kept for the family-specific character presentation encoders. */
  137. float appearanceValue{};
  138. /** Compact default destination hash used until a later runtime selection replaces it. */
  139. std::uint32_t lastOrbitedDestination{};
  140. /** Server policy that arms content checks only with the matching family-5 flag. */
  141. bool contentBypass{};
  142. /** Native DestinyRecordDefinition row of the equipped earned title. */
  143. std::uint16_t equippedTitleRecordIndex{kUnequippedTitleRecordIndex};
  144. /**
  145. * Runtime-only socket entries the player has selected at least once. Selected entries still
  146. * publish active; this mask keeps a later inactive entry acquired instead of new. Unverified:
  147. * defaulted all-set, assuming the Client only allows clicking an already-acquired node.
  148. */
  149. std::uint64_t acquiredSubclassAbilityMask{~std::uint64_t{0}};
  150. /** Authored loadout keyed only by stable semantic equipment slots. */
  151. account::inventory::Equipment equipment;
  152. /** Unequipped items routed into their installed character-inventory bucket ranges. */
  153. account::inventory::CharacterItems inventory;
  154. /** Non-instanced character materials granted at runtime. */
  155. account::inventory::CharacterStacks stacks;
  156. /** Next row generation; equip transactions consume two values for the two moved items. */
  157. std::uint32_t nextInventorySerial{};
  158. };
  159. /** Account identity shared by backend object families. */
  160. struct AccountState {
  161. std::uint64_t primarySoid{};
  162. /** Economy policy comes from configuration, never from item-specific runtime constants. */
  163. std::array<DismantleRewardPolicy, kDismantleRewardPolicyCapacity> dismantleRewards{};
  164. std::size_t dismantleRewardCount{};
  165. std::array<RecordRewardPolicy, kRecordRewardPolicyCapacity> recordRewards{};
  166. std::size_t recordRewardCount{};
  167. /** Account-wide currencies and materials, placed by bucket rather than by authored slot. */
  168. std::array<account::inventory::ProfileItem, account::inventory::kProfileItemCapacity>
  169. profileItems{};
  170. std::size_t profileItemCount{};
  171. std::array<CharacterState, kCharacterCapacity> characters{};
  172. std::size_t characterCount{};
  173. account::settings::AccountSettings settings;
  174. };
  175. namespace account {
  176. [[nodiscard]] bool valid(const AccountState& state) noexcept;
  177. /** Checks settings-authored State before runtime-only profile stack SOIDs are assigned. */
  178. [[nodiscard]] bool valid_authored(const AccountState& state) noexcept;
  179. [[nodiscard]] std::uint64_t selected_character_soid(const AccountState& state) noexcept;
  180. /**
  181. * Reports the character the family-zero banner pair names.
  182. * The pair is published before any pick. A refusal spends the family's only acceptance window,
  183. * so it falls back to the first character.
  184. * @param state Account snapshot read under the lock.
  185. * @return The character's SOID, or zero when the account owns none.
  186. */
  187. [[nodiscard]] std::uint64_t banner_character_soid(const AccountState& state) noexcept;
  188. /** Finds the settings override for a record claim. */
  189. [[nodiscard]] bool find_record_reward(const AccountState& state,
  190. std::uint16_t recordIndex,
  191. RecordRewardPolicy& reward) noexcept;
  192. } // namespace account
  193. } // namespace sunrise::state