@@ -20,7 +20,6 @@ use image::{DynamicImage, ImageFormat};
2020use img_parts:: webp:: WebP ;
2121use reqwest:: { Client , StatusCode } ;
2222use serde:: Deserialize ;
23- use tokio:: task:: spawn_blocking;
2423
2524use crate :: { models:: VehicleAvailability , prelude:: * , tankopedia:: dvpl:: Dvpl } ;
2625
@@ -48,17 +47,12 @@ impl BundleTankopedia {
4847 pub async fn run ( self ) -> Result {
4948 let client = Client :: new ( ) ;
5049
51- let translations: HashMap < String , String > = {
52- let path = self . data_path . join ( "Strings" ) . join ( "en.yaml.dvpl" ) ;
53- serde_yaml:: from_reader ( Dvpl :: read ( path) . await ?. into_reader ( ) . await ?) ?
54- } ;
50+ let vehicles_path = self . data_path . join ( "XML" ) . join ( "item_defs" ) . join ( "vehicles" ) ;
51+ let parameters_path = self . data_path . join ( "3d" ) . join ( "Tanks" ) . join ( "Parameters" ) ;
5552
5653 static NATIONS : [ & str ; 9 ] = [
5754 "germany" , "usa" , "china" , "france" , "uk" , "japan" , "other" , "european" , "ussr" ,
5855 ] ;
59-
60- let vehicles_path = self . data_path . join ( "XML" ) . join ( "item_defs" ) . join ( "vehicles" ) ;
61- let parameters_path = self . data_path . join ( "3d" ) . join ( "Tanks" ) . join ( "Parameters" ) ;
6256 let mut vehicles: Vec < _ > = stream:: iter ( NATIONS )
6357 . then ( |nation| {
6458 self . load_nation ( vehicles_path. join ( nation) , parameters_path. join ( nation) , & client)
@@ -70,6 +64,11 @@ impl BundleTankopedia {
7064 // Sort the vehicles for pretty Git diffs when new vehicles are added.
7165 vehicles. sort_unstable_by_key ( |( _, vehicle, _) | vehicle. tank_id ) ;
7266
67+ let translations: HashMap < String , String > = {
68+ let path = self . data_path . join ( "Strings" ) . join ( "en.yaml.dvpl" ) ;
69+ serde_yaml:: from_reader ( Dvpl :: read ( path) . await ?. into_reader ( ) . await ?) ?
70+ } ;
71+
7372 let mut module = File :: options ( )
7473 . write ( true )
7574 . create ( true )
@@ -78,21 +77,88 @@ impl BundleTankopedia {
7877 let vendored_path = Path :: new ( "src" ) . join ( "tankopedia" ) . join ( "vendored" ) ;
7978 create_dir_all ( & vendored_path) ?;
8079
80+ if !self . skip_images {
81+ Self :: save_images ( & vendored_path, & vehicles) ?;
82+ }
83+
8184 writeln ! (
8285 & mut module,
8386 "//! Auto-generated tankopedia, to update run `blitz-tanks bundle-tankopedia`." ,
8487 ) ?;
8588 writeln ! ( & mut module) ?;
86- writeln ! ( & mut module, "use phf::{{phf_map, Map}};" ) ?;
87- writeln ! ( & mut module) ?;
8889 writeln ! (
8990 & mut module,
9091 "use crate::models::{{TankId, Vehicle, VehicleAvailability::*, VehicleType::*}};"
9192 ) ?;
9293 writeln ! ( & mut module) ?;
93- writeln ! ( & mut module, "pub static TANKOPEDIA: Map<u16, Vehicle> = phf_map! {{" ) ?;
94+ Self :: write_all_tank_ids ( & mut module, & vehicles) ?;
95+ writeln ! ( & mut module) ?;
96+ Self :: write_is_known_tank_id_function ( & mut module, & vehicles) ?;
97+ writeln ! ( & mut module) ?;
98+ Self :: write_get_vehicle_function ( & mut module, & vehicles, & translations) ?;
99+
100+ Ok ( ( ) )
101+ }
102+
103+ #[ instrument( skip_all) ]
104+ fn save_images (
105+ vendored_path : & Path ,
106+ vehicles : & [ ( VehicleXmlDetails , VehicleJsonDetails , DynamicImage ) ] ,
107+ ) -> Result {
108+ info ! ( "📦 Saving images…" ) ;
94109 for ( xml_details, json_details, image) in vehicles {
95- info ! ( json_details. tank_id, json_details. user_string, "📦 Saving…" ) ;
110+ info ! ( json_details. tank_id, xml_details. user_string_key) ;
111+ let path = vendored_path. join ( json_details. tank_id . to_string ( ) ) . with_extension ( "webp" ) ;
112+ image. save ( path) ?;
113+ }
114+ Ok ( ( ) )
115+ }
116+
117+ #[ instrument( skip_all) ]
118+ fn write_all_tank_ids (
119+ mut writer : impl Write ,
120+ vehicles : & [ ( VehicleXmlDetails , VehicleJsonDetails , DynamicImage ) ] ,
121+ ) -> Result {
122+ info ! ( "📦 Writing tank IDs…" ) ;
123+ writeln ! ( writer, "pub static ALL_TANK_IDS: [TankId; {}] = [" , vehicles. len( ) ) ?;
124+ for ( _, json_details, _) in vehicles {
125+ writeln ! ( writer, " TankId({})," , json_details. tank_id) ?;
126+ }
127+ writeln ! ( writer, "];" ) ?;
128+ Ok ( ( ) )
129+ }
130+
131+ #[ instrument( skip_all) ]
132+ fn write_is_known_tank_id_function (
133+ mut writer : impl Write ,
134+ vehicles : & [ ( VehicleXmlDetails , VehicleJsonDetails , DynamicImage ) ] ,
135+ ) -> Result {
136+ info ! ( "📦 Writing `is_known_tank_id()`…" ) ;
137+ writeln ! ( writer, "pub const fn is_known_tank_id(tank_id: TankId) -> bool {{" ) ?;
138+ writeln ! ( writer, " matches!(" ) ?;
139+ writeln ! ( writer, " tank_id," ) ?;
140+ for ( i, ( _, json_details, _) ) in vehicles. iter ( ) . enumerate ( ) {
141+ if i != 0 {
142+ writeln ! ( writer, " | TankId({})" , json_details. tank_id) ?;
143+ } else {
144+ writeln ! ( writer, " TankId({})" , json_details. tank_id) ?;
145+ }
146+ }
147+ writeln ! ( writer, " )" ) ?;
148+ writeln ! ( writer, "}}" ) ?;
149+ Ok ( ( ) )
150+ }
151+
152+ #[ instrument( skip_all) ]
153+ fn write_get_vehicle_function (
154+ mut writer : impl Write ,
155+ vehicles : & [ ( VehicleXmlDetails , VehicleJsonDetails , DynamicImage ) ] ,
156+ translations : & HashMap < String , String > ,
157+ ) -> Result {
158+ info ! ( "📦 Writing `get_vehicle()`…" ) ;
159+ writeln ! ( writer, "pub const fn get_vehicle(tank_id: TankId) -> Option<Vehicle> {{" ) ?;
160+ writeln ! ( writer, " match tank_id {{" ) ?;
161+ for ( xml_details, json_details, _) in vehicles {
96162 let short_user_string_key = xml_details. short_user_string_key ( ) ;
97163 let name = translations
98164 // Take the short name from the client.
@@ -102,31 +168,26 @@ impl BundleTankopedia {
102168 // Fall back to the long name from the API.
103169 . unwrap_or ( & json_details. user_string ) ;
104170
105- writeln ! ( & mut module , " {}_u16 => Vehicle {{" , json_details. tank_id) ?;
106- writeln ! ( & mut module , " tank_id: TankId({:?})," , json_details. tank_id) ?;
107- writeln ! ( & mut module , " name: {:?}," , name) ?;
108- writeln ! ( & mut module , " tier: {:?}," , json_details. tier) ?;
109- writeln ! ( & mut module , " type_: {:?}," , json_details. type_) ?;
171+ writeln ! ( writer , " TankId({}) => Some( Vehicle {{" , json_details. tank_id) ?;
172+ writeln ! ( writer , " tank_id: TankId({:?})," , json_details. tank_id) ?;
173+ writeln ! ( writer , " name: {:?}," , name) ?;
174+ writeln ! ( writer , " tier: {:?}," , json_details. tier) ?;
175+ writeln ! ( writer , " type_: {:?}," , json_details. type_) ?;
110176 writeln ! (
111- & mut module ,
112- " availability: {:?}," ,
113- VehicleAvailability :: from( & json_details) ,
177+ writer ,
178+ " availability: {:?}," ,
179+ VehicleAvailability :: from( json_details) ,
114180 ) ?;
115181 writeln ! (
116- & mut module ,
117- r#" image_content: include_bytes!("vendored/{}.webp"),"# ,
182+ writer ,
183+ r#" image_content: include_bytes!("vendored/{}.webp"),"# ,
118184 json_details. tank_id
119185 ) ?;
120- writeln ! ( & mut module, r#" }},"# ) ?;
121-
122- if !self . skip_images {
123- let path =
124- vendored_path. join ( json_details. tank_id . to_string ( ) ) . with_extension ( "webp" ) ;
125- spawn_blocking ( move || image. save ( path) ) . await ??;
126- }
186+ writeln ! ( writer, r#" }}),"# ) ?;
127187 }
128- writeln ! ( & mut module, "}};" ) ?;
129-
188+ writeln ! ( writer, " _ => None," ) ?;
189+ writeln ! ( writer, " }}" ) ?;
190+ writeln ! ( writer, "}}" ) ?;
130191 Ok ( ( ) )
131192 }
132193
@@ -207,7 +268,7 @@ impl BundleTankopedia {
207268 . await ?;
208269 let parameters: VehicleParameters =
209270 serde_yaml:: from_reader ( dvpl. into_reader ( ) . await ?) ?;
210- self . extract_vehicle_icon ( & parameters. resources_path . big_icon_path ) . await ?
271+ self . extract_vehicle_icon ( & parameters. resource_paths . big_icon_path ) . await ?
211272 }
212273 } ;
213274 let Some ( image) = image else {
@@ -364,11 +425,11 @@ enum VehicleType {
364425#[ derive( Deserialize ) ]
365426struct VehicleParameters {
366427 #[ serde( rename = "resourcesPath" ) ]
367- resources_path : ResourcesPath ,
428+ resource_paths : ResourcePaths ,
368429}
369430
370431#[ derive( Deserialize ) ]
371- struct ResourcesPath {
432+ struct ResourcePaths {
372433 /// Path to the icon resource, for example: `~res:/Gfx/UI/BigTankIcons/ussr-KV_1s_BP`.
373434 #[ serde( rename = "bigIconPath" ) ]
374435 big_icon_path : String ,
0 commit comments