replicate_membership.h 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #pragma once
  2. #include <cstddef>
  3. #include <cstdint>
  4. #include <span>
  5. #include "../../encoding/bit_writer.h"
  6. #include "../../gameplay/descriptor/join_descriptor.h"
  7. #include "activity_client_identity_parser.h"
  8. #include "client_authoritative_data.h"
  9. namespace sunrise::middleware::bap::activity_message::replicate_membership {
  10. /** Membership snapshots use activity message type 12. */
  11. inline constexpr std::uint32_t kMessageType = 12;
  12. /** One local player plus a reflected host is 29,968 meaningful bits. */
  13. inline constexpr std::size_t kMeaningfulBitCount = 29'968;
  14. /** The host-present snapshot is byte-aligned at 3,746 bytes. */
  15. inline constexpr std::size_t kEncodedSize = 3'746;
  16. /** One filled descriptor makes its record 1,024 bits longer and shifts every later field. */
  17. inline constexpr std::size_t kDescriptorBitCount = gameplay::descriptor::kDescriptorSize * 8U;
  18. /** Byte size once one record carries a descriptor. */
  19. inline constexpr std::size_t kCitizenEncodedSize =
  20. kEncodedSize + gameplay::descriptor::kDescriptorSize;
  21. /**
  22. * One remote-citizen advertisement placed in a single region record.
  23. * The record is picked by region index. The client adopts only the record whose index matches
  24. * its pending region.
  25. */
  26. struct CitizenAdvertisement final {
  27. std::array<std::byte, gameplay::descriptor::kDescriptorSize> descriptor{};
  28. /** The ambassador's activity-host id. It is not the descriptor's own session id. */
  29. std::uint64_t onlineSessionId{};
  30. /** Region index of the record that carries it. */
  31. std::int32_t regionIndex{};
  32. /**
  33. * Ambassador member slot. It must differ from the joining client's own slot. An equal slot
  34. * picks the local-ambassador stage instead of the citizen stage.
  35. */
  36. std::uint8_t ambassadorSlot{};
  37. bool present{};
  38. };
  39. /** Inputs for one local-player membership snapshot. */
  40. struct MembershipSnapshot final {
  41. client_identity::ClientIdentity identity{};
  42. client_authoritative_data::SpawnState spawn{};
  43. client_authoritative_data::TeleportState teleport{};
  44. /** Empty unless the gameplay channel is advertising an endpoint this run. */
  45. CitizenAdvertisement citizen{};
  46. std::uint32_t revision{};
  47. /** Stable session epoch; changing it clears the client's peer table. */
  48. std::uint32_t epoch{};
  49. /** Transition token copied into every member lane of every region. */
  50. std::uint8_t transitionToken{};
  51. };
  52. /** @return Encoded byte size for one snapshot, which grows with a citizen advertisement. */
  53. [[nodiscard]] constexpr std::size_t encoded_size(const MembershipSnapshot& snapshot) noexcept {
  54. return snapshot.citizen.present ? kCitizenEncodedSize : kEncodedSize;
  55. }
  56. /**
  57. * Encodes one full-player membership snapshot. No allocation.
  58. * @param snapshot Checked identity, revision, transition, and host-echo values.
  59. * @param output Caller storage, left unchanged when validation fails or it is too small.
  60. * @param written Receives 3,746 on success or zero on failure.
  61. * @return True when the host-present body was encoded.
  62. */
  63. [[nodiscard]] bool encode_replicate_membership(const MembershipSnapshot& snapshot,
  64. std::span<std::byte> output,
  65. std::size_t& written) noexcept;
  66. /** The local member begins after root, revision, and epoch fields. */
  67. inline constexpr std::size_t kMemberStartBit = 65;
  68. /** The full identity shifts the region block to bit 835. */
  69. inline constexpr std::size_t kRegionBlockStartBit = 835;
  70. /** The host-present region block ends before top-level field four. */
  71. inline constexpr std::size_t kRegionBlockEndBit = 29'899;
  72. /** @return Bit at which the region block ends for one snapshot. */
  73. [[nodiscard]] constexpr std::size_t
  74. region_block_end_bit(const MembershipSnapshot& snapshot) noexcept {
  75. return snapshot.citizen.present ? kRegionBlockEndBit + kDescriptorBitCount : kRegionBlockEndBit;
  76. }
  77. /** @return True when the teleport slice-set index fits its fixed wire field. */
  78. [[nodiscard]] bool valid(const MembershipSnapshot& snapshot) noexcept;
  79. /**
  80. * Writes the one populated member and 31 absent member slots.
  81. * @param writer Fixed-buffer writer positioned at bit 65.
  82. * @param identity Exact client identity accepted for the current join.
  83. * @return True when the writer reaches the region-block presence bit.
  84. */
  85. [[nodiscard]] bool write_member_table(encoding::bits::Writer& writer,
  86. const client_identity::ClientIdentity& identity) noexcept;
  87. /**
  88. * Writes all 64 state-zero regions and the host-present tail.
  89. * @param writer Fixed-buffer writer positioned at bit 835.
  90. * @param snapshot Transition token and reflected host state.
  91. * @return True when the writer reaches top-level field four.
  92. */
  93. [[nodiscard]] bool write_region_block(encoding::bits::Writer& writer,
  94. const MembershipSnapshot& snapshot) noexcept;
  95. } // namespace sunrise::middleware::bap::activity_message::replicate_membership