11use anyhow:: { Ok , Result , bail} ;
22use egui:: Context ;
3- use log:: debug;
4- use maxima:: core:: LockedMaxima ;
5- use std:: sync:: mpsc:: Sender ;
3+ use log:: { debug, info } ;
4+ use maxima:: { core:: { service_layer :: { ServiceGame , ServiceGameImagesRequestBuilder , ServiceLayerClient , SERVICE_REQUEST_GAMEIMAGES } , LockedMaxima } , util :: native :: maxima_dir } ;
5+ use std:: { fs , sync:: mpsc:: Sender } ;
66
77use crate :: {
8- bridge_thread:: { InteractThreadGameListResponse , MaximaLibResponse } ,
9- GameDetailsWrapper , GameInfo , GameUIImagesWrapper ,
8+ bridge_thread:: { InteractThreadGameListResponse , MaximaLibResponse } , ui_image:: UIImageCacheLoaderCommand , GameDetailsWrapper , GameInfo
109} ;
1110
11+ async fn get_preferred_hero_image ( images : & Option < ServiceGame > ) -> Option < String > {
12+ if images. is_none ( ) {
13+ return None ;
14+ }
15+
16+ let key_art = images. as_ref ( ) . unwrap ( ) . key_art ( ) ;
17+ if key_art. is_none ( ) {
18+ return None ;
19+ }
20+
21+ let key_art = key_art. as_ref ( ) . unwrap ( ) ;
22+
23+ debug ! ( "{:?}" , key_art) ;
24+ if let Some ( img) = key_art. aspect_10x3_image ( ) {
25+ return Some ( img. path ( ) . clone ( ) ) ;
26+ }
27+
28+ if let Some ( img) = key_art. aspect_2x1_image ( ) {
29+ return Some ( img. path ( ) . clone ( ) ) ;
30+ }
31+
32+ if let Some ( img) = key_art. aspect_16x9_image ( ) {
33+ return Some ( img. path ( ) . clone ( ) ) ;
34+ }
35+
36+ None
37+ }
38+
39+ fn get_logo_image ( images : & Option < ServiceGame > ) -> Option < String > {
40+ if images. is_none ( ) {
41+ return None ;
42+ }
43+
44+ let logo_set = images. as_ref ( ) . unwrap ( ) . primary_logo ( ) ;
45+ if logo_set. is_none ( ) {
46+ return None ;
47+ }
48+
49+ let largest_logo = logo_set. as_ref ( ) . unwrap ( ) . largest_image ( ) ;
50+ if largest_logo. is_none ( ) {
51+ return None ;
52+ }
53+
54+ Some ( largest_logo. as_ref ( ) . unwrap ( ) . path ( ) . to_string ( ) )
55+ }
56+
57+ async fn handle_images ( slug : String , locale : String , has_hero : bool , has_logo : bool , channel : Sender < UIImageCacheLoaderCommand > , service_layer : ServiceLayerClient ) -> Result < ( ) > {
58+ debug ! ( "handling image downloads for {}" , & slug) ;
59+ let images = service_layer
60+ . request ( SERVICE_REQUEST_GAMEIMAGES , ServiceGameImagesRequestBuilder :: default ( )
61+ . should_fetch_context_image ( !has_logo)
62+ . should_fetch_backdrop_images ( !has_hero)
63+ . game_slug ( slug. clone ( ) )
64+ . locale ( locale. clone ( ) )
65+ . build ( ) ?) . await ?;
66+
67+ if !has_hero {
68+ if let Some ( hero) = get_preferred_hero_image ( & images) . await {
69+ channel. send ( UIImageCacheLoaderCommand :: ProvideRemote ( crate :: ui_image:: UIImageType :: Hero ( slug. clone ( ) ) , hero) ) . unwrap ( )
70+ }
71+ }
72+
73+ if !has_logo {
74+ if let Some ( logo) = get_logo_image ( & images) {
75+ channel. send ( UIImageCacheLoaderCommand :: ProvideRemote ( crate :: ui_image:: UIImageType :: Logo ( slug) , logo) ) ?
76+ } else {
77+ channel. send ( UIImageCacheLoaderCommand :: Stub ( crate :: ui_image:: UIImageType :: Logo ( slug) ) ) ?
78+ }
79+ }
80+
81+ Ok ( ( ) )
82+ }
83+
84+
1285pub async fn get_games_request (
1386 maxima_arc : LockedMaxima ,
1487 channel : Sender < MaximaLibResponse > ,
88+ channel1 : Sender < UIImageCacheLoaderCommand > ,
1589 ctx : & Context ,
1690) -> Result < ( ) > {
1791 debug ! ( "recieved request to load games" ) ;
1892 let mut maxima = maxima_arc. lock ( ) . await ;
93+ let service_layer = maxima. service_layer ( ) . clone ( ) ;
94+ let locale = maxima. locale ( ) . short_str ( ) . to_owned ( ) ;
1995 let logged_in = maxima. auth_storage ( ) . lock ( ) . await . current ( ) . is_some ( ) ;
2096 if !logged_in {
2197 bail ! ( "Ignoring request to load games, not logged in." ) ;
2298 }
2399
100+
24101 let owned_games = maxima. mut_library ( ) . games ( ) . await ;
25102
103+
26104 if owned_games. len ( ) <= 0 {
27105 return Ok ( ( ) ) ;
28106 }
29107
30108 for game in owned_games {
109+ info ! ( "processing {}" , & game. base_offer( ) . slug( ) ) ;
31110 let game_info = GameInfo {
32111 slug : game. base_offer ( ) . slug ( ) . to_string ( ) ,
33112 offer : game. base_offer ( ) . offer ( ) . offer_id ( ) . to_string ( ) ,
34113 name : game. name ( ) ,
35- images : GameUIImagesWrapper :: Unloaded ,
36114 details : GameDetailsWrapper :: Unloaded ,
37115 dlc : game. extra_offers ( ) . clone ( ) ,
38116 installed : game. base_offer ( ) . installed ( ) . await ,
39117 has_cloud_saves : game. base_offer ( ) . offer ( ) . has_cloud_save ( ) ,
40118 } ;
119+ let slug = game_info. slug . clone ( ) ;
41120 let settings = crate :: GameSettings {
42121 //TODO: eventually support cloud saves, the option is here for that but for now, keep it disabled in ui!
43122 cloud_saves : true ,
@@ -49,6 +128,30 @@ pub async fn get_games_request(
49128 settings
50129 } ) ;
51130 channel. send ( res) ?;
131+
132+ let game_hero = maxima_dir ( )
133+ . unwrap ( )
134+ . join ( "cache/ui/images/" )
135+ . join ( & slug)
136+ . join ( "hero.jpg" ) ;
137+ let game_logo = maxima_dir ( )
138+ . unwrap ( )
139+ . join ( "cache/ui/images/" )
140+ . join ( & slug)
141+ . join ( "logo.png" ) ;
142+ let has_hero = fs:: metadata ( & game_hero) . is_ok ( ) ;
143+ let has_logo = fs:: metadata ( & game_logo) . is_ok ( ) ;
144+
145+ if !has_hero || !has_logo {
146+ //we're like 20 tasks deep i swear but this shit's gonna be real fast, trust
147+ let slug_send = slug. clone ( ) ;
148+ let locale_send = locale. clone ( ) ;
149+ let channel_send = channel1. clone ( ) ;
150+ let service_layer_send = service_layer. clone ( ) ;
151+ tokio:: task:: spawn ( async move { handle_images ( slug_send, locale_send, has_hero, has_logo, channel_send, service_layer_send) . await } ) ;
152+ tokio:: task:: yield_now ( ) . await ;
153+
154+ }
52155
53156 egui:: Context :: request_repaint ( & ctx) ;
54157 }
0 commit comments