Bladeren bron

fix catalyst providing a second perk copy instead of overriding

stan 21 uur geleden
bovenliggende
commit
5dc628ec50

+ 19 - 8
Sunrise/src/middleware/datagen/character_record/appearance/character_appearance_banks.cpp

@@ -1,11 +1,15 @@
 #include <algorithm>
 
+#include "../../../../state/build_data/items/catalysts/exotic_catalyst_catalog.h"
 #include "../../../../state/build_data/runtime.h"
 #include "internal.h"
 
 namespace sunrise::middleware::datagen::character_record::appearance {
 namespace {
 
+/** The base Tesseract plug is replaced by the completed Worldline catalyst. */
+constexpr std::uint32_t kTesseractPlugHash = 0xD91C01C9U;
+
 /**
  * Socket types in priority order, most load-bearing first.
  * A loadout has more distinct plug hashes than the overflow bank holds, so this order decides
@@ -62,19 +66,19 @@ struct Ranked {
     return left.lane < right.lane;
 }
 
-/**
- * Appends one definition's sandbox perks to a bank.
- * @param definitionIndex Native item or plug index.
- * @param count Occupied entries, advanced per appended perk.
- */
+/** A completed catalyst replaces the base Tesseract without changing the other perks. */
 void append_perks(std::uint16_t definitionIndex,
                   std::span<std::uint16_t> bank,
-                  std::size_t& count) noexcept {
+                  std::size_t& count,
+                  bool completedCatalyst) noexcept {
     details::Definition detail{};
     if (definitionIndex == details::kUnavailableItemIndex
         || !state::build_data::find_configured_item_detail(definitionIndex, detail)) {
         return;
     }
+    if (completedCatalyst && detail.definitionHash == kTesseractPlugHash) {
+        return;
+    }
     const std::size_t perks = detail.sandboxPerkCount < detail.sandboxPerks.size()
                                   ? detail.sandboxPerkCount
                                   : detail.sandboxPerks.size();
@@ -91,9 +95,16 @@ void append_perks(std::uint16_t definitionIndex,
 void append_item_perks(const Equipped& equipped,
                        std::span<std::uint16_t> bank,
                        std::size_t& count) noexcept {
-    append_perks(equipped.definitionIndex, bank, count);
+    namespace catalysts = state::build_data::items::catalysts;
+    const catalysts::Result catalyst = catalysts::resolve(equipped.definitionIndex);
+    const bool completedCatalyst =
+        catalyst.error == catalysts::Error::none
+        && catalyst.availability == catalysts::Availability::released
+        && resolve_effective_plug(equipped, catalyst.completed.socketLane)
+               == catalyst.completed.effectDefinitionIndex;
+    append_perks(equipped.definitionIndex, bank, count, completedCatalyst);
     for (std::size_t lane = 0; lane < equipped.laneCount; ++lane) {
-        append_perks(resolve_effective_plug(equipped, lane), bank, count);
+        append_perks(resolve_effective_plug(equipped, lane), bank, count, completedCatalyst);
     }
 }
 

+ 53 - 0
Sunrise/src/middleware/datagen/character_record/character_record_encoder.cpp

@@ -1,8 +1,12 @@
 #include "character_record_encoder.h"
 
 #include <algorithm>
+#include <array>
+#include <cstdio>
 #include <cstring>
+#include <span>
 
+#include "../../../core/logging/log.h"
 #include "appearance/internal.h"
 
 namespace sunrise::middleware::datagen::character_record {
@@ -61,6 +65,53 @@ constexpr std::size_t kCardFlagOffset = 8;
     return true;
 }
 
+/** Longest perk-bank report line, including the trailing entries. */
+constexpr std::size_t kBankReportCapacity = 1'024;
+
+/**
+ * Reports one perk bank's occupied entries. Diagnostic only.
+ * @param family Record family the bank belongs to.
+ * @param bank Bank name.
+ * @param entries Bank contents.
+ */
+void report_perk_bank(const char* family,
+                      const char* bank,
+                      std::span<const std::uint16_t> entries) noexcept {
+    std::array<char, kBankReportCapacity> line{};
+    int written = std::snprintf(
+        line.data(), line.size(), "ev=appearance stage=perk_bank family=%s bank=%s", family, bank);
+    if (written <= 0) {
+        return;
+    }
+    for (const std::uint16_t entry : entries) {
+        if (entry == layout::kEmptyDefinitionIndex) {
+            continue;
+        }
+        const auto used = static_cast<std::size_t>(written);
+        if (used >= line.size()) {
+            break;
+        }
+        const int more = std::snprintf(line.data() + used, line.size() - used, " %u", entry);
+        if (more <= 0) {
+            break;
+        }
+        written += more;
+    }
+    core::log::write(core::log::Channel::server, core::log::Level::debug, line.data());
+}
+
+/**
+ * Reports all four perk banks of one record. Diagnostic only.
+ * @param family Record family the banks belong to.
+ * @param block Appearance block carrying the banks.
+ */
+void report_perk_banks(const char* family, const layout::Appearance& block) noexcept {
+    report_perk_bank(family, "index", block.indexBank);
+    report_perk_bank(family, "weaponA", block.smallBankA);
+    report_perk_bank(family, "weaponB", block.smallBankB);
+    report_perk_bank(family, "weaponC", block.smallBankC);
+}
+
 /** @param light Equipment light. @return The trailing summary block both records carry. */
 [[nodiscard]] layout::Summary build_summary(std::int32_t light,
                                             std::uint16_t titleRecordIndex) noexcept {
@@ -110,6 +161,7 @@ bool encode_family3(const state::CharacterState& character,
         || !build_shared(character, instances, light, identity, block)) {
         return false;
     }
+    report_perk_banks("3", block);
     const auto record = output.first(kFamily3RecordSize);
     copy_record(identity,
                 block,
@@ -141,6 +193,7 @@ bool encode_family0(const state::CharacterState& character,
         || !build_shared(character, instances, light, identity, block)) {
         return false;
     }
+    report_perk_banks("0", block);
     const auto record = output.first(kFamily0RecordSize);
     copy_record(identity,
                 block,

+ 0 - 6
Sunrise/src/server/bap/encrypted/push/queuez/queuez_subscription.cpp

@@ -211,11 +211,6 @@ void append_queuez_notification(Scratch& scratch,
         return;
     }
     after = stagedAfter;
-    // The client sends its subscribe just before it writes the record state, so this first copy
-    // arrives while the record still reads its previous state and is refused. Family zero has
-    // nothing else behind it, so the delayed copy is the one that lands.
-    armsBannerRepush = subscription.familyType == queuez::kBannerFamilyType;
-
     if (subscription.familyType == queuez::kRosterFamilyType && !stagedAfter.family4Active) {
         queuez::SessionState companionAfter{};
         if (append_family4_companion(scratch,
@@ -241,7 +236,6 @@ void append_queuez_notification(Scratch& scratch,
                                        written,
                                        bannerDelivered)) {
             after = bannerDelivered;
-            armsBannerRepush = true;
         }
     }
 }