Commit 7aa49e453f0b5d067cd53961b7457c7c99663a82
1 parent
fca9591f
LiteLoader 1.6.4_02 - dev only - added comments to LoginManager, some minor tweaks
Showing
3 changed files
with
322 additions
and
157 deletions
debug/com/mumfrey/liteloader/debug/LoginManager.java
@@ -5,15 +5,17 @@ import java.io.FileReader; | @@ -5,15 +5,17 @@ import java.io.FileReader; | ||
5 | import java.io.FileWriter; | 5 | import java.io.FileWriter; |
6 | import java.io.IOException; | 6 | import java.io.IOException; |
7 | import java.net.Proxy; | 7 | import java.net.Proxy; |
8 | +import java.util.HashMap; | ||
8 | import java.util.Map; | 9 | import java.util.Map; |
9 | import java.util.UUID; | 10 | import java.util.UUID; |
10 | import java.util.logging.Logger; | 11 | import java.util.logging.Logger; |
11 | 12 | ||
13 | +import javax.swing.JOptionPane; | ||
14 | + | ||
12 | import com.google.common.base.Strings; | 15 | import com.google.common.base.Strings; |
13 | import com.google.gson.Gson; | 16 | import com.google.gson.Gson; |
14 | import com.google.gson.GsonBuilder; | 17 | import com.google.gson.GsonBuilder; |
15 | -import com.google.gson.JsonIOException; | ||
16 | -import com.google.gson.JsonSyntaxException; | 18 | +import com.google.gson.annotations.SerializedName; |
17 | import com.mojang.authlib.Agent; | 19 | import com.mojang.authlib.Agent; |
18 | import com.mojang.authlib.GameProfile; | 20 | import com.mojang.authlib.GameProfile; |
19 | import com.mojang.authlib.exceptions.AuthenticationException; | 21 | import com.mojang.authlib.exceptions.AuthenticationException; |
@@ -28,24 +30,62 @@ import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; | @@ -28,24 +30,62 @@ import com.mojang.authlib.yggdrasil.YggdrasilUserAuthentication; | ||
28 | */ | 30 | */ |
29 | public class LoginManager | 31 | public class LoginManager |
30 | { | 32 | { |
33 | + /** | ||
34 | + * Logger instance | ||
35 | + */ | ||
31 | private static Logger logger = Logger.getLogger("liteloader"); | 36 | private static Logger logger = Logger.getLogger("liteloader"); |
32 | 37 | ||
38 | + /** | ||
39 | + * Gson instance for serialising and deserialising the authentication data | ||
40 | + */ | ||
33 | private static Gson gson = new GsonBuilder().setPrettyPrinting().create(); | 41 | private static Gson gson = new GsonBuilder().setPrettyPrinting().create(); |
34 | 42 | ||
43 | + /** | ||
44 | + * Authentication service | ||
45 | + */ | ||
35 | private YggdrasilAuthenticationService authService; | 46 | private YggdrasilAuthenticationService authService; |
36 | 47 | ||
48 | + /** | ||
49 | + * Authentication agent | ||
50 | + */ | ||
37 | private YggdrasilUserAuthentication authentication; | 51 | private YggdrasilUserAuthentication authentication; |
38 | 52 | ||
53 | + /** | ||
54 | + * JSON file to load/save auth data from | ||
55 | + */ | ||
39 | private File jsonFile; | 56 | private File jsonFile; |
40 | 57 | ||
58 | + /** | ||
59 | + * Username read from the auth JSON file, we use this as the default in the login dialog in | ||
60 | + * case login fails. This is stored in the JSON even if authentication is not successful so that | ||
61 | + * we can display the same username next time | ||
62 | + */ | ||
41 | private String defaultUsername; | 63 | private String defaultUsername; |
42 | 64 | ||
65 | + /** | ||
66 | + * Minecraft screen name read from the auth JSON file. Use this as default in case the login fails | ||
67 | + * or is skipped (when offline) so that at least the Minecraft client has a sensible display name. | ||
68 | + * Defaults to user.name when not specified | ||
69 | + */ | ||
43 | private String defaultDisplayName = System.getProperty("user.name"); | 70 | private String defaultDisplayName = System.getProperty("user.name"); |
44 | 71 | ||
72 | + /** | ||
73 | + * True if login should not be attempted, skips the authentication attempt and the login dialog | ||
74 | + */ | ||
45 | private boolean offline = false; | 75 | private boolean offline = false; |
46 | 76 | ||
47 | - private boolean showDialog = false; | 77 | + /** |
78 | + * If authentication fails with token then the first attempt will be to use the user/pass specified | ||
79 | + * on the command line (if any). This flag is set AFTER that first attempt so that we know to display | ||
80 | + * the login dialog anyway (eg. the login on the command line was bad) | ||
81 | + */ | ||
82 | + private boolean forceShowLoginDialog = false; | ||
48 | 83 | ||
84 | + /** | ||
85 | + * ctor | ||
86 | + * | ||
87 | + * @param jsonFile | ||
88 | + */ | ||
49 | public LoginManager(File jsonFile) | 89 | public LoginManager(File jsonFile) |
50 | { | 90 | { |
51 | this.jsonFile = jsonFile; | 91 | this.jsonFile = jsonFile; |
@@ -55,7 +95,8 @@ public class LoginManager | @@ -55,7 +95,8 @@ public class LoginManager | ||
55 | } | 95 | } |
56 | 96 | ||
57 | /** | 97 | /** |
58 | - * | 98 | + * When authenticaion fails, we regenerate the auth service and agent because trying again with the same |
99 | + * client data will fail. | ||
59 | */ | 100 | */ |
60 | public void resetAuth() | 101 | public void resetAuth() |
61 | { | 102 | { |
@@ -64,12 +105,11 @@ public class LoginManager | @@ -64,12 +105,11 @@ public class LoginManager | ||
64 | } | 105 | } |
65 | 106 | ||
66 | /** | 107 | /** |
67 | - * @throws JsonIOException | ||
68 | - * @throws JsonSyntaxException | 108 | + * Load auth data from the json file |
69 | */ | 109 | */ |
70 | private void load() | 110 | private void load() |
71 | { | 111 | { |
72 | - if (this.jsonFile.exists()) | 112 | + if (this.jsonFile != null && this.jsonFile.exists()) |
73 | { | 113 | { |
74 | FileReader fileReader = null; | 114 | FileReader fileReader = null; |
75 | 115 | ||
@@ -78,7 +118,7 @@ public class LoginManager | @@ -78,7 +118,7 @@ public class LoginManager | ||
78 | fileReader = new FileReader(this.jsonFile); | 118 | fileReader = new FileReader(this.jsonFile); |
79 | AuthData authData = LoginManager.gson.fromJson(fileReader, AuthData.class); | 119 | AuthData authData = LoginManager.gson.fromJson(fileReader, AuthData.class); |
80 | 120 | ||
81 | - if (authData != null) | 121 | + if (authData != null && authData.validate()) |
82 | { | 122 | { |
83 | this.logInfo("Initialising Yggdrasil authentication service with client token: %s", authData.getClientToken()); | 123 | this.logInfo("Initialising Yggdrasil authentication service with client token: %s", authData.getClientToken()); |
84 | this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, authData.getClientToken()); | 124 | this.authService = new YggdrasilAuthenticationService(Proxy.NO_PROXY, authData.getClientToken()); |
@@ -101,38 +141,57 @@ public class LoginManager | @@ -101,38 +141,57 @@ public class LoginManager | ||
101 | } | 141 | } |
102 | } | 142 | } |
103 | 143 | ||
144 | + /** | ||
145 | + * Save auth data to the JSON file | ||
146 | + */ | ||
104 | private void save() | 147 | private void save() |
105 | { | 148 | { |
106 | - FileWriter fileWriter = null; | ||
107 | - | ||
108 | - try | 149 | + if (this.jsonFile != null) |
109 | { | 150 | { |
110 | - fileWriter = new FileWriter(this.jsonFile); | 151 | + FileWriter fileWriter = null; |
111 | 152 | ||
112 | - AuthData authData = new AuthData(this.authService, this.authentication, this.offline, this.defaultUsername, this.defaultDisplayName); | ||
113 | - LoginManager.gson.toJson(authData, fileWriter); | ||
114 | - } | ||
115 | - catch (IOException ex) { ex.printStackTrace(); } | ||
116 | - finally | ||
117 | - { | ||
118 | try | 153 | try |
119 | { | 154 | { |
120 | - if (fileWriter != null) fileWriter.close(); | 155 | + fileWriter = new FileWriter(this.jsonFile); |
156 | + | ||
157 | + AuthData authData = new AuthData(this.authService, this.authentication, this.offline, this.defaultUsername, this.defaultDisplayName); | ||
158 | + LoginManager.gson.toJson(authData, fileWriter); | ||
121 | } | 159 | } |
122 | catch (IOException ex) { ex.printStackTrace(); } | 160 | catch (IOException ex) { ex.printStackTrace(); } |
161 | + finally | ||
162 | + { | ||
163 | + try | ||
164 | + { | ||
165 | + if (fileWriter != null) fileWriter.close(); | ||
166 | + } | ||
167 | + catch (IOException ex) { ex.printStackTrace(); } | ||
168 | + } | ||
123 | } | 169 | } |
124 | - | ||
125 | } | 170 | } |
126 | 171 | ||
172 | + /** | ||
173 | + * Attempt to login. If authentication data are found on disk then tries first to log in with | ||
174 | + * the stored token. If the token login fails then attempts to log in with the username and password | ||
175 | + * specified. If no user or pass are specified or if they fail then displays a login dialog to | ||
176 | + * allow the user to login. If login succeeds then the token is stored on disk and the method | ||
177 | + * returns. | ||
178 | + * | ||
179 | + * If the user presses cancel in the login dialog then the method returns false. | ||
180 | + * | ||
181 | + * @param username User name to log in with if token login fails, if null displays the login dialog immediately | ||
182 | + * @param password Password to log in with if token login fails, if null displays the login dialog immediately | ||
183 | + * @param remainingTries Number of loops to go through before giving up, decremented for each try, specify -1 for unlimited | ||
184 | + * @return false if the user presses cancel in the login dialog, otherwise returns true | ||
185 | + */ | ||
127 | public boolean login(String username, String password, int remainingTries) | 186 | public boolean login(String username, String password, int remainingTries) |
128 | { | 187 | { |
129 | - if (this.offline || remainingTries < 1) | 188 | + if (this.offline || remainingTries == 0) |
130 | { | 189 | { |
131 | this.logInfo("LoginManager is set to work offline, skipping login"); | 190 | this.logInfo("LoginManager is set to work offline, skipping login"); |
132 | return false; | 191 | return false; |
133 | } | 192 | } |
134 | 193 | ||
135 | - this.logInfo("Remaining login tries: %d", remainingTries); | 194 | + this.logInfo("Remaining login tries: %s", remainingTries > 0 ? remainingTries : "unlimited"); |
136 | 195 | ||
137 | try | 196 | try |
138 | { | 197 | { |
@@ -153,37 +212,50 @@ public class LoginManager | @@ -153,37 +212,50 @@ public class LoginManager | ||
153 | { | 212 | { |
154 | this.logInfo("Authentication agent reported invalid credentials: %s", ex.getMessage()); | 213 | this.logInfo("Authentication agent reported invalid credentials: %s", ex.getMessage()); |
155 | this.resetAuth(); | 214 | this.resetAuth(); |
156 | - | ||
157 | - if (username == null) | ||
158 | - { | ||
159 | - username = this.defaultUsername; | ||
160 | - } | ||
161 | 215 | ||
162 | - if (this.showDialog || username == null || password == null) | 216 | + if (remainingTries > 1) |
163 | { | 217 | { |
164 | - LoginPanel loginPanel = LoginPanel.getLoginPanel(username, password, this.showDialog ? ex.getMessage() : null); | ||
165 | - if (!loginPanel.showModalDialog()) | 218 | + if (username == null) |
166 | { | 219 | { |
167 | - this.logInfo("User cancelled login dialog"); | 220 | + username = this.defaultUsername; |
221 | + } | ||
222 | + | ||
223 | + if (this.forceShowLoginDialog || username == null || password == null) | ||
224 | + { | ||
225 | + LoginPanel loginPanel = LoginPanel.getLoginPanel(username, password, this.forceShowLoginDialog ? ex.getMessage() : null); | ||
226 | + boolean dialogResult = loginPanel.showModalDialog(); | ||
168 | this.offline = loginPanel.workOffline(); | 227 | this.offline = loginPanel.workOffline(); |
169 | - if (this.offline) this.save(); | ||
170 | - return false; | 228 | + this.defaultUsername = loginPanel.getUsername(); |
229 | + | ||
230 | + if (!dialogResult) | ||
231 | + { | ||
232 | + this.logInfo("User cancelled login dialog"); | ||
233 | + return false; | ||
234 | + } | ||
235 | + | ||
236 | + if (this.offline) | ||
237 | + { | ||
238 | + 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) | ||
239 | + { | ||
240 | + this.offline = false; | ||
241 | + remainingTries = Math.max(remainingTries, 3); | ||
242 | + } | ||
243 | + } | ||
244 | + | ||
245 | + username = loginPanel.getUsername(); | ||
246 | + password = loginPanel.getPassword(); | ||
247 | + this.save(); | ||
171 | } | 248 | } |
172 | - | ||
173 | - username = loginPanel.getUsername(); | ||
174 | - password = loginPanel.getPassword(); | ||
175 | - this.offline = loginPanel.workOffline(); | ||
176 | - this.save(); | ||
177 | - } | ||
178 | - | ||
179 | - if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) | ||
180 | - { | ||
181 | - this.authentication.setUsername(username); | ||
182 | - this.authentication.setPassword(password); | 249 | + |
250 | + if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) | ||
251 | + { | ||
252 | + this.authentication.setUsername(username); | ||
253 | + this.authentication.setPassword(password); | ||
254 | + } | ||
255 | + | ||
256 | + this.forceShowLoginDialog = true; | ||
257 | + this.login(username, password, --remainingTries); | ||
183 | } | 258 | } |
184 | - | ||
185 | - this.showDialog = true; | ||
186 | - this.login(username, password, --remainingTries); | ||
187 | } | 259 | } |
188 | catch (AuthenticationException ex) | 260 | catch (AuthenticationException ex) |
189 | { | 261 | { |
@@ -194,12 +266,34 @@ public class LoginManager | @@ -194,12 +266,34 @@ public class LoginManager | ||
194 | return false; | 266 | return false; |
195 | } | 267 | } |
196 | 268 | ||
269 | + /** | ||
270 | + * Get whether user logged in | ||
271 | + */ | ||
272 | + public boolean isLoggedIn() | ||
273 | + { | ||
274 | + return this.authentication.isLoggedIn(); | ||
275 | + } | ||
276 | + | ||
277 | + /** | ||
278 | + * Get whether we are able to play online or not | ||
279 | + */ | ||
280 | + public boolean canPlayOnline() | ||
281 | + { | ||
282 | + return this.authentication.canPlayOnline(); | ||
283 | + } | ||
284 | + | ||
285 | + /** | ||
286 | + * Get the profile name (minecraft player name) from login | ||
287 | + */ | ||
197 | public String getProfileName() | 288 | public String getProfileName() |
198 | { | 289 | { |
199 | GameProfile selectedProfile = this.authentication.getSelectedProfile(); | 290 | GameProfile selectedProfile = this.authentication.getSelectedProfile(); |
200 | return selectedProfile != null ? selectedProfile.getName() : this.defaultDisplayName; | 291 | return selectedProfile != null ? selectedProfile.getName() : this.defaultDisplayName; |
201 | } | 292 | } |
202 | 293 | ||
294 | + /** | ||
295 | + * Get the session token | ||
296 | + */ | ||
203 | public String getAuthenticatedToken() | 297 | public String getAuthenticatedToken() |
204 | { | 298 | { |
205 | String accessToken = this.authentication.getAuthenticatedToken(); | 299 | String accessToken = this.authentication.getAuthenticatedToken(); |
@@ -211,16 +305,25 @@ public class LoginManager | @@ -211,16 +305,25 @@ public class LoginManager | ||
211 | LoginManager.logger.info(String.format(message, params)); | 305 | LoginManager.logger.info(String.format(message, params)); |
212 | } | 306 | } |
213 | 307 | ||
308 | + /** | ||
309 | + * Struct for Gson serialisation of authenticaion settings | ||
310 | + * | ||
311 | + * @author Adam Mummery-Smith | ||
312 | + */ | ||
214 | class AuthData | 313 | class AuthData |
215 | { | 314 | { |
315 | + @SerializedName("clientToken") | ||
216 | private String clientToken; | 316 | private String clientToken; |
217 | 317 | ||
318 | + @SerializedName("workOffline") | ||
218 | private boolean workOffline; | 319 | private boolean workOffline; |
219 | 320 | ||
321 | + @SerializedName("authData") | ||
220 | private Map<String, String> credentials; | 322 | private Map<String, String> credentials; |
221 | 323 | ||
222 | public AuthData() | 324 | public AuthData() |
223 | { | 325 | { |
326 | + // default ctor for Gson | ||
224 | } | 327 | } |
225 | 328 | ||
226 | public AuthData(YggdrasilAuthenticationService authService, YggdrasilUserAuthentication authentication, boolean workOffline, String defaultUserName, String defaultDisplayName) | 329 | public AuthData(YggdrasilAuthenticationService authService, YggdrasilUserAuthentication authentication, boolean workOffline, String defaultUserName, String defaultDisplayName) |
@@ -236,6 +339,16 @@ public class LoginManager | @@ -236,6 +339,16 @@ public class LoginManager | ||
236 | this.credentials.put("displayName", defaultDisplayName); | 339 | this.credentials.put("displayName", defaultDisplayName); |
237 | } | 340 | } |
238 | 341 | ||
342 | + /** | ||
343 | + * Called after Gson deserialisation to check that deserialisation was successful | ||
344 | + */ | ||
345 | + public boolean validate() | ||
346 | + { | ||
347 | + if (this.clientToken == null) this.clientToken = UUID.randomUUID().toString(); | ||
348 | + if (this.credentials == null) this.credentials = new HashMap<String, String>(); | ||
349 | + return true; | ||
350 | + } | ||
351 | + | ||
239 | public String getClientToken() | 352 | public String getClientToken() |
240 | { | 353 | { |
241 | return this.clientToken; | 354 | return this.clientToken; |
debug/com/mumfrey/liteloader/debug/LoginPanel.java
@@ -44,154 +44,184 @@ import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE; | @@ -44,154 +44,184 @@ import static javax.swing.WindowConstants.DISPOSE_ON_CLOSE; | ||
44 | public class LoginPanel extends JPanel | 44 | public class LoginPanel extends JPanel |
45 | { | 45 | { |
46 | private static final long serialVersionUID = 1L; | 46 | private static final long serialVersionUID = 1L; |
47 | + | ||
48 | + private GridBagLayout panelLoginLayout; | ||
49 | + | ||
50 | + private JPanel panelTitle; | ||
51 | + private JPanel panelCentre; | ||
52 | + private JPanel panelPadding; | ||
53 | + private JPanel panelBottom; | ||
54 | + private JLabel lblTitle; | ||
55 | + private JLabel lblSubTitle; | ||
56 | + private JLabel lblMessage; | ||
57 | + private JLabel lblUserName; | ||
58 | + private JLabel lblPassword; | ||
47 | private TextField txtUsername; | 59 | private TextField txtUsername; |
48 | private TextField txtPassword; | 60 | private TextField txtPassword; |
49 | private JButton btnLogin; | 61 | private JButton btnLogin; |
50 | private JButton btnCancel; | 62 | private JButton btnCancel; |
63 | + private JCheckBox chkOffline; | ||
51 | 64 | ||
52 | - private boolean loginClicked = false; | ||
53 | - | ||
54 | private JDialog dialog; | 65 | private JDialog dialog; |
55 | - private JCheckBox chkOffline; | ||
56 | - private JLabel lblLogIn; | ||
57 | - private JPanel panelLogin; | ||
58 | - private JPanel panelButtons; | ||
59 | - private JPanel panelPadding; | ||
60 | - private JLabel lblNewLabel; | ||
61 | - private JLabel lblPassword; | ||
62 | 66 | ||
63 | - private CustomFocusTraversal tabOrder = new CustomFocusTraversal(); | ||
64 | - private JLabel lblMessage; | 67 | + private ListFocusTraversal tabOrder = new ListFocusTraversal(); |
68 | + | ||
69 | + private boolean dialogResult = false; | ||
65 | 70 | ||
66 | public LoginPanel(String username, String password, String error) | 71 | public LoginPanel(String username, String password, String error) |
67 | { | 72 | { |
73 | + Color backColour = new Color(102, 118, 144); | ||
74 | + | ||
68 | this.setFocusable(false); | 75 | this.setFocusable(false); |
69 | this.setPreferredSize(new Dimension(400, 260)); | 76 | this.setPreferredSize(new Dimension(400, 260)); |
70 | this.setBackground(new Color(105, 105, 105)); | 77 | this.setBackground(new Color(105, 105, 105)); |
71 | this.setLayout(new BorderLayout(0, 0)); | 78 | this.setLayout(new BorderLayout(0, 0)); |
72 | 79 | ||
73 | - this.lblLogIn = new JLabel("Log In"); | ||
74 | - this.lblLogIn.setFocusable(false); | ||
75 | - this.lblLogIn.setBorder(new EmptyBorder(10, 16, 10, 16)); | ||
76 | - this.lblLogIn.setOpaque(true); | ||
77 | - this.lblLogIn.setBackground(new Color(119, 136, 153)); | ||
78 | - this.lblLogIn.setFont(new Font("Tahoma", Font.BOLD, 18)); | ||
79 | - this.lblLogIn.setForeground(new Color(255, 255, 255)); | ||
80 | - this.lblLogIn.setPreferredSize(new Dimension(400, 64)); | ||
81 | - this.add(this.lblLogIn, BorderLayout.NORTH); | ||
82 | - | ||
83 | - this.panelButtons = new JPanel(); | ||
84 | - this.panelButtons.setFocusable(false); | ||
85 | - this.panelButtons.setBackground(new Color(112, 128, 144)); | ||
86 | - this.panelButtons.setPreferredSize(new Dimension(400, 32)); | ||
87 | - this.add(this.panelButtons, BorderLayout.SOUTH); | ||
88 | - this.panelButtons.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); | 80 | + this.panelTitle = new JPanel(); |
81 | + this.panelTitle.setBackground(backColour); | ||
82 | + this.panelTitle.setPreferredSize(new Dimension(400, 64)); | ||
83 | + this.panelTitle.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); | ||
89 | 84 | ||
90 | - this.chkOffline = new JCheckBox("Never ask me to log in (always run offline)"); | ||
91 | - this.chkOffline.setPreferredSize(new Dimension(386, 23)); | ||
92 | - this.chkOffline.setForeground(new Color(255, 255, 255)); | ||
93 | - this.chkOffline.setOpaque(false); | ||
94 | - this.panelButtons.add(this.chkOffline); | 85 | + this.panelBottom = new JPanel(); |
86 | + this.panelBottom.setBackground(backColour); | ||
87 | + this.panelBottom.setPreferredSize(new Dimension(400, 32)); | ||
88 | + this.panelBottom.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5)); | ||
95 | 89 | ||
96 | this.panelPadding = new JPanel(); | 90 | this.panelPadding = new JPanel(); |
97 | - this.panelPadding.setFocusable(false); | ||
98 | this.panelPadding.setBorder(new EmptyBorder(4, 8, 8, 8)); | 91 | this.panelPadding.setBorder(new EmptyBorder(4, 8, 8, 8)); |
99 | this.panelPadding.setOpaque(false); | 92 | this.panelPadding.setOpaque(false); |
100 | - this.add(this.panelPadding, BorderLayout.CENTER); | ||
101 | this.panelPadding.setLayout(new BorderLayout(0, 0)); | 93 | this.panelPadding.setLayout(new BorderLayout(0, 0)); |
102 | 94 | ||
103 | - this.panelLogin = new JPanel(); | ||
104 | - this.panelLogin.setFocusable(false); | ||
105 | - this.panelPadding.add(this.panelLogin); | ||
106 | - this.panelLogin.setOpaque(false); | ||
107 | - this.panelLogin.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Yggdrasil Login", TitledBorder.LEADING, TitledBorder.TOP, null, new Color(255, 255, 255))); | ||
108 | - GridBagLayout gbl_panelLogin = new GridBagLayout(); | ||
109 | - gbl_panelLogin.columnWidths = new int[] {30, 80, 120, 120, 30}; | ||
110 | - gbl_panelLogin.rowHeights = new int[] {24, 32, 32, 32}; | ||
111 | - gbl_panelLogin.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; | ||
112 | - gbl_panelLogin.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0}; | ||
113 | - this.panelLogin.setLayout(gbl_panelLogin); | 95 | + this.panelCentre = new JPanel(); |
96 | + this.panelCentre.setOpaque(false); | ||
97 | + this.panelCentre.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Yggdrasil Login", TitledBorder.LEADING, TitledBorder.TOP, null, Color.WHITE)); | ||
98 | + this.panelLoginLayout = new GridBagLayout(); | ||
99 | + this.panelLoginLayout.columnWidths = new int[] {30, 80, 120, 120, 30}; | ||
100 | + this.panelLoginLayout.rowHeights = new int[] {24, 32, 32, 32}; | ||
101 | + this.panelLoginLayout.columnWeights = new double[]{0.0, 0.0, 0.0, 0.0, Double.MIN_VALUE}; | ||
102 | + this.panelLoginLayout.rowWeights = new double[]{0.0, 0.0, 0.0, 0.0}; | ||
103 | + this.panelCentre.setLayout(this.panelLoginLayout); | ||
104 | + | ||
105 | + this.lblTitle = new JLabel("Log in to minecraft.net"); | ||
106 | + this.lblTitle.setBorder(new EmptyBorder(4, 16, 0, 16)); | ||
107 | + this.lblTitle.setFont(new Font("Tahoma", Font.BOLD, 18)); | ||
108 | + this.lblTitle.setForeground(Color.WHITE); | ||
109 | + this.lblTitle.setPreferredSize(new Dimension(400, 26)); | ||
110 | + | ||
111 | + this.lblSubTitle = new JLabel("Your password will not be stored, logging in with Yggdrasil"); | ||
112 | + this.lblSubTitle.setBorder(new EmptyBorder(0, 16, 0, 16)); | ||
113 | + this.lblSubTitle.setForeground(Color.WHITE); | ||
114 | + this.lblSubTitle.setPreferredSize(new Dimension(400, 16)); | ||
115 | + | ||
116 | + this.lblMessage = new JLabel("Enter your login details for minecraft.net"); | ||
117 | + this.lblMessage.setForeground(Color.WHITE); | ||
118 | + | ||
119 | + this.lblUserName = new JLabel("User name"); | ||
120 | + this.lblUserName.setForeground(Color.WHITE); | ||
121 | + | ||
122 | + this.lblPassword = new JLabel("Password"); | ||
123 | + this.lblPassword.setForeground(Color.WHITE); | ||
114 | 124 | ||
125 | + this.txtUsername = new TextField(); | ||
126 | + this.txtUsername.setPreferredSize(new Dimension(200, 22)); | ||
127 | + this.txtUsername.setText(username); | ||
128 | + | ||
129 | + this.txtPassword = new TextField(); | ||
130 | + this.txtPassword.setEchoChar('*'); | ||
131 | + this.txtPassword.setPreferredSize(new Dimension(200, 22)); | ||
132 | + this.txtPassword.setText(password); | ||
133 | + | ||
115 | this.btnLogin = new JButton("Log in"); | 134 | this.btnLogin = new JButton("Log in"); |
116 | this.btnLogin.addActionListener(new ActionListener() { | 135 | this.btnLogin.addActionListener(new ActionListener() { |
117 | @Override public void actionPerformed(ActionEvent e) { | 136 | @Override public void actionPerformed(ActionEvent e) { |
118 | LoginPanel.this.onLoginClick(); | 137 | LoginPanel.this.onLoginClick(); |
119 | } | 138 | } |
120 | }); | 139 | }); |
121 | - | 140 | + |
122 | this.btnCancel = new JButton("Cancel"); | 141 | this.btnCancel = new JButton("Cancel"); |
123 | this.btnCancel.addActionListener(new ActionListener() { | 142 | this.btnCancel.addActionListener(new ActionListener() { |
124 | @Override public void actionPerformed(ActionEvent e) { | 143 | @Override public void actionPerformed(ActionEvent e) { |
125 | LoginPanel.this.onCancelClick(); | 144 | LoginPanel.this.onCancelClick(); |
126 | } | 145 | } |
127 | }); | 146 | }); |
147 | + | ||
148 | + this.chkOffline = new JCheckBox("Never ask me to log in (always run offline)"); | ||
149 | + this.chkOffline.setPreferredSize(new Dimension(380, 23)); | ||
150 | + this.chkOffline.setForeground(Color.WHITE); | ||
151 | + this.chkOffline.setOpaque(false); | ||
152 | + this.chkOffline.addActionListener(new ActionListener() | ||
153 | + { | ||
154 | + @Override public void actionPerformed(ActionEvent e) | ||
155 | + { | ||
156 | + LoginPanel.this.onOfflineCheckedChanged(); | ||
157 | + } | ||
158 | + }); | ||
159 | + | ||
160 | + GridBagConstraints lblMessageConstraints = new GridBagConstraints(); | ||
161 | + lblMessageConstraints.anchor = GridBagConstraints.WEST; | ||
162 | + lblMessageConstraints.gridwidth = 2; | ||
163 | + lblMessageConstraints.insets = new Insets(0, 0, 5, 5); | ||
164 | + lblMessageConstraints.gridx = 2; | ||
165 | + lblMessageConstraints.gridy = 0; | ||
128 | 166 | ||
129 | - this.lblMessage = new JLabel("Enter your login details for minecraft.net"); | ||
130 | - this.lblMessage.setForeground(new Color(255, 255, 255)); | ||
131 | - GridBagConstraints gbc_lblNewLabel_1 = new GridBagConstraints(); | ||
132 | - gbc_lblNewLabel_1.anchor = GridBagConstraints.WEST; | ||
133 | - gbc_lblNewLabel_1.gridwidth = 2; | ||
134 | - gbc_lblNewLabel_1.insets = new Insets(0, 0, 5, 5); | ||
135 | - gbc_lblNewLabel_1.gridx = 2; | ||
136 | - gbc_lblNewLabel_1.gridy = 0; | ||
137 | - this.panelLogin.add(this.lblMessage, gbc_lblNewLabel_1); | 167 | + GridBagConstraints lblUserNameConstraints = new GridBagConstraints(); |
168 | + lblUserNameConstraints.anchor = GridBagConstraints.WEST; | ||
169 | + lblUserNameConstraints.fill = GridBagConstraints.VERTICAL; | ||
170 | + lblUserNameConstraints.insets = new Insets(0, 0, 5, 5); | ||
171 | + lblUserNameConstraints.gridx = 1; | ||
172 | + lblUserNameConstraints.gridy = 1; | ||
138 | 173 | ||
139 | - this.lblNewLabel = new JLabel("User name"); | ||
140 | - this.lblNewLabel.setFocusable(false); | ||
141 | - this.lblNewLabel.setForeground(new Color(255, 255, 255)); | ||
142 | - GridBagConstraints gbc_lblNewLabel = new GridBagConstraints(); | ||
143 | - gbc_lblNewLabel.anchor = GridBagConstraints.WEST; | ||
144 | - gbc_lblNewLabel.fill = GridBagConstraints.VERTICAL; | ||
145 | - gbc_lblNewLabel.insets = new Insets(0, 0, 5, 5); | ||
146 | - gbc_lblNewLabel.gridx = 1; | ||
147 | - gbc_lblNewLabel.gridy = 1; | ||
148 | - this.panelLogin.add(this.lblNewLabel, gbc_lblNewLabel); | 174 | + GridBagConstraints lblPasswordConstraints = new GridBagConstraints(); |
175 | + lblPasswordConstraints.anchor = GridBagConstraints.WEST; | ||
176 | + lblPasswordConstraints.fill = GridBagConstraints.VERTICAL; | ||
177 | + lblPasswordConstraints.insets = new Insets(0, 0, 5, 5); | ||
178 | + lblPasswordConstraints.gridx = 1; | ||
179 | + lblPasswordConstraints.gridy = 2; | ||
149 | 180 | ||
150 | - this.txtUsername = new TextField(); | ||
151 | - this.txtUsername.setPreferredSize(new Dimension(200, 22)); | ||
152 | - this.txtUsername.setText(username); | ||
153 | - GridBagConstraints gbc_txtUsername = new GridBagConstraints(); | ||
154 | - gbc_txtUsername.gridwidth = 2; | ||
155 | - gbc_txtUsername.fill = GridBagConstraints.HORIZONTAL; | ||
156 | - gbc_txtUsername.insets = new Insets(0, 0, 5, 0); | ||
157 | - gbc_txtUsername.gridx = 2; | ||
158 | - gbc_txtUsername.gridy = 1; | ||
159 | - this.panelLogin.add(this.txtUsername, gbc_txtUsername); | 181 | + GridBagConstraints txtUsernameConstraints = new GridBagConstraints(); |
182 | + txtUsernameConstraints.gridwidth = 2; | ||
183 | + txtUsernameConstraints.fill = GridBagConstraints.HORIZONTAL; | ||
184 | + txtUsernameConstraints.insets = new Insets(0, 0, 5, 0); | ||
185 | + txtUsernameConstraints.gridx = 2; | ||
186 | + txtUsernameConstraints.gridy = 1; | ||
160 | 187 | ||
161 | - this.lblPassword = new JLabel("Password"); | ||
162 | - this.lblPassword.setFocusable(false); | ||
163 | - this.lblPassword.setForeground(Color.WHITE); | ||
164 | - GridBagConstraints gbc_lblPassword = new GridBagConstraints(); | ||
165 | - gbc_lblPassword.anchor = GridBagConstraints.WEST; | ||
166 | - gbc_lblPassword.fill = GridBagConstraints.VERTICAL; | ||
167 | - gbc_lblPassword.insets = new Insets(0, 0, 5, 5); | ||
168 | - gbc_lblPassword.gridx = 1; | ||
169 | - gbc_lblPassword.gridy = 2; | ||
170 | - this.panelLogin.add(this.lblPassword, gbc_lblPassword); | 188 | + GridBagConstraints txtPasswordConstraints = new GridBagConstraints(); |
189 | + txtPasswordConstraints.gridwidth = 2; | ||
190 | + txtPasswordConstraints.insets = new Insets(0, 0, 5, 0); | ||
191 | + txtPasswordConstraints.fill = GridBagConstraints.HORIZONTAL; | ||
192 | + txtPasswordConstraints.gridx = 2; | ||
193 | + txtPasswordConstraints.gridy = 2; | ||
171 | 194 | ||
172 | - this.txtPassword = new TextField(); | ||
173 | - this.txtPassword.setEchoChar('*'); | ||
174 | - this.txtPassword.setPreferredSize(new Dimension(200, 22)); | ||
175 | - this.txtPassword.setText(password); | ||
176 | - GridBagConstraints gbc_txtPassword = new GridBagConstraints(); | ||
177 | - gbc_txtPassword.gridwidth = 2; | ||
178 | - gbc_txtPassword.insets = new Insets(0, 0, 5, 0); | ||
179 | - gbc_txtPassword.fill = GridBagConstraints.HORIZONTAL; | ||
180 | - gbc_txtPassword.gridx = 2; | ||
181 | - gbc_txtPassword.gridy = 2; | ||
182 | - this.panelLogin.add(this.txtPassword, gbc_txtPassword); | ||
183 | - GridBagConstraints gbc_btnCancel = new GridBagConstraints(); | ||
184 | - gbc_btnCancel.anchor = GridBagConstraints.EAST; | ||
185 | - gbc_btnCancel.insets = new Insets(0, 0, 0, 5); | ||
186 | - gbc_btnCancel.gridx = 2; | ||
187 | - gbc_btnCancel.gridy = 3; | ||
188 | - this.panelLogin.add(this.btnCancel, gbc_btnCancel); | ||
189 | - GridBagConstraints gbc_btnLogin = new GridBagConstraints(); | ||
190 | - gbc_btnLogin.fill = GridBagConstraints.HORIZONTAL; | ||
191 | - gbc_btnLogin.gridx = 3; | ||
192 | - gbc_btnLogin.gridy = 3; | ||
193 | - this.panelLogin.add(this.btnLogin, gbc_btnLogin); | 195 | + GridBagConstraints btnLoginConstraints = new GridBagConstraints(); |
196 | + btnLoginConstraints.fill = GridBagConstraints.HORIZONTAL; | ||
197 | + btnLoginConstraints.gridx = 3; | ||
198 | + btnLoginConstraints.gridy = 3; | ||
199 | + | ||
200 | + GridBagConstraints btnCancelConstraints = new GridBagConstraints(); | ||
201 | + btnCancelConstraints.anchor = GridBagConstraints.EAST; | ||
202 | + btnCancelConstraints.insets = new Insets(0, 0, 0, 5); | ||
203 | + btnCancelConstraints.gridx = 2; | ||
204 | + btnCancelConstraints.gridy = 3; | ||
205 | + | ||
206 | + this.add(this.panelTitle, BorderLayout.NORTH); | ||
207 | + this.add(this.panelPadding, BorderLayout.CENTER); | ||
208 | + this.add(this.panelBottom, BorderLayout.SOUTH); | ||
209 | + | ||
210 | + this.panelPadding.add(this.panelCentre); | ||
194 | 211 | ||
212 | + this.panelTitle.add(this.lblTitle); | ||
213 | + this.panelTitle.add(this.lblSubTitle); | ||
214 | + | ||
215 | + this.panelCentre.add(this.lblMessage, lblMessageConstraints); | ||
216 | + this.panelCentre.add(this.lblUserName, lblUserNameConstraints); | ||
217 | + this.panelCentre.add(this.lblPassword, lblPasswordConstraints); | ||
218 | + this.panelCentre.add(this.txtUsername, txtUsernameConstraints); | ||
219 | + this.panelCentre.add(this.txtPassword, txtPasswordConstraints); | ||
220 | + this.panelCentre.add(this.btnLogin, btnLoginConstraints); | ||
221 | + this.panelCentre.add(this.btnCancel, btnCancelConstraints); | ||
222 | + | ||
223 | + this.panelBottom.add(this.chkOffline); | ||
224 | + | ||
195 | this.tabOrder.add(this.txtUsername); | 225 | this.tabOrder.add(this.txtUsername); |
196 | this.tabOrder.add(this.txtPassword); | 226 | this.tabOrder.add(this.txtPassword); |
197 | this.tabOrder.add(this.btnLogin); | 227 | this.tabOrder.add(this.btnLogin); |
@@ -218,7 +248,7 @@ public class LoginPanel extends JPanel | @@ -218,7 +248,7 @@ public class LoginPanel extends JPanel | ||
218 | 248 | ||
219 | protected void onLoginClick() | 249 | protected void onLoginClick() |
220 | { | 250 | { |
221 | - this.loginClicked = true; | 251 | + this.dialogResult = true; |
222 | this.dialog.setVisible(false); | 252 | this.dialog.setVisible(false); |
223 | } | 253 | } |
224 | 254 | ||
@@ -227,6 +257,14 @@ public class LoginPanel extends JPanel | @@ -227,6 +257,14 @@ public class LoginPanel extends JPanel | ||
227 | this.dialog.setVisible(false); | 257 | this.dialog.setVisible(false); |
228 | } | 258 | } |
229 | 259 | ||
260 | + protected void onOfflineCheckedChanged() | ||
261 | + { | ||
262 | + boolean selected = this.chkOffline.isSelected(); | ||
263 | + this.btnLogin.setText(selected ? "Work Offline" : "Log In"); | ||
264 | + this.txtUsername.setEnabled(!selected); | ||
265 | + this.txtPassword.setEnabled(!selected); | ||
266 | + } | ||
267 | + | ||
230 | /** | 268 | /** |
231 | * @param dialog | 269 | * @param dialog |
232 | * @param panel | 270 | * @param panel |
@@ -252,7 +290,7 @@ public class LoginPanel extends JPanel | @@ -252,7 +290,7 @@ public class LoginPanel extends JPanel | ||
252 | { | 290 | { |
253 | this.dialog.setVisible(true); | 291 | this.dialog.setVisible(true); |
254 | this.dialog.dispose(); | 292 | this.dialog.dispose(); |
255 | - return this.loginClicked; | 293 | + return this.dialogResult; |
256 | } | 294 | } |
257 | 295 | ||
258 | public String getUsername() | 296 | public String getUsername() |
@@ -290,7 +328,7 @@ public class LoginPanel extends JPanel | @@ -290,7 +328,7 @@ public class LoginPanel extends JPanel | ||
290 | return panel; | 328 | return panel; |
291 | } | 329 | } |
292 | 330 | ||
293 | - class CustomFocusTraversal extends FocusTraversalPolicy | 331 | + class ListFocusTraversal extends FocusTraversalPolicy |
294 | { | 332 | { |
295 | private final List<Component> components = new ArrayList<Component>(); | 333 | private final List<Component> components = new ArrayList<Component>(); |
296 | 334 |
debug/com/mumfrey/liteloader/debug/Start.java
1 | package com.mumfrey.liteloader.debug; | 1 | package com.mumfrey.liteloader.debug; |
2 | import java.io.File; | 2 | import java.io.File; |
3 | +import java.util.logging.ConsoleHandler; | ||
4 | +import java.util.logging.Handler; | ||
3 | import java.util.logging.Logger; | 5 | import java.util.logging.Logger; |
4 | 6 | ||
5 | import net.minecraft.launchwrapper.Launch; | 7 | import net.minecraft.launchwrapper.Launch; |
6 | 8 | ||
7 | import com.mumfrey.liteloader.launch.LiteLoaderTweaker; | 9 | import com.mumfrey.liteloader.launch.LiteLoaderTweaker; |
10 | +import com.mumfrey.liteloader.util.log.LiteLoaderLogFormatter; | ||
8 | 11 | ||
9 | /** | 12 | /** |
10 | * Wrapper class for LaunchWrapper Main class, which logs into minecraft.net first so that online shizzle can be tested | 13 | * Wrapper class for LaunchWrapper Main class, which logs into minecraft.net first so that online shizzle can be tested |
@@ -23,6 +26,8 @@ public abstract class Start | @@ -23,6 +26,8 @@ public abstract class Start | ||
23 | */ | 26 | */ |
24 | public static void main(String[] args) | 27 | public static void main(String[] args) |
25 | { | 28 | { |
29 | + Start.prepareLogger(); | ||
30 | + | ||
26 | String usernameFromCmdLine = (args.length > 0) ? args[0] : null; | 31 | String usernameFromCmdLine = (args.length > 0) ? args[0] : null; |
27 | String passwordFromCmdLine = (args.length > 1) ? args[1] : null; | 32 | String passwordFromCmdLine = (args.length > 1) ? args[1] : null; |
28 | 33 | ||
@@ -46,4 +51,13 @@ public abstract class Start | @@ -46,4 +51,13 @@ public abstract class Start | ||
46 | 51 | ||
47 | Launch.main(args); | 52 | Launch.main(args); |
48 | } | 53 | } |
54 | + | ||
55 | + private static void prepareLogger() | ||
56 | + { | ||
57 | + for (Handler handler : Start.logger.getParent().getHandlers()) | ||
58 | + { | ||
59 | + if (handler instanceof ConsoleHandler) | ||
60 | + handler.setFormatter(new LiteLoaderLogFormatter()); | ||
61 | + } | ||
62 | + } | ||
49 | } | 63 | } |