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 }