package_bounty_build.cpp 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. #include <cstring>
  2. #include "internal.h"
  3. namespace sunrise::client::content::items::packages {
  4. namespace {
  5. namespace domain = state::build_data::bounties;
  6. /** @param blob Source bytes. @param offset Field offset. @param value Receives the field. */
  7. template <typename Value>
  8. [[nodiscard]] bool
  9. read(std::span<const std::byte> blob, std::size_t offset, Value& value) noexcept {
  10. if (offset > blob.size() || blob.size() - offset < sizeof value) {
  11. return false;
  12. }
  13. std::memcpy(&value, blob.data() + offset, sizeof value);
  14. return true;
  15. }
  16. } // namespace
  17. /**
  18. * Reads the item-type of every repeatable bounty, which is the key a vendor pool is grouped by.
  19. * No sale row and no vendor field names a pool, so the shared item-type pair is what joins one.
  20. * @param source Installed package source.
  21. * @param storage Pass storage holding the item rows and receiving the bounty rows.
  22. * @param itemCount Item rows this pass built.
  23. * @return True when the strings table read and produced at least one row.
  24. */
  25. bool build_bounties(const reader::Source& source,
  26. Storage& storage,
  27. std::size_t itemCount) noexcept {
  28. storage.bountyCount = 0;
  29. std::uint32_t tableClass = 0;
  30. tables::Array rows{};
  31. if (!reader::read_tag(source,
  32. storage.scratch,
  33. tables::kItemStringsIndexTag,
  34. storage.itemStringsTable,
  35. tableClass)
  36. || !tables::find_array_at(std::span<const std::byte>{storage.itemStringsTable},
  37. tables::kTableArrayDescriptor,
  38. rows)
  39. || rows.elementClass != tables::kItemStringsIndexRowClass || rows.count < itemCount) {
  40. return false;
  41. }
  42. const std::span<const std::byte> table{storage.itemStringsTable};
  43. for (std::size_t item = 0; item < itemCount; ++item) {
  44. const state::build_data::items::Definition& definition = storage.rows[item];
  45. if (definition.bucketId != domain::kBountyBucketId
  46. || definition.tier != domain::kBountyTier) {
  47. continue;
  48. }
  49. if (storage.bountyCount >= domain::kDefinitionCapacity) {
  50. storage.bountyCount = 0;
  51. return false;
  52. }
  53. tables::IndexRow entry{};
  54. domain::Definition& row = storage.bountyRows[storage.bountyCount];
  55. row = {};
  56. row.itemIndex = definition.definitionIndex;
  57. // A bounty whose strings blob will not read carries no pool key, so it is dropped rather
  58. // than published with a zero pair that would merge it into every other unnamed row.
  59. if (!tables::index_row(table, rows, definition.definitionIndex, entry)
  60. || !reader::read_tag(source, storage.scratch, entry.targetTag, storage.definition)
  61. || !read(std::span<const std::byte>{storage.definition},
  62. tables::kItemStringsTypePairOffset,
  63. row.itemType.bank)
  64. || !read(std::span<const std::byte>{storage.definition},
  65. tables::kItemStringsTypeHashOffset,
  66. row.itemType.hash)
  67. || row.itemType.hash == 0) {
  68. continue;
  69. }
  70. ++storage.bountyCount;
  71. }
  72. return storage.bountyCount != 0;
  73. }
  74. } // namespace sunrise::client::content::items::packages