فهرست منبع

Refresh the account on pickup so a chapter appears without a relaunch

A pickup is not a web service transaction, so nothing staged an account image
for the peer that caused it: publish_account_mutation deliberately skips the
origin because a transaction carries the change back in its own response. A
grant had to wait for some unrelated action, or a relaunch, before the client
saw it.

Every active peer is now armed to re-read the account after a grant, the origin
included, so a chapter appears immediately and a second pickup in the same run
sees the first already held.

Confirmed working, and bluntly: the client re-reads the whole account graph, so
the Menagerie chalice notification fires on each pickup. Narrowing the push to
what actually changed would remove that.

Also recorded: the record visibility gate is not profile flag 90. Setting it to
one changed nothing, as setting it to two changed nothing before, so the earlier
negative holds and the obscuring is driven from somewhere else.
Millie 2 هفته پیش
والد
کامیت
562f3f61a4

+ 1 - 0
Sunrise/src/middleware/datagen/family4/account/account_encoder.cpp

@@ -99,6 +99,7 @@ bool encode(const state::AccountState& state, std::span<std::byte> output) noexc
     // Claims are laid over the authored bank on the way out, so a claimed record reads Acquired on
     // the next image. The authored policy itself is immutable and is never edited.
     (void)state::record_claims::apply(object.acquiredFlags);
+
     for (layout::CharacterUnlockBlock& block : object.characterUnlocks) {
         block.flags = unlocks.characterFlags;
     }

+ 26 - 0
Sunrise/src/server/bap/bap_route.cpp

@@ -184,6 +184,32 @@ void clear_session(Session& session) noexcept {
 
 } // namespace
 
+/** Arms every active peer to re-read the account, including the origin. */
+void arm_account_resync_everywhere() noexcept {
+    g_accountGeneration = g_accountGeneration == (std::numeric_limits<std::uint64_t>::max)()
+                              ? 1
+                              : g_accountGeneration + 1;
+    std::size_t armed = 0;
+    for (auto& peer : g_sessions) {
+        if (peer.id == 0 || !peer.authenticated || !peer.queuez.family4Active) {
+            continue;
+        }
+        peer.accountResyncGeneration = g_accountGeneration;
+        peer.accountResyncArmed = true;
+        ++armed;
+    }
+    std::array<char, core::log::kLineCapacity> line{};
+    const int count =
+        std::snprintf(line.data(), line.size(),
+                      "ev=queuez stage=resync_arm_all result=ok generation=%llu peers=%zu",
+                      static_cast<unsigned long long>(g_accountGeneration), armed);
+    if (count > 0) {
+        core::log::write(core::log::Channel::server, core::log::Level::debug,
+                         {line.data(), static_cast<std::size_t>(count)});
+    }
+}
+
+
 /** Applies one serialized BAP connection lifecycle event. */
 bool consume(const client::network::BapRequest& request,
              client::network::BapResponse& response) noexcept {

+ 8 - 0
Sunrise/src/server/bap/encrypted/activity_message/receipts/activity_message_receipts.cpp

@@ -9,6 +9,7 @@
 #include <algorithm>
 #include "../../../../../state/build_data/collectibles/collectible_catalog.h"
 #include "../../../../../state/build_data/sobjects/sobject_catalog.h"
+#include "../../../../bap/internal.h"
 #include "activity_message_receipts.h"
 
 #include <array>
@@ -370,6 +371,13 @@ Framed frame_incident(const message::Request& request) noexcept {
                 }
                 const std::uint16_t node = state::lore::book_for_bubble(bubble);
                 const state::lore::GrantOutcome outcome = state::lore::grant_next_chapter(node);
+                if (outcome == state::lore::GrantOutcome::granted) {
+                    // Nothing else will stage an account image for this peer: a pickup is not a web
+                    // service transaction and has no response to carry the change back. Arm every
+                    // peer, the origin included, so the chapter appears without a relaunch and a
+                    // second pickup in the same run sees the first one already held.
+                    bap::arm_account_resync_everywhere();
+                }
                 report(outcome == state::lore::GrantOutcome::granted ? core::log::Level::info
                                                                      : core::log::Level::warn,
                        "ev=activity stage=lore bubble=0x%08X node=%u result=%s record=%u",

+ 10 - 0
Sunrise/src/server/bap/internal.h

@@ -182,6 +182,16 @@ struct Session {
     bool abilityRefreshArmed{};
 };
 
+/**
+ * Arms every active peer to re-read the account, including the one that caused the change.
+ *
+ * `publish_account_mutation` deliberately skips the origin, because a web service transaction
+ * carries the new account back in its own response. A change made outside such a transaction has no
+ * response to carry, so the peer that caused it would otherwise keep showing stale state until some
+ * unrelated action happened to stage an image. Picking up a collectible is such a change.
+ */
+void arm_account_resync_everywhere() noexcept;
+
 namespace plaintext {
 
 /**