| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- #include "bap_connection_publication.h"
- #include <Windows.h>
- namespace sunrise::server::bap::encrypted {
- namespace {
- /** Measured delay before the second Family-4 snapshot. */
- constexpr std::uint64_t kFamily4RepushDelayMs = 400;
- /** The banner pair lands the same unsolicited way and hits the same record-state race. */
- constexpr std::uint64_t kBannerRepushDelayMs = 400;
- /**
- * Delay before the ability-icon re-derivation owed by a subclass selection.
- * The Client content-extraction pump that rebuilds the invalidated ability buckets runs on the
- * next few RunCallbacks pumps, well under this window.
- */
- constexpr std::uint64_t kAbilityRefreshDelayMs = 500;
- /**
- * How long the roster keeps its faster cadence after a load starts.
- * The slice-set load step costs 9.2 to 14.1 s, so this covers it.
- */
- constexpr std::uint64_t kTransitionWindowMs = 15'000;
- } // namespace
- /** Captures the connection fields one service outcome carries. */
- ConnectionFields connection_fields(const ServiceOutcome& outcome) noexcept {
- ConnectionFields fields{};
- const auto* plan = transaction_if<activity_message::ActivityPlan>(outcome);
- if (plan == nullptr) {
- return fields;
- }
- if (plan->delivery == activity_message::Delivery::joinNotifications) {
- fields.joinMemberKey = plan->entitySlotMutation.memberKey;
- fields.joinCharacterSoid = plan->joinCharacterSoid;
- fields.joinsActivity = true;
- }
- // The initial load is a transition too, and its token does not arrive for several seconds.
- fields.opensTransitionWindow =
- plan->delivery == activity_message::Delivery::joinNotifications || plan->transitionStarted;
- if (plan->mutationDomain == activity_message::MutationDomain::patchEpoch) {
- fields.patchEpoch = plan->patchEpoch;
- fields.retainsPatchEpoch = true;
- }
- return fields;
- }
- /** Publishes the captured connection fields after a successful commit. */
- void publish_connection_fields(Session& session,
- const transactions::Publication& publication,
- const ConnectionFields& fields) noexcept {
- if (publication.hasActivitySessionBinding) {
- // Only the first binding decides the link's kind. A link that allocated its own session
- // also joins later, and that join must not reclassify it.
- if (session.activitySessionId == 0 && publication.activitySessionFromJoin) {
- session.activityJoinedForeignSession = true;
- }
- session.activitySessionId = publication.activitySessionId;
- }
- if (fields.joinMemberKey != 0) {
- session.activityMemberKey = fields.joinMemberKey;
- }
- if (fields.joinCharacterSoid != 0) {
- session.activityCharacterSoid = fields.joinCharacterSoid;
- }
- if (fields.retainsPatchEpoch) {
- session.activityPatchEpoch = fields.patchEpoch;
- session.activityPatchEpochSeen = true;
- }
- if (fields.opensTransitionWindow) {
- session.activityTransitionUntilTick = GetTickCount64() + kTransitionWindowMs;
- }
- // A join resets the client's roster container, so the warm-up is re-armed. Its unconditional
- // state-byte moves make the client deactivate and rebuild every roster-owned object, and the
- // player object binds to the published membership only on that rebuild.
- if (fields.joinsActivity) {
- session.activityRosterSends = 0;
- session.activityRosterGroups = 0;
- }
- }
- /** Arms the owed Family-4 and banner re-pushes when the queuez publication asks for them. */
- void arm_repushes(Session& session, const queuez::StagedPublication& queuezPublication) noexcept {
- const std::uint64_t now = GetTickCount64();
- if (queuezPublication.armsAbilityRefresh) {
- session.abilityRefreshDueTick = now + kAbilityRefreshDelayMs;
- session.abilityRefreshArmed = true;
- }
- if (queuezPublication.armsFamily4Repush && queuezPublication.family4RepushRoot != 0) {
- session.family4RepushDueTick = now + kFamily4RepushDelayMs;
- session.family4RepushRoot = queuezPublication.family4RepushRoot;
- session.family4RepushArmed = true;
- }
- // Armed on its own signal, not on family four's. Family zero re-subscribes on every record
- // cycle, and each subscribe needs a delayed copy because the immediate answer arrives too soon.
- if (queuezPublication.armsBannerRepush && queuezPublication.bannerRepushRoot != 0) {
- session.bannerRepushDueTick = now + kBannerRepushDelayMs;
- session.bannerRepushRoot = queuezPublication.bannerRepushRoot;
- session.bannerRepushArmed = true;
- }
- }
- } // namespace sunrise::server::bap::encrypted
|