11package glowredman .defaultserverlist ;
22
3+ import static net .minecraftforge .common .config .Configuration .CATEGORY_GENERAL ;
4+
35import java .io .File ;
4- import java .io .IOException ;
56import java .io .Reader ;
67import java .net .URL ;
78import java .nio .charset .StandardCharsets ;
1516import java .util .Map ;
1617
1718import net .minecraft .client .multiplayer .ServerData ;
19+ import net .minecraftforge .common .config .Configuration ;
1820
1921import org .apache .commons .io .IOUtils ;
2022
2123import com .google .common .reflect .TypeToken ;
2224import com .google .gson .Gson ;
23- import com .google .gson .GsonBuilder ;
2425import com .google .gson .annotations .SerializedName ;
2526
26- import cpw .mods .fml .common .FMLLog ;
27-
2827public class Config {
2928
30- public static ConfigObj config = new ConfigObj ();
3129 public static final List <ServerData > SERVERS = new ArrayList <>();
32- private static final Gson GSON = new GsonBuilder ().setPrettyPrinting ().create ();
33- private static Path configPath ;
34-
35- public static void preInit (File configDir ) {
36- Reader fileReader = null ;
37- try {
38- configPath = configDir .toPath ().resolve ("defaultserverlist.json" );
39-
40- if (!Files .exists (configPath )) {
41- saveConfig (config );
42- } else {
43- fileReader = Files .newBufferedReader (configPath , StandardCharsets .UTF_8 );
44- config = GSON .fromJson (fileReader , ConfigObj .class );
30+ public static boolean allowModifications ;
31+ private static Configuration config ;
32+
33+ /*
34+ * spotless:off
35+ *
36+ * NOTE: There are three different representations for server list entries:
37+ * - String array: The entries are in the format ip|name. This is used for the new configs.
38+ * - Map<String, String>: The key is the name, the value is the ip. This is used for remote server lists.
39+ * - List<ServerData>: This is used by Minecraft.
40+ *
41+ * spotless:on
42+ */
43+
44+ public static void init (File configDir ) {
45+
46+ // Setup
47+ File configFile = new File (configDir , "defaultserverlist.cfg" );
48+ Path legacyConfigPath = configDir .toPath ().resolve ("defaultserverlist.json" );
49+ boolean migrate = !configFile .exists () && Files .exists (legacyConfigPath );
50+ Gson gson = new Gson ();
51+ config = new Configuration (configFile );
52+
53+ // Migrate to new config file if needed.
54+ if (migrate ) {
55+ LoadingPlugin .LOGGER .info ("Found legacy config, attempting to migrate..." );
56+ try (Reader fileReader = Files .newBufferedReader (legacyConfigPath )) {
57+ ConfigObj legacyConfig = gson .fromJson (fileReader , ConfigObj .class );
58+ config .get (CATEGORY_GENERAL , "useURL" , false ).set (legacyConfig .useURL );
59+ config .get (CATEGORY_GENERAL , "allowModifications" , true ).set (legacyConfig .allowModifications );
60+ config .get (CATEGORY_GENERAL , "url" , "" ).set (legacyConfig .url );
61+ config .get (CATEGORY_GENERAL , "servers" , new String [0 ]).set (toArray (legacyConfig .servers ));
62+ config .get (CATEGORY_GENERAL , "prevDefaultServers" , new String [0 ])
63+ .set (legacyConfig .prevDefaultServers .toArray (new String [0 ]));
64+ Files .delete (legacyConfigPath );
65+ LoadingPlugin .LOGGER .info ("Migration successful!" );
66+ } catch (Exception e ) {
67+ LoadingPlugin .LOGGER .error ("Migration failed!" , e );
4568 }
69+ }
4670
47- if (config .useURL ) {
48- try {
49- // servers that are currently at the remote location
50- Map <String , String > remoteDefaultServers = GSON .fromJson (
51- IOUtils .toString (new URL (config .url ), StandardCharsets .UTF_8 ),
52- new TypeToken <LinkedHashMap <String , String >>() {
53-
54- private static final long serialVersionUID = -1786059589535074931L ;
55- }.getType ());
56-
57- if (config .allowModifications ) {
58- // servers that were added to the remote location since the last time the list was fetched
59- Map <String , String > diff = new LinkedHashMap <>();
60-
61- // calculate diff
62- remoteDefaultServers .forEach ((name , ip ) -> {
63- if (!config .prevDefaultServers .contains (ip )) {
64- diff .put (name , ip );
65- }
66- });
67-
68- // save if the remote location was updated
69- if (!diff .isEmpty ()) {
70- config .servers .putAll (diff );
71- config .prevDefaultServers = remoteDefaultServers .values ();
72- saveConfig (config );
71+ // get config values and convert them to a usable format. This also adds comments to the properties.
72+ boolean useURL = config .getBoolean (
73+ "useURL" ,
74+ CATEGORY_GENERAL ,
75+ false ,
76+ "Whether or not the default servers should be fetched from a remote location." );
77+ allowModifications = config .getBoolean (
78+ "allowModifications" ,
79+ CATEGORY_GENERAL ,
80+ true ,
81+ "Whether or not the user should be able to delete, modify or change the order of the default servers." );
82+ String url = config .getString (
83+ "url" ,
84+ CATEGORY_GENERAL ,
85+ "" ,
86+ "The remote location to fetch the default servers from. The returned content must be in JSON format (formatted as a map where the keys are the server names and the values the corresponding ip-adresses)." );
87+ Map <String , String > servers = toMap (
88+ config .getStringList (
89+ "servers" ,
90+ CATEGORY_GENERAL ,
91+ new String [0 ],
92+ "The default servers. Format: ip|name" ));
93+ String [] prevDefaultServersArray = config
94+ .getStringList ("prevDefaultServers" , CATEGORY_GENERAL , new String [0 ], "DO NOT EDIT!" );
95+ Collection <String > prevDefaultServers = new ArrayList <>(prevDefaultServersArray .length );
96+ Arrays .stream (prevDefaultServersArray ).forEachOrdered (prevDefaultServers ::add );
97+
98+ // Fetch servers from the specified remote location.
99+ if (useURL ) {
100+ try {
101+ // servers that are currently at the remote location
102+ Map <String , String > remoteDefaultServers = gson .fromJson (
103+ IOUtils .toString (new URL (url ), StandardCharsets .UTF_8 ),
104+ new TypeToken <LinkedHashMap <String , String >>() {
105+
106+ private static final long serialVersionUID = -1786059589535074931L ;
107+ }.getType ());
108+
109+ if (allowModifications ) {
110+ // servers that were added to the remote location since the last time the list was fetched
111+ Map <String , String > diff = new LinkedHashMap <>();
112+
113+ // calculate diff
114+ for (Map .Entry <String , String > entry : remoteDefaultServers .entrySet ()) {
115+ String ip = entry .getValue ();
116+ if (!prevDefaultServers .contains (ip )) {
117+ diff .put (entry .getKey (), ip );
73118 }
119+ }
74120
75- } else {
76- config .servers = remoteDefaultServers ;
77- saveConfig (config );
121+ // save if the remote location was updated
122+ if (!diff .isEmpty ()) {
123+ servers .putAll (diff );
124+ prevDefaultServers = remoteDefaultServers .values ();
125+ setStringList ("servers" , toArray (servers ));
126+ setStringList ("prevDefaultServers" , prevDefaultServers .toArray (new String [0 ]));
78127 }
79- } catch ( Exception e ) {
80- FMLLog . warning (
81- "Could not get default server list from default location! Are you connected to the internet?" ) ;
82- e . printStackTrace ( );
128+
129+ } else {
130+ servers = remoteDefaultServers ;
131+ setStringList ( "servers" , toArray ( servers ) );
83132 }
133+ } catch (Exception e ) {
134+ LoadingPlugin .LOGGER
135+ .error ("Could not get default server list from {}! Are you connected to the internet?" , url , e );
84136 }
137+ }
138+
139+ // save the config if it changed.
140+ if (config .hasChanged ()) {
141+ config .save ();
142+ }
85143
86- config .servers .forEach ((name , ip ) -> SERVERS .add (new ServerData (name , ip )));
144+ // Convert from Map<String, String> to List<ServerData>
145+ servers .forEach ((name , ip ) -> SERVERS .add (new ServerData (name , ip )));
146+ }
87147
88- } catch (Exception e ) {
89- FMLLog .severe ("Could not parse default server list!" );
90- e .printStackTrace ();
91- } finally {
92- IOUtils .closeQuietly (fileReader );
148+ private static String [] toArray (Map <String , String > map ) {
149+ String [] array = new String [map .size ()];
150+ int i = 0 ;
151+ for (Map .Entry <String , String > entry : map .entrySet ()) {
152+ array [i ] = entry .getValue () + '|' + entry .getKey ();
153+ i ++;
93154 }
155+ return array ;
94156 }
95157
96- public static void saveConfig (ConfigObj config ) throws IOException {
97- File f = configPath .toFile ();
98- if (f .exists ()) {
99- f .delete ();
158+ private static Map <String , String > toMap (String [] array ) {
159+ Map <String , String > map = new LinkedHashMap <>(array .length );
160+ for (String entry : array ) {
161+ String [] parts = entry .split ("\\ |" , 2 );
162+ if (parts .length < 2 ) {
163+ LoadingPlugin .LOGGER .warn ("Could not parse entry {} because not '|' was found!" , entry );
164+ continue ;
165+ }
166+ map .put (parts [1 ], parts [0 ]);
100167 }
101- Files .write (configPath , Arrays .asList (GSON .toJson (config )), StandardCharsets .UTF_8 );
168+ return map ;
169+ }
170+
171+ public static void saveServers (String [] servers ) {
172+ setStringList ("servers" , servers );
173+ config .save ();
174+ }
175+
176+ private static void setStringList (String key , String [] values ) {
177+ // config.get(CATEGORY_GENERAL, key, new String[0]).set(values); resets the comment so we can't use that here
178+ config .getCategory (CATEGORY_GENERAL ).get (key ).set (values );
102179 }
103180
181+ @ Deprecated
104182 public static final class ConfigObj {
105183
106184 public boolean useURL = false ;
@@ -110,11 +188,5 @@ public static final class ConfigObj {
110188
111189 @ SerializedName ("DO_NOT_EDIT_prevDefaultServers" )
112190 public Collection <String > prevDefaultServers = new ArrayList <>();
113-
114- public ConfigObj () {}
115-
116- public ConfigObj (Map <String , String > servers ) {
117- this .servers = servers ;
118- }
119191 }
120192}
0 commit comments