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