squad_auth_body.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <optional>
  6. #include <span>
  7. namespace sunrise::middleware::bap::activity_message::squad_auth {
  8. /** ClientRef slot type for the activity-local squad sensor body. */
  9. inline constexpr std::uint8_t kSlotType = 1;
  10. /** Runtime schema handle for the slot-type-1 auth body. */
  11. inline constexpr std::uint32_t kSchema = 0x80807EC9;
  12. /**
  13. * The count lane is four bits wide, but the array it indexes holds eight elements.
  14. * The client walker does not clamp, so a count of 9 to 15 runs past the array.
  15. * The bound is the array, never the lane.
  16. */
  17. inline constexpr std::size_t kMinimumRequestedCountLength = 1;
  18. inline constexpr std::size_t kMaximumRequestedCountLength = 8;
  19. /** Fixed fields and presence bits outside the requested-count values. */
  20. inline constexpr std::size_t kBaseBitCount = 59;
  21. /** Each requested member count is one signed 32-bit field. */
  22. inline constexpr std::size_t kRequestedCountBitCount = 32;
  23. /** The name hash is always sent: an absent field reads as zero, which is a real name. */
  24. inline constexpr std::size_t kNameHashBitCount = 32;
  25. /**
  26. * Spawn references `.11` and `.12`, each one nested 0x80809C42 ClientRef after a presence bit.
  27. * The unset form keeps the package's authored rule; only `.12` may carry a set spawn rule.
  28. */
  29. inline constexpr std::size_t kSpawnReferenceBitCount = 55;
  30. inline constexpr std::size_t kSpawnReferenceCount = 2;
  31. /** Exact nested field-5 payload: lane selector plus four actor-definition profile values. */
  32. inline constexpr std::size_t kAuthoredProfileBitCount = 13;
  33. /** A present `.10` destination ClientRef and a present `.17` 31-bit request revision. */
  34. inline constexpr std::size_t kDestinationBitCount = 55 + 31;
  35. /** Exact meaningful bit count for one body. This is the only copy of the sum. */
  36. [[nodiscard]] constexpr std::size_t exact_body_bit_count(std::size_t counts,
  37. bool destination = false) noexcept {
  38. return kBaseBitCount + kAuthoredProfileBitCount + kSpawnReferenceBitCount * kSpawnReferenceCount
  39. + kRequestedCountBitCount * counts + kNameHashBitCount
  40. + (destination ? kDestinationBitCount : 0);
  41. }
  42. /** Buffer one squad body needs at the full requested-count length. */
  43. inline constexpr std::size_t kMaximumBitCount =
  44. exact_body_bit_count(kMaximumRequestedCountLength, true);
  45. inline constexpr std::size_t kMaximumByteCount = (kMaximumBitCount + 7) / 8;
  46. /** A retained body may carry the objective fields too, up to 1,313 bits. */
  47. inline constexpr std::size_t kMaximumRetainedBitCount = 1'313;
  48. inline constexpr std::size_t kMaximumRetainedByteCount = (kMaximumRetainedBitCount + 7U) / 8U;
  49. /** Spawn generation is an unsigned logical value stored in a 31-bit field. */
  50. inline constexpr std::uint32_t kMaximumGeneration = 0x7FFFFFFF;
  51. /** Mode 3 skips ordinary placement and keeps the requests for a passenger delivery. */
  52. enum class Mode : std::uint8_t {
  53. mode0 = 0,
  54. mode2 = 2,
  55. reserve = 3,
  56. };
  57. [[nodiscard]] constexpr bool valid_mode(Mode mode) noexcept {
  58. return mode == Mode::mode0 || mode == Mode::mode2 || mode == Mode::reserve;
  59. }
  60. /** Last accepted positive spawn generation for one ClientRef. */
  61. struct GenerationGuard final {
  62. std::uint32_t last{};
  63. bool hasLast{};
  64. };
  65. /** The type-1 squad that member actor-spawn actions fill; the client reads it from `.10`. */
  66. struct Destination final {
  67. std::uint32_t registryKey{};
  68. std::uint16_t slotIndex{};
  69. };
  70. /** A type-66 spawn rule of the same object; the client uses it instead of the package rule. */
  71. struct SpawnRule final {
  72. std::uint32_t registryKey{};
  73. std::uint16_t slotIndex{};
  74. };
  75. /** One canonical activity-local squad request. Zero counts select native actor destruction. */
  76. struct Preset final {
  77. std::span<const std::int32_t> requestedCounts{};
  78. std::uint32_t generation{};
  79. Mode mode{Mode::mode0};
  80. std::optional<std::uint32_t> nameHash{};
  81. /** Actor-definition bytes +56..+59; field 5.0 remains the exact candidate lane zero. */
  82. std::array<std::int8_t, 4> authoredProfile{};
  83. /** Sent as `.10` with `.17` equal to the generation; absent leaves both fields out. */
  84. std::optional<Destination> destination{};
  85. /** Sent as `.12`, the rule reference the point resolver reads at +0xA0; absent keeps the
  86. * package rule. */
  87. std::optional<SpawnRule> spawnRule{};
  88. };
  89. /** Finds the next positive 31-bit spawn generation without wrapping. */
  90. [[nodiscard]] bool next_generation(const GenerationGuard& guard, std::uint32_t& next) noexcept;
  91. /**
  92. * Encodes one canonical slot-type-1 body without changing a refused output buffer.
  93. * Counts must be nonnegative and the generation must be newer than the guard.
  94. */
  95. [[nodiscard]] bool encode(const Preset& preset,
  96. const GenerationGuard& guard,
  97. std::span<std::byte> output,
  98. std::size_t& writtenBytes,
  99. std::size_t& writtenBits) noexcept;
  100. } // namespace sunrise::middleware::bap::activity_message::squad_auth