1010import dev .koifysh .archipelago .network .client .*;
1111import org .apache .hc .core5 .net .URIBuilder ;
1212
13+ import com .google .gson .Gson ;
14+
1315import java .io .*;
1416import java .net .URI ;
1517import java .net .URISyntaxException ;
18+ import java .nio .file .Path ;
19+ import java .nio .file .Paths ;
1620import java .util .*;
1721import java .util .logging .Logger ;
1822
1923public abstract class Client {
2024
2125 private final static Logger LOGGER = Logger .getLogger (Client .class .getName ());
2226
23- private final String dataPackageLocation = "./APData/DataPackage.ser" ;
27+ private static String OS = System .getProperty ("os.name" ).toLowerCase ();
28+
29+ private static final Path windowsDataPackageCache ;
30+
31+ private static final Path otherDataPackageCache ;
32+
33+ static
34+ {
35+ String appData = System .getenv ("LOCALAPPDATA" );
36+ String winHome = System .getenv ("USERPROFILE" );
37+ String userHome = System .getProperty ("user.home" );
38+
39+ if (appData == null || appData .isEmpty ()) {
40+ windowsDataPackageCache = Paths .get (winHome , "appdata" ,"local" ,"Archipelago" ,"cache" ,"datapackage" );
41+ } else {
42+ windowsDataPackageCache = Paths .get (appData , "Archipelago" , "cache" , "datapackage" );
43+ }
44+
45+ otherDataPackageCache = Paths .get (userHome , ".cache" , "Archipelago" , "datapackage" );
46+ }
47+
48+ private static Path dataPackageLocation ;
49+
50+ protected Map <String ,String > versions ;
51+
52+ protected ArrayList <String > games ;
53+
54+ private final static Gson gson = new Gson ();
2455
2556 private int hintPoints ;
2657
@@ -40,7 +71,7 @@ public abstract class Client {
4071 private final ItemManager itemManager ;
4172 private final EventManager eventManager ;
4273
43- public static final Version protocolVersion = new Version (0 , 4 , 7 );
74+ public static final Version protocolVersion = new Version (0 , 6 , 1 );
4475
4576 private int team ;
4677 private int slot ;
@@ -52,7 +83,16 @@ public abstract class Client {
5283 private int itemsHandlingFlags = 0b000;
5384
5485 public Client () {
55- loadDataPackage ();
86+ //Determine what platform we are on
87+ if (OS .startsWith ("windows" )){
88+ dataPackageLocation = windowsDataPackageCache ;
89+ } else {
90+ dataPackageLocation = otherDataPackageCache ;
91+ }
92+
93+ if (dataPackage == null ){
94+ dataPackage = new DataPackage ();
95+ }
5696
5797 UUID = dataPackage .getUUID ();
5898
@@ -117,45 +157,84 @@ public void removeTag(String tag) {
117157 }
118158
119159
120- private void loadDataPackage () {
121- try {
122- FileInputStream fileInput = new FileInputStream (dataPackageLocation );
123- ObjectInputStream objectInput = new ObjectInputStream (fileInput );
124-
125- dataPackage = (DataPackage ) objectInput .readObject ();
126- fileInput .close ();
127- objectInput .close ();
128-
129- } catch (IOException e ) {
130- LOGGER .info ("no dataPackage found creating a new one." );
131- dataPackage = new DataPackage ();
132- saveDataPackage ();
133- } catch (ClassNotFoundException e ) {
134- LOGGER .info ("Failed to Read Previous datapackage. Creating new one." );
135- dataPackage = new DataPackage ();
160+ protected void loadDataPackage () {
161+ synchronized (Client .class ){
162+ File directoryPath = dataPackageLocation .toFile ();
163+
164+ //ensure the path to the cache exists
165+ if (directoryPath .exists () && directoryPath .isDirectory ()){
166+ //loop through all Archipelago cache folders to find valid data package files
167+ Map <String ,File > localGamesList = new HashMap <String ,File >();
168+
169+ for (File gameDir : directoryPath .listFiles ()){
170+ if (gameDir .isDirectory ()){
171+ localGamesList .put (gameDir .getName (), gameDir );
172+ }
173+ }
174+
175+ if (localGamesList .isEmpty ()){
176+ //cache doesn't exist. Create the filepath
177+ boolean success = directoryPath .mkdirs ();
178+ if (success ){
179+ LOGGER .info ("DataPackage directory didn't exist. Starting from a new one." );
180+ } else {
181+ LOGGER .severe ("Failed to make directories for datapackage cache." );
182+ }
183+ return ;
184+ }
185+
186+ for (String gameName : games ) {
187+ File dir = localGamesList .get (gameName );
188+
189+ if (null == dir ){
190+ continue ;
191+ }
192+
193+ //check all checksums
194+ for (File version : dir .listFiles ()){
195+ String versionStr = versions .get (gameName );
196+ if (versionStr != null && versionStr .equals (version .getName ())) {
197+ try (FileReader reader = new FileReader (version )){
198+ updateDataPackage (gson .fromJson (reader , DataPackage .class ));
199+ LOGGER .info ("Read datapackage for Game: " .concat (gameName ).concat (" Checksum: " ).concat (version .getName ()));
200+ } catch (IOException e ){
201+ LOGGER .info ("Failed to read a datapackage. Starting with a new one." );
202+ }
203+ }
204+ }
205+ }
206+ }
136207 }
137208 }
138209
139- void saveDataPackage () {
140- try {
141- File dataPackageFile = new File (dataPackageLocation );
142-
143- //noinspection ResultOfMethodCallIgnored
144- dataPackageFile .getParentFile ().mkdirs ();
145- //noinspection ResultOfMethodCallIgnored
146- dataPackageFile .createNewFile ();
147-
148- FileOutputStream fileOut = new FileOutputStream (dataPackageFile );
149- ObjectOutputStream objectOut = new ObjectOutputStream (fileOut );
150-
151- objectOut .writeObject (dataPackage );
210+ public void saveDataPackage () {
211+ synchronized (Client .class ){
212+ //Loop through games to ensure we have folders for each of them in the cache
213+ for (String gameName : games ){
214+ File gameFolder = dataPackageLocation .resolve (gameName ).toFile ();
215+ if (!gameFolder .exists ()){
216+ //game folder not found. Make it
217+ gameFolder .mkdirs ();
218+ }
219+
220+ //save the datapackage
221+ String gameVersion = versions .get (gameName );
222+ if (gameVersion == null ) {
223+ continue ;
224+ }
225+
226+ //if key is for this game
227+ File filePath = dataPackageLocation .resolve (gameName ).resolve (gameVersion ).toFile ();
228+
229+ try (Writer writer = new FileWriter (filePath )){
230+ //if game is in list of games, save it
231+ gson .toJson (dataPackage .getGame (gameName ), writer );
232+ LOGGER .info ("Saving datapackage for Game: " .concat (gameName ).concat (" Checksum: " ).concat (gameVersion ));
233+ } catch (IOException e ) {
234+ LOGGER .warning ("unable to save DataPackage." );
235+ }
152236
153-
154- fileOut .close ();
155- objectOut .close ();
156-
157- } catch (IOException e ) {
158- LOGGER .warning ("unable to save DataPackage." );
237+ }
159238 }
160239 }
161240
@@ -518,6 +597,21 @@ public void dataStorageSetNotify(Collection<String> keys) {
518597 * <td> dict[str, list[str]] </td>
519598 * <td> item_name_groups belonging to the requested game. </td>
520599 * </tr>
600+ * <tr>
601+ * <td> location_name_groups_{game_name} </td>
602+ * <td> dict[str, list[str]] </td>
603+ * <td> location_name_groups belonging to the requested game. </td>
604+ * </tr>
605+ * <tr>
606+ * <td> client_status_{team}_{slot} </td>
607+ * <td> ClientStatus </td>
608+ * <td> The current game status of the requested player. </td>
609+ * </tr>
610+ * <tr>
611+ * <td> race_mode </td>
612+ * <td> int </td>
613+ * <td> 0 if race mode is disabled, and 1 if it's enabled. </td>
614+ * </tr>
521615 * </table>
522616 *
523617 * @param keys a list of keys to retrieve values for
0 commit comments