001 package net.minecraft.client.gui;
002
003 import cpw.mods.fml.relauncher.Side;
004 import cpw.mods.fml.relauncher.SideOnly;
005 import java.io.DataInputStream;
006 import java.io.DataOutputStream;
007 import java.io.IOException;
008 import java.net.InetSocketAddress;
009 import java.net.Socket;
010 import java.util.Collections;
011 import java.util.List;
012 import net.minecraft.client.multiplayer.GuiConnecting;
013 import net.minecraft.client.multiplayer.LanServer;
014 import net.minecraft.client.multiplayer.LanServerList;
015 import net.minecraft.client.multiplayer.ServerAddress;
016 import net.minecraft.client.multiplayer.ServerData;
017 import net.minecraft.client.multiplayer.ServerList;
018 import net.minecraft.client.multiplayer.ThreadLanServerFind;
019 import net.minecraft.network.packet.Packet;
020 import net.minecraft.util.ChatAllowedCharacters;
021 import net.minecraft.util.MathHelper;
022 import net.minecraft.util.StatCollector;
023 import net.minecraft.util.StringTranslate;
024 import org.lwjgl.input.Keyboard;
025
026 @SideOnly(Side.CLIENT)
027 public class GuiMultiplayer extends GuiScreen
028 {
029 /** Number of outstanding ThreadPollServers threads */
030 private static int threadsPending = 0;
031
032 /** Lock object for use with synchronized() */
033 private static Object lock = new Object();
034
035 /**
036 * A reference to the screen object that created this. Used for navigating between screens.
037 */
038 private GuiScreen parentScreen;
039
040 /** Slot container for the server list */
041 private GuiSlotServer serverSlotContainer;
042 private ServerList internetServerList;
043
044 /** Index of the currently selected server */
045 private int selectedServer = -1;
046
047 /** The 'Edit' button */
048 private GuiButton buttonEdit;
049
050 /** The 'Join Server' button */
051 private GuiButton buttonSelect;
052
053 /** The 'Delete' button */
054 private GuiButton buttonDelete;
055
056 /** The 'Delete' button was clicked */
057 private boolean deleteClicked = false;
058
059 /** The 'Add server' button was clicked */
060 private boolean addClicked = false;
061
062 /** The 'Edit' button was clicked */
063 private boolean editClicked = false;
064
065 /** The 'Direct Connect' button was clicked */
066 private boolean directClicked = false;
067
068 /** This GUI's lag tooltip text or null if no lag icon is being hovered. */
069 private String lagTooltip = null;
070
071 /** Instance of ServerData. */
072 private ServerData theServerData = null;
073 private LanServerList localNetworkServerList;
074 private ThreadLanServerFind localServerFindThread;
075 private int field_74039_z;
076 private boolean field_74024_A;
077 private List listofLanServers = Collections.emptyList();
078
079 public GuiMultiplayer(GuiScreen par1GuiScreen)
080 {
081 this.parentScreen = par1GuiScreen;
082 }
083
084 /**
085 * Adds the buttons (and other controls) to the screen in question.
086 */
087 public void initGui()
088 {
089 Keyboard.enableRepeatEvents(true);
090 this.controlList.clear();
091
092 if (!this.field_74024_A)
093 {
094 this.field_74024_A = true;
095 this.internetServerList = new ServerList(this.mc);
096 this.internetServerList.loadServerList();
097 this.localNetworkServerList = new LanServerList();
098
099 try
100 {
101 this.localServerFindThread = new ThreadLanServerFind(this.localNetworkServerList);
102 this.localServerFindThread.start();
103 }
104 catch (Exception var2)
105 {
106 System.out.println("Unable to start LAN server detection: " + var2.getMessage());
107 }
108
109 this.serverSlotContainer = new GuiSlotServer(this);
110 }
111 else
112 {
113 this.serverSlotContainer.func_77207_a(this.width, this.height, 32, this.height - 64);
114 }
115
116 this.initGuiControls();
117 }
118
119 /**
120 * Populate the GuiScreen controlList
121 */
122 public void initGuiControls()
123 {
124 StringTranslate var1 = StringTranslate.getInstance();
125 this.controlList.add(this.buttonEdit = new GuiButton(7, this.width / 2 - 154, this.height - 28, 70, 20, var1.translateKey("selectServer.edit")));
126 this.controlList.add(this.buttonDelete = new GuiButton(2, this.width / 2 - 74, this.height - 28, 70, 20, var1.translateKey("selectServer.delete")));
127 this.controlList.add(this.buttonSelect = new GuiButton(1, this.width / 2 - 154, this.height - 52, 100, 20, var1.translateKey("selectServer.select")));
128 this.controlList.add(new GuiButton(4, this.width / 2 - 50, this.height - 52, 100, 20, var1.translateKey("selectServer.direct")));
129 this.controlList.add(new GuiButton(3, this.width / 2 + 4 + 50, this.height - 52, 100, 20, var1.translateKey("selectServer.add")));
130 this.controlList.add(new GuiButton(8, this.width / 2 + 4, this.height - 28, 70, 20, var1.translateKey("selectServer.refresh")));
131 this.controlList.add(new GuiButton(0, this.width / 2 + 4 + 76, this.height - 28, 75, 20, var1.translateKey("gui.cancel")));
132 boolean var2 = this.selectedServer >= 0 && this.selectedServer < this.serverSlotContainer.getSize();
133 this.buttonSelect.enabled = var2;
134 this.buttonEdit.enabled = var2;
135 this.buttonDelete.enabled = var2;
136 }
137
138 /**
139 * Called from the main game loop to update the screen.
140 */
141 public void updateScreen()
142 {
143 super.updateScreen();
144 ++this.field_74039_z;
145
146 if (this.localNetworkServerList.getWasUpdated())
147 {
148 this.listofLanServers = this.localNetworkServerList.getLanServers();
149 this.localNetworkServerList.setWasNotUpdated();
150 }
151 }
152
153 /**
154 * Called when the screen is unloaded. Used to disable keyboard repeat events
155 */
156 public void onGuiClosed()
157 {
158 Keyboard.enableRepeatEvents(false);
159
160 if (this.localServerFindThread != null)
161 {
162 this.localServerFindThread.interrupt();
163 this.localServerFindThread = null;
164 }
165 }
166
167 /**
168 * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
169 */
170 protected void actionPerformed(GuiButton par1GuiButton)
171 {
172 if (par1GuiButton.enabled)
173 {
174 if (par1GuiButton.id == 2)
175 {
176 String var2 = this.internetServerList.getServerData(this.selectedServer).serverName;
177
178 if (var2 != null)
179 {
180 this.deleteClicked = true;
181 StringTranslate var3 = StringTranslate.getInstance();
182 String var4 = var3.translateKey("selectServer.deleteQuestion");
183 String var5 = "\'" + var2 + "\' " + var3.translateKey("selectServer.deleteWarning");
184 String var6 = var3.translateKey("selectServer.deleteButton");
185 String var7 = var3.translateKey("gui.cancel");
186 GuiYesNo var8 = new GuiYesNo(this, var4, var5, var6, var7, this.selectedServer);
187 this.mc.displayGuiScreen(var8);
188 }
189 }
190 else if (par1GuiButton.id == 1)
191 {
192 this.joinServer(this.selectedServer);
193 }
194 else if (par1GuiButton.id == 4)
195 {
196 this.directClicked = true;
197 this.mc.displayGuiScreen(new GuiScreenServerList(this, this.theServerData = new ServerData(StatCollector.translateToLocal("selectServer.defaultName"), "")));
198 }
199 else if (par1GuiButton.id == 3)
200 {
201 this.addClicked = true;
202 this.mc.displayGuiScreen(new GuiScreenAddServer(this, this.theServerData = new ServerData(StatCollector.translateToLocal("selectServer.defaultName"), "")));
203 }
204 else if (par1GuiButton.id == 7)
205 {
206 this.editClicked = true;
207 ServerData var9 = this.internetServerList.getServerData(this.selectedServer);
208 this.theServerData = new ServerData(var9.serverName, var9.serverIP);
209 this.theServerData.setHideAddress(var9.isHidingAddress());
210 this.mc.displayGuiScreen(new GuiScreenAddServer(this, this.theServerData));
211 }
212 else if (par1GuiButton.id == 0)
213 {
214 this.mc.displayGuiScreen(this.parentScreen);
215 }
216 else if (par1GuiButton.id == 8)
217 {
218 this.mc.displayGuiScreen(new GuiMultiplayer(this.parentScreen));
219 }
220 else
221 {
222 this.serverSlotContainer.actionPerformed(par1GuiButton);
223 }
224 }
225 }
226
227 public void confirmClicked(boolean par1, int par2)
228 {
229 if (this.deleteClicked)
230 {
231 this.deleteClicked = false;
232
233 if (par1)
234 {
235 this.internetServerList.removeServerData(par2);
236 this.internetServerList.saveServerList();
237 this.selectedServer = -1;
238 }
239
240 this.mc.displayGuiScreen(this);
241 }
242 else if (this.directClicked)
243 {
244 this.directClicked = false;
245
246 if (par1)
247 {
248 this.connectToServer(this.theServerData);
249 }
250 else
251 {
252 this.mc.displayGuiScreen(this);
253 }
254 }
255 else if (this.addClicked)
256 {
257 this.addClicked = false;
258
259 if (par1)
260 {
261 this.internetServerList.addServerData(this.theServerData);
262 this.internetServerList.saveServerList();
263 this.selectedServer = -1;
264 }
265
266 this.mc.displayGuiScreen(this);
267 }
268 else if (this.editClicked)
269 {
270 this.editClicked = false;
271
272 if (par1)
273 {
274 ServerData var3 = this.internetServerList.getServerData(this.selectedServer);
275 var3.serverName = this.theServerData.serverName;
276 var3.serverIP = this.theServerData.serverIP;
277 var3.setHideAddress(this.theServerData.isHidingAddress());
278 this.internetServerList.saveServerList();
279 }
280
281 this.mc.displayGuiScreen(this);
282 }
283 }
284
285 /**
286 * Fired when a key is typed. This is the equivalent of KeyListener.keyTyped(KeyEvent e).
287 */
288 protected void keyTyped(char par1, int par2)
289 {
290 int var3 = this.selectedServer;
291
292 if (par2 == 59)
293 {
294 this.mc.gameSettings.hideServerAddress = !this.mc.gameSettings.hideServerAddress;
295 this.mc.gameSettings.saveOptions();
296 }
297 else
298 {
299 if (isShiftKeyDown() && par2 == 200)
300 {
301 if (var3 > 0 && var3 < this.internetServerList.countServers())
302 {
303 this.internetServerList.swapServers(var3, var3 - 1);
304 --this.selectedServer;
305
306 if (var3 < this.internetServerList.countServers() - 1)
307 {
308 this.serverSlotContainer.func_77208_b(-this.serverSlotContainer.slotHeight);
309 }
310 }
311 }
312 else if (isShiftKeyDown() && par2 == 208)
313 {
314 if (var3 < this.internetServerList.countServers() - 1)
315 {
316 this.internetServerList.swapServers(var3, var3 + 1);
317 ++this.selectedServer;
318
319 if (var3 > 0)
320 {
321 this.serverSlotContainer.func_77208_b(this.serverSlotContainer.slotHeight);
322 }
323 }
324 }
325 else if (par1 == 13)
326 {
327 this.actionPerformed((GuiButton)this.controlList.get(2));
328 }
329 else
330 {
331 super.keyTyped(par1, par2);
332 }
333 }
334 }
335
336 /**
337 * Draws the screen and all the components in it.
338 */
339 public void drawScreen(int par1, int par2, float par3)
340 {
341 this.lagTooltip = null;
342 StringTranslate var4 = StringTranslate.getInstance();
343 this.drawDefaultBackground();
344 this.serverSlotContainer.drawScreen(par1, par2, par3);
345 this.drawCenteredString(this.fontRenderer, var4.translateKey("multiplayer.title"), this.width / 2, 20, 16777215);
346 super.drawScreen(par1, par2, par3);
347
348 if (this.lagTooltip != null)
349 {
350 this.func_74007_a(this.lagTooltip, par1, par2);
351 }
352 }
353
354 /**
355 * Join server by slot index
356 */
357 private void joinServer(int par1)
358 {
359 if (par1 < this.internetServerList.countServers())
360 {
361 this.connectToServer(this.internetServerList.getServerData(par1));
362 }
363 else
364 {
365 par1 -= this.internetServerList.countServers();
366
367 if (par1 < this.listofLanServers.size())
368 {
369 LanServer var2 = (LanServer)this.listofLanServers.get(par1);
370 this.connectToServer(new ServerData(var2.getServerMotd(), var2.getServerIpPort()));
371 }
372 }
373 }
374
375 private void connectToServer(ServerData par1ServerData)
376 {
377 this.mc.displayGuiScreen(new GuiConnecting(this.mc, par1ServerData));
378 }
379
380 private static void func_74017_b(ServerData par1ServerData) throws IOException
381 {
382 ServerAddress var1 = ServerAddress.func_78860_a(par1ServerData.serverIP);
383 Socket var2 = null;
384 DataInputStream var3 = null;
385 DataOutputStream var4 = null;
386
387 try
388 {
389 var2 = new Socket();
390 var2.setSoTimeout(3000);
391 var2.setTcpNoDelay(true);
392 var2.setTrafficClass(18);
393 var2.connect(new InetSocketAddress(var1.getIP(), var1.getPort()), 3000);
394 var3 = new DataInputStream(var2.getInputStream());
395 var4 = new DataOutputStream(var2.getOutputStream());
396 var4.write(254);
397 var4.write(1);
398
399 if (var3.read() != 255)
400 {
401 throw new IOException("Bad message");
402 }
403
404 String var5 = Packet.readString(var3, 256);
405 char[] var6 = var5.toCharArray();
406
407 for (int var7 = 0; var7 < var6.length; ++var7)
408 {
409 if (var6[var7] != 167 && var6[var7] != 0 && ChatAllowedCharacters.allowedCharacters.indexOf(var6[var7]) < 0)
410 {
411 var6[var7] = 63;
412 }
413 }
414
415 var5 = new String(var6);
416 int var8;
417 int var9;
418 String[] var26;
419
420 if (var5.startsWith("\u00a7") && var5.length() > 1)
421 {
422 var26 = var5.substring(1).split("\u0000");
423
424 if (MathHelper.parseIntWithDefault(var26[0], 0) == 1)
425 {
426 par1ServerData.serverMOTD = var26[3];
427 par1ServerData.field_82821_f = MathHelper.parseIntWithDefault(var26[1], par1ServerData.field_82821_f);
428 par1ServerData.gameVersion = var26[2];
429 var8 = MathHelper.parseIntWithDefault(var26[4], 0);
430 var9 = MathHelper.parseIntWithDefault(var26[5], 0);
431
432 if (var8 >= 0 && var9 >= 0)
433 {
434 par1ServerData.populationInfo = "\u00a77" + var8 + "\u00a78/\u00a77" + var9;
435 }
436 else
437 {
438 par1ServerData.populationInfo = "\u00a78???";
439 }
440 }
441 else
442 {
443 par1ServerData.gameVersion = "???";
444 par1ServerData.serverMOTD = "\u00a78???";
445 par1ServerData.field_82821_f = 52;
446 par1ServerData.populationInfo = "\u00a78???";
447 }
448 }
449 else
450 {
451 var26 = var5.split("\u00a7");
452 var5 = var26[0];
453 var8 = -1;
454 var9 = -1;
455
456 try
457 {
458 var8 = Integer.parseInt(var26[1]);
459 var9 = Integer.parseInt(var26[2]);
460 }
461 catch (Exception var24)
462 {
463 ;
464 }
465
466 par1ServerData.serverMOTD = "\u00a77" + var5;
467
468 if (var8 >= 0 && var9 > 0)
469 {
470 par1ServerData.populationInfo = "\u00a77" + var8 + "\u00a78/\u00a77" + var9;
471 }
472 else
473 {
474 par1ServerData.populationInfo = "\u00a78???";
475 }
476
477 par1ServerData.gameVersion = "1.3";
478 par1ServerData.field_82821_f = 50;
479 }
480 }
481 finally
482 {
483 try
484 {
485 if (var3 != null)
486 {
487 var3.close();
488 }
489 }
490 catch (Throwable var23)
491 {
492 ;
493 }
494
495 try
496 {
497 if (var4 != null)
498 {
499 var4.close();
500 }
501 }
502 catch (Throwable var22)
503 {
504 ;
505 }
506
507 try
508 {
509 if (var2 != null)
510 {
511 var2.close();
512 }
513 }
514 catch (Throwable var21)
515 {
516 ;
517 }
518 }
519 }
520
521 protected void func_74007_a(String par1Str, int par2, int par3)
522 {
523 if (par1Str != null)
524 {
525 int var4 = par2 + 12;
526 int var5 = par3 - 12;
527 int var6 = this.fontRenderer.getStringWidth(par1Str);
528 this.drawGradientRect(var4 - 3, var5 - 3, var4 + var6 + 3, var5 + 8 + 3, -1073741824, -1073741824);
529 this.fontRenderer.drawStringWithShadow(par1Str, var4, var5, -1);
530 }
531 }
532
533 static ServerList getInternetServerList(GuiMultiplayer par0GuiMultiplayer)
534 {
535 return par0GuiMultiplayer.internetServerList;
536 }
537
538 static List getListOfLanServers(GuiMultiplayer par0GuiMultiplayer)
539 {
540 return par0GuiMultiplayer.listofLanServers;
541 }
542
543 static int getSelectedServer(GuiMultiplayer par0GuiMultiplayer)
544 {
545 return par0GuiMultiplayer.selectedServer;
546 }
547
548 static int getAndSetSelectedServer(GuiMultiplayer par0GuiMultiplayer, int par1)
549 {
550 return par0GuiMultiplayer.selectedServer = par1;
551 }
552
553 /**
554 * Return buttonSelect GuiButton
555 */
556 static GuiButton getButtonSelect(GuiMultiplayer par0GuiMultiplayer)
557 {
558 return par0GuiMultiplayer.buttonSelect;
559 }
560
561 /**
562 * Return buttonEdit GuiButton
563 */
564 static GuiButton getButtonEdit(GuiMultiplayer par0GuiMultiplayer)
565 {
566 return par0GuiMultiplayer.buttonEdit;
567 }
568
569 /**
570 * Return buttonDelete GuiButton
571 */
572 static GuiButton getButtonDelete(GuiMultiplayer par0GuiMultiplayer)
573 {
574 return par0GuiMultiplayer.buttonDelete;
575 }
576
577 static void func_74008_b(GuiMultiplayer par0GuiMultiplayer, int par1)
578 {
579 par0GuiMultiplayer.joinServer(par1);
580 }
581
582 static int func_74010_g(GuiMultiplayer par0GuiMultiplayer)
583 {
584 return par0GuiMultiplayer.field_74039_z;
585 }
586
587 static Object func_74011_h()
588 {
589 return lock;
590 }
591
592 static int func_74012_i()
593 {
594 return threadsPending;
595 }
596
597 static int func_74021_j()
598 {
599 return threadsPending++;
600 }
601
602 static void func_82291_a(ServerData par0ServerData) throws IOException
603 {
604 func_74017_b(par0ServerData);
605 }
606
607 static int func_74018_k()
608 {
609 return threadsPending--;
610 }
611
612 static String func_74009_a(GuiMultiplayer par0GuiMultiplayer, String par1Str)
613 {
614 return par0GuiMultiplayer.lagTooltip = par1Str;
615 }
616 }