squad_objective_auth.h 4.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. #pragma once
  2. #include <array>
  3. #include <cstddef>
  4. #include <cstdint>
  5. #include <span>
  6. #include "../../encoding/bit_writer.h"
  7. #include "auth_fields.h"
  8. #include "scriptable_auth_body.h"
  9. #include "squad_auth_body.h"
  10. // Objective updates preserve placement fields and may refresh player awareness once per revision.
  11. namespace sunrise::middleware::bap::activity_message::squad_objective {
  12. namespace fields = auth_fields;
  13. inline constexpr std::uint32_t kSchema = squad_auth::kSchema;
  14. inline constexpr std::size_t kBits = 153;
  15. inline constexpr std::size_t kBytes = 20;
  16. /** Optional root .14 adds one 31-bit awareness revision. */
  17. inline constexpr std::size_t kMaximumBits = kBits + fields::kCounterWidth;
  18. inline constexpr std::size_t kMaximumBytes = (kMaximumBits + 7U) / 8U;
  19. /** Absent presence bits for fields .1 to .12. */
  20. inline constexpr std::uint8_t kAbsentMiddleFieldCount = 12;
  21. /** Root .15 carries the biased -1 sentinel; its role is unverified. */
  22. inline constexpr std::uint8_t kField15Width = 6;
  23. /** Root .16 task group: 5 bits with bias one, so -1 requests costs without a link. */
  24. inline constexpr std::uint8_t kTaskGroupWidth = 5;
  25. inline constexpr std::int32_t kTaskGroupBias = 1;
  26. inline constexpr std::int32_t kNoTaskGroup = -1;
  27. /** One objective sensor carries this many task groups. */
  28. inline constexpr std::int32_t kTaskGroupCount = 24;
  29. /** Root .18 active, 2 bits, written as the active wire value. */
  30. inline constexpr std::uint8_t kActiveWidth = 2;
  31. inline constexpr std::uint32_t kActiveValue = 2;
  32. /** Root .19 mode, 3 bits with bias one. Reserve keeps the counts for a delivery. */
  33. inline constexpr std::uint8_t kModeWidth = 3;
  34. inline constexpr std::uint32_t kModeBias = 1;
  35. struct Request final {
  36. std::uint32_t registryKey{};
  37. std::uint32_t revision{};
  38. std::uint16_t objectiveIndex{};
  39. std::int32_t taskGroup{kNoTaskGroup};
  40. bool reserved{};
  41. bool refreshPlayerAwareness{};
  42. };
  43. [[nodiscard]] constexpr std::size_t bit_count(const Request& request) noexcept {
  44. return request.refreshPlayerAwareness ? kMaximumBits : kBits;
  45. }
  46. [[nodiscard]] constexpr std::size_t byte_count(const Request& request) noexcept {
  47. return (bit_count(request) + 7U) / 8U;
  48. }
  49. /**
  50. * Encodes the objective assignment.
  51. * @param output Exactly byte_count(request) bytes.
  52. * @return False on an out-of-range revision, index or task group.
  53. */
  54. [[nodiscard]] inline bool encode(const Request& request, std::span<std::byte> output) noexcept {
  55. if (output.size() != byte_count(request) || request.registryKey == 0 || request.revision == 0
  56. || request.revision > fields::kMaximumCounter
  57. || request.objectiveIndex > fields::kMaximumClientRefIndex
  58. || request.taskGroup < kNoTaskGroup || request.taskGroup >= kTaskGroupCount) {
  59. return false;
  60. }
  61. const auto mode = static_cast<std::uint32_t>(request.reserved ? squad_auth::Mode::reserve
  62. : squad_auth::Mode::mode2);
  63. encoding::bits::Writer writer(output);
  64. std::size_t written = 0;
  65. const std::array<fields::Field, 9> tail{{
  66. {1, fields::kPresenceWidth}, // .15 present
  67. {0, kField15Width},
  68. {1, fields::kPresenceWidth}, // .16 present
  69. {static_cast<std::uint32_t>(request.taskGroup + kTaskGroupBias), kTaskGroupWidth},
  70. {0, fields::kPresenceWidth}, // .17 absent
  71. {kActiveValue, kActiveWidth},
  72. {mode + kModeBias, kModeWidth},
  73. {1, fields::kPresenceWidth}, // .20 present
  74. {fields::kClientRefAbsentKey, 32}, // no name
  75. }};
  76. return writer.write(1, fields::kPresenceWidth)
  77. && fields::write_client_ref(
  78. writer, request.registryKey, scriptable_auth::kType3SlotType, request.objectiveIndex)
  79. && writer.write(0, kAbsentMiddleFieldCount) && writer.write(1, fields::kPresenceWidth)
  80. && writer.write(request.revision, fields::kCounterWidth)
  81. && writer.write(request.refreshPlayerAwareness, fields::kPresenceWidth)
  82. && (!request.refreshPlayerAwareness
  83. || writer.write(request.revision, fields::kCounterWidth))
  84. && fields::write_fields(writer, tail)
  85. && fields::finish_exact(writer, bit_count(request), byte_count(request), written);
  86. }
  87. } // namespace sunrise::middleware::bap::activity_message::squad_objective