internal.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. #pragma once
  2. #include <array>
  3. #include <bitset>
  4. #include <cstddef>
  5. #include <cstdint>
  6. #include <span>
  7. #include <vector>
  8. #include "../../../../core/filesystem/path.h"
  9. #include "../../../../middleware/content/packages/reader/reader.h"
  10. #include "../../../../middleware/content/packages/tables/definition_index_table.h"
  11. #include "../../../../middleware/content/packages/tables/items.h"
  12. #include "../../../../state/build_data/abilities/definition.h"
  13. #include "../../../../state/build_data/bounties/definition.h"
  14. #include "../../../../state/build_data/collectibles/collectible_catalog.h"
  15. #include "../../../../state/build_data/constants/definition.h"
  16. #include "../../../../state/build_data/inventory/buckets/definition.h"
  17. #include "../../../../state/build_data/items/catalysts/definition.h"
  18. #include "../../../../state/build_data/items/details/definition.h"
  19. #include "../../../../state/build_data/items/item_catalog.h"
  20. #include "../../../../state/build_data/material_requirements/material_requirement_catalog.h"
  21. #include "../../../../state/build_data/progressions/definition.h"
  22. #include "../../../../state/build_data/runtime.h"
  23. #include "../../../../state/build_data/season_pass/definition.h"
  24. #include "../../../../state/build_data/sobjects/sobject_catalog.h"
  25. #include "package_reward_build.h"
  26. namespace sunrise::client::content::items::packages {
  27. namespace reader = middleware::content::packages::reader;
  28. namespace tables = middleware::content::packages::tables;
  29. /** Equippable rows, their initial plugs, and authored override plugs. */
  30. inline constexpr std::size_t kDetailCapacity =
  31. state::build_data::items::details::kDefinitionCapacity;
  32. /** Native item indices selected for the deduplicated detail closure. */
  33. using DetailRequests = std::bitset<state::build_data::items::kDefinitionCapacity>;
  34. /** Authored definition hashes one pass looks for while walking the item index table. */
  35. struct AuthoredHashes {
  36. std::array<std::uint32_t, kDetailCapacity> values{};
  37. std::size_t count{};
  38. };
  39. /** Everything the detail pass needs to read one requested definition from the packages. */
  40. struct DetailSource {
  41. const reader::Source* source{};
  42. reader::Scratch* scratch{};
  43. /** Item index table blob owning the located array. */
  44. std::span<const std::byte> table{};
  45. tables::Array array{};
  46. std::vector<std::byte>* definition{};
  47. };
  48. /** The container name is not always unique, so every match is a candidate. */
  49. inline constexpr std::size_t kContainerCandidates = 16;
  50. /** A slot is a signed 16-bit value, so the widest addressable slot space is this. */
  51. inline constexpr std::size_t kSlotSpace = 32768;
  52. /** Value of an unmapped slot. Every bank domain uses 0xFFFF as its unavailable index. */
  53. inline constexpr std::uint16_t kUnmappedSlot = 0xFFFFU;
  54. static_assert(kUnmappedSlot == state::build_data::nodes::kUnavailableValueIndex);
  55. static_assert(kUnmappedSlot == state::build_data::records::kUnavailableValueIndex);
  56. static_assert(kUnmappedSlot == state::build_data::season_pass::kUnavailableFlagIndex);
  57. static_assert(kUnmappedSlot
  58. == state::build_data::items::catalysts::kUnavailableCompletionFlagIndex);
  59. /** Bank index per unlock slot, indexed by slot. The first mapping row of a slot wins. */
  60. using SlotMap = std::array<std::uint16_t, kSlotSpace>;
  61. /** Saved-bank indices resolved from the root's flag and value mapping tables. */
  62. struct SlotMaps {
  63. SlotMap accountFlag{};
  64. SlotMap profileFlag{};
  65. SlotMap characterFlag{};
  66. SlotMap accountValue{};
  67. SlotMap characterValue{};
  68. };
  69. /** Lock-owned storage kept off the caller stack, shared by every stage of the pass. */
  70. struct Storage {
  71. reader::Scratch scratch{};
  72. /** Read once per root. Every domain resolves its unlock slots through these. */
  73. SlotMaps slotMaps{};
  74. RewardBuild rewardBuild{};
  75. /** Node rows held until the value slot and owned records are resolved. */
  76. std::array<state::build_data::nodes::Definition, state::build_data::nodes::kDefinitionCapacity>
  77. nodeRows{};
  78. /** Record rows held until the completion flag mapping is resolved. */
  79. std::array<state::build_data::records::Definition,
  80. state::build_data::records::kDefinitionCapacity>
  81. recordRows{};
  82. /** Flat objective, interval and reward banks the record rows name by range. */
  83. std::array<state::build_data::records::Objective,
  84. state::build_data::records::kObjectiveCapacity>
  85. recordObjectives{};
  86. std::array<state::build_data::records::Interval, state::build_data::records::kIntervalCapacity>
  87. recordIntervals{};
  88. std::array<state::build_data::records::Reward, state::build_data::records::kRewardCapacity>
  89. recordRewards{};
  90. std::size_t nodeCount{};
  91. std::size_t recordCount{};
  92. std::size_t recordObjectiveCount{};
  93. std::size_t recordIntervalCount{};
  94. std::size_t recordRewardCount{};
  95. /** Objective and record display tables, held while the record pass joins them. */
  96. std::vector<std::byte> objectiveTable{};
  97. std::vector<std::byte> displayTable{};
  98. /** Progression, item index, per-item strings and unlock slot tables, held across one join. */
  99. std::vector<std::byte> progressionTable{};
  100. std::vector<std::byte> itemIndexTable{};
  101. std::vector<std::byte> itemStringsTable{};
  102. std::vector<std::byte> unlockSlotTable{};
  103. std::vector<std::byte> container{};
  104. std::vector<std::byte> child{};
  105. std::vector<std::byte> root{};
  106. std::vector<std::byte> definition{};
  107. std::vector<std::byte> questParentDefinition{};
  108. std::vector<std::byte> questValueMap{};
  109. /** Shared reusable/randomized plug-set table read from investment-root slot 51. */
  110. std::vector<std::byte> plugSetTable{};
  111. /** Dense item-indexed catalyst completion expressions for this package pass. */
  112. std::vector<state::build_data::items::catalysts::CompletionCondition>
  113. catalystCompletionConditions{};
  114. /** Dense socket-type-indexed acquired-state gates for this package pass. */
  115. std::vector<state::build_data::items::catalysts::AcquisitionGate> catalystAcquisitionGates{};
  116. /** Dense native objective completion values used by legacy catalyst progress items. */
  117. std::vector<std::int32_t> catalystObjectiveValues{};
  118. /** Compact 0..3 special plug-category code of every dense installed item row. */
  119. std::array<std::uint8_t, state::build_data::items::kDefinitionCapacity> specialPlugCategories{};
  120. /** Inventory routing rows held until the paired bucket-definition table is resolved. */
  121. std::array<state::build_data::inventory::buckets::Descriptor,
  122. state::build_data::inventory::buckets::kDescriptorCapacity>
  123. bucketRows{};
  124. std::size_t bucketCount{};
  125. std::array<std::int8_t, state::build_data::inventory::buckets::kDescriptorCapacity>
  126. equipmentSlotByBucket{};
  127. DetailRequests detailRequests{};
  128. std::array<std::uint16_t, kDetailCapacity> requestedDetailIndices{};
  129. std::vector<state::build_data::items::details::Definition> details{};
  130. std::vector<std::byte> abilityTable{};
  131. std::vector<std::byte> abilityPool{};
  132. std::array<state::build_data::abilities::Definition,
  133. state::build_data::abilities::kDefinitionCapacity>
  134. abilityRows{};
  135. std::array<state::build_data::socket_entry_buckets::Definition,
  136. state::build_data::socket_entry_buckets::kDefinitionCapacity>
  137. entryBucketRows{};
  138. std::array<state::build_data::progressions::Definition,
  139. state::build_data::progressions::kDefinitionCapacity>
  140. progressionRows{};
  141. std::array<state::build_data::progressions::Step,
  142. state::build_data::progressions::kStepCapacity>
  143. progressionSteps{};
  144. std::size_t progressionStepCount{};
  145. /** Season pass reward rows and the wrapper items they grant. */
  146. std::array<state::build_data::season_pass::Reward,
  147. state::build_data::season_pass::kRewardCapacity>
  148. seasonPassRewards{};
  149. std::size_t seasonPassRewardCount{};
  150. /** Repeatable bounty rows, keyed by the item-type pair their pool shares. */
  151. std::array<state::build_data::bounties::Definition,
  152. state::build_data::bounties::kDefinitionCapacity>
  153. bountyRows{};
  154. std::size_t bountyCount{};
  155. std::array<state::build_data::collectibles::Definition,
  156. state::build_data::collectibles::kDefinitionCapacity>
  157. collectibleRows{};
  158. std::array<state::build_data::material_requirements::Definition,
  159. state::build_data::material_requirements::kDefinitionCapacity>
  160. materialRequirementRows{};
  161. std::array<state::build_data::items::Definition, state::build_data::items::kDefinitionCapacity>
  162. rows{};
  163. /** Incident-target rows held until the sobject table is published. */
  164. std::array<state::build_data::sobjects::Definition,
  165. state::build_data::sobjects::kDefinitionCapacity>
  166. sobjectRows{};
  167. };
  168. /**
  169. * Collects the authored equipment and plug hashes every configured character names.
  170. * Hashes are sorted so the index-table walk can test each row by binary search instead of
  171. * rescanning the whole authored set per row.
  172. * @param output Receives the sorted unique authored hashes.
  173. * @return True when the account is good and every hash fits.
  174. */
  175. [[nodiscard]] bool collect_authored_hashes(AuthoredHashes& output) noexcept;
  176. /** @param hashes Sorted authored hashes. @param hash Row hash. @return True when authored. */
  177. [[nodiscard]] bool authored(const AuthoredHashes& hashes, std::uint32_t hash) noexcept;
  178. /**
  179. * @param row Installed item row.
  180. * @return True when its bucket maps to an equipment slot
  181. * supported by the generated loadout.
  182. */
  183. [[nodiscard]] bool equippable(const tables::items::Row& row) noexcept;
  184. /** Publishes parsed inventory buckets after applying the extracted item-slot relation. */
  185. [[nodiscard]] bool publish_buckets(Storage& storage) noexcept;
  186. /** @return True when the catalyst catalog is published or cannot exist on this executable. */
  187. [[nodiscard]] bool exotic_catalysts_settled() noexcept;
  188. /** Adds one native definition index to the deduplicated request set. */
  189. void request(std::uint16_t definitionIndex, DetailRequests& requested) noexcept;
  190. /**
  191. * Adds every socket lane's initial plug to the requested set.
  192. * A lane using native defaults falls back to this plug, so its detail must exist.
  193. * @param row Item row already read from its definition blob.
  194. * @param itemDefinitionCount Installed item-table bound.
  195. * @param requested Requested-set storage.
  196. */
  197. void append_initial_plugs(const tables::items::Row& row,
  198. std::uint64_t itemDefinitionCount,
  199. DetailRequests& requested) noexcept;
  200. /**
  201. * Materializes requested native indices in ascending order.
  202. * @param requested Deduplicated native-index set.
  203. * @param output Fixed detail-index storage.
  204. * @param count Receives the number of selected rows, or zero when output is too small.
  205. * @return True when every selected row fits.
  206. */
  207. [[nodiscard]] bool materialize_requests(const DetailRequests& requested,
  208. std::span<std::uint16_t> output,
  209. std::size_t& count) noexcept;
  210. /**
  211. * Reads one requested definition and turns it into its cached detail form.
  212. * @param source Located item index table and package reader state.
  213. * @param definitionIndex Native item index.
  214. * @param detail Receives the cached detail.
  215. * @param item Receives the raw definition row the detail was built from.
  216. * @return True when the row is found and its definition blob reads.
  217. */
  218. [[nodiscard]] bool build_detail(const DetailSource& source,
  219. std::uint16_t definitionIndex,
  220. state::build_data::items::details::Definition& detail,
  221. tables::items::Row& item) noexcept;
  222. /**
  223. * Reads the stat rows the installed investment constants blob names.
  224. * @param source Package source.
  225. * @param scratch Reader scratch.
  226. * @param root Investment root bytes.
  227. * @param blob Scratch storage for the constants blob.
  228. * @param output Receives the extracted stat rows.
  229. * @return True when the blob reads and carries every named row.
  230. */
  231. [[nodiscard]] bool
  232. read_investment_constants(const reader::Source& source,
  233. reader::Scratch& scratch,
  234. std::span<const std::byte> root,
  235. std::vector<std::byte>& blob,
  236. state::build_data::constants::InvestmentConstants& output) noexcept;
  237. /**
  238. * Builds the ability buckets one subclass publishes under one ability selection.
  239. * @param source Package source.
  240. * @param scratch Reader scratch.
  241. * @param listDefinition Socket-entry-list definition bytes of the subclass.
  242. * @param blob Scratch storage reused for every pool blob.
  243. * @param selection The character's 5 selected socket entries.
  244. * @param output Receives the 12 buckets and the overflow bank.
  245. * @return True when every selected entry reaches a bucket of its own.
  246. */
  247. [[nodiscard]] bool build_ability_buckets(const reader::Source& source,
  248. reader::Scratch& scratch,
  249. std::span<const std::byte> listDefinition,
  250. std::vector<std::byte>& blob,
  251. const state::build_data::abilities::Selection& selection,
  252. state::build_data::abilities::Definition& output) noexcept;
  253. /**
  254. * Builds one ability bucket row per distinct subclass and ability selection in use.
  255. * Two characters on the same subclass with the same ability selection publish identical
  256. * buckets, so the row is keyed by both and built once.
  257. * @param source Package source.
  258. * @param scratch Reader scratch.
  259. * @param root Investment root bytes.
  260. * @param table Scratch storage for the socket entry list table.
  261. * @param definition Scratch storage for one socket entry list definition.
  262. * @param blob Scratch storage reused for every pool blob.
  263. * @param output Row storage.
  264. * @param count Receives the number of rows built.
  265. * @return True when the table reads; a subclass that fails is skipped, not fatal.
  266. */
  267. [[nodiscard]] bool build_character_abilities(
  268. const reader::Source& source,
  269. reader::Scratch& scratch,
  270. std::span<const std::byte> root,
  271. std::vector<std::byte>& table,
  272. std::vector<std::byte>& definition,
  273. std::vector<std::byte>& blob,
  274. std::span<state::build_data::abilities::Definition> output,
  275. std::size_t& count,
  276. std::span<state::build_data::socket_entry_buckets::Definition> entryBucketOutput,
  277. std::size_t& entryBucketCount) noexcept;
  278. /**
  279. * Resolves which of the 12 semantic ability buckets every entry in one socket-entry list reaches.
  280. * @param source Package source.
  281. * @param scratch Reader scratch.
  282. * @param listDefinition One socket-entry list's definition bytes.
  283. * @param blob Scratch storage reused for every pool blob.
  284. * @param output Receives one resolved bucket per entry, or the no-destination sentinel.
  285. * @return True when the list's entries read.
  286. */
  287. [[nodiscard]] bool resolve_entry_buckets(
  288. const reader::Source& source,
  289. reader::Scratch& scratch,
  290. std::span<const std::byte> listDefinition,
  291. std::vector<std::byte>& blob,
  292. std::array<std::uint8_t, state::build_data::socket_entry_lists::kEntryCapacity>&
  293. output) noexcept;
  294. /**
  295. * Reads one root's two unlock mapping tables into the pass slot maps.
  296. * @param source Package source.
  297. * @param storage Pass storage receiving the four maps.
  298. * @param root Investment root bytes.
  299. * @return True when both account maps read. A character map may stay unmapped.
  300. */
  301. [[nodiscard]] bool read_unlock_slot_maps(const reader::Source& source,
  302. Storage& storage,
  303. std::span<const std::byte> root) noexcept;
  304. /** @param map Slot map. @param slot Raw unlock slot. @return Bank index, or the unmapped one. */
  305. [[nodiscard]] std::uint16_t bank_index(const SlotMap& map, std::int32_t slot) noexcept;
  306. /**
  307. * Reads nodes and resolves their value slots, owned records and lore parent bars.
  308. * The record rows must already be built: a node's lore-book flag and parent bar come from them.
  309. * @param source Package source.
  310. * @param storage Pass storage holding the record rows and the objective bank.
  311. * @param root Investment root bytes.
  312. * @return True when the node table read and produced at least one row.
  313. */
  314. [[nodiscard]] bool build_nodes(const reader::Source& source,
  315. Storage& storage,
  316. std::span<const std::byte> root) noexcept;
  317. /**
  318. * Reads records and resolves their flags, objectives, intervals and rewards.
  319. * @param source Package source.
  320. * @param storage Pass storage receiving the record rows and all three flat banks.
  321. * @param root Investment root bytes.
  322. * @return True when the record table read and produced at least one row.
  323. */
  324. [[nodiscard]] bool build_records(const reader::Source& source,
  325. Storage& storage,
  326. std::span<const std::byte> root) noexcept;
  327. /**
  328. * Reads progression definitions, their rank steps, and their replicated-object slots.
  329. * @param source Package source.
  330. * @param scratch Reader scratch.
  331. * @param root Investment root bytes.
  332. * @param blob Scratch storage for the progression table.
  333. * @param output Definition storage.
  334. * @param count Receives the definitions read.
  335. * @param steps Flat step bank storage the definitions name by range.
  336. * @param stepCount Receives the steps read.
  337. * @return True when the table read and produced at least one row.
  338. */
  339. [[nodiscard]] bool build_progressions(const reader::Source& source,
  340. reader::Scratch& scratch,
  341. std::span<const std::byte> root,
  342. std::vector<std::byte>& blob,
  343. std::span<state::build_data::progressions::Definition> output,
  344. std::size_t& count,
  345. std::span<state::build_data::progressions::Step> steps,
  346. std::size_t& stepCount) noexcept;
  347. /** Reads the season pass reward list and the wrapper items it grants. */
  348. [[nodiscard]] bool build_season_pass(const reader::Source& source,
  349. Storage& storage,
  350. std::span<const std::byte> root) noexcept;
  351. /** Reads the item-type of every repeatable bounty, which is what groups a vendor pool. */
  352. [[nodiscard]] bool
  353. build_bounties(const reader::Source& source, Storage& storage, std::size_t itemCount) noexcept;
  354. /**
  355. * Copies the block key material this pass borrows.
  356. * @param keys Receives the primary, alternate and nonce material.
  357. * @return True when the installed key table and the bootstrap token are both there.
  358. */
  359. [[nodiscard]] bool collect_keys(reader::BlockKeys& keys) noexcept;
  360. /**
  361. * Collects every catalogue tag carrying the container name.
  362. * @param candidates Receives the candidate tags.
  363. * @param count Receives the number of candidates.
  364. * @return True when the catalogue names at least one.
  365. */
  366. [[nodiscard]] bool
  367. investment_globals_tags(std::array<std::uint32_t, kContainerCandidates>& candidates,
  368. std::size_t& count) noexcept;
  369. /** @param directory Receives the installed packages directory. @return True when it exists. */
  370. [[nodiscard]] bool package_directory(core::path::Buffer& directory) noexcept;
  371. /** @param slot Requested-set position. @param definitionIndex Native item index that failed. */
  372. void report_detail_failure(std::size_t slot, std::uint16_t definitionIndex) noexcept;
  373. /** @param count Ability bucket rows the pass built, one per subclass and ability selection. */
  374. void report_ability_count(std::size_t count) noexcept;
  375. /** Reports a bounded number of exact subclass/ability extraction failures per process. */
  376. void report_ability_failure(const char* stage,
  377. std::size_t character,
  378. std::size_t first,
  379. std::size_t second) noexcept;
  380. /** Reports requested, retained, and skipped detail closure rows. */
  381. void report_detail_count(std::size_t requested, std::size_t built) noexcept;
  382. /**
  383. * Reports the item index-table walk, including rows the pass could not read.
  384. * @param walked Table entries the pass visited.
  385. * @param rows Readable rows it retained.
  386. * @param skipped Entries omitted because their index row or definition was malformed.
  387. * @param truncated True when the walk stopped early because the row storage filled.
  388. */
  389. void report_row_count(std::size_t walked,
  390. std::size_t rows,
  391. std::size_t skipped,
  392. bool truncated) noexcept;
  393. /** Reports the exact socket-rule, deduplicated-pool, member, and skipped-lane counts. */
  394. void report_socket_plug_count(std::size_t rules,
  395. std::size_t pools,
  396. std::size_t members,
  397. std::size_t skipped) noexcept;
  398. /**
  399. * Reports released, placeholder, and unsupported catalyst catalog counts.
  400. * @param report Complete catalog report from the build pass.
  401. * @param built True when all released catalyst relations were safe.
  402. */
  403. void report_catalyst_catalog(const state::build_data::items::catalysts::Report& report,
  404. bool built) noexcept;
  405. /** Reports the validated installed bucket/equipment-slot coverage. */
  406. void report_bucket_equipment_mapping(std::size_t mappedSlots) noexcept;
  407. /** Reports the first rejected bucket-definition invariant in one process. */
  408. void report_bucket_equipment_failure(const char* stage,
  409. std::size_t first,
  410. std::size_t second) noexcept;
  411. /**
  412. * Reports the pass outcome once.
  413. * @param published Rows published, or zero on failure.
  414. * @param reason Stage the pass reached, named in the line.
  415. */
  416. void report(std::size_t published, const char* reason) noexcept;
  417. /**
  418. * Publishes the inventory bucket descriptors from the root's bucket table.
  419. * @param source Package source.
  420. * @param storage Pass storage.
  421. * @param root Investment root bytes.
  422. * @return True when the table reads and publishes.
  423. */
  424. [[nodiscard]] bool build_buckets(const reader::Source& source,
  425. Storage& storage,
  426. std::span<const std::byte> root) noexcept;
  427. /**
  428. * Publishes the socket entry list table from the root.
  429. * @param source Package source.
  430. * @param storage Pass storage.
  431. * @param root Investment root bytes.
  432. * @return True when the table reads and publishes.
  433. */
  434. [[nodiscard]] bool build_socket_entry_lists(const reader::Source& source,
  435. Storage& storage,
  436. std::span<const std::byte> root) noexcept;
  437. /** Reads and publishes the dense collectible-to-item mapping. */
  438. [[nodiscard]] bool build_collectibles(const reader::Source& source,
  439. Storage& storage,
  440. std::span<const std::byte> root,
  441. std::uint64_t itemDefinitionCount) noexcept;
  442. /**
  443. * Walks the located item index table, then publishes every domain that depends on it.
  444. * @param source Package source.
  445. * @param storage Pass storage holding the located table blob.
  446. * @param table Located item index array.
  447. * @param rowCount Receives the dense item rows published.
  448. * @param reason Receives the step name when a stage fails.
  449. * @return True when the dense table and every dependent domain publish.
  450. */
  451. [[nodiscard]] bool build_item_rows(const reader::Source& source,
  452. Storage& storage,
  453. const tables::Array& table,
  454. std::size_t& rowCount,
  455. const char*& reason) noexcept;
  456. /** Reads and publishes every native material-requirement set from investment-root slot 96. */
  457. [[nodiscard]] bool build_material_requirements(const reader::Source& source,
  458. Storage& storage,
  459. std::span<const std::byte> root,
  460. std::uint64_t itemDefinitionCount) noexcept;
  461. } // namespace sunrise::client::content::items::packages