squad_auth_body.h 4.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  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.
  27. * Both always carry the unset form, which is the sentinel that keeps the package's own
  28. * authored spawn rule. 32-bit key, 7-bit type, 16-bit index, after one presence bit.
  29. */
  30. inline constexpr std::size_t kSpawnReferenceBitCount = 55;
  31. inline constexpr std::size_t kSpawnReferenceCount = 2;
  32. /** Exact nested field-5 payload: lane selector plus four actor-definition profile values. */
  33. inline constexpr std::size_t kAuthoredProfileBitCount = 13;
  34. /**
  35. * Exact meaningful bit count for one body carrying this many requested counts.
  36. * It lives here so the sum has one home. A second copy in the roster encoder drifted from this
  37. * one and refused every squad body Sunrise sent; that copy is gone.
  38. */
  39. [[nodiscard]] constexpr std::size_t exact_body_bit_count(std::size_t counts) noexcept {
  40. return kBaseBitCount + kAuthoredProfileBitCount + kSpawnReferenceBitCount * kSpawnReferenceCount
  41. + kRequestedCountBitCount * counts + kNameHashBitCount;
  42. }
  43. /** Buffer one squad body needs at the full requested-count length. */
  44. inline constexpr std::size_t kMaximumBitCount = exact_body_bit_count(kMaximumRequestedCountLength);
  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. /** One canonical activity-local squad request. Zero counts select native actor destruction. */
  66. struct Preset final {
  67. std::span<const std::int32_t> requestedCounts{};
  68. std::uint32_t generation{};
  69. Mode mode{Mode::mode0};
  70. std::optional<std::uint32_t> nameHash{};
  71. /** Actor-definition bytes +56..+59; field 5.0 remains the exact candidate lane zero. */
  72. std::array<std::int8_t, 4> authoredProfile{};
  73. };
  74. /** Finds the next positive 31-bit spawn generation without wrapping. */
  75. [[nodiscard]] bool next_generation(const GenerationGuard& guard, std::uint32_t& next) noexcept;
  76. /**
  77. * Encodes one canonical slot-type-1 body without changing a refused output buffer.
  78. * Counts must be nonnegative and the generation must be newer than the guard.
  79. */
  80. [[nodiscard]] bool encode(const Preset& preset,
  81. const GenerationGuard& guard,
  82. std::span<std::byte> output,
  83. std::size_t& writtenBytes,
  84. std::size_t& writtenBits) noexcept;
  85. } // namespace sunrise::middleware::bap::activity_message::squad_auth