2525import lol .hyper .customlauncher .tools .JSONUtils ;
2626import org .apache .logging .log4j .LogManager ;
2727import org .apache .logging .log4j .Logger ;
28+ import org .json .JSONArray ;
2829import org .json .JSONObject ;
2930
3031import javax .swing .Timer ;
3637import java .time .Instant ;
3738import java .time .LocalDateTime ;
3839import java .time .ZoneId ;
40+ import java .time .ZonedDateTime ;
3941import java .time .temporal .ChronoUnit ;
4042import java .util .List ;
4143import java .util .*;
@@ -48,7 +50,15 @@ public class InvasionTrackerPanel extends JPanel {
4850 /**
4951 * All current invasions saved locally.
5052 */
51- private final Map <String , Invasion > invasions = new HashMap <>();
53+ private final Map <Integer , Invasion > invasions = new HashMap <>();
54+ /**
55+ * Cog ID map.
56+ */
57+ private final Map <Integer , String > cogMap = new HashMap <>();
58+ /**
59+ * District ID map.
60+ */
61+ private final Map <Integer , String > districtMap = new HashMap <>();
5262 /**
5363 * The table for displaying invasions.
5464 */
@@ -121,6 +131,23 @@ public InvasionTrackerPanel(ConfigHandler configHandler) {
121131 timer .setDelay (500 );
122132 timer .start ();
123133
134+ // fetch ToonHQ's data
135+ logger .info ("Fetching ToonHQ district data..." );
136+ JSONArray districts = JSONUtils .requestJSONArray ("https://toonhq.org/api/districts/" );
137+ logger .info ("Fetching ToonHQ cog data..." );
138+ JSONArray cogs = JSONUtils .requestJSONArray ("https://toonhq.org/api/cogs/" );
139+
140+ if (districts == null || cogs == null ) {
141+ logger .info ("No districts or cogs found" );
142+ logger .info ("Cog data: {}" , cogs );
143+ logger .info ("District data: {}" , districts );
144+ isDown = true ;
145+ return ;
146+ }
147+
148+ updateDistrictMap (districts );
149+ updateCogMap (cogs );
150+
124151 // start the timer for reading the API
125152 startInvasionRefresh ();
126153 }
@@ -132,7 +159,7 @@ private void updateInvasionListGUI() {
132159 invasionTableModel .setRowCount (0 );
133160 // create a separate list of all the invasions
134161 List <Invasion > sortedInvasions = new ArrayList <>();
135- for (Map .Entry <String , Invasion > entry : invasions .entrySet ()) {
162+ for (Map .Entry <Integer , Invasion > entry : invasions .entrySet ()) {
136163 sortedInvasions .add (entry .getValue ());
137164 }
138165 // sort this new list alphabetically
@@ -149,7 +176,7 @@ private void updateInvasionListGUI() {
149176 timeLeft = "Mega Invasion" ;
150177 } else {
151178 cogs = invasion .getCogsDefeated () + "/" + invasion .getCogsTotal ();
152- timeLeftSeconds = ChronoUnit .SECONDS .between (LocalDateTime .now (), invasion .endTime );
179+ timeLeftSeconds = ChronoUnit .SECONDS .between (LocalDateTime .now (), invasion .getEndTime () );
153180 if (timeLeftSeconds <= 0 ) {
154181 timeLeft = "Ending soon..." ;
155182 } else {
@@ -213,7 +240,7 @@ public void showNotification(Invasion invasion, boolean newInvasion) {
213240 * Make the request and handle the information it returns.
214241 */
215242 private void makeRequest () {
216- String INVASION_URL = "https://api.toon.plus/ invasions" ;
243+ String INVASION_URL = "https://toonhq.org/api/ invasions/1/ " ;
217244 JSONObject lastResult = JSONUtils .requestJSON (INVASION_URL );
218245
219246 // if the request failed, stop the task
@@ -225,63 +252,111 @@ private void makeRequest() {
225252
226253 isDown = false ; // make sure to set this to false since we can read the API
227254
228- // iterate through each of the invasions (separate JSONs)
229- Iterator < String > keys = lastResult .keys ( );
230- while ( keys . hasNext () ) {
231- String key = keys . next ( );
232- // each key is stored as district/cogType
233- String district = key . substring ( 0 , key . indexOf ( '/' ) );
234- // if we do not have that invasion stored, create a new invasion object
235- // and add it to the list
236- if (! invasions . containsKey ( district )) {
237- JSONObject temp = lastResult . getJSONObject ( key );
238- String cogType = temp . getString ( "Type" );
239- int cogsDefeated = temp . getInt ( "CurrentProgress" );
240- int cogsTotal = temp . getInt ( "MaxProgress" );
241- boolean megaInvasion = temp . getBoolean ( "MegaInvasion" );
242- Invasion newInvasion = new Invasion (district , cogType , cogsTotal , megaInvasion );
255+ // iterate through each of the invasions
256+ JSONArray invasionsArray = lastResult .getJSONArray ( "invasions" );
257+ for ( int i = 0 ; i < invasionsArray . length (); i ++ ) {
258+ JSONObject invasion = invasionsArray . getJSONObject ( i );
259+ int districtId = invasion . getInt ( " district" );
260+ String districtName = districtMap . get ( districtId );
261+ String cogType = cogMap . get ( invasion . getInt ( "cog" ));
262+ int cogsTotal = invasion . getInt ( "total" );
263+ int cogsDefeated = invasion . getInt ( "defeated" );
264+ double defeatRate = invasion . getDouble ( "defeat_rate" );
265+
266+ // this is a new invasion that we are not tracking currently
267+ if (! invasions . containsKey ( districtId )) {
268+ // store the information about it
269+ Invasion newInvasion = new Invasion (districtName , cogType , cogsTotal , false );
243270 newInvasion .updateCogsDefeated (cogsDefeated );
244- newInvasion .endTime = Instant .parse (temp .getString ("EstimatedCompletion" )).atZone (ZoneId .systemDefault ());
245- invasions .put (district , newInvasion );
271+ newInvasion .setDefeatRate (defeatRate );
272+ invasions .put (districtId , newInvasion );
273+
274+ // show notification for it
246275 if (configHandler .showCogInvasionNotifications ()) {
247276 showNotification (newInvasion , true );
248277 }
249- logger .info ("Tracking new invasion for {}. Cogs: {}/{}. ETA: {}" , district , cogsDefeated , cogsTotal , newInvasion .endTime );
278+
279+ // calculate how long it has left (estimate)
280+ double secondsRemaining = (cogsTotal - cogsDefeated ) / defeatRate ;
281+ ZonedDateTime estimatedEnd = Instant .now ().plusSeconds ((long ) secondsRemaining ).atZone (ZoneId .systemDefault ());
282+ newInvasion .setEndTime (estimatedEnd );
283+
284+ logger .info ("Tracking new invasion for {}. Cogs: {}/{}" , districtName , cogsDefeated , cogsTotal );
250285 } else {
251- // if we already have it saved, update the information that we have saved already
252- // we want to update the total cogs defeated and the end time
253- Invasion tempInv = invasions . get ( district );
254- JSONObject temp = lastResult . getJSONObject ( key );
255- // ignore mega invasion cog count
256- if (! temp . getBoolean ( "MegaInvasion" )) {
257- int cogsDefeated = temp . getInt ( "CurrentProgress" ) ;
258- logger . info ( "Updating invasion details for {}. Cogs: {} -> {}. ETA: {}" , district , tempInv . getCogsDefeated (), cogsDefeated , tempInv . endTime );
259- tempInv .updateCogsDefeated ( cogsDefeated );
260- tempInv . endTime = Instant . parse ( temp . getString ( "EstimatedCompletion" )). atZone ( ZoneId . systemDefault ());
261- }
286+ // update the information for the invasion
287+ Invasion tempInv = invasions . get ( districtId );
288+ tempInv . updateCogsDefeated ( cogsDefeated );
289+ tempInv . setDefeatRate ( defeatRate );
290+
291+ // calculate how long it has left (estimate)
292+ double secondsRemaining = ( cogsTotal - cogsDefeated ) / defeatRate ;
293+ ZonedDateTime estimatedEnd = Instant . now (). plusSeconds (( long ) secondsRemaining ). atZone ( ZoneId . systemDefault () );
294+ tempInv .setEndTime ( estimatedEnd );
295+
296+ logger . info ( "Updating invasion for {}. Cogs: {}/{}" , districtName , cogsDefeated , cogsTotal );
262297 }
263298 }
264299
265300 // we look at the current invasion list and see if any invasions
266301 // are not on the invasion JSON (aka that invasion is gone)
267- Iterator <Map .Entry <String , Invasion >> it = invasions .entrySet ().iterator ();
302+ Iterator <Map .Entry <Integer , Invasion >> it = invasions .entrySet ().iterator ();
268303 while (it .hasNext ()) {
269- Map .Entry <String , Invasion > pair = it .next ();
270- String cogType = pair .getValue ().getCogType ();
271- String district = pair .getKey ();
272- // district/cog name
273- String key = district + "/" + cogType ;
274- // if the invasion no longer exists on the API, remove it from our list
275- if (!lastResult .has (key )) {
304+ Map .Entry <Integer , Invasion > pair = it .next ();
305+ boolean isOnApi = false ;
306+ for (int i = 0 ; i < invasionsArray .length (); i ++) {
307+ JSONObject invasion = invasionsArray .getJSONObject (i );
308+ int districtId = invasion .getInt ("district" );
309+ if (pair .getKey ().equals (districtId )) {
310+ isOnApi = true ;
311+ }
312+ }
313+
314+ if (!isOnApi ) {
276315 String savedDuration = (System .nanoTime () - pair .getValue ().getCacheStartTime ()) / 1000000000 + " seconds." ;
277316 if (configHandler .showCogInvasionNotifications ()) {
278317 showNotification (pair .getValue (), false );
279318 }
280319 it .remove ();
281- logger .info ("Removing saved invasion for {}. Tracked for {}" , district , savedDuration );
320+ logger .info ("Removing saved invasion for {}. Tracked for {}" , pair . getKey () , savedDuration );
282321 }
283322 }
284323 runs ++;
285324 lastFetched = System .currentTimeMillis ();
286325 }
326+
327+ /**
328+ * Update the district ID map from ToonHQ.
329+ *
330+ * @param data The JSON data from their API.
331+ */
332+ private void updateDistrictMap (JSONArray data ) {
333+ for (int i = 0 ; i < data .length (); i ++) {
334+ JSONObject district = data .getJSONObject (i );
335+ int gameId = district .getInt ("game" );
336+ // make sure we pull TTR districts (id = 1)
337+ if (gameId == 1 ) {
338+ int id = district .getInt ("id" );
339+ String name = district .getString ("name" );
340+ districtMap .put (id , name );
341+ }
342+ }
343+ }
344+
345+ /**
346+ * Update the cog ID map from ToonHQ.
347+ *
348+ * @param data The JSON data from their API.
349+ */
350+ private void updateCogMap (JSONArray data ) {
351+ for (int i = 0 ; i < data .length (); i ++) {
352+ JSONObject cog = data .getJSONObject (i );
353+ int gameId = cog .getInt ("game" );
354+ // make sure we pull TTR cogs (id = 1)
355+ if (gameId == 1 ) {
356+ int id = cog .getInt ("id" );
357+ String name = cog .getString ("name" );
358+ cogMap .put (id , name );
359+ }
360+ }
361+ }
287362}
0 commit comments