Commit c1d0711910c35c766c55c46e6ddf89b3465a6a04

Authored by Mumfrey
1 parent 068b6528

Relocate debug sources

debug/com/mumfrey/liteloader/debug/LoginManager.java renamed to src/debug/java/com/mumfrey/liteloader/debug/LoginManager.java
1 -package com.mumfrey.liteloader.debug;  
2 -  
3 -import java.io.File;  
4 -import java.io.FileReader;  
5 -import java.io.FileWriter;  
6 -import java.io.IOException;  
7 -import java.lang.reflect.Type;  
8 -import java.net.Proxy;  
9 -import java.util.HashMap;  
10 -import java.util.Map;  
11 -import java.util.UUID;  
12 -  
13 -import javax.swing.JOptionPane;  
14 -  
15 -import com.google.common.base.Strings;  
16 -import com.google.gson.Gson;  
17 -import com.google.gson.GsonBuilder;  
18 -import com.google.gson.JsonArray;  
19 -import com.google.gson.JsonElement;  
20 -import com.google.gson.JsonObject;  
21 -import com.google.gson.JsonPrimitive;  
22 -import com.google.gson.JsonSerializationContext;  
23 -import com.google.gson.JsonSerializer;  
24 -import com.google.gson.annotations.SerializedName;  
25 -import com.mojang.authlib.Agent;  
26 -import com.mojang.authlib.GameProfile;  
27 -import com.mojang.authlib.UserType;  
28 -import com.mojang.authlib.exceptions.AuthenticationException;  
29 -import com.mojang.authlib.exceptions.InvalidCredentialsException;  
30 -import com.mojang.authlib.properties.Property;  
31 -import com.mojang.authlib.properties.PropertyMap;  
32 -import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;  
33 -import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;  
34 -import com.mumfrey.liteloader.util.log.LiteLoaderLogger;  
35 -  
36 -/**  
37 - * Manages login requests against Yggdrasil for use in MCP  
38 - *  
39 - * @author Adam Mummery-Smith  
40 - */  
41 -public class LoginManager  
42 -{  
43 - /**  
44 - * Gson instance for serialising and deserialising the authentication data  
45 - */  
46 - private static Gson gson = new GsonBuilder().setPrettyPrinting().create();  
47 -  
48 - /**  
49 - * Authentication service  
50 - */  
51 - private YggdrasilAuthenticationService authService;  
52 -  
53 - /**  
54 - * Authentication agent  
55 - */  
56 - private YggdrasilUserAuthentication authentication;  
57 -  
58 - /**  
59 - * JSON file to load/save auth data from  
60 - */  
61 - private File jsonFile;  
62 -  
63 - /**  
64 - * Username read from the auth JSON file, we use this as the default in the login dialog in  
65 - * case login fails. This is stored in the JSON even if authentication is not successful so that  
66 - * we can display the same username next time  
67 - */  
68 - private String defaultUsername;  
69 -  
70 - /**  
71 - * Minecraft screen name read from the auth JSON file. Use this as default in case the login fails  
72 - * or is skipped (when offline) so that at least the Minecraft client has a sensible display name.  
73 - * Defaults to user.name when not specified  
74 - */  
75 - private String defaultDisplayName = System.getProperty("user.name");  
76 -  
77 - /**  
78 - * True if login should not be attempted, skips the authentication attempt and the login dialog  
79 - */  
80 - private boolean offline = false;  
81 -  
82 - /**  
83 - * If authentication fails with token then the first attempt will be to use the user/pass specified  
84 - * on the command line (if any). This flag is set AFTER that first attempt so that we know to display  
85 - * the login dialog anyway (eg. the login on the command line was bad)  
86 - */  
87 - private boolean forceShowLoginDialog = false;  
88 -  
89 - /**  
90 - * ctor  
91 - *  
92 - * @param jsonFile  
93 - */  
94 - public LoginManager(File jsonFile)  
95 - {  
96 - this.jsonFile = jsonFile;  
97 -  
98 - this.resetAuth();  
99 - this.load();  
100 - }  
101 -  
102 - /**  
103 - * When authenticaion fails, we regenerate the auth service and agent because trying again with the same  
104 - * client data will fail.  
105 - */  
106 - public void resetAuth()  
107 - {  
108 - this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString());  
109 - this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);  
110 - }  
111 -  
112 - /**  
113 - * Load auth data from the json file  
114 - */  
115 - private void load()  
116 - {  
117 - if (this.jsonFile != null && this.jsonFile.exists())  
118 - {  
119 - FileReader fileReader = null;  
120 -  
121 - try  
122 - {  
123 - fileReader = new FileReader(this.jsonFile);  
124 - AuthData authData = LoginManager.gson.fromJson(fileReader, AuthData.class);  
125 -  
126 - if (authData != null && authData.validate())  
127 - {  
128 - LiteLoaderLogger.info("Initialising Yggdrasil authentication service with client token: %s", authData.getClientToken());  
129 - this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, authData.getClientToken());  
130 - this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);  
131 - authData.loadFromStorage(this.authentication);  
132 - this.offline = authData.workOffline();  
133 - this.defaultUsername = authData.getUsername();  
134 - this.defaultDisplayName = authData.getDisplayName();  
135 - }  
136 - }  
137 - catch (IOException ex) {}  
138 - finally  
139 - {  
140 - try  
141 - {  
142 - if (fileReader != null) fileReader.close();  
143 - }  
144 - catch (IOException ex) {}  
145 - }  
146 - }  
147 - }  
148 -  
149 - /**  
150 - * Save auth data to the JSON file  
151 - */  
152 - private void save()  
153 - {  
154 - if (this.jsonFile != null)  
155 - {  
156 - FileWriter fileWriter = null;  
157 -  
158 - try  
159 - {  
160 - fileWriter = new FileWriter(this.jsonFile);  
161 -  
162 - AuthData authData = new AuthData(this.authService, this.authentication, this.offline, this.defaultUsername, this.defaultDisplayName);  
163 - LoginManager.gson.toJson(authData, fileWriter);  
164 - }  
165 - catch (IOException ex) { ex.printStackTrace(); }  
166 - finally  
167 - {  
168 - try  
169 - {  
170 - if (fileWriter != null) fileWriter.close();  
171 - }  
172 - catch (IOException ex) { ex.printStackTrace(); }  
173 - }  
174 - }  
175 - }  
176 -  
177 - /**  
178 - * Attempt to login. If authentication data are found on disk then tries first to log in with  
179 - * the stored token. If the token login fails then attempts to log in with the username and password  
180 - * specified. If no user or pass are specified or if they fail then displays a login dialog to  
181 - * allow the user to login. If login succeeds then the token is stored on disk and the method  
182 - * returns.  
183 - *  
184 - * If the user presses cancel in the login dialog then the method returns false.  
185 - *  
186 - * @param username User name to log in with if token login fails, if null displays the login dialog immediately  
187 - * @param password Password to log in with if token login fails, if null displays the login dialog immediately  
188 - * @param remainingTries Number of loops to go through before giving up, decremented for each try, specify -1 for unlimited  
189 - * @return false if the user presses cancel in the login dialog, otherwise returns true  
190 - */  
191 - public boolean login(String username, String password, int remainingTries)  
192 - {  
193 - if (this.offline || remainingTries == 0)  
194 - {  
195 - LiteLoaderLogger.info("LoginManager is set to work offline, skipping login");  
196 - return false;  
197 - }  
198 -  
199 - LiteLoaderLogger.info("Remaining login tries: %s", remainingTries > 0 ? remainingTries : "unlimited");  
200 -  
201 - try  
202 - {  
203 - LiteLoaderLogger.info("Attempting login, contacting Mojang auth servers...");  
204 -  
205 - this.authentication.logIn();  
206 -  
207 - if (this.authentication.isLoggedIn())  
208 - {  
209 - LiteLoaderLogger.info("LoginManager logged in successfully. Can play online = %s", this.authentication.canPlayOnline());  
210 - this.save();  
211 - return true;  
212 - }  
213 -  
214 - LiteLoaderLogger.info("LoginManager failed to log in, unspecified status.");  
215 - }  
216 - catch (InvalidCredentialsException ex)  
217 - {  
218 - LiteLoaderLogger.info("Authentication agent reported invalid credentials: %s", ex.getMessage());  
219 - this.resetAuth();  
220 -  
221 - if (remainingTries > 1)  
222 - {  
223 - if (username == null)  
224 - {  
225 - username = this.defaultUsername;  
226 - }  
227 -  
228 - if (this.forceShowLoginDialog || username == null || password == null)  
229 - {  
230 - LoginPanel loginPanel = LoginPanel.getLoginPanel(username, password, this.forceShowLoginDialog ? ex.getMessage() : null);  
231 - boolean dialogResult = loginPanel.showModalDialog();  
232 - this.offline = loginPanel.workOffline();  
233 - this.defaultUsername = loginPanel.getUsername();  
234 -  
235 - if (!dialogResult)  
236 - {  
237 - LiteLoaderLogger.info("User cancelled login dialog");  
238 - return false;  
239 - }  
240 -  
241 - if (this.offline)  
242 - {  
243 - if (JOptionPane.showConfirmDialog(null, "<html>You have chosen to work offline. You will never be prompted to log in again.<br /><br />If you would like to re-enable login please delete the file <span style=\"color: #0000FF\">.auth.json</span> from the working dir<br />or press Cancel to return to the login dialog.</html>", "Confirm work offline", JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE) == JOptionPane.CANCEL_OPTION)  
244 - {  
245 - this.offline = false;  
246 - remainingTries = Math.max(remainingTries, 3);  
247 - }  
248 - }  
249 -  
250 - username = loginPanel.getUsername();  
251 - password = loginPanel.getPassword();  
252 - this.save();  
253 - }  
254 -  
255 - if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password))  
256 - {  
257 - this.authentication.setUsername(username);  
258 - this.authentication.setPassword(password);  
259 - }  
260 -  
261 - this.forceShowLoginDialog = true;  
262 - this.login(username, password, --remainingTries);  
263 - }  
264 - }  
265 - catch (AuthenticationException ex)  
266 - {  
267 - ex.printStackTrace();  
268 - }  
269 -  
270 - this.save();  
271 - return false;  
272 - }  
273 -  
274 - /**  
275 - * Get whether user logged in  
276 - */  
277 - public boolean isLoggedIn()  
278 - {  
279 - return this.authentication.isLoggedIn();  
280 - }  
281 -  
282 - /**  
283 - * Get whether we are able to play online or not  
284 - */  
285 - public boolean canPlayOnline()  
286 - {  
287 - return this.authentication.canPlayOnline();  
288 - }  
289 -  
290 - /**  
291 - * Get the profile name (minecraft player name) from login  
292 - */  
293 - public String getProfileName()  
294 - {  
295 - GameProfile selectedProfile = this.authentication.getSelectedProfile();  
296 - return selectedProfile != null ? selectedProfile.getName() : this.defaultDisplayName;  
297 - }  
298 -  
299 - /**  
300 - * Get the profile name (minecraft player name) from login  
301 - */  
302 - public String getUUID()  
303 - {  
304 - GameProfile selectedProfile = this.authentication.getSelectedProfile();  
305 - return selectedProfile != null ? selectedProfile.getId().toString().replace("-", "") : this.defaultDisplayName;  
306 - }  
307 -  
308 - /**  
309 - * Get the session token  
310 - */  
311 - public String getAuthenticatedToken()  
312 - {  
313 - String accessToken = this.authentication.getAuthenticatedToken();  
314 - return accessToken != null ? accessToken : "-";  
315 - }  
316 -  
317 - public String getUserType()  
318 - {  
319 - UserType userType = this.authentication.getUserType();  
320 - return (userType != null ? userType : UserType.LEGACY).toString().toLowerCase();  
321 - }  
322 -  
323 - public String getUserProperties()  
324 - {  
325 - PropertyMap userProperties = this.authentication.getUserProperties();  
326 - return userProperties != null ? (new GsonBuilder()).registerTypeAdapter(PropertyMap.class, new UserPropertiesSerializer()).create().toJson(userProperties) : "{}";  
327 - }  
328 -  
329 - class UserPropertiesSerializer implements JsonSerializer<PropertyMap>  
330 - {  
331 - @Override  
332 - public JsonElement serialize(PropertyMap propertyMap, Type argType, JsonSerializationContext context)  
333 - {  
334 - JsonObject result = new JsonObject();  
335 -  
336 - for (String key : propertyMap.keySet())  
337 - {  
338 - JsonArray values = new JsonArray();  
339 - for (Property property : propertyMap.get(key))  
340 - {  
341 - values.add(new JsonPrimitive(property.getValue()));  
342 - }  
343 -  
344 - result.add(key, values);  
345 - }  
346 -  
347 - return result;  
348 - }  
349 - }  
350 -  
351 -  
352 - /**  
353 - * Struct for Gson serialisation of authenticaion settings  
354 - *  
355 - * @author Adam Mummery-Smith  
356 - */  
357 - class AuthData  
358 - {  
359 - @SerializedName("clientToken")  
360 - private String clientToken;  
361 -  
362 - @SerializedName("workOffline")  
363 - private boolean workOffline;  
364 -  
365 - @SerializedName("authData")  
366 - private Map<String, Object> credentials;  
367 -  
368 - public AuthData()  
369 - {  
370 - // default ctor for Gson  
371 - }  
372 -  
373 - public AuthData(YggdrasilAuthenticationService authService, YggdrasilUserAuthentication authentication, boolean workOffline, String defaultUserName, String defaultDisplayName)  
374 - {  
375 - this.clientToken = authService.getClientToken();  
376 - this.credentials = authentication.saveForStorage();  
377 - this.workOffline = workOffline;  
378 -  
379 - if (defaultUserName != null && !this.credentials.containsKey("username"))  
380 - this.credentials.put("username", defaultUserName);  
381 -  
382 - if (defaultDisplayName != null && !this.credentials.containsKey("displayName"))  
383 - this.credentials.put("displayName", defaultDisplayName);  
384 - }  
385 -  
386 - /**  
387 - * Called after Gson deserialisation to check that deserialisation was successful  
388 - */  
389 - public boolean validate()  
390 - {  
391 - if (this.clientToken == null) this.clientToken = UUID.randomUUID().toString();  
392 - if (this.credentials == null) this.credentials = new HashMap<String, Object>();  
393 - return true;  
394 - }  
395 -  
396 - public String getClientToken()  
397 - {  
398 - return this.clientToken;  
399 - }  
400 -  
401 - public void setClientToken(String clientToken)  
402 - {  
403 - this.clientToken = clientToken;  
404 - }  
405 -  
406 - public void loadFromStorage(YggdrasilUserAuthentication authentication)  
407 - {  
408 - authentication.loadFromStorage(this.credentials);  
409 - }  
410 -  
411 - public boolean workOffline()  
412 - {  
413 - return this.workOffline;  
414 - }  
415 -  
416 - public String getUsername()  
417 - {  
418 - return this.credentials != null ? this.credentials.get("username").toString() : null;  
419 - }  
420 -  
421 - public String getDisplayName()  
422 - {  
423 - return this.credentials != null && this.credentials.containsKey("displayName") ? this.credentials.get("displayName").toString() : System.getProperty("user.name");  
424 - }  
425 - }  
426 -} 1 +package com.mumfrey.liteloader.debug;
  2 +
  3 +import java.io.File;
  4 +import java.io.FileReader;
  5 +import java.io.FileWriter;
  6 +import java.io.IOException;
  7 +import java.lang.reflect.Type;
  8 +import java.net.Proxy;
  9 +import java.util.HashMap;
  10 +import java.util.Map;
  11 +import java.util.UUID;
  12 +
  13 +import javax.swing.JOptionPane;
  14 +
  15 +import com.google.common.base.Strings;
  16 +import com.google.gson.Gson;
  17 +import com.google.gson.GsonBuilder;
  18 +import com.google.gson.JsonArray;
  19 +import com.google.gson.JsonElement;
  20 +import com.google.gson.JsonObject;
  21 +import com.google.gson.JsonPrimitive;
  22 +import com.google.gson.JsonSerializationContext;
  23 +import com.google.gson.JsonSerializer;
  24 +import com.google.gson.annotations.SerializedName;
  25 +import com.mojang.authlib.Agent;
  26 +import com.mojang.authlib.GameProfile;
  27 +import com.mojang.authlib.UserType;
  28 +import com.mojang.authlib.exceptions.AuthenticationException;
  29 +import com.mojang.authlib.exceptions.InvalidCredentialsException;
  30 +import com.mojang.authlib.properties.Property;
  31 +import com.mojang.authlib.properties.PropertyMap;
  32 +import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
  33 +import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication;
  34 +import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
  35 +
  36 +/**
  37 + * Manages login requests against Yggdrasil for use in MCP
  38 + *
  39 + * @author Adam Mummery-Smith
  40 + */
  41 +public class LoginManager
  42 +{
  43 + /**
  44 + * Gson instance for serialising and deserialising the authentication data
  45 + */
  46 + private static Gson gson = new GsonBuilder().setPrettyPrinting().create();
  47 +
  48 + /**
  49 + * Authentication service
  50 + */
  51 + private YggdrasilAuthenticationService authService;
  52 +
  53 + /**
  54 + * Authentication agent
  55 + */
  56 + private YggdrasilUserAuthentication authentication;
  57 +
  58 + /**
  59 + * JSON file to load/save auth data from
  60 + */
  61 + private File jsonFile;
  62 +
  63 + /**
  64 + * Username read from the auth JSON file, we use this as the default in the login dialog in
  65 + * case login fails. This is stored in the JSON even if authentication is not successful so that
  66 + * we can display the same username next time
  67 + */
  68 + private String defaultUsername;
  69 +
  70 + /**
  71 + * Minecraft screen name read from the auth JSON file. Use this as default in case the login fails
  72 + * or is skipped (when offline) so that at least the Minecraft client has a sensible display name.
  73 + * Defaults to user.name when not specified
  74 + */
  75 + private String defaultDisplayName = System.getProperty("user.name");
  76 +
  77 + /**
  78 + * True if login should not be attempted, skips the authentication attempt and the login dialog
  79 + */
  80 + private boolean offline = false;
  81 +
  82 + /**
  83 + * If authentication fails with token then the first attempt will be to use the user/pass specified
  84 + * on the command line (if any). This flag is set AFTER that first attempt so that we know to display
  85 + * the login dialog anyway (eg. the login on the command line was bad)
  86 + */
  87 + private boolean forceShowLoginDialog = false;
  88 +
  89 + /**
  90 + * ctor
  91 + *
  92 + * @param jsonFile
  93 + */
  94 + public LoginManager(File jsonFile)
  95 + {
  96 + this.jsonFile = jsonFile;
  97 +
  98 + this.resetAuth();
  99 + this.load();
  100 + }
  101 +
  102 + /**
  103 + * When authenticaion fails, we regenerate the auth service and agent because trying again with the same
  104 + * client data will fail.
  105 + */
  106 + public void resetAuth()
  107 + {
  108 + this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString());
  109 + this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);
  110 + }
  111 +
  112 + /**
  113 + * Load auth data from the json file
  114 + */
  115 + private void load()
  116 + {
  117 + if (this.jsonFile != null && this.jsonFile.exists())
  118 + {
  119 + FileReader fileReader = null;
  120 +
  121 + try
  122 + {
  123 + fileReader = new FileReader(this.jsonFile);
  124 + AuthData authData = LoginManager.gson.fromJson(fileReader, AuthData.class);
  125 +
  126 + if (authData != null && authData.validate())
  127 + {
  128 + LiteLoaderLogger.info("Initialising Yggdrasil authentication service with client token: %s", authData.getClientToken());
  129 + this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, authData.getClientToken());
  130 + this.authentication = new YggdrasilUserAuthentication(this.authService, Agent.MINECRAFT);
  131 + authData.loadFromStorage(this.authentication);
  132 + this.offline = authData.workOffline();
  133 + this.defaultUsername = authData.getUsername();
  134 + this.defaultDisplayName = authData.getDisplayName();
  135 + }
  136 + }
  137 + catch (IOException ex) {}
  138 + finally
  139 + {
  140 + try
  141 + {
  142 + if (fileReader != null) fileReader.close();
  143 + }
  144 + catch (IOException ex) {}
  145 + }
  146 + }
  147 + }
  148 +
  149 + /**
  150 + * Save auth data to the JSON file
  151 + */
  152 + private void save()
  153 + {
  154 + if (this.jsonFile != null)
  155 + {
  156 + FileWriter fileWriter = null;
  157 +
  158 + try
  159 + {
  160 + fileWriter = new FileWriter(this.jsonFile);
  161 +
  162 + AuthData authData = new AuthData(this.authService, this.authentication, this.offline, this.defaultUsername, this.defaultDisplayName);
  163 + LoginManager.gson.toJson(authData, fileWriter);
  164 + }
  165 + catch (IOException ex) { ex.printStackTrace(); }
  166 + finally
  167 + {
  168 + try
  169 + {
  170 + if (fileWriter != null) fileWriter.close();
  171 + }
  172 + catch (IOException ex) { ex.printStackTrace(); }
  173 + }
  174 + }
  175 + }
  176 +
  177 + /**
  178 + * Attempt to login. If authentication data are found on disk then tries first to log in with
  179 + * the stored token. If the token login fails then attempts to log in with the username and password
  180 + * specified. If no user or pass are specified or if they fail then displays a login dialog to
  181 + * allow the user to login. If login succeeds then the token is stored on disk and the method
  182 + * returns.
  183 + *
  184 + * If the user presses cancel in the login dialog then the method returns false.
  185 + *
  186 + * @param username User name to log in with if token login fails, if null displays the login dialog immediately
  187 + * @param password Password to log in with if token login fails, if null displays the login dialog immediately
  188 + * @param remainingTries Number of loops to go through before giving up, decremented for each try, specify -1 for unlimited
  189 + * @return false if the user presses cancel in the login dialog, otherwise returns true
  190 + */
  191 + public boolean login(String username, String password, int remainingTries)
  192 + {
  193 + if (this.offline || remainingTries == 0)
  194 + {
  195 + LiteLoaderLogger.info("LoginManager is set to work offline, skipping login");
  196 + return false;
  197 + }
  198 +
  199 + LiteLoaderLogger.info("Remaining login tries: %s", remainingTries > 0 ? remainingTries : "unlimited");
  200 +
  201 + try
  202 + {
  203 + LiteLoaderLogger.info("Attempting login, contacting Mojang auth servers...");
  204 +
  205 + this.authentication.logIn();
  206 +
  207 + if (this.authentication.isLoggedIn())
  208 + {
  209 + LiteLoaderLogger.info("LoginManager logged in successfully. Can play online = %s", this.authentication.canPlayOnline());
  210 + this.save();
  211 + return true;
  212 + }
  213 +
  214 + LiteLoaderLogger.info("LoginManager failed to log in, unspecified status.");
  215 + }
  216 + catch (InvalidCredentialsException ex)
  217 + {
  218 + LiteLoaderLogger.info("Authentication agent reported invalid credentials: %s", ex.getMessage());
  219 + this.resetAuth();
  220 +
  221 + if (remainingTries > 1)
  222 + {
  223 + if (username == null)
  224 + {
  225 + username = this.defaultUsername;
  226 + }
  227 +
  228 + if (this.forceShowLoginDialog || username == null || password == null)
  229 + {
  230 + LoginPanel loginPanel = LoginPanel.getLoginPanel(username, password, this.forceShowLoginDialog ? ex.getMessage() : null);
  231 + boolean dialogResult = loginPanel.showModalDialog();
  232 + this.offline = loginPanel.workOffline();
  233 + this.defaultUsername = loginPanel.getUsername();
  234 +
  235 + if (!dialogResult)
  236 + {
  237 + LiteLoaderLogger.info("User cancelled login dialog");
  238 + return false;
  239 + }
  240 +
  241 + if (this.offline)
  242 + {
  243 + if (JOptionPane.showConfirmDialog(null, "<html>You have chosen to work offline. You will never be prompted to log in again.<br /><br />If you would like to re-enable login please delete the file <span style=\"color: #0000FF\">.auth.json</span> from the working dir<br />or press Cancel to return to the login dialog.</html>", "Confirm work offline", JOptionPane.OK_CANCEL_OPTION, JOptionPane.INFORMATION_MESSAGE) == JOptionPane.CANCEL_OPTION)
  244 + {
  245 + this.offline = false;
  246 + remainingTries = Math.max(remainingTries, 3);
  247 + }
  248 + }
  249 +
  250 + username = loginPanel.getUsername();
  251 + password = loginPanel.getPassword();
  252 + this.save();
  253 + }
  254 +
  255 + if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password))
  256 + {
  257 + this.authentication.setUsername(username);
  258 + this.authentication.setPassword(password);
  259 + }
  260 +
  261 + this.forceShowLoginDialog = true;
  262 + this.login(username, password, --remainingTries);
  263 + }
  264 + }
  265 + catch (AuthenticationException ex)
  266 + {
  267 + ex.printStackTrace();
  268 + }
  269 +
  270 + this.save();
  271 + return false;
  272 + }
  273 +
  274 + /**
  275 + * Get whether user logged in
  276 + */
  277 + public boolean isLoggedIn()
  278 + {
  279 + return this.authentication.isLoggedIn();
  280 + }
  281 +
  282 + /**
  283 + * Get whether we are able to play online or not
  284 + */
  285 + public boolean canPlayOnline()
  286 + {
  287 + return this.authentication.canPlayOnline();
  288 + }
  289 +
  290 + /**
  291 + * Get the profile name (minecraft player name) from login
  292 + */
  293 + public String getProfileName()
  294 + {
  295 + GameProfile selectedProfile = this.authentication.getSelectedProfile();
  296 + return selectedProfile != null ? selectedProfile.getName() : this.defaultDisplayName;
  297 + }
  298 +
  299 + /**
  300 + * Get the profile name (minecraft player name) from login
  301 + */
  302 + public String getUUID()
  303 + {
  304 + GameProfile selectedProfile = this.authentication.getSelectedProfile();
  305 + return selectedProfile != null ? selectedProfile.getId().toString().replace("-", "") : this.defaultDisplayName;
  306 + }
  307 +
  308 + /**
  309 + * Get the session token
  310 + */
  311 + public String getAuthenticatedToken()
  312 + {
  313 + String accessToken = this.authentication.getAuthenticatedToken();
  314 + return accessToken != null ? accessToken : "-";
  315 + }
  316 +
  317 + public String getUserType()
  318 + {
  319 + UserType userType = this.authentication.getUserType();
  320 + return (userType != null ? userType : UserType.LEGACY).toString().toLowerCase();
  321 + }
  322 +
  323 + public String getUserProperties()
  324 + {
  325 + PropertyMap userProperties = this.authentication.getUserProperties();
  326 + return userProperties != null ? (new GsonBuilder()).registerTypeAdapter(PropertyMap.class, new UserPropertiesSerializer()).create().toJson(userProperties) : "{}";
  327 + }
  328 +
  329 + class UserPropertiesSerializer implements JsonSerializer<PropertyMap>
  330 + {
  331 + @Override
  332 + public JsonElement serialize(PropertyMap propertyMap, Type argType, JsonSerializationContext context)
  333 + {
  334 + JsonObject result = new JsonObject();
  335 +
  336 + for (String key : propertyMap.keySet())
  337 + {
  338 + JsonArray values = new JsonArray();
  339 + for (Property property : propertyMap.get(key))
  340 + {
  341 + values.add(new JsonPrimitive(property.getValue()));
  342 + }
  343 +
  344 + result.add(key, values);
  345 + }
  346 +
  347 + return result;
  348 + }
  349 + }
  350 +
  351 +
  352 + /**
  353 + * Struct for Gson serialisation of authenticaion settings
  354 + *
  355 + * @author Adam Mummery-Smith
  356 + */
  357 + class AuthData
  358 + {
  359 + @SerializedName("clientToken")
  360 + private String clientToken;
  361 +
  362 + @SerializedName("workOffline")
  363 + private boolean workOffline;
  364 +
  365 + @SerializedName("authData")
  366 + private Map<String, Object> credentials;
  367 +
  368 + public AuthData()
  369 + {
  370 + // default ctor for Gson
  371 + }
  372 +
  373 + public AuthData(YggdrasilAuthenticationService authService, YggdrasilUserAuthentication authentication, boolean workOffline, String defaultUserName, String defaultDisplayName)
  374 + {
  375 + this.clientToken = authService.getClientToken();
  376 + this.credentials = authentication.saveForStorage();
  377 + this.workOffline = workOffline;
  378 +
  379 + if (defaultUserName != null && !this.credentials.containsKey("username"))
  380 + this.credentials.put("username", defaultUserName);
  381 +
  382 + if (defaultDisplayName != null && !this.credentials.containsKey("displayName"))
  383 + this.credentials.put("displayName", defaultDisplayName);
  384 + }
  385 +
  386 + /**
  387 + * Called after Gson deserialisation to check that deserialisation was successful
  388 + */
  389 + public boolean validate()
  390 + {
  391 + if (this.clientToken == null) this.clientToken = UUID.randomUUID().toString();
  392 + if (this.credentials == null) this.credentials = new HashMap<String, Object>();
  393 + return true;
  394 + }
  395 +
  396 + public String getClientToken()
  397 + {
  398 + return this.clientToken;
  399 + }
  400 +
  401 + public void setClientToken(String clientToken)
  402 + {
  403 + this.clientToken = clientToken;
  404 + }
  405 +
  406 + public void loadFromStorage(YggdrasilUserAuthentication authentication)
  407 + {
  408 + authentication.loadFromStorage(this.credentials);
  409 + }
  410 +
  411 + public boolean workOffline()
  412 + {
  413 + return this.workOffline;
  414 + }
  415 +
  416 + public String getUsername()
  417 + {
  418 + return this.credentials != null ? this.credentials.get("username").toString() : null;
  419 + }
  420 +
  421 + public String getDisplayName()
  422 + {
  423 + return this.credentials != null && this.credentials.containsKey("displayName") ? this.credentials.get("displayName").toString() : System.getProperty("user.name");
  424 + }
  425 + }
  426 +}
