Forráskód Böngészése

Decode the reflected field shapes lane 2 uses after the relic Knight dies

A union arm is read by the ordinary per-type reader (86657, union reader
0x1409F3D60, family-4 table 0x141F94F38): a scalar arm takes the union field's
own zero width and reads no bits, a nested arm is a no-op, and a type-34 arm is
the selected-schema reader. Type 12 shares RAW64's form. Types 20, 30 and 31
share type 18's mode-one reader and type 21 the nullable-u32 reader; one helper
now applies those aliases to fields and union arms alike. Type 37 is a nested
walk of the schema its reader's global names, 808092FF (24 bits).

Without these, component 80803D3B on the Knight's child dropped its frame, the
creates in that frame were lost, and every later frame failed on group size.
Confetti3 1 hónapja
szülő
commit
f9a63df2e2

+ 14 - 4
Sunrise/src/middleware/bap/activity_message/wire_schema/activity_wire_codec_decode_runtime.h

@@ -786,6 +786,14 @@ private:
                 && resolver_.isZeroBitType(resolver_.context, field.typeCode)) {
                 return RuntimeWalkStatus::complete;
             }
+            // The native union reader dispatches through the per-type table, where a nested
+            // arm is a no-op and a type-34 arm is the ordinary selected-schema reader.
+            if (field.typeCode == 1) {
+                return RuntimeWalkStatus::complete;
+            }
+            if (field.typeCode == 34) {
+                return walk_selected(owner, field, occurrence, depth);
+            }
             return walk_inline_type(owner, field, occurrence, memory, depth + 1);
         }
         if (field.typeCode == 28) {
@@ -817,10 +825,12 @@ private:
                          ValueRole::customIndex);
             return RuntimeWalkStatus::complete;
         }
-        const bool raw64 = field.typeCode == 35;
+        const bool raw64 = is_raw64(field.typeCode);
         const std::uint8_t nativeWidth = raw64 ? 64 : storage_width(field.typeCode);
         const std::uint8_t width = raw64 ? 64 : runtime_declared_width(field);
-        if (nativeWidth == 0 || width == 0) {
+        // Native scalar readers read param[1] bits; a zero width (a union field's own params) reads
+        // none.
+        if (nativeWidth == 0) {
             return RuntimeWalkStatus::unsupportedField;
         }
         const std::uint32_t at = static_cast<std::uint32_t>(reader_.position());
@@ -861,7 +871,7 @@ private:
                             || field.typeCode == 27 || field.typeCode == 28 || field.typeCode == 39
                             || field.typeCode == 40 || field.typeCode == 42 || field.typeCode == 43
                             || field.typeCode == 44 || field.typeCode == 45;
-        const bool raw64 = field.typeCode == 35;
+        const bool raw64 = is_raw64(field.typeCode);
         const bool zeroBit = resolver_.isZeroBitType != nullptr
                              && resolver_.isZeroBitType(resolver_.context, field.typeCode);
         // A selected field carries its schema handle on the wire, so it is structural but must
@@ -876,7 +886,7 @@ private:
         }
         const std::uint8_t nativeWidth = structural || raw64 ? 0 : storage_width(field.typeCode);
         const std::uint8_t declaredWidth = structural || raw64 ? 0 : runtime_declared_width(field);
