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