feat(import-fifa17): classify every club family, not just kits
Kits were recognised by the id range 6_300_000..=6_400_654, so stadiums, badges, balls and league logos all fell through to `Other` and were silently dropped from the import — a club could own them and Core would never hear. Club items are now settled by `cardsubtypeid` (kit 9, stadium 10, badge 11, ball 30, league logo 31), which is the discriminator the client's own club-item resolver uses and cannot collide with the other classes: consumables occupy 51..=341 and staff 4/6/8. The render gate generalises with it. Each family ships a CONSTANT cardassetid (kit 35, stadium 36, ball 37, badge 39, logo 40 — verified across all 2302 shipped rows), so a copy carrying anything else is deferred rather than drawn as the wrong art. Only kits additionally require a teamid, because their identity resolver keys on it and real owned kits carry it; demanding one of the other families would defer every legitimate badge, ball and stadium. League logos map to `misc`: they have no equipped slot, so Core holds them as generic owned content rather than inventing a designation. The real profile is unaffected (it owns no club items beyond its kits) and its emitted catalog is byte-identical.
This commit is contained in:
@@ -83,7 +83,7 @@ fn classification_balances_across_disjoint_classes() {
|
||||
c.player_cards,
|
||||
c.consumables,
|
||||
c.staff,
|
||||
c.kits,
|
||||
c.club_items,
|
||||
c.other
|
||||
),
|
||||
(5, 2, 1, 1, 1, 0)
|
||||
@@ -767,14 +767,86 @@ fn disagreeing_render_metadata_defers_rather_than_guessing() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kit_missing_render_metadata_defers() {
|
||||
fn club_item_missing_render_metadata_defers() {
|
||||
// No cardassetid at all: it cannot be drawn, whatever family it claims.
|
||||
let item = r#"{"id":100000501,"resourceId":6300006,"assetId":6300006,
|
||||
"cardsubtypeid":9,"itemState":"activeHomeKit"}"#
|
||||
.to_string();
|
||||
let plan = plan_non_player_definitions(&profile(&[item], "[]", 100000600));
|
||||
assert!(plan.supported.is_empty());
|
||||
assert_eq!(plan.deferred.len(), 1);
|
||||
assert_eq!(
|
||||
plan.deferred[0].reason,
|
||||
"missing_club_item_render_metadata"
|
||||
);
|
||||
|
||||
// Correct kit art, but no team: the kit identity resolver keys on teamid.
|
||||
let item = r#"{"id":100000502,"resourceId":6300007,"assetId":6300007,
|
||||
"cardsubtypeid":9,"cardassetid":35,"itemState":"activeHomeKit"}"#
|
||||
.to_string();
|
||||
let plan = plan_non_player_definitions(&profile(&[item], "[]", 100000600));
|
||||
assert!(plan.supported.is_empty());
|
||||
assert_eq!(plan.deferred[0].reason, "missing_kit_render_metadata");
|
||||
|
||||
// A kit carrying another family's art is not the item it claims to be.
|
||||
let item = r#"{"id":100000503,"resourceId":6300008,"assetId":6300008,
|
||||
"cardsubtypeid":9,"cardassetid":39,"teamid":21}"#
|
||||
.to_string();
|
||||
let plan = plan_non_player_definitions(&profile(&[item], "[]", 100000600));
|
||||
assert!(plan.supported.is_empty());
|
||||
assert_eq!(
|
||||
plan.deferred[0].reason,
|
||||
"missing_club_item_render_metadata"
|
||||
);
|
||||
}
|
||||
|
||||
/// Club items are settled by `cardsubtypeid`, not by the id range they occupy.
|
||||
/// Keying kits off 6_300_000..=6_400_654 classified every OTHER club family as
|
||||
/// `Other`, so a badge, ball, stadium or league logo was silently dropped from
|
||||
/// the import even though its definition table ships with the game.
|
||||
#[test]
|
||||
fn every_club_family_classifies_and_imports() {
|
||||
let club = |id: i64, resource: i64, subtype: i64, art: i64| {
|
||||
format!(
|
||||
r#"{{"id":{id},"resourceId":{resource},"assetId":{resource},
|
||||
"cardsubtypeid":{subtype},"cardassetid":{art},"teamid":21}}"#
|
||||
)
|
||||
};
|
||||
let items = vec![
|
||||
club(100000501, 6_300_006, 9, 35), // kit
|
||||
club(100000502, 6_200_001, 10, 36), // stadium
|
||||
club(100000503, 6_000_012, 11, 39), // badge
|
||||
club(100000504, 8_120_194, 30, 37), // ball
|
||||
club(100000505, 8_010_001, 31, 40), // league logo
|
||||
];
|
||||
let counts = count_items(&profile(&items, "[]", 100000600));
|
||||
assert_eq!(counts.club_items, 5, "no club family falls through to Other");
|
||||
assert_eq!(counts.other, 0);
|
||||
|
||||
let plan = plan_non_player_definitions(&profile(&items, "[]", 100000600));
|
||||
assert!(plan.deferred.is_empty(), "{:?}", plan.deferred);
|
||||
let kind = |cid: &str| {
|
||||
plan.supported
|
||||
.iter()
|
||||
.find(|d| d.card_id == cid)
|
||||
.unwrap_or_else(|| panic!("{cid} not imported"))
|
||||
.kind
|
||||
};
|
||||
assert_eq!(kind("fifa17_6300006"), ContentKind::Kit);
|
||||
assert_eq!(kind("fifa17_6200001"), ContentKind::Stadium);
|
||||
assert_eq!(kind("fifa17_6000012"), ContentKind::Badge);
|
||||
assert_eq!(kind("fifa17_8120194"), ContentKind::Ball);
|
||||
// A league logo has no equipped slot, so it is generic owned content.
|
||||
assert_eq!(kind("fifa17_8010001"), ContentKind::Misc);
|
||||
// A club item's carddbid IS its asset id.
|
||||
assert_eq!(
|
||||
plan.supported
|
||||
.iter()
|
||||
.find(|d| d.card_id == "fifa17_6000012")
|
||||
.unwrap()
|
||||
.asset_id,
|
||||
Some(6_000_012)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user