feat(fifa17): project owned kits with active home/away designation
Closes the server side of the FUT kit selector. Ownership stays generic in
Core (submodule bump: club_kit_assignments + GET/PUT /club/kits); this
commit adds the FIFA17 representation, the host projection and importer
support.
adapter:
* ContentKind::Kit ("kit") so kits are classified alongside player/staff/
consumable instead of being mistaken for 0-rated players.
* Fifa17CardIdentity carries card_asset_id and team_id; RawCard keeps both
optional because the emitted catalog writes null for non-kit definitions.
* shape_kit_item emits only the fields the client's kit path reads
(id/resourceId/assetId/cardassetid/cardsubtypeid/itemState/owners/
untradeable/teamid) — no attributeList, no itemType.
* itemState on the wire is the STRING token activeHomeKit/activeAwayKit;
the 101/102 integers are the client's post-deserialisation runtime enum
(item+0x5c) and are never emitted.
* club_stats S_KITS (0x28) now counts owned kits instead of a hard zero.
host:
* CoreKitAssignments + CoreAccess::get_active_kits (GET /club/kits),
defaulting to no active kits so a Core without the endpoint degrades
instead of fabricating a designation.
* handle_club classifies type=player|kit, rejects any other type with an
empty page and outcome=unsupported_type, and now always fetches
unpaginated from Core: kind and transfer-pile membership are host-side
concepts Core cannot express, so filtering and pagination must both
happen after shaping or pages come back short.
importer:
* ItemClass::Kit (cardsubtypeid == 9 and resourceId in 6_300_000..=6_400_654),
kit counts/balances, and card_asset_id/team_id carried into the emitted
catalog and manifest.
* a kit group missing cardassetid == 35 or teamid is DEFERRED
(missing_kit_render_metadata) rather than defaulted; conflicting render
metadata across instances defers as render_metadata_conflict.
staging: sold-staging-up.py seeds two owned kits (6300006 home / 6400003
away, team 21) plus both active designations so the projection can be
verified over HTTP before involving the client.
This commit is contained in:
@@ -15,9 +15,9 @@ use openfut_identity::JsonIdentityStore;
|
||||
use openfut_utas_host::account_store::AccountStore;
|
||||
use openfut_utas_host::{
|
||||
classify, handle_club, handle_put_squad, handle_squad_active, handle_squad_list,
|
||||
handle_user_mass_info, read_request, ClubDeps, CoreAccess, CoreError, CoreExtState, CorePage,
|
||||
CoreReplaceRequest, CoreReplaceResult, CoreSquadRead, CoreSquadSlot, Fifa17IdentityResolver,
|
||||
HttpCoreClient, PassClient, Route, Server, SquadDeps,
|
||||
handle_user_mass_info, read_request, ClubDeps, CoreAccess, CoreError, CoreExtState,
|
||||
CoreKitAssignments, CorePage, CoreReplaceRequest, CoreReplaceResult, CoreSquadRead,
|
||||
CoreSquadSlot, Fifa17IdentityResolver, HttpCoreClient, PassClient, Route, Server, SquadDeps,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use serde_json::Value;
|
||||
@@ -338,11 +338,13 @@ fn club_excludes_listed_items_and_paginates_the_visible_set() {
|
||||
|
||||
// oc2 has an active transfer-market listing.
|
||||
let hidden: std::collections::HashSet<String> = ["oc2".to_string()].into_iter().collect();
|
||||
let active_kits = CoreKitAssignments::default();
|
||||
let deps = ClubDeps {
|
||||
core: core.as_ref(),
|
||||
entities: &ents,
|
||||
assets: resolver.as_ref(),
|
||||
hidden: &hidden,
|
||||
active_kits: &active_kits,
|
||||
};
|
||||
let (resp, log) = handle_club("", &deps);
|
||||
let v: Value = serde_json::from_slice(&resp.body).unwrap();
|
||||
@@ -370,13 +372,14 @@ fn club_excludes_listed_items_and_paginates_the_visible_set() {
|
||||
);
|
||||
assert_eq!(log2.total, 2);
|
||||
|
||||
// Nothing hidden → the fast Core-paginated path, all three visible.
|
||||
// Nothing hidden → all three player items remain visible.
|
||||
let none: std::collections::HashSet<String> = std::collections::HashSet::new();
|
||||
let deps_all = ClubDeps {
|
||||
core: core.as_ref(),
|
||||
entities: &ents,
|
||||
assets: resolver.as_ref(),
|
||||
hidden: &none,
|
||||
active_kits: &active_kits,
|
||||
};
|
||||
let (resp3, log3) = handle_club("", &deps_all);
|
||||
let v3: Value = serde_json::from_slice(&resp3.body).unwrap();
|
||||
@@ -384,6 +387,67 @@ fn club_excludes_listed_items_and_paginates_the_visible_set() {
|
||||
assert_eq!(log3.total, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn club_projects_only_owned_kits_with_active_designations() {
|
||||
let core = Arc::new(FakeCore::new(
|
||||
vec![
|
||||
item(
|
||||
"player",
|
||||
"card_player",
|
||||
90,
|
||||
"ST",
|
||||
"Argentina",
|
||||
"Premier League",
|
||||
"Chelsea",
|
||||
),
|
||||
item("home", "kit_home", 0, "", "", "", ""),
|
||||
item("away", "kit_away", 0, "", "", "", ""),
|
||||
],
|
||||
3,
|
||||
));
|
||||
let catalog = Fifa17CardCatalog::from_json_str(
|
||||
r#"{"schema_version":1,"game":"fifa17","cards":{
|
||||
"card_player":{"asset_id":20801},
|
||||
"kit_home":{"asset_id":6300006,"kind":"kit","subtype":9,
|
||||
"card_asset_id":35,"team_id":21,"rareflag":0},
|
||||
"kit_away":{"asset_id":6400003,"kind":"kit","subtype":9,
|
||||
"card_asset_id":35,"team_id":21,"rareflag":0}
|
||||
}}"#,
|
||||
)
|
||||
.unwrap();
|
||||
let resolver = Arc::new(Fifa17IdentityResolver::new(
|
||||
catalog,
|
||||
Arc::new(JsonIdentityStore::open(unique_store_path()).unwrap()),
|
||||
));
|
||||
let ents = entities();
|
||||
let hidden = std::collections::HashSet::new();
|
||||
let active_kits = CoreKitAssignments {
|
||||
home_owned_card_id: Some("home".into()),
|
||||
away_owned_card_id: Some("away".into()),
|
||||
};
|
||||
let deps = ClubDeps {
|
||||
core: core.as_ref(),
|
||||
entities: &ents,
|
||||
assets: resolver.as_ref(),
|
||||
hidden: &hidden,
|
||||
active_kits: &active_kits,
|
||||
};
|
||||
|
||||
let (kit_response, kit_log) = handle_club("type=kit", &deps);
|
||||
let kits: Value = serde_json::from_slice(&kit_response.body).unwrap();
|
||||
assert_eq!(kit_log.total, 2);
|
||||
assert_eq!(kits["itemData"][0]["itemState"], "activeHomeKit");
|
||||
assert_eq!(kits["itemData"][1]["itemState"], "activeAwayKit");
|
||||
assert_eq!(kits["itemData"][0]["cardassetid"], 35);
|
||||
assert_eq!(kits["itemData"][0]["teamid"], 21);
|
||||
|
||||
let (player_response, player_log) = handle_club("type=player", &deps);
|
||||
let players: Value = serde_json::from_slice(&player_response.body).unwrap();
|
||||
assert_eq!(player_log.total, 1);
|
||||
assert_eq!(players["itemData"].as_array().unwrap().len(), 1);
|
||||
assert_eq!(players["itemData"][0]["itemType"], "player");
|
||||
}
|
||||
|
||||
// ── /club served from Core ─────────────────────────────────────────────────
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user