package_collectible_build.cpp 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #include <cstring>
  2. #include <limits>
  3. #include "../../../../state/build_data/runtime.h"
  4. #include "internal.h"
  5. namespace sunrise::client::content::items::packages {
  6. /** Reads the fixed collectible table and publishes its native-index item links. */
  7. bool build_collectibles(const reader::Source& source,
  8. Storage& storage,
  9. std::span<const std::byte> root,
  10. std::uint64_t itemDefinitionCount) noexcept {
  11. namespace domain = state::build_data::collectibles;
  12. if (state::build_data::collectible_definitions_ready()) {
  13. return true;
  14. }
  15. if (itemDefinitionCount == 0
  16. || itemDefinitionCount > state::build_data::items::kDefinitionCapacity) {
  17. return false;
  18. }
  19. std::uint32_t requirementTableTag = 0;
  20. std::uint32_t requirementTableClass = 0;
  21. tables::Array requirementSets{};
  22. if (!tables::slot_tag(root, tables::kMaterialRequirementTableSlot, requirementTableTag)
  23. || requirementTableTag == 0
  24. || tables::package_of(requirementTableTag) == tables::kAbsentPackageId
  25. || !reader::read_tag(
  26. source, storage.scratch, requirementTableTag, storage.definition, requirementTableClass)
  27. || requirementTableClass != tables::kMaterialRequirementTableClass
  28. || !tables::find_array_at(std::span<const std::byte>{storage.definition},
  29. tables::kTableArrayDescriptor,
  30. requirementSets)
  31. || requirementSets.elementClass != tables::kMaterialRequirementSetRowClass
  32. || requirementSets.count == 0
  33. || requirementSets.count > (std::numeric_limits<std::uint16_t>::max)()) {
  34. return false;
  35. }
  36. const std::span<const std::byte> requirementTable{storage.definition};
  37. if (requirementSets.dataOffset > requirementTable.size()
  38. || requirementSets.count > (requirementTable.size() - requirementSets.dataOffset)
  39. / tables::kMaterialRequirementSetRowStride) {
  40. return false;
  41. }
  42. std::uint32_t tableTag = 0;
  43. std::uint32_t tableClass = 0;
  44. tables::Array rows{};
  45. if (!tables::slot_tag(root, tables::kCollectibleTableSlot, tableTag) || tableTag == 0
  46. || tables::package_of(tableTag) == tables::kAbsentPackageId
  47. || !reader::read_tag(source, storage.scratch, tableTag, storage.child, tableClass)
  48. || tableClass != tables::kCollectibleTableClass
  49. || !tables::find_array_at(
  50. std::span<const std::byte>{storage.child}, tables::kTableArrayDescriptor, rows)
  51. || rows.elementClass != tables::kCollectibleRowClass || rows.count == 0
  52. || rows.count > storage.collectibleRows.size()) {
  53. return false;
  54. }
  55. const std::span<const std::byte> table{storage.child};
  56. if (rows.dataOffset > table.size()
  57. || rows.count > (table.size() - rows.dataOffset) / tables::kCollectibleRowStride) {
  58. return false;
  59. }
  60. for (std::uint64_t row = 0; row < rows.count; ++row) {
  61. const std::size_t at =
  62. rows.dataOffset + static_cast<std::size_t>(row) * tables::kCollectibleRowStride;
  63. std::uint32_t collectibleHash = 0;
  64. std::uint16_t itemDefinitionIndex = domain::kUnavailableItemDefinitionIndex;
  65. std::uint16_t requirementSetIndex = domain::kUnavailableMaterialRequirementSetIndex;
  66. std::memcpy(&collectibleHash,
  67. table.data() + at + tables::kCollectibleHashOffset,
  68. sizeof collectibleHash);
  69. std::memcpy(&itemDefinitionIndex,
  70. table.data() + at + tables::kCollectibleItemIndexOffset,
  71. sizeof itemDefinitionIndex);
  72. std::memcpy(&requirementSetIndex,
  73. table.data() + at + tables::kCollectibleMaterialRequirementIndexOffset,
  74. sizeof requirementSetIndex);
  75. if (itemDefinitionIndex != domain::kUnavailableItemDefinitionIndex
  76. && itemDefinitionIndex >= itemDefinitionCount) {
  77. return false;
  78. }
  79. domain::Definition& output = storage.collectibleRows[static_cast<std::size_t>(row)];
  80. output = {};
  81. output.collectibleHash = collectibleHash;
  82. output.collectibleIndex = static_cast<std::uint16_t>(row);
  83. output.itemDefinitionIndex = itemDefinitionIndex;
  84. if (requirementSetIndex == domain::kUnavailableMaterialRequirementSetIndex) {
  85. continue;
  86. }
  87. if (requirementSetIndex >= requirementSets.count) {
  88. return false;
  89. }
  90. const std::size_t setAt = requirementSets.dataOffset
  91. + static_cast<std::size_t>(requirementSetIndex)
  92. * tables::kMaterialRequirementSetRowStride;
  93. std::uint32_t requirementSetHash = 0;
  94. std::int64_t descriptorRelative = 0;
  95. std::memcpy(&requirementSetHash,
  96. requirementTable.data() + setAt + tables::kMaterialRequirementSetHashOffset,
  97. sizeof requirementSetHash);
  98. std::memcpy(&descriptorRelative,
  99. requirementTable.data() + setAt
  100. + tables::kMaterialRequirementSetArrayPointerOffset,
  101. sizeof descriptorRelative);
  102. const std::size_t pointerAt = setAt + tables::kMaterialRequirementSetArrayPointerOffset;
  103. if (requirementSetHash == 0 || descriptorRelative < -static_cast<std::int64_t>(pointerAt)
  104. || descriptorRelative
  105. > static_cast<std::int64_t>(requirementTable.size() - pointerAt)) {
  106. return false;
  107. }
  108. const auto descriptorSigned = static_cast<std::int64_t>(pointerAt) + descriptorRelative;
  109. if (descriptorSigned < 0) {
  110. return false;
  111. }
  112. tables::Array requirements{};
  113. if (!tables::find_array_at(
  114. requirementTable, static_cast<std::size_t>(descriptorSigned), requirements)
  115. || requirements.elementClass != tables::kMaterialRequirementRowClass
  116. || requirements.count == 0 || requirements.count > output.materialRequirements.size()
  117. || requirements.dataOffset > requirementTable.size()
  118. || requirements.count > (requirementTable.size() - requirements.dataOffset)
  119. / tables::kMaterialRequirementRowStride) {
  120. return false;
  121. }
  122. output.materialRequirementSetHash = requirementSetHash;
  123. output.materialRequirementSetIndex = requirementSetIndex;
  124. output.materialRequirementCount = static_cast<std::uint8_t>(requirements.count);
  125. for (std::size_t requirement = 0; requirement < requirements.count; ++requirement) {
  126. const std::size_t requirementAt =
  127. requirements.dataOffset + requirement * tables::kMaterialRequirementRowStride;
  128. std::uint32_t nativeItemIndex = 0;
  129. std::uint32_t quantity = 0;
  130. std::uint8_t deleteOnAction = 0;
  131. std::uint8_t omitFromRequirements = 0;
  132. std::uint16_t sentinel = 0;
  133. std::memcpy(&nativeItemIndex,
  134. requirementTable.data() + requirementAt
  135. + tables::kMaterialRequirementItemIndexOffset,
  136. sizeof nativeItemIndex);
  137. std::memcpy(&quantity,
  138. requirementTable.data() + requirementAt
  139. + tables::kMaterialRequirementQuantityOffset,
  140. sizeof quantity);
  141. std::memcpy(&deleteOnAction,
  142. requirementTable.data() + requirementAt
  143. + tables::kMaterialRequirementDeleteOffset,
  144. sizeof deleteOnAction);
  145. std::memcpy(&omitFromRequirements,
  146. requirementTable.data() + requirementAt
  147. + tables::kMaterialRequirementOmitOffset,
  148. sizeof omitFromRequirements);
  149. std::memcpy(&sentinel,
  150. requirementTable.data() + requirementAt
  151. + tables::kMaterialRequirementSentinelOffset,
  152. sizeof sentinel);
  153. if (nativeItemIndex >= itemDefinitionCount
  154. || nativeItemIndex > (std::numeric_limits<std::uint16_t>::max)() || quantity == 0
  155. || deleteOnAction > 1 || omitFromRequirements > 1 || sentinel != 0xFFFFU) {
  156. return false;
  157. }
  158. output.materialRequirements[requirement] = {
  159. quantity,
  160. static_cast<std::uint16_t>(nativeItemIndex),
  161. deleteOnAction != 0,
  162. omitFromRequirements != 0,
  163. };
  164. }
  165. }
  166. return state::build_data::publish_collectible_definitions(
  167. std::span(storage.collectibleRows).first(static_cast<std::size_t>(rows.count)));
  168. }
  169. } // namespace sunrise::client::content::items::packages