-        if (!structural && !raw64 && (nativeWidth == 0 || declaredWidth == 0)) {
+        if (!structural && !raw64 && nativeWidth == 0) {
             return RuntimeWalkStatus::unsupportedField;
         }
         for (std::uint32_t index = 0; index < repeats; ++index) {

+ 12 - 3
Sunrise/src/middleware/bap/activity_message/wire_schema/activity_wire_codec_encode_runtime.h

@@ -58,7 +58,7 @@ struct RuntimeAuthoredValue final {
     if (field.typeCode == 11) {
         return value.kind == ValueKind::real32 && std::isfinite(value.realValue);
     }
-    if (field.typeCode == 35) {
+    if (is_raw64(field.typeCode)) {
         return value.kind == ValueKind::unsignedInteger;
     }
     const std::uint8_t width = storage_width(field.typeCode);
@@ -234,10 +234,11 @@ private:
         if (!valid_runtime_scalar(field, value)) {
             return RuntimeWalkStatus::unsupportedField;
         }
-        const bool raw64 = field.typeCode == 35;
+        const bool raw64 = is_raw64(field.typeCode);
         const std::uint8_t nativeWidth = raw64 ? 64 : storage_width(field.typeCode);
         const std::uint8_t declaredWidth = raw64 ? 64 : runtime_declared_width(field);
-        if (nativeWidth == 0 || declaredWidth == 0) {
+        // Mirrors the decoder: a zero declared width writes no bits.
+        if (nativeWidth == 0) {
             return RuntimeWalkStatus::unsupportedField;
         }
         std::uint64_t decoded = 0;
@@ -784,6 +785,14 @@ private:
                 && resolver_.isZeroBitType(resolver_.context, field.typeCode)) {
                 return RuntimeWalkStatus::complete;
             }
+            // The native union reader dispatches through the per-type table, where a nested
+            // arm is a no-op and a type-34 arm is the ordinary selected-schema reader.
+            if (field.typeCode == 1) {
+                return RuntimeWalkStatus::complete;
+            }
+            if (field.typeCode == 34) {
+                return write_selected(owner, field, occurrence, depth);
+            }
             return write_inline_type(owner, field, occurrence, memory, depth + 1);
         }
         if (field.typeCode == 28) {

+ 5 - 0
Sunrise/src/middleware/bap/activity_message/wire_schema/activity_wire_codec_internal.h

@@ -114,6 +114,11 @@ public:
     }
 }
 
+/** Types 12 and 35 are raw 64-bit words, read and written whole. */
+[[nodiscard]] constexpr bool is_raw64(std::uint8_t typeCode) noexcept {
+    return typeCode == 12 || typeCode == 35;
+}
+
 /** @return A low bit mask of the given width. Width 0 masks everything away. */
 [[nodiscard]] constexpr std::uint64_t mask(std::uint8_t width) noexcept {
     return width == 64  ? (std::numeric_limits<std::uint64_t>::max)()

+ 47 - 30
Sunrise/src/middleware/gameplay/external/composite_entity_codec.cpp

@@ -79,6 +79,49 @@ read_schema(const void* raw, std::uint32_t rowIndex, wire::runtime::SchemaView&
            && output.row == rowIndex;
 }
 
+/** Reference types that share one native reader decode through one walker case. */
+[[nodiscard]] std::uint8_t reference_alias(format::RuntimeCodecFamily family,
+                                           std::uint8_t type) noexcept {
+    if (family != format::RuntimeCodecFamily::sobjectModeZero && type == 30) {
+        return 18;
+    }
+    // Type 21 uses the native nullable-u32 reader in every family: one present bit, then 32.
+    if (type == 21) {
+        return 22;
+    }
+    if (family == format::RuntimeCodecFamily::sobjectModeOne) {
+        // Types 18, 20, 30 and 31 share one native mode-one reader.
+        if (type == 20 || type == 31) {
+            return 18;
+        }
+        if (type == 29) {
+            return 43;
+        }
+    }
+    return type;
+}
+
+/** Rewrites one field view to the type its family's native reader implements. */
+[[nodiscard]] bool canonicalize_field(const void* raw,
+                                      format::RuntimeCodecFamily family,
+                                      wire::runtime::FieldView& output) noexcept {
+    output.typeCode = reference_alias(family, output.typeCode);
+    // The family-1/4 NESTED_CUSTOM reader (0x1409F7400) is a plain nested walk of one fixed schema,
+    // the one its global at 0x141FA32E0 names on 86657: a 19-bit real and a 5-bit int8, 24 bits.
+    constexpr std::uint32_t kNestedCustomSchema = 0x808092FFU;
+    if (family == format::RuntimeCodecFamily::sobjectModeOne && output.typeCode == 37) {
+        wire::runtime::SchemaView nested{};
+        if (!find_schema(raw, kNestedCustomSchema, nested)) {
+            return false;
+        }
+        output.typeCode = 1;
+        output.nestedSchemaRow = nested.row;
+        // Its fields carry no presence bits, so it needs no slot in the component bitmap.
+        output.hasBitmapOffset = true;
+    }
+    return true;
+}
+
 /** Converts one SDK field row into the generic runtime walker view. */
 [[nodiscard]] bool
 read_field(const void* raw, std::uint32_t rowIndex, wire::runtime::FieldView& output) noexcept {
@@ -101,17 +144,7 @@ read_field(const void* raw, std::uint32_t rowIndex, wire::runtime::FieldView& ou
             }
             output.nestedSchemaRow = target.row;
         }
-        if ((context->family != format::RuntimeCodecFamily::sobjectModeZero
-             && output.typeCode == 30)
-            || (context->family == format::RuntimeCodecFamily::sobjectModeOne
-                && output.typeCode == 20)) {
-            output.typeCode = 18;
-        }
-        if (context->family == format::RuntimeCodecFamily::sobjectModeOne
-            && output.typeCode == 29) {
-            output.typeCode = 43;
-        }
-        return true;
+        return canonicalize_field(raw, context->family, output);
     }
     const format::RuntimeField& row = context->catalog->runtimeFields[rowIndex];
     if (row.schemaIndex >= context->catalog->runtimeSchemas.size()
@@ -161,13 +194,8 @@ read_field(const void* raw, std::uint32_t rowIndex, wire::runtime::FieldView& ou
                                     ? 0
                                     : static_cast<std::int32_t>(row.bits);
     output.typeCode = static_cast<std::uint8_t>(row.typeCode);
-    if ((context->family != format::RuntimeCodecFamily::sobjectModeZero && output.typeCode == 30)
-        || (context->family == format::RuntimeCodecFamily::sobjectModeOne
-            && output.typeCode == 20)) {
-        output.typeCode = 18;
-    }
-    if (context->family == format::RuntimeCodecFamily::sobjectModeOne && output.typeCode == 29) {
-        output.typeCode = 43;
+    if (!canonicalize_field(raw, context->family, output)) {
+        return false;
     }
     output.presence =
         static_cast<std::uint8_t>((row.flags & format::kRuntimeFieldPresenceBit) != 0);
@@ -229,18 +257,7 @@ static std::uint8_t canonical_type(const void* raw, std::uint8_t type) noexcept
     if (context.family == format::RuntimeCodecFamily::sobjectModeZero && type == 27) {
         return 0;
     }
-    if (context.family != format::RuntimeCodecFamily::sobjectModeZero && type == 30) {
-        return 18;
-    }
-    if (context.family == format::RuntimeCodecFamily::sobjectModeOne) {
-        if (type == 20) {
-            return 18;
-        }
-        if (type == 29) {
-            return 43;
-        }
-    }
-    return type;
+    return reference_alias(context.family, type);
 }
 
 /** The native action selector chooses one exact SDK-declared payload schema. */