fix(fifa17): preserve versioned resourceId on the wire (no special->base collapse)

shape_item emitted resourceId/definitionId = asset_id (base), collapsing every
versioned (special) card onto its base definition on the /club and squad wire.
The dev 32-card fixture is base-only (version 0), so Slice 7 never exposed it;
the real profile (1531 versioned cards) did.

Fifa17Identity now carries resource_id (= (version<<24)|asset_id, == asset_id
for a base card). shape_item emits resourceId/definitionId from resource_id and
assetId/cardassetid from asset_id — versioned and base stay distinct. The host
resolver populates resource_id from the catalog's reconstructed resource_id
(the catalog already parsed version; it was dropped before shaping).

Regression test: versioned 117617092 (v7 of asset 176580) shapes resourceId/
definitionId=117617092, assetId/cardassetid=176580.

Verified on the real staged /club: 1949 items, wire-id set exact, 0
wire->resourceId mismatches, 0 duplicate-multiplicity mismatches vs the source
manifest. adapter 111 + host 24 tests green; clippy -D warnings clean.
This commit is contained in:
funman300
2026-08-12 20:46:48 +00:00
parent 1631d3b1a2
commit e187cd49a2
5 changed files with 43 additions and 3 deletions
@@ -88,6 +88,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000001, item_id: 100000001,
asset_id: 20801, asset_id: 20801,
resource_id: 20801,
}, },
)])); )]));
let items = vec![item( let items = vec![item(
@@ -155,6 +156,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000002, item_id: 100000002,
asset_id: 158023, asset_id: 158023,
resource_id: 158023,
}, },
)])); )]));
// Synthetic club "Northgate United" has no FIFA team id. // Synthetic club "Northgate United" has no FIFA team id.
+36 -3
View File
@@ -52,7 +52,13 @@ pub struct CoreOwnedItem {
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Fifa17Identity { pub struct Fifa17Identity {
pub item_id: u32, pub item_id: u32,
/// Base FIFA player asset (low 24 bits the client resolves art/name from).
pub asset_id: u32, pub asset_id: u32,
/// Full versioned resource id = `(version << 24) | asset_id`. Equals
/// `asset_id` for a version-0 base card. This is the wire
/// `resourceId`/`definitionId`, kept DISTINCT from `asset_id` so a versioned
/// (special) card never collapses onto its base on the wire.
pub resource_id: u32,
} }
/// Supplies the FIFA numeric identity for a Core item. Returning `None` means /// Supplies the FIFA numeric identity for a Core item. Returning `None` means
@@ -80,7 +86,10 @@ fn discard_value(rating: u8) -> i64 {
} }
} }
/// Build one FIFA `_item` object (version byte 0x00 → `resourceId == assetId`). /// Build one FIFA `_item` object. `resourceId`/`definitionId` carry the full
/// versioned resource id; `assetId`/`cardassetid` carry the base asset. For a
/// version-0 base card these coincide; for a special they differ and MUST NOT
/// be collapsed.
/// ///
/// This is the single source of truth for a player item's on-wire shape; the /// This is the single source of truth for a player item's on-wire shape; the
/// `/club` envelope and squad projection both call it, so their items are /// `/club` envelope and squad projection both call it, so their items are
@@ -104,10 +113,10 @@ pub fn shape_item(
.collect(); .collect();
json!({ json!({
"id": id.item_id, "id": id.item_id,
"resourceId": asset, "resourceId": id.resource_id,
"assetId": asset, "assetId": asset,
"cardassetid": asset, "cardassetid": asset,
"definitionId": asset, "definitionId": id.resource_id,
"cardsubtypeid": 0, "cardsubtypeid": 0,
"itemType": "player", "itemType": "player",
"rareflag": 1, "rareflag": 1,
@@ -162,6 +171,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000001, item_id: 100000001,
asset_id: 20801, asset_id: 20801,
resource_id: 20801,
}, },
&ent, &ent,
); );
@@ -193,6 +203,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000030, item_id: 100000030,
asset_id: 101490, asset_id: 101490,
resource_id: 101490,
}, },
&ent, &ent,
); );
@@ -201,6 +212,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000031, item_id: 100000031,
asset_id: 101490, asset_id: 101490,
resource_id: 101490,
}, },
&ent, &ent,
); );
@@ -215,4 +227,25 @@ mod tests {
assert_eq!(a["id"], 100000030); assert_eq!(a["id"], 100000030);
assert_eq!(b["id"], 100000031); assert_eq!(b["id"], 100000031);
} }
#[test]
fn versioned_special_keeps_resourceid_distinct_from_assetid() {
// A versioned (special) card: resourceId/definitionId carry the full
// versioned id; assetId/cardassetid stay the base asset. They MUST NOT
// collapse. (resource 117617092 = version 7 of asset 176580.)
let ent = entities();
let it = shape_item(
&item("oc-v", "fifa17_117617092", 92, "ST"),
Fifa17Identity {
item_id: 100000384,
asset_id: 176580,
resource_id: 117617092,
},
&ent,
);
assert_eq!(it["resourceId"], 117617092, "versioned resource id on the wire");
assert_eq!(it["definitionId"], 117617092);
assert_eq!(it["assetId"], 176580, "base asset id preserved");
assert_eq!(it["cardassetid"], 176580);
}
} }
@@ -287,6 +287,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000042, item_id: 100000042,
asset_id: 20801, asset_id: 20801,
resource_id: 20801,
}, },
)])); )]));
let input = one_slot_input(&owned, SquadExtInput::Fresh(fresh_ext())); let input = one_slot_input(&owned, SquadExtInput::Fresh(fresh_ext()));
@@ -359,6 +360,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000030, item_id: 100000030,
asset_id: 101490, asset_id: 101490,
resource_id: 101490,
}, },
), ),
( (
@@ -366,6 +368,7 @@ mod tests {
Fifa17Identity { Fifa17Identity {
item_id: 100000031, item_id: 100000031,
asset_id: 101490, asset_id: 101490,
resource_id: 101490,
}, },
), ),
])); ]));
@@ -110,6 +110,7 @@ fn oracle_tables() -> (HashMap<String, CoreOwnedItem>, TableIdentity) {
Fifa17Identity { Fifa17Identity {
item_id: wire as u32, item_id: wire as u32,
asset_id: asset, asset_id: asset,
resource_id: asset,
}, },
); );
} }
+1
View File
@@ -551,6 +551,7 @@ impl ItemIdentityResolver for Fifa17IdentityResolver {
// Wire ids live in 1e8..9e8 (policy) — well within u32. // Wire ids live in 1e8..9e8 (policy) — well within u32.
item_id: wire as u32, item_id: wire as u32,
asset_id: ident.asset_id, asset_id: ident.asset_id,
resource_id: ident.resource_id,
}) })
} }
} }