| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123 |
- #include "replicate_membership.h"
- namespace sunrise::middleware::bap::activity_message::replicate_membership {
- namespace {
- /** The host table has one fixed record for each of 64 bubbles. */
- constexpr std::size_t kRegionCount = 64;
- /** Each bubble's state-zero slice-set index is 8 times its bubble index. */
- constexpr std::uint32_t kRegionIndexStride = 8;
- /** Region indices use the signed 32-bit midpoint as their wire bias. */
- constexpr std::uint32_t kRegionIndexBias = 0x80000000U;
- /** Each record carries one transition-token byte for every member slot. */
- constexpr std::size_t kRegionTokenCount = 32;
- /** Spawn and teleport state fields use 3 bits. */
- constexpr std::uint8_t kStateBitWidth = 3;
- /** Teleport slice-set indices use 10 bits. */
- constexpr std::uint8_t kSliceSetBitWidth = 10;
- /** Signed host-state fields add 1 before writing their unsigned value. */
- constexpr std::int32_t kSignedFieldBias = 1;
- /** Ambassadorship state fields are 2 bits at bias 1, so wire 2 stores the assigned state 1. */
- constexpr std::uint64_t kAmbassadorAssigned = 2;
- /** Member-slot fields are 6 bits at bias 1. */
- constexpr std::uint8_t kSlotBitWidth = 6;
- /**
- * Ambassador slot named by a record with no advertisement, at bias 1, so wire 2 stores slot 1.
- * It must never store the client's own slot 0. A record naming slot 0 makes the client claim the
- * region, and the next differing slot then revokes it for good.
- */
- constexpr std::uint64_t kUnadvertisedAmbassadorSlot = 2;
- /** The join-descriptor element count is an unclamped 8-bit field; only 128 is usable. */
- constexpr std::uint64_t kDescriptorCount = 128;
- /**
- * Writes one state-zero region record.
- * A record carrying the citizen advertisement is 1,024 bits longer than the others.
- * @param writer Fixed-buffer writer sitting at the record start.
- * @param bubble Bubble index, 0 through 63.
- * @param snapshot Transition token and optional citizen advertisement.
- * @return True when every fixed field fits.
- */
- [[nodiscard]] bool write_region(encoding::bits::Writer& writer,
- std::size_t bubble,
- const MembershipSnapshot& snapshot) noexcept {
- const std::uint32_t region = static_cast<std::uint32_t>(bubble) * kRegionIndexStride;
- const bool advertise = snapshot.citizen.present
- && static_cast<std::int32_t>(region) == snapshot.citizen.regionIndex;
- const std::uint64_t ambassadorSlot =
- advertise ? static_cast<std::uint64_t>(snapshot.citizen.ambassadorSlot) + kSignedFieldBias
- : kUnadvertisedAmbassadorSlot;
- bool encoded = writer.write(kRegionIndexBias + region, 32) && writer.write(1, 2)
- && writer.write(0, 8) && writer.write(kAmbassadorAssigned, 2)
- && writer.write(ambassadorSlot, kSlotBitWidth) && writer.write(0, 1)
- && writer.write(0, 32) && writer.write(0, 8) && writer.write(0, 32);
- for (std::size_t member = 0; encoded && member < kRegionTokenCount; ++member) {
- encoded = writer.write(snapshot.transitionToken, 8);
- }
- if (!advertise) {
- return encoded && writer.write(0, 8) && writer.write(0, 64);
- }
- encoded = encoded && writer.write(kDescriptorCount, 8);
- for (const std::byte value : snapshot.citizen.descriptor) {
- encoded = encoded && writer.write(std::to_integer<std::uint64_t>(value), 8);
- }
- return encoded && writer.write(snapshot.citizen.onlineSessionId, 64);
- }
- /**
- * Writes one host key, low byte first.
- * @param writer Fixed-buffer writer sitting after the host presence bit.
- * @param key Host-order key shared with the populated member.
- * @return True when all 8 key bytes fit.
- */
- [[nodiscard]] bool write_host_key(encoding::bits::Writer& writer, std::uint64_t key) noexcept {
- for (std::size_t index = 0; index < sizeof key; ++index) {
- if (!writer.write((key >> (index * 8U)) & 0xFFU, 8)) {
- return false;
- }
- }
- return true;
- }
- /**
- * Writes the current host-state tail after all region records.
- * @param writer Fixed-buffer writer sitting at the first spawn field.
- * @param snapshot Reflected host key, spawn state and teleport state.
- * @return True when the host-present tail fits.
- */
- [[nodiscard]] bool write_host_tail(encoding::bits::Writer& writer,
- const MembershipSnapshot& snapshot) noexcept {
- // Both state fields are 3 bits at bias 1, so a logical -1 encodes as wire zero, which is fatal
- // in each: the spawn reader then refuses every spawn, and the teleport reader arms a teleport
- // every cycle and de-instantiates the world. So a negative mirror is sent as a neutral zero.
- const auto spawnState = static_cast<std::uint8_t>(
- (snapshot.spawn.state < 0 ? 0 : snapshot.spawn.state) + kSignedFieldBias);
- const auto teleportState = static_cast<std::uint8_t>(
- (snapshot.teleport.state < 0 ? 0 : snapshot.teleport.state) + kSignedFieldBias);
- const auto sliceSetIndex =
- static_cast<std::uint32_t>(snapshot.teleport.sliceSetIndex + kSignedFieldBias);
- return writer.write(snapshot.spawn.opaqueByte, 8) && writer.write(spawnState, kStateBitWidth)
- && writer.write(snapshot.spawn.opaqueValue, 64) && writer.write(0, 4)
- && writer.write(teleportState, kStateBitWidth)
- && writer.write(snapshot.teleport.token, 8)
- && writer.write(sliceSetIndex, kSliceSetBitWidth)
- && writer.write(snapshot.teleport.sliceSetHash, 32) && writer.write(0, 1)
- && writer.write(1, 1) && write_host_key(writer, snapshot.identity.memberKey)
- && writer.write(0, 1) && writer.write(0, 1);
- }
- } // namespace
- /** Writes all 64 state-zero regions and the host-present tail. */
- bool write_region_block(encoding::bits::Writer& writer,
- const MembershipSnapshot& snapshot) noexcept {
- bool encoded = writer.bit_count() == kRegionBlockStartBit;
- for (std::size_t bubble = 0; encoded && bubble < kRegionCount; ++bubble) {
- encoded = write_region(writer, bubble, snapshot);
- }
- return encoded && write_host_tail(writer, snapshot)
- && writer.bit_count() == region_block_end_bit(snapshot);
- }
- } // namespace sunrise::middleware::bap::activity_message::replicate_membership
|