@@ -14,6 +14,11 @@ class RPCNGame
1414 private string $ defaultIcon ;
1515 private string $ pic1JsonPath ;
1616 private string $ pic1BasePath ;
17+ private string $ trophiesJsonPath ;
18+ private string $ trophiesIconBasePath ;
19+ private string $ trophiesSetsPath ;
20+ private int $ trophiesCacheTime ;
21+ private array $ raritySettings ;
1722
1823 public bool $ has_error = false ;
1924 public string $ gameTitle = 'Unknown Game ' ;
@@ -30,6 +35,9 @@ class RPCNGame
3035 public array $ chartDataHourly = [];
3136 public array $ chartDataDaily = [];
3237 public array $ chartDataAllTime = [];
38+ public bool $ hasTrophies = false ;
39+ public int $ totalTrophies = 0 ;
40+ public array $ trophies = [];
3341
3442 public function __construct (
3543 string $ cacheDir ,
@@ -44,21 +52,31 @@ public function __construct(
4452 string $ iconBasePath ,
4553 string $ defaultIcon ,
4654 string $ pic1JsonPath = '' ,
47- string $ pic1BasePath = ''
55+ string $ pic1BasePath = '' ,
56+ string $ trophiesJsonPath = '' ,
57+ string $ trophiesIconBasePath = '' ,
58+ string $ trophiesSetsPath = '' ,
59+ int $ trophiesCacheTime = 3600 ,
60+ array $ raritySettings = []
4861 ) {
49- $ this ->cacheDir = rtrim ($ cacheDir , '/ ' ) . '/ ' ;
50- $ this ->cacheTime = $ cacheTime ;
51- $ this ->maxDisplayRows = $ maxDisplayRows ;
52- $ this ->badwordsFile = $ badwordsFile ;
53- $ this ->blacklistFile = $ blacklistFile ;
54- $ this ->violationLog = $ violationLog ;
55- $ this ->apiBase = rtrim ($ apiBase , '/ ' );
56- $ this ->parsersPath = rtrim ($ parsersPath , '/ ' ) . '/ ' ;
57- $ this ->logFile = $ logFile ;
58- $ this ->iconBasePath = rtrim ($ iconBasePath , '/ ' ) . '/ ' ;
59- $ this ->defaultIcon = $ defaultIcon ;
60- $ this ->pic1JsonPath = $ pic1JsonPath ;
61- $ this ->pic1BasePath = rtrim ($ pic1BasePath , '/ ' ). '/ ' ;
62+ $ this ->cacheDir = rtrim ($ cacheDir , '/ ' ) . '/ ' ;
63+ $ this ->cacheTime = $ cacheTime ;
64+ $ this ->maxDisplayRows = $ maxDisplayRows ;
65+ $ this ->badwordsFile = $ badwordsFile ;
66+ $ this ->blacklistFile = $ blacklistFile ;
67+ $ this ->violationLog = $ violationLog ;
68+ $ this ->apiBase = rtrim ($ apiBase , '/ ' );
69+ $ this ->parsersPath = rtrim ($ parsersPath , '/ ' ) . '/ ' ;
70+ $ this ->logFile = $ logFile ;
71+ $ this ->iconBasePath = rtrim ($ iconBasePath , '/ ' ) . '/ ' ;
72+ $ this ->defaultIcon = $ defaultIcon ;
73+ $ this ->pic1JsonPath = $ pic1JsonPath ;
74+ $ this ->pic1BasePath = rtrim ($ pic1BasePath , '/ ' ) . '/ ' ;
75+ $ this ->trophiesJsonPath = $ trophiesJsonPath ;
76+ $ this ->trophiesIconBasePath = rtrim ($ trophiesIconBasePath , '/ ' ) . '/ ' ;
77+ $ this ->trophiesSetsPath = rtrim ($ trophiesSetsPath , '/ ' ) . '/ ' ;
78+ $ this ->trophiesCacheTime = $ trophiesCacheTime ;
79+ $ this ->raritySettings = $ raritySettings ;
6280 }
6381
6482 private function log_error (string $ message ): void
@@ -154,6 +172,83 @@ private function fetch_api(string $url, string $cacheFile): string
154172 return '' ;
155173 }
156174
175+ private function loadTrophies (string $ commId ): void
176+ {
177+ $ cacheFile = $ this ->cacheDir . "trophies_ {$ commId }.json " ;
178+ $ url = $ this ->apiBase . "/trophy/ " . rawurlencode ($ commId );
179+
180+ $ json = $ this ->fetch_api ($ url , $ cacheFile );
181+ if ($ json === '' ) return ;
182+
183+ $ apiData = json_decode ($ json , true );
184+ if (!is_array ($ apiData )) return ;
185+
186+ $ localFile = $ this ->trophiesSetsPath . $ commId . '.json ' ;
187+ if (!file_exists ($ localFile )) return ;
188+
189+ $ localData = json_decode (@file_get_contents ($ localFile ), true );
190+ if (!is_array ($ localData ) || empty ($ localData ['trophies ' ])) return ;
191+
192+ $ this ->hasTrophies = true ;
193+ $ this ->totalTrophies = (int )($ localData ['totalItemCount ' ] ?? count ($ localData ['trophies ' ]));
194+
195+ $ uniquePlayers = (int )($ apiData ['uniquePlayers ' ] ?? 0 );
196+ $ earnerMap = [];
197+ foreach ($ apiData ['trophies ' ] ?? [] as $ t )
198+ {
199+ $ earnerMap [(int )$ t ['trophyId ' ]] = (int )$ t ['earnerCount ' ];
200+ }
201+
202+ $ iconMap = [];
203+ if ($ this ->trophiesJsonPath !== '' && file_exists ($ this ->trophiesJsonPath ))
204+ {
205+ $ mapData = json_decode (@file_get_contents ($ this ->trophiesJsonPath ), true );
206+ if (isset ($ mapData [$ commId ]))
207+ {
208+ $ iconMap = $ mapData [$ commId ];
209+ }
210+ }
211+
212+ foreach ($ localData ['trophies ' ] as $ t )
213+ {
214+ $ trophyId = (int )$ t ['trophyId ' ];
215+ $ tId = (string )$ trophyId ;
216+
217+ $ iconHash = $ iconMap [$ tId ] ?? '' ;
218+ $ iconUrl = $ iconHash !== '' ? $ this ->trophiesIconBasePath . $ iconHash . '.png ' : $ this ->defaultIcon ;
219+
220+ $ earnerCount = $ earnerMap [$ trophyId ] ?? 0 ;
221+ $ pct = ($ uniquePlayers > 0 )
222+ ? round ($ earnerCount / $ uniquePlayers * 100 , 2 )
223+ : 0.0 ;
224+
225+ $ rarity = 'Common ' ;
226+ $ rarityColor = '#a0aec0 ' ;
227+ foreach ($ this ->raritySettings as $ setting )
228+ {
229+ if (($ pct == 0.0 && $ setting ['max_pct ' ] == 0.0 ) || ($ pct > 0.0 && $ pct <= $ setting ['max_pct ' ]))
230+ {
231+ $ rarity = $ setting ['name ' ];
232+ $ rarityColor = $ setting ['color ' ];
233+ break ;
234+ }
235+ }
236+
237+ $ this ->trophies [] = [
238+ 'id ' => $ trophyId ,
239+ 'hidden ' => (bool )($ t ['trophyHidden ' ] ?? false ),
240+ 'type ' => $ t ['trophyType ' ] ?? 'unknown ' ,
241+ 'name ' => $ t ['trophyName ' ] ?? 'Unknown ' ,
242+ 'detail ' => $ t ['trophyDetail ' ] ?? '' ,
243+ 'earnerCount ' => $ earnerCount ,
244+ 'percentage ' => $ pct ,
245+ 'rarity ' => $ rarity ,
246+ 'rarityColor ' => $ rarityColor ,
247+ 'icon ' => $ iconUrl ,
248+ ];
249+ }
250+ }
251+
157252 // Leaderboard ajax
158253 public function handle_ajax (string $ commId , ?string $ boardIdParam ): void
159254 {
@@ -383,6 +478,8 @@ public function load_page_data(string $commId, RPCNStats $stats, ?mysqli $db): v
383478 $ this ->boards = is_array ($ loaded ) ? ($ loaded ['config ' ]['names ' ] ?? []) : [];
384479 }
385480
481+ $ this ->loadTrophies ($ commId );
482+
386483 // Database stats
387484 if ($ db === null ) return ;
388485
@@ -729,7 +826,12 @@ private function loadDbStats(mysqli $db, string $commId, RPCNStats $stats): void
729826 $ icon_base_path ,
730827 $ default_icon ,
731828 $ pic1_json ,
732- $ pic1_base_path
829+ $ pic1_base_path ,
830+ $ trophies_json ?? '' ,
831+ $ trophies_icon_base_path ?? '' ,
832+ $ trophies_sets_path ?? '' ,
833+ (int )($ trophies_cache_time ?? 3600 ),
834+ $ trophies_rarity_settings ?? []
733835);
734836
735837if ($ isAjax )
0 commit comments