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 }