debug/com/mumfrey/liteloader/debug/LoginPanel.java renamed to src/debug/java/com/mumfrey/liteloader/debug/LoginPanel.java
1 -package com.mumfrey.liteloader.debug;  
2 -  
3 -import static javax.swing.WindowConstants.*;  
4 -  
5 -import java.awt.*;  
6 -import java.awt.event.ActionEvent;  
7 -import java.awt.event.ActionListener;  
8 -import java.awt.event.WindowAdapter;  
9 -import java.awt.event.WindowEvent;  
10 -import java.util.ArrayList;  
11 -import java.util.List;  
12 -  
13 -import javax.swing.JButton;  
14 -import javax.swing.JCheckBox;  
15 -import javax.swing.JDialog;  
16 -import javax.swing.JLabel;  
17 -import javax.swing.JPanel;  
18 -import javax.swing.UIManager;  
19 -import javax.swing.border.EmptyBorder;  
20 -import javax.swing.border.TitledBorder;  
21 -  
22 -/**  
23 - * JPanel displayed in a JDialog to prompt the user for login credentials for minecraft  
24 - *  
25 - * @author Adam Mummery-Smith  
26 - */  
27 -public class LoginPanel extends JPanel  
28 -{  
29 - private static final long serialVersionUID = 1L;  
30 -  
31 - private GridBagLayout panelLoginLayout;  
32 -  
33 - private JPanel panelTitle;  
34 - private JPanel panelCentre;  
35 - private JPanel panelPadding;  
36 - private JPanel panelBottom;  
37 - private JLabel lblTitle;  
38 - private JLabel lblSubTitle;  
39 - private JLabel lblMessage;  
40 - private JLabel lblUserName;  
41 - private JLabel lblPassword;  
42 - private TextField txtUsername;  
43 - private TextField txtPassword;  
44 - private JButton btnLogin;  
45 - private JButton btnCancel;  
46 - private JCheckBox chkOffline;  
47 -  
48 - private JDialog dialog;  
49 -  
50 - private ListFocusTraversal tabOrder = new ListFocusTraversal();  
51 -  
52 - private boolean dialogResult = false;  
53 -  
54 - public LoginPanel(String username, String password, String error)  
55 - {  
56 - Color backColour = new Color(102, 118, 144);  
57 -  
58 - this.setFocusable(false);  
59 - this.setPreferredSize(new Dimension(400, 260));  
60 - this.setBackground(new Color(105, 105, 105));  
61 - this.setLayout(new BorderLayout(0, 0));  
62 -  
63 - this.panelTitle = new JPanel();  
64 - this.panelTitle.setBackground(backColour);  
65 - this.panelTitle.setPreferredSize(new Dimension(400, 64));  
66 - this.panelTitle.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));  
67 -  
68 - this.panelBottom = new JPanel();  
69 - this.panelBottom.setBackground(backColour);  
70 - this.panelBottom.setPreferredSize(new Dimension(400, 32));  
71 - this.panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));  
72 -  
73 - this.panelPadding = new JPanel();  
74 - this.panelPadding.setBorder(new EmptyBorder(4, 8, 8, 8));  
75 - this.panelPadding.setOpaque(false);  
76 - this.panelPadding.setLayout(new BorderLayout(0, 0));  
77 -  
78 - this.panelCentre = new JPanel();  
79 - this.panelCentre.setOpaque(false);  
80 - this.panelCentre.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Yggdrasil Login", TitledBorder.LEADING, TitledBorder.TOP, null, Color.WHITE));  
81 - this.panelLoginLayout = new GridBagLayout();  
82 - this.panelLoginLayout.columnWidths = new int[] {30, 80, 120, 120, 30};  
83 - this.panelLoginLayout.rowHeights = new int[] {24, 32, 32, 32};  
84 - this.panelLoginLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};  
85 - this.panelLoginLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0};  
86 - this.panelCentre.setLayout(this.panelLoginLayout);  
87 -  
88 - this.lblTitle = new JLabel("Log in to minecraft.net");  
89 - this.lblTitle.setBorder(new EmptyBorder(4, 16, 0, 16));  
90 - this.lblTitle.setFont(new Font("Tahoma", Font.BOLD, 18));  
91 - this.lblTitle.setForeground(Color.WHITE);  
92 - this.lblTitle.setPreferredSize(new Dimension(400, 26));  
93 -  
94 - this.lblSubTitle = new JLabel("Your password will not be stored, logging in with Yggdrasil");  
95 - this.lblSubTitle.setBorder(new EmptyBorder(0, 16, 0, 16));  
96 - this.lblSubTitle.setForeground(Color.WHITE);  
97 - this.lblSubTitle.setPreferredSize(new Dimension(400, 16));  
98 -  
99 - this.lblMessage = new JLabel("Enter your login details for minecraft.net");  
100 - this.lblMessage.setForeground(Color.WHITE);  
101 -  
102 - this.lblUserName = new JLabel("User name");  
103 - this.lblUserName.setForeground(Color.WHITE);  
104 -  
105 - this.lblPassword = new JLabel("Password");  
106 - this.lblPassword.setForeground(Color.WHITE);  
107 -  
108 - this.txtUsername = new TextField();  
109 - this.txtUsername.setPreferredSize(new Dimension(200, 22));  
110 - this.txtUsername.setText(username);  
111 -  
112 - this.txtPassword = new TextField();  
113 - this.txtPassword.setEchoChar('*');  
114 - this.txtPassword.setPreferredSize(new Dimension(200, 22));  
115 - this.txtPassword.setText(password);  
116 -  
117 - this.btnLogin = new JButton("Log in");  
118 - this.btnLogin.addActionListener(new ActionListener() {  
119 - @Override public void actionPerformed(ActionEvent e) {  
120 - LoginPanel.this.onLoginClick();  
121 - }  
122 - });  
123 -  
124 - this.btnCancel = new JButton("Cancel");  
125 - this.btnCancel.addActionListener(new ActionListener() {  
126 - @Override public void actionPerformed(ActionEvent e) {  
127 - LoginPanel.this.onCancelClick();  
128 - }  
129 - });  
130 -  
131 - this.chkOffline = new JCheckBox("Never ask me to log in (always run offline)");  
132 - this.chkOffline.setPreferredSize(new Dimension(380, 23));  
133 - this.chkOffline.setForeground(Color.WHITE);  
134 - this.chkOffline.setOpaque(false);  
135 - this.chkOffline.addActionListener(new ActionListener()  
136 - {  
137 - @Override public void actionPerformed(ActionEvent e)  
138 - {  
139 - LoginPanel.this.onOfflineCheckedChanged();  
140 - }  
141 - });  
142 -  
143 - GridBagConstraints lblMessageConstraints = new GridBagConstraints();  
144 - lblMessageConstraints.anchor = GridBagConstraints.WEST;  
145 - lblMessageConstraints.gridwidth = 2;  
146 - lblMessageConstraints.insets = new Insets(0, 0, 5, 5);  
147 - lblMessageConstraints.gridx = 2;  
148 - lblMessageConstraints.gridy = 0;  
149 -  
150 - GridBagConstraints lblUserNameConstraints = new GridBagConstraints();  
151 - lblUserNameConstraints.anchor = GridBagConstraints.WEST;  
152 - lblUserNameConstraints.fill = GridBagConstraints.VERTICAL;  
153 - lblUserNameConstraints.insets = new Insets(0, 0, 5, 5);  
154 - lblUserNameConstraints.gridx = 1;  
155 - lblUserNameConstraints.gridy = 1;  
156 -  
157 - GridBagConstraints lblPasswordConstraints = new GridBagConstraints();  
158 - lblPasswordConstraints.anchor = GridBagConstraints.WEST;  
159 - lblPasswordConstraints.fill = GridBagConstraints.VERTICAL;  
160 - lblPasswordConstraints.insets = new Insets(0, 0, 5, 5);  
161 - lblPasswordConstraints.gridx = 1;  
162 - lblPasswordConstraints.gridy = 2;  
163 -  
164 - GridBagConstraints txtUsernameConstraints = new GridBagConstraints();  
165 - txtUsernameConstraints.gridwidth = 2;  
166 - txtUsernameConstraints.fill = GridBagConstraints.HORIZONTAL;  
167 - txtUsernameConstraints.insets = new Insets(0, 0, 5, 0);  
168 - txtUsernameConstraints.gridx = 2;  
169 - txtUsernameConstraints.gridy = 1;  
170 -  
171 - GridBagConstraints txtPasswordConstraints = new GridBagConstraints();  
172 - txtPasswordConstraints.gridwidth = 2;  
173 - txtPasswordConstraints.insets = new Insets(0, 0, 5, 0);  
174 - txtPasswordConstraints.fill = GridBagConstraints.HORIZONTAL;  
175 - txtPasswordConstraints.gridx = 2;  
176 - txtPasswordConstraints.gridy = 2;  
177 -  
178 - GridBagConstraints btnLoginConstraints = new GridBagConstraints();  
179 - btnLoginConstraints.fill = GridBagConstraints.HORIZONTAL;  
180 - btnLoginConstraints.gridx = 3;  
181 - btnLoginConstraints.gridy = 3;  
182 -  
183 - GridBagConstraints btnCancelConstraints = new GridBagConstraints();  
184 - btnCancelConstraints.anchor = GridBagConstraints.EAST;  
185 - btnCancelConstraints.insets = new Insets(0, 0, 0, 5);  
186 - btnCancelConstraints.gridx = 2;  
187 - btnCancelConstraints.gridy = 3;  
188 -  
189 - this.add(this.panelTitle, BorderLayout.NORTH);  
190 - this.add(this.panelPadding, BorderLayout.CENTER);  
191 - this.add(this.panelBottom, BorderLayout.SOUTH);  
192 -  
193 - this.panelPadding.add(this.panelCentre);  
194 -  
195 - this.panelTitle.add(this.lblTitle);  
196 - this.panelTitle.add(this.lblSubTitle);  
197 -  
198 - this.panelCentre.add(this.lblMessage, lblMessageConstraints);  
199 - this.panelCentre.add(this.lblUserName, lblUserNameConstraints);  
200 - this.panelCentre.add(this.lblPassword, lblPasswordConstraints);  
201 - this.panelCentre.add(this.txtUsername, txtUsernameConstraints);  
202 - this.panelCentre.add(this.txtPassword, txtPasswordConstraints);  
203 - this.panelCentre.add(this.btnLogin, btnLoginConstraints);  
204 - this.panelCentre.add(this.btnCancel, btnCancelConstraints);  
205 -  
206 - this.panelBottom.add(this.chkOffline);  
207 -  
208 - this.tabOrder.add(this.txtUsername);  
209 - this.tabOrder.add(this.txtPassword);  
210 - this.tabOrder.add(this.btnLogin);  
211 - this.tabOrder.add(this.btnCancel);  
212 - this.tabOrder.add(this.chkOffline);  
213 -  
214 - if (error != null)  
215 - {  
216 - this.lblMessage.setText(error);  
217 - this.lblMessage.setForeground(new Color(255, 180, 180));  
218 - }  
219 - }  
220 -  
221 - protected void onShowDialog()  
222 - {  
223 - if (this.txtUsername.getText().length() > 0)  
224 - {  
225 - if (this.txtPassword.getText().length() > 0)  
226 - this.txtUsername.select(0, this.txtUsername.getText().length());  
227 - else  
228 - this.txtPassword.requestFocusInWindow();  
229 - }  
230 - }  
231 -  
232 - protected void onLoginClick()  
233 - {  
234 - this.dialogResult = true;  
235 - this.dialog.setVisible(false);  
236 - }  
237 -  
238 - protected void onCancelClick()  
239 - {  
240 - this.dialog.setVisible(false);  
241 - }  
242 -  
243 - protected void onOfflineCheckedChanged()  
244 - {  
245 - boolean selected = this.chkOffline.isSelected();  
246 - this.btnLogin.setText(selected ? "Work Offline" : "Log In");  
247 - this.txtUsername.setEnabled(!selected);  
248 - this.txtPassword.setEnabled(!selected);  
249 - }  
250 -  
251 - /**  
252 - * @param dialog  
253 - */  
254 - public void setDialog(JDialog dialog)  
255 - {  
256 - this.dialog = dialog;  
257 -  
258 - this.dialog.addWindowListener(new WindowAdapter()  
259 - {  
260 - @Override  
261 - public void windowOpened(WindowEvent e)  
262 - {  
263 - LoginPanel.this.onShowDialog();  
264 - }  
265 - });  
266 -  
267 - this.dialog.getRootPane().setDefaultButton(this.btnLogin);  
268 - this.dialog.setFocusTraversalPolicy(this.tabOrder);  
269 - }  
270 -  
271 - public boolean showModalDialog()  
272 - {  
273 - this.dialog.setVisible(true);  
274 - this.dialog.dispose();  
275 - return this.dialogResult;  
276 - }  
277 -  
278 - public String getUsername()  
279 - {  
280 - return this.txtUsername.getText();  
281 - }  
282 -  
283 - public String getPassword()  
284 - {  
285 - return this.txtPassword.getText();  
286 - }  
287 -  
288 - public boolean workOffline()  
289 - {  
290 - return this.chkOffline.isSelected();  
291 - }  
292 -  
293 - public static LoginPanel getLoginPanel(String username, String password, String error)  
294 - {  
295 - if (username == null) username = "";  
296 - if (password == null) password = "";  
297 -  
298 - final JDialog dialog = new JDialog();  
299 - final LoginPanel panel = new LoginPanel(username, password, error);  
300 - panel.setDialog(dialog);  
301 -  
302 - dialog.setContentPane(panel);  
303 - dialog.setTitle("Yggdrasil Login");  
304 - dialog.setResizable(false);  
305 - dialog.pack();  
306 - dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE);  
307 - dialog.setLocationRelativeTo(null);  
308 - dialog.setModal(true);  
309 -  
310 - return panel;  
311 - }  
312 -  
313 - class ListFocusTraversal extends FocusTraversalPolicy  
314 - {  
315 - private final List<Component> components = new ArrayList<Component>();  
316 -  
317 - void add(Component component)  
318 - {  
319 - this.components.add(component);  
320 - }  
321 -  
322 - @Override  
323 - public Component getComponentAfter(Container container, Component component)  
324 - {  
325 - int index = this.components.indexOf(component) + 1;  
326 - if (index >= this.components.size()) return this.components.get(0);  
327 - return this.components.get(index);  
328 - }  
329 -  
330 - @Override  
331 - public Component getComponentBefore(Container container, Component component)  
332 - {  
333 - int index = this.components.indexOf(component) - 1;  
334 - if (index < 0) return this.getLastComponent(container);  
335 - return this.components.get(index);  
336 - }  
337 -  
338 - @Override  
339 - public Component getFirstComponent(Container container)  
340 - {  
341 - return this.components.get(0);  
342 - }  
343 -  
344 - @Override  
345 - public Component getLastComponent(Container container)  
346 - {  
347 - return this.components.get(this.components.size() - 1);  
348 - }  
349 -  
350 - @Override  
351 - public Component getDefaultComponent(Container container)  
352 - {  
353 - return this.getFirstComponent(container);  
354 - }  
355 - }  
356 -} 1 +package com.mumfrey.liteloader.debug;
  2 +
  3 +import static javax.swing.WindowConstants.*;
  4 +
  5 +import java.awt.*;
  6 +import java.awt.event.ActionEvent;
  7 +import java.awt.event.ActionListener;
  8 +import java.awt.event.WindowAdapter;
  9 +import java.awt.event.WindowEvent;
  10 +import java.util.ArrayList;
  11 +import java.util.List;
  12 +
  13 +import javax.swing.JButton;
  14 +import javax.swing.JCheckBox;
  15 +import javax.swing.JDialog;
  16 +import javax.swing.JLabel;
  17 +import javax.swing.JPanel;
  18 +import javax.swing.UIManager;
  19 +import javax.swing.border.EmptyBorder;
  20 +import javax.swing.border.TitledBorder;
  21 +
  22 +/**
  23 + * JPanel displayed in a JDialog to prompt the user for login credentials for minecraft
  24 + *
  25 + * @author Adam Mummery-Smith
  26 + */
  27 +public class LoginPanel extends JPanel
  28 +{
  29 + private static final long serialVersionUID = 1L;
  30 +
  31 + private GridBagLayout panelLoginLayout;
  32 +
  33 + private JPanel panelTitle;
  34 + private JPanel panelCentre;
  35 + private JPanel panelPadding;
  36 + private JPanel panelBottom;
  37 + private JLabel lblTitle;
  38 + private JLabel lblSubTitle;
  39 + private JLabel lblMessage;
  40 + private JLabel lblUserName;
  41 + private JLabel lblPassword;
  42 + private TextField txtUsername;
  43 + private TextField txtPassword;
  44 + private JButton btnLogin;
  45 + private JButton btnCancel;
  46 + private JCheckBox chkOffline;
  47 +
  48 + private JDialog dialog;
  49 +
  50 + private ListFocusTraversal tabOrder = new ListFocusTraversal();
  51 +
  52 + private boolean dialogResult = false;
  53 +
  54 + public LoginPanel(String username, String password, String error)
  55 + {
  56 + Color backColour = new Color(102, 118, 144);
  57 +
  58 + this.setFocusable(false);
  59 + this.setPreferredSize(new Dimension(400, 260));
  60 + this.setBackground(new Color(105, 105, 105));
  61 + this.setLayout(new BorderLayout(0, 0));
  62 +
  63 + this.panelTitle = new JPanel();
  64 + this.panelTitle.setBackground(backColour);
  65 + this.panelTitle.setPreferredSize(new Dimension(400, 64));
  66 + this.panelTitle.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
  67 +
  68 + this.panelBottom = new JPanel();
  69 + this.panelBottom.setBackground(backColour);
  70 + this.panelBottom.setPreferredSize(new Dimension(400, 32));
  71 + this.panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));
  72 +
  73 + this.panelPadding = new JPanel();
  74 + this.panelPadding.setBorder(new EmptyBorder(4, 8, 8, 8));
  75 + this.panelPadding.setOpaque(false);
  76 + this.panelPadding.setLayout(new BorderLayout(0, 0));
  77 +
  78 + this.panelCentre = new JPanel();
  79 + this.panelCentre.setOpaque(false);
  80 + this.panelCentre.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Yggdrasil Login", TitledBorder.LEADING, TitledBorder.TOP, null, Color.WHITE));
  81 + this.panelLoginLayout = new GridBagLayout();
  82 + this.panelLoginLayout.columnWidths = new int[] {30, 80, 120, 120, 30};
  83 + this.panelLoginLayout.rowHeights = new int[] {24, 32, 32, 32};
  84 + this.panelLoginLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE};
  85 + this.panelLoginLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0};
  86 + this.panelCentre.setLayout(this.panelLoginLayout);
  87 +
  88 + this.lblTitle = new JLabel("Log in to minecraft.net");
  89 + this.lblTitle.setBorder(new EmptyBorder(4, 16, 0, 16));
  90 + this.lblTitle.setFont(new Font("Tahoma", Font.BOLD, 18));
  91 + this.lblTitle.setForeground(Color.WHITE);
  92 + this.lblTitle.setPreferredSize(new Dimension(400, 26));
  93 +
  94 + this.lblSubTitle = new JLabel("Your password will not be stored, logging in with Yggdrasil");
  95 + this.lblSubTitle.setBorder(new EmptyBorder(0, 16, 0, 16));
  96 + this.lblSubTitle.setForeground(Color.WHITE);
  97 + this.lblSubTitle.setPreferredSize(new Dimension(400, 16));
  98 +
  99 + this.lblMessage = new JLabel("Enter your login details for minecraft.net");
  100 + this.lblMessage.setForeground(Color.WHITE);
  101 +
  102 + this.lblUserName = new JLabel("User name");
  103 + this.lblUserName.setForeground(Color.WHITE);
  104 +
  105 + this.lblPassword = new JLabel("Password");
  106 + this.lblPassword.setForeground(Color.WHITE);
  107 +
  108 + this.txtUsername = new TextField();
  109 + this.txtUsername.setPreferredSize(new Dimension(200, 22));
  110 + this.txtUsername.setText(username);
  111 +
  112 + this.txtPassword = new TextField();
  113 + this.txtPassword.setEchoChar('*');
  114 + this.txtPassword.setPreferredSize(new Dimension(200, 22));
  115 + this.txtPassword.setText(password);
  116 +
  117 + this.btnLogin = new JButton("Log in");
  118 + this.btnLogin.addActionListener(new ActionListener() {
  119 + @Override public void actionPerformed(ActionEvent e) {
  120 + LoginPanel.this.onLoginClick();
  121 + }
  122 + });
  123 +
  124 + this.btnCancel = new JButton("Cancel");
  125 + this.btnCancel.addActionListener(new ActionListener() {
  126 + @Override public void actionPerformed(ActionEvent e) {
  127 + LoginPanel.this.onCancelClick();
  128 + }
  129 + });
  130 +
  131 + this.chkOffline = new JCheckBox("Never ask me to log in (always run offline)");
  132 + this.chkOffline.setPreferredSize(new Dimension(380, 23));
  133 + this.chkOffline.setForeground(Color.WHITE);
  134 + this.chkOffline.setOpaque(false);
  135 + this.chkOffline.addActionListener(new ActionListener()
  136 + {
  137 + @Override public void actionPerformed(ActionEvent e)
  138 + {
  139 + LoginPanel.this.onOfflineCheckedChanged();
  140 + }
  141 + });
  142 +
  143 + GridBagConstraints lblMessageConstraints = new GridBagConstraints();
  144 + lblMessageConstraints.anchor = GridBagConstraints.WEST;
  145 + lblMessageConstraints.gridwidth = 2;
  146 + lblMessageConstraints.insets = new Insets(0, 0, 5, 5);
  147 + lblMessageConstraints.gridx = 2;
  148 + lblMessageConstraints.gridy = 0;
  149 +
  150 + GridBagConstraints lblUserNameConstraints = new GridBagConstraints();
  151 + lblUserNameConstraints.anchor = GridBagConstraints.WEST;
  152 + lblUserNameConstraints.fill = GridBagConstraints.VERTICAL;
  153 + lblUserNameConstraints.insets = new Insets(0, 0, 5, 5);
  154 + lblUserNameConstraints.gridx = 1;
  155 + lblUserNameConstraints.gridy = 1;
  156 +
  157 + GridBagConstraints lblPasswordConstraints = new GridBagConstraints();
  158 + lblPasswordConstraints.anchor = GridBagConstraints.WEST;
  159 + lblPasswordConstraints.fill = GridBagConstraints.VERTICAL;
  160 + lblPasswordConstraints.insets = new Insets(0, 0, 5, 5);
  161 + lblPasswordConstraints.gridx = 1;
  162 + lblPasswordConstraints.gridy = 2;
  163 +
  164 + GridBagConstraints txtUsernameConstraints = new GridBagConstraints();
  165 + txtUsernameConstraints.gridwidth = 2;
  166 + txtUsernameConstraints.fill = GridBagConstraints.HORIZONTAL;
  167 + txtUsernameConstraints.insets = new Insets(0, 0, 5, 0);
  168 + txtUsernameConstraints.gridx = 2;
  169 + txtUsernameConstraints.gridy = 1;
  170 +
  171 + GridBagConstraints txtPasswordConstraints = new GridBagConstraints();
  172 + txtPasswordConstraints.gridwidth = 2;
  173 + txtPasswordConstraints.insets = new Insets(0, 0, 5, 0);
  174 + txtPasswordConstraints.fill = GridBagConstraints.HORIZONTAL;
  175 + txtPasswordConstraints.gridx = 2;
  176 + txtPasswordConstraints.gridy = 2;
  177 +
  178 + GridBagConstraints btnLoginConstraints = new GridBagConstraints();
  179 + btnLoginConstraints.fill = GridBagConstraints.HORIZONTAL;
  180 + btnLoginConstraints.gridx = 3;
  181 + btnLoginConstraints.gridy = 3;
  182 +
  183 + GridBagConstraints btnCancelConstraints = new GridBagConstraints();
  184 + btnCancelConstraints.anchor = GridBagConstraints.EAST;
  185 + btnCancelConstraints.insets = new Insets(0, 0, 0, 5);
  186 + btnCancelConstraints.gridx = 2;
  187 + btnCancelConstraints.gridy = 3;
  188 +
  189 + this.add(this.panelTitle, BorderLayout.NORTH);
  190 + this.add(this.panelPadding, BorderLayout.CENTER);
  191 + this.add(this.panelBottom, BorderLayout.SOUTH);
  192 +
  193 + this.panelPadding.add(this.panelCentre);
  194 +
  195 + this.panelTitle.add(this.lblTitle);
  196 + this.panelTitle.add(this.lblSubTitle);
  197 +
  198 + this.panelCentre.add(this.lblMessage, lblMessageConstraints);
  199 + this.panelCentre.add(this.lblUserName, lblUserNameConstraints);
  200 + this.panelCentre.add(this.lblPassword, lblPasswordConstraints);
  201 + this.panelCentre.add(this.txtUsername, txtUsernameConstraints);
  202 + this.panelCentre.add(this.txtPassword, txtPasswordConstraints);
  203 + this.panelCentre.add(this.btnLogin, btnLoginConstraints);
  204 + this.panelCentre.add(this.btnCancel, btnCancelConstraints);
  205 +
  206 + this.panelBottom.add(this.chkOffline);
  207 +
  208 + this.tabOrder.add(this.txtUsername);
  209 + this.tabOrder.add(this.txtPassword);
  210 + this.tabOrder.add(this.btnLogin);
  211 + this.tabOrder.add(this.btnCancel);
  212 + this.tabOrder.add(this.chkOffline);
  213 +
  214 + if (error != null)
  215 + {
  216 + this.lblMessage.setText(error);
  217 + this.lblMessage.setForeground(new Color(255, 180, 180));
  218 + }
  219 + }
  220 +
  221 + protected void onShowDialog()
  222 + {
  223 + if (this.txtUsername.getText().length() > 0)
  224 + {
  225 + if (this.txtPassword.getText().length() > 0)
  226 + this.txtUsername.select(0, this.txtUsername.getText().length());
  227 + else
  228 + this.txtPassword.requestFocusInWindow();
  229 + }
  230 + }
  231 +
  232 + protected void onLoginClick()
  233 + {
  234 + this.dialogResult = true;
  235 + this.dialog.setVisible(false);
  236 + }
  237 +
  238 + protected void onCancelClick()
  239 + {
  240 + this.dialog.setVisible(false);
  241 + }
  242 +
  243 + protected void onOfflineCheckedChanged()
  244 + {
  245 + boolean selected = this.chkOffline.isSelected();
  246 + this.btnLogin.setText(selected ? "Work Offline" : "Log In");
  247 + this.txtUsername.setEnabled(!selected);
  248 + this.txtPassword.setEnabled(!selected);
  249 + }
  250 +
  251 + /**
  252 + * @param dialog
  253 + */
  254 + public void setDialog(JDialog dialog)
  255 + {
  256 + this.dialog = dialog;
  257 +
  258 + this.dialog.addWindowListener(new WindowAdapter()
  259 + {
  260 + @Override
  261 + public void windowOpened(WindowEvent e)
  262 + {
  263 + LoginPanel.this.onShowDialog();
  264 + }
  265 + });
  266 +
  267 + this.dialog.getRootPane().setDefaultButton(this.btnLogin);
  268 + this.dialog.setFocusTraversalPolicy(this.tabOrder);
  269 + }
  270 +
  271 + public boolean showModalDialog()
  272 + {
  273 + this.dialog.setVisible(true);
  274 + this.dialog.dispose();
  275 + return this.dialogResult;
  276 + }
  277 +
  278 + public String getUsername()
  279 + {
  280 + return this.txtUsername.getText();
  281 + }
  282 +
  283 + public String getPassword()
  284 + {
  285 + return this.txtPassword.getText();
  286 + }
  287 +
  288 + public boolean workOffline()
  289 + {
  290 + return this.chkOffline.isSelected();
  291 + }
  292 +
  293 + public static LoginPanel getLoginPanel(String username, String password, String error)
  294 + {
  295 + if (username == null) username = "";
  296 + if (password == null) password = "";
  297 +
  298 + final JDialog dialog = new JDialog();
  299 + final LoginPanel panel = new LoginPanel(username, password, error);
  300 + panel.setDialog(dialog);
  301 +
  302 + dialog.setContentPane(panel);
  303 + dialog.setTitle("Yggdrasil Login");
  304 + dialog.setResizable(false);
  305 + dialog.pack();
  306 + dialog.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
  307 + dialog.setLocationRelativeTo(null);
  308 + dialog.setModal(true);
  309 +
  310 + return panel;
  311 + }
  312 +
  313 + class ListFocusTraversal extends FocusTraversalPolicy
  314 + {
  315 + private final List<Component> components = new ArrayList<Component>();
  316 +
  317 + void add(Component component)
  318 + {
  319 + this.components.add(component);
  320 + }
  321 +
  322 + @Override
  323 + public Component getComponentAfter(Container container, Component component)
  324 + {
  325 + int index = this.components.indexOf(component) + 1;
  326 + if (index >= this.components.size()) return this.components.get(0);
  327 + return this.components.get(index);
  328 + }
  329 +
  330 + @Override
  331 + public Component getComponentBefore(Container container, Component component)
  332 + {
  333 + int index = this.components.indexOf(component) - 1;
  334 + if (index < 0) return this.getLastComponent(container);
  335 + return this.components.get(index);
  336 + }
  337 +
  338 + @Override
  339 + public Component getFirstComponent(Container container)
  340 + {
  341 + return this.components.get(0);
  342 + }
  343 +
  344 + @Override
  345 + public Component getLastComponent(Container container)
  346 + {
  347 + return this.components.get(this.components.size() - 1);
  348 + }
  349 +
  350 + @Override
  351 + public Component getDefaultComponent(Container container)
  352 + {
  353 + return this.getFirstComponent(container);
  354 + }
  355 + }
  356 +}
