package_season_pass_build.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. #include <algorithm>
  2. #include <limits>
  3. #include "../../../../middleware/content/packages/tables/internal.h"
  4. #include "../../../../state/build_data/season_pass/season_pass_catalog.h"
  5. #include "../../../../state/progression/season_pass_reward_catalog.h"
  6. #include "core/logging/log.h"
  7. #include "internal.h"
  8. #include "package_reward_build.h"
  9. namespace sunrise::client::content::items::packages {
  10. namespace {
  11. namespace domain = state::build_data::season_pass;
  12. bool read_season_reward(Storage& storage,
  13. std::span<const std::byte> progressionTable,
  14. const tables::Array& itemRows,
  15. std::size_t at,
  16. domain::Reward& reward) noexcept {
  17. std::uint32_t rank = 0;
  18. std::uint32_t itemIndex = 0;
  19. std::uint32_t claimSlot = 0;
  20. tables::IndexRow entry{};
  21. if (!tables::read(progressionTable, at + tables::kProgressionRewardRankOffset, rank)
  22. || !tables::read(
  23. progressionTable, at + tables::kProgressionRewardItemIndexOffset, itemIndex)
  24. || !tables::read(
  25. progressionTable, at + tables::kProgressionRewardQuantityOffset, reward.quantity)
  26. || !tables::read(
  27. progressionTable, at + tables::kProgressionRewardClaimSlotOffset, claimSlot)
  28. || reward.quantity == 0
  29. || reward.quantity > static_cast<std::uint32_t>((std::numeric_limits<std::int32_t>::max)())
  30. || rank > (std::numeric_limits<std::uint8_t>::max)()
  31. || itemIndex > (std::numeric_limits<std::uint16_t>::max)()
  32. || claimSlot > (std::numeric_limits<std::uint16_t>::max)()
  33. || !tables::index_row(storage.itemIndexTable, itemRows, itemIndex, entry)) {
  34. return false;
  35. }
  36. reward.itemHash = entry.definitionHash;
  37. reward.itemIndex = static_cast<std::uint16_t>(itemIndex);
  38. reward.requiredRank = static_cast<std::uint8_t>(rank);
  39. std::size_t socketCount = 0;
  40. if (!read_reward_sockets(progressionTable,
  41. at + tables::kProgressionRewardSocketsOffset,
  42. reward.sockets,
  43. socketCount)) {
  44. return false;
  45. }
  46. reward.socketCount = static_cast<std::uint8_t>(socketCount);
  47. std::size_t conditionCount = 0;
  48. if (!storage.rewardBuild.conditions.read_list(progressionTable,
  49. at + tables::kProgressionRewardConditionsOffset,
  50. reward.condition,
  51. conditionCount)) {
  52. return false;
  53. }
  54. reward.conditionCount = static_cast<std::uint8_t>(conditionCount);
  55. // A reward with no claim flag carries slot 0.
  56. if (claimSlot != 0) {
  57. reward.claimFlagIndex =
  58. bank_index(storage.slotMaps.accountFlag, static_cast<std::int32_t>(claimSlot));
  59. }
  60. if (!domain::valid(std::span(&reward, 1))
  61. || (claimSlot != 0 && reward.claimFlagIndex == domain::kUnavailableFlagIndex)
  62. || !std::all_of(reward.sockets.begin(),
  63. reward.sockets.begin() + reward.socketCount,
  64. [&](const auto& socket) {
  65. return socket.socketType != state::build_data::rewards::kAbsent
  66. && (socket.plugItem == state::build_data::rewards::kAbsent
  67. || socket.plugItem < itemRows.count);
  68. })) {
  69. return false;
  70. }
  71. return true;
  72. }
  73. } // namespace
  74. /** Preserves native reward order for opcode-2400 claim indices. */
  75. bool build_season_pass(const reader::Source& source,
  76. Storage& storage,
  77. std::span<const std::byte> root) noexcept {
  78. storage.seasonPassRewardCount = 0;
  79. std::uint32_t itemTableTag = 0;
  80. tables::Array itemRows{};
  81. if (!tables::slot_tag(root, tables::kItemTableSlot, itemTableTag) || itemTableTag == 0
  82. || !reader::read_tag(source, storage.scratch, itemTableTag, storage.itemIndexTable)
  83. || !tables::find_array_at(std::span<const std::byte>{storage.itemIndexTable},
  84. tables::kTableArrayDescriptor,
  85. itemRows)
  86. || itemRows.elementClass != tables::kItemIndexTableClass) {
  87. return false;
  88. }
  89. std::uint32_t tableTag = 0;
  90. tables::Array progressions{};
  91. if (!tables::slot_tag(root, tables::kProgressionTableSlot, tableTag) || tableTag == 0
  92. || !reader::read_tag(source, storage.scratch, tableTag, storage.progressionTable)
  93. || !tables::find_array_at(std::span<const std::byte>{storage.progressionTable},
  94. tables::kTableArrayDescriptor,
  95. progressions)
  96. || progressions.elementClass != tables::kProgressionTableClass
  97. || progressions.count <= state::progression::season_pass::kProgressionDefinitionIndex) {
  98. return false;
  99. }
  100. const std::span<const std::byte> progressionTable{storage.progressionTable};
  101. const std::size_t passAt = progressions.dataOffset
  102. + state::progression::season_pass::kProgressionDefinitionIndex
  103. * tables::kProgressionRowStride;
  104. tables::Array rewards{};
  105. if (!tables::read_array(progressionTable,
  106. passAt + tables::kProgressionRewardField,
  107. tables::kProgressionRewardRowClass,
  108. tables::kProgressionRewardStride,
  109. rewards)
  110. || rewards.count == 0 || rewards.count > domain::kRewardCapacity) {
  111. return false;
  112. }
  113. std::size_t skipped = 0;
  114. for (std::uint64_t row = 0; row < rewards.count; ++row) {
  115. const std::size_t at =
  116. rewards.dataOffset + static_cast<std::size_t>(row) * tables::kProgressionRewardStride;
  117. auto& reward = storage.seasonPassRewards[row];
  118. reward = {};
  119. if (!read_season_reward(storage, progressionTable, itemRows, at, reward)) {
  120. reward = {};
  121. ++skipped;
  122. }
  123. }
  124. if (skipped != 0) {
  125. core::log::writef(core::log::Channel::client,
  126. core::log::Level::warn,
  127. "ev=pkg stage=season_pass skipped=%zu",
  128. skipped);
  129. }
  130. storage.seasonPassRewardCount = static_cast<std::size_t>(rewards.count);
  131. return storage.seasonPassRewardCount != 0;
  132. }
  133. } // namespace sunrise::client::content::items::packages