debug/com/mumfrey/liteloader/debug/Start.java renamed to src/debug/java/com/mumfrey/liteloader/debug/Start.java
1 -package com.mumfrey.liteloader.debug;  
2 -  
3 -import java.io.File;  
4 -import java.util.ArrayList;  
5 -import java.util.HashMap;  
6 -import java.util.HashSet;  
7 -import java.util.List;  
8 -import java.util.Map;  
9 -import java.util.Map.Entry;  
10 -import java.util.Set;  
11 -  
12 -import net.minecraft.launchwrapper.Launch;  
13 -  
14 -import com.google.common.base.Strings;  
15 -import com.google.common.collect.ImmutableSet;  
16 -import com.mumfrey.liteloader.launch.LiteLoaderTweaker;  
17 -import com.mumfrey.liteloader.launch.LiteLoaderTweakerServer;  
18 -import com.mumfrey.liteloader.util.log.LiteLoaderLogger;  
19 -  
20 -/**  
21 - * Wrapper class for LaunchWrapper Main class, which logs in using Yggdrasil first so that online shizzle can be tested  
22 - *  
23 - * @author Adam Mummery-Smith  
24 - */  
25 -public abstract class Start  
26 -{  
27 - /**  
28 - * Number of times to retry Yggdrasil login  
29 - */  
30 - private static final int LOGIN_RETRIES = 5;  
31 -  
32 - /**  
33 - * Arguments which are allowed to have multiple occurrences  
34 - */  
35 - private static final Set<String> MULTI_VALUE_ARGS = ImmutableSet.<String>of(  
36 - "--tweakClass"  
37 - );  
38 -  
39 - /**  
40 - * Entry point.  
41 - *  
42 - * @param args  
43 - */  
44 - public static void main(String[] args)  
45 - {  
46 - System.setProperty("mcpenv", "true");  
47 - Launch.main(Start.processArgs(args));  
48 - }  
49 -  
50 - /**  
51 - * Process the launch-time args, since we may be being launched by GradleStart we need to parse  
52 - * out any values passed in and ensure we replace them with our own  
53 - */  
54 - private static String[] processArgs(String[] args)  
55 - {  
56 - List<String> unqualifiedArgs = new ArrayList<String>();  
57 - Map<String, Set<String>> qualifiedArgs = new HashMap<String, Set<String>>();  
58 -  
59 - Start.parseArgs(args, unqualifiedArgs, qualifiedArgs);  
60 -  
61 - if (Start.hasArg(unqualifiedArgs, "server"))  
62 - {  
63 - Start.addRequiredArgsServer(args, unqualifiedArgs, qualifiedArgs);  
64 - }  
65 - else  
66 - {  
67 - Start.addRequiredArgsClient(args, unqualifiedArgs, qualifiedArgs);  
68 - }  
69 -  
70 - args = Start.combineArgs(args, unqualifiedArgs, qualifiedArgs);  
71 -  
72 - return args;  
73 - }  
74 -  
75 - private static boolean hasArg(List<String> args, String target)  
76 - {  
77 - for (String arg : args)  
78 - {  
79 - if (target.equalsIgnoreCase(arg))  
80 - return true;  
81 - }  
82 -  
83 - return false;  
84 - }  
85 -  
86 - /**  
87 - * Read the args from the command line into the qualified and unqualified collections  
88 - */  
89 - private static void parseArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)  
90 - {  
91 - String qualifier = null;  
92 - for (String arg : args)  
93 - {  
94 - boolean isQualifier = arg.startsWith("-");  
95 -  
96 - if (isQualifier)  
97 - {  
98 - if (qualifier != null) unqualifiedArgs.add(qualifier);  
99 - qualifier = arg;  
100 - }  
101 - else if (qualifier != null)  
102 - {  
103 - Start.addArg(qualifiedArgs, qualifier, arg);  
104 - qualifier = null;  
105 - }  
106 - else  
107 - {  
108 - unqualifiedArgs.add(arg);  
109 - }  
110 - }  
111 -  
112 - if (qualifier != null) unqualifiedArgs.add(qualifier);  
113 - }  
114 -  
115 - private static void addRequiredArgsClient(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)  
116 - {  
117 - LoginManager loginManager = Start.doLogin(qualifiedArgs);  
118 -  
119 - File gameDir = new File(System.getProperty("user.dir"));  
120 - File assetsDir = new File(gameDir, "assets");  
121 -  
122 - Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweaker.class.getName());  
123 - Start.addArg(qualifiedArgs, "--username", loginManager.getProfileName());  
124 - Start.addArg(qualifiedArgs, "--uuid", loginManager.getUUID());  
125 - Start.addArg(qualifiedArgs, "--accessToken", loginManager.getAuthenticatedToken());  
126 - Start.addArg(qualifiedArgs, "--userType", loginManager.getUserType());  
127 - Start.addArg(qualifiedArgs, "--userProperties", loginManager.getUserProperties());  
128 - Start.addArg(qualifiedArgs, "--version", "mcp");  
129 - Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());  
130 - Start.addArg(qualifiedArgs, "--assetIndex", LiteLoaderTweaker.VERSION);  
131 - Start.addArg(qualifiedArgs, "--assetsDir", assetsDir.getAbsolutePath());  
132 - }  
133 -  
134 - private static void addRequiredArgsServer(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)  
135 - {  
136 - File gameDir = new File(System.getProperty("user.dir"));  
137 -  
138 - Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweakerServer.class.getName());  
139 - Start.addArg(qualifiedArgs, "--version", "mcp");  
140 - Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());  
141 - }  
142 -  
143 - private static LoginManager doLogin(Map<String, Set<String>> qualifiedArgs)  
144 - {  
145 - File loginJson = new File(new File(System.getProperty("user.dir")), ".auth.json");  
146 - LoginManager loginManager = new LoginManager(loginJson);  
147 -  
148 - String usernameFromCmdLine = Start.getArg(qualifiedArgs, "--username");  
149 - String passwordFromCmdLine = Start.getArg(qualifiedArgs, "--password");  
150 -  
151 - loginManager.login(usernameFromCmdLine, passwordFromCmdLine, Start.LOGIN_RETRIES);  
152 -  
153 - LiteLoaderLogger.info("Launching game as %s", loginManager.getProfileName());  
154 -  
155 - return loginManager;  
156 - }  
157 -  
158 - private static void addArg(Map<String, Set<String>> qualifiedArgs, String qualifier, String arg)  
159 - {  
160 - Set<String> args = qualifiedArgs.get(qualifier);  
161 -  
162 - if (args == null)  
163 - {  
164 - args = new HashSet<String>();  
165 - qualifiedArgs.put(qualifier, args);  
166 - }  
167 -  
168 - if (!Start.MULTI_VALUE_ARGS.contains(qualifier))  
169 - args.clear();  
170 -  
171 - args.add(arg);  
172 - }  
173 -  
174 - private static String getArg(Map<String, Set<String>> qualifiedArgs, String arg)  
175 - {  
176 - if (qualifiedArgs.containsKey(arg))  
177 - {  
178 - return qualifiedArgs.get(arg).iterator().next();  
179 - }  
180 -  
181 - return null;  
182 - }  
183 -  
184 - private static String[] combineArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)  
185 - {  
186 - for (Entry<String, Set<String>> qualifiedArg : qualifiedArgs.entrySet())  
187 - {  
188 - for (String argValue : qualifiedArg.getValue())  
189 - {  
190 - unqualifiedArgs.add(qualifiedArg.getKey());  
191 - if (!Strings.isNullOrEmpty(argValue)) unqualifiedArgs.add(argValue);  
192 - }  
193 - }  
194 -  
195 - return unqualifiedArgs.toArray(args);  
196 - }  
197 -} 1 +package com.mumfrey.liteloader.debug;
  2 +
  3 +import java.io.File;
  4 +import java.util.ArrayList;
  5 +import java.util.HashMap;
  6 +import java.util.HashSet;
  7 +import java.util.List;
  8 +import java.util.Map;
  9 +import java.util.Map.Entry;
  10 +import java.util.Set;
  11 +
  12 +import net.minecraft.launchwrapper.Launch;
  13 +
  14 +import com.google.common.base.Strings;
  15 +import com.google.common.collect.ImmutableSet;
  16 +import com.mumfrey.liteloader.launch.LiteLoaderTweaker;
  17 +import com.mumfrey.liteloader.launch.LiteLoaderTweakerServer;
  18 +import com.mumfrey.liteloader.util.log.LiteLoaderLogger;
  19 +
  20 +/**
  21 + * Wrapper class for LaunchWrapper Main class, which logs in using Yggdrasil first so that online shizzle can be tested
  22 + *
  23 + * @author Adam Mummery-Smith
  24 + */
  25 +public abstract class Start
  26 +{
  27 + /**
  28 + * Number of times to retry Yggdrasil login
  29 + */
  30 + private static final int LOGIN_RETRIES = 5;
  31 +
  32 + /**
  33 + * Arguments which are allowed to have multiple occurrences
  34 + */
  35 + private static final Set<String> MULTI_VALUE_ARGS = ImmutableSet.<String>of(
  36 + "--tweakClass"
  37 + );
  38 +
  39 + /**
  40 + * Entry point.
  41 + *
  42 + * @param args
  43 + */
  44 + public static void main(String[] args)
  45 + {
  46 + System.setProperty("mcpenv", "true");
  47 + Launch.main(Start.processArgs(args));
  48 + }
  49 +
  50 + /**
  51 + * Process the launch-time args, since we may be being launched by GradleStart we need to parse
  52 + * out any values passed in and ensure we replace them with our own
  53 + */
  54 + private static String[] processArgs(String[] args)
  55 + {
  56 + List<String> unqualifiedArgs = new ArrayList<String>();
  57 + Map<String, Set<String>> qualifiedArgs = new HashMap<String, Set<String>>();
  58 +
  59 + Start.parseArgs(args, unqualifiedArgs, qualifiedArgs);
  60 +
  61 + if (Start.hasArg(unqualifiedArgs, "server"))
  62 + {
  63 + Start.addRequiredArgsServer(args, unqualifiedArgs, qualifiedArgs);
  64 + }
  65 + else
  66 + {
  67 + Start.addRequiredArgsClient(args, unqualifiedArgs, qualifiedArgs);
  68 + }
  69 +
  70 + args = Start.combineArgs(args, unqualifiedArgs, qualifiedArgs);
  71 +
  72 + return args;
  73 + }
  74 +
  75 + private static boolean hasArg(List<String> args, String target)
  76 + {
  77 + for (String arg : args)
  78 + {
  79 + if (target.equalsIgnoreCase(arg))
  80 + return true;
  81 + }
  82 +
  83 + return false;
  84 + }
  85 +
  86 + /**
  87 + * Read the args from the command line into the qualified and unqualified collections
  88 + */
  89 + private static void parseArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  90 + {
  91 + String qualifier = null;
  92 + for (String arg : args)
  93 + {
  94 + boolean isQualifier = arg.startsWith("-");
  95 +
  96 + if (isQualifier)
  97 + {
  98 + if (qualifier != null) unqualifiedArgs.add(qualifier);
  99 + qualifier = arg;
  100 + }
  101 + else if (qualifier != null)
  102 + {
  103 + Start.addArg(qualifiedArgs, qualifier, arg);
  104 + qualifier = null;
  105 + }
  106 + else
  107 + {
  108 + unqualifiedArgs.add(arg);
  109 + }
  110 + }
  111 +
  112 + if (qualifier != null) unqualifiedArgs.add(qualifier);
  113 + }
  114 +
  115 + private static void addRequiredArgsClient(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  116 + {
  117 + LoginManager loginManager = Start.doLogin(qualifiedArgs);
  118 +
  119 + File gameDir = new File(System.getProperty("user.dir"));
  120 + File assetsDir = new File(gameDir, "assets");
  121 +
  122 + Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweaker.class.getName());
  123 + Start.addArg(qualifiedArgs, "--username", loginManager.getProfileName());
  124 + Start.addArg(qualifiedArgs, "--uuid", loginManager.getUUID());
  125 + Start.addArg(qualifiedArgs, "--accessToken", loginManager.getAuthenticatedToken());
  126 + Start.addArg(qualifiedArgs, "--userType", loginManager.getUserType());
  127 + Start.addArg(qualifiedArgs, "--userProperties", loginManager.getUserProperties());
  128 + Start.addArg(qualifiedArgs, "--version", "mcp");
  129 + Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());
  130 + Start.addArg(qualifiedArgs, "--assetIndex", LiteLoaderTweaker.VERSION);
  131 + Start.addArg(qualifiedArgs, "--assetsDir", assetsDir.getAbsolutePath());
  132 + }
  133 +
  134 + private static void addRequiredArgsServer(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  135 + {
  136 + File gameDir = new File(System.getProperty("user.dir"));
  137 +
  138 + Start.addArg(qualifiedArgs, "--tweakClass", LiteLoaderTweakerServer.class.getName());
  139 + Start.addArg(qualifiedArgs, "--version", "mcp");
  140 + Start.addArg(qualifiedArgs, "--gameDir", gameDir.getAbsolutePath());
  141 + }
  142 +
  143 + private static LoginManager doLogin(Map<String, Set<String>> qualifiedArgs)
  144 + {
  145 + File loginJson = new File(new File(System.getProperty("user.dir")), ".auth.json");
  146 + LoginManager loginManager = new LoginManager(loginJson);
  147 +
  148 + String usernameFromCmdLine = Start.getArg(qualifiedArgs, "--username");
  149 + String passwordFromCmdLine = Start.getArg(qualifiedArgs, "--password");
  150 +
  151 + loginManager.login(usernameFromCmdLine, passwordFromCmdLine, Start.LOGIN_RETRIES);
  152 +
  153 + LiteLoaderLogger.info("Launching game as %s", loginManager.getProfileName());
  154 +
  155 + return loginManager;
  156 + }
  157 +
  158 + private static void addArg(Map<String, Set<String>> qualifiedArgs, String qualifier, String arg)
  159 + {
  160 + Set<String> args = qualifiedArgs.get(qualifier);
  161 +
  162 + if (args == null)
  163 + {
  164 + args = new HashSet<String>();
  165 + qualifiedArgs.put(qualifier, args);
  166 + }
  167 +
  168 + if (!Start.MULTI_VALUE_ARGS.contains(qualifier))
  169 + args.clear();
  170 +
  171 + args.add(arg);
  172 + }
  173 +
  174 + private static String getArg(Map<String, Set<String>> qualifiedArgs, String arg)
  175 + {
  176 + if (qualifiedArgs.containsKey(arg))
  177 + {
  178 + return qualifiedArgs.get(arg).iterator().next();
  179 + }
  180 +
  181 + return null;
  182 + }
  183 +
  184 + private static String[] combineArgs(String[] args, List<String> unqualifiedArgs, Map<String, Set<String>> qualifiedArgs)
  185 + {
  186 + for (Entry<String, Set<String>> qualifiedArg : qualifiedArgs.entrySet())
  187 + {
  188 + for (String argValue : qualifiedArg.getValue())
  189 + {
  190 + unqualifiedArgs.add(qualifiedArg.getKey());
  191 + if (!Strings.isNullOrEmpty(argValue)) unqualifiedArgs.add(argValue);
  192 + }
  193 + }
  194 +
  195 + return unqualifiedArgs.toArray(args);
  196 + }
  197 +}