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 } 318 } 319 320 /** 321 * Draws the screen and all the components in it. 322 */ 323 public void drawScreen(int par1, int par2, float par3) 324 { 325 this.lagTooltip = null; 326 StringTranslate var4 = StringTranslate.getInstance(); 327 this.drawDefaultBackground(); 328 this.serverSlotContainer.drawScreen(par1, par2, par3); 329 this.drawCenteredString(this.fontRenderer, var4.translateKey("multiplayer.title"), this.width / 2, 20, 16777215); 330 super.drawScreen(par1, par2, par3); 331 332 if (this.lagTooltip != null) 333 { 334 this.func_74007_a(this.lagTooltip, par1, par2); 335 } 336 } 337 338 /** 339 * Join server by slot index 340 */ 341 private void joinServer(int par1) 342 { 343 if (par1 < this.internetServerList.countServers()) 344 { 345 this.func_74002_a(this.internetServerList.getServerData(par1)); 346 } 347 else 348 { 349 par1 -= this.internetServerList.countServers(); 350 351 if (par1 < this.field_74026_B.size()) 352 { 353 LanServer var2 = (LanServer)this.field_74026_B.get(par1); 354 this.func_74002_a(new ServerData(var2.func_77487_a(), var2.func_77488_b())); 355 } 356 } 357 } 358 359 private void func_74002_a(ServerData par1ServerData) 360 { 361 this.mc.displayGuiScreen(new GuiConnecting(this.mc, par1ServerData)); 362 } 363 364 private static void func_74017_b(ServerData par1ServerData) throws IOException 365 { 366 ServerAddress var1 = ServerAddress.func_78860_a(par1ServerData.serverIP); 367 Socket var2 = null; 368 DataInputStream var3 = null; 369 DataOutputStream var4 = null; 370 371 try 372 { 373 var2 = new Socket(); 374 var2.setSoTimeout(3000); 375 var2.setTcpNoDelay(true); 376 var2.setTrafficClass(18); 377 var2.connect(new InetSocketAddress(var1.getIP(), var1.getPort()), 3000); 378 var3 = new DataInputStream(var2.getInputStream()); 379 var4 = new DataOutputStream(var2.getOutputStream()); 380 var4.write(254); 381 var4.write(1); 382 383 if (var3.read() != 255) 384 { 385 throw new IOException("Bad message"); 386 } 387 388 String var5 = Packet.readString(var3, 256); 389 char[] var6 = var5.toCharArray(); 390 391 for (int var7 = 0; var7 < var6.length; ++var7) 392 { 393 if (var6[var7] != 167 && var6[var7] != 0 && ChatAllowedCharacters.allowedCharacters.indexOf(var6[var7]) < 0) 394 { 395 var6[var7] = 63; 396 } 397 } 398 399 var5 = new String(var6); 400 int var8; 401 int var9; 402 String[] var26; 403 404 if (var5.startsWith("\u00a7") && var5.length() > 1) 405 { 406 var26 = var5.substring(1).split("\u0000"); 407 408 if (MathHelper.func_82715_a(var26[0], 0) == 1) 409 { 410 par1ServerData.serverMOTD = var26[3]; 411 par1ServerData.field_82821_f = MathHelper.func_82715_a(var26[1], par1ServerData.field_82821_f); 412 par1ServerData.gameVersion = var26[2]; 413 var8 = MathHelper.func_82715_a(var26[4], 0); 414 var9 = MathHelper.func_82715_a(var26[5], 0); 415 416 if (var8 >= 0 && var9 >= 0) 417 { 418 par1ServerData.populationInfo = "\u00a77" + var8 + "\u00a78/\u00a77" + var9; 419 } 420 else 421 { 422 par1ServerData.populationInfo = "\u00a78???"; 423 } 424 } 425 else 426 { 427 par1ServerData.gameVersion = "???"; 428 par1ServerData.serverMOTD = "\u00a78???"; 429 par1ServerData.field_82821_f = 48; 430 par1ServerData.populationInfo = "\u00a78???"; 431 } 432 } 433 else 434 { 435 var26 = var5.split("\u00a7"); 436 var5 = var26[0]; 437 var8 = -1; 438 var9 = -1; 439 440 try 441 { 442 var8 = Integer.parseInt(var26[1]); 443 var9 = Integer.parseInt(var26[2]); 444 } 445 catch (Exception var24) 446 { 447 ; 448 } 449 450 par1ServerData.serverMOTD = "\u00a77" + var5; 451 452 if (var8 >= 0 && var9 > 0) 453 { 454 par1ServerData.populationInfo = "\u00a77" + var8 + "\u00a78/\u00a77" + var9; 455 } 456 else 457 { 458 par1ServerData.populationInfo = "\u00a78???"; 459 } 460 461 par1ServerData.gameVersion = "1.3"; 462 par1ServerData.field_82821_f = 46; 463 } 464 } 465 finally 466 { 467 try 468 { 469 if (var3 != null) 470 { 471 var3.close(); 472 } 473 } 474 catch (Throwable var23) 475 { 476 ; 477 } 478 479 try 480 { 481 if (var4 != null) 482 { 483 var4.close(); 484 } 485 } 486 catch (Throwable var22) 487 { 488 ; 489 } 490 491 try 492 { 493 if (var2 != null) 494 { 495 var2.close(); 496 } 497 } 498 catch (Throwable var21) 499 { 500 ; 501 } 502 } 503 } 504 505 protected void func_74007_a(String par1Str, int par2, int par3) 506 { 507 if (par1Str != null) 508 { 509 int var4 = par2 + 12; 510 int var5 = par3 - 12; 511 int var6 = this.fontRenderer.getStringWidth(par1Str); 512 this.drawGradientRect(var4 - 3, var5 - 3, var4 + var6 + 3, var5 + 8 + 3, -1073741824, -1073741824); 513 this.fontRenderer.drawStringWithShadow(par1Str, var4, var5, -1); 514 } 515 } 516 517 static ServerList func_74006_a(GuiMultiplayer par0GuiMultiplayer) 518 { 519 return par0GuiMultiplayer.internetServerList; 520 } 521 522 static List func_74003_b(GuiMultiplayer par0GuiMultiplayer) 523 { 524 return par0GuiMultiplayer.field_74026_B; 525 } 526 527 static int func_74020_c(GuiMultiplayer par0GuiMultiplayer) 528 { 529 return par0GuiMultiplayer.selectedServer; 530 } 531 532 static int func_74015_a(GuiMultiplayer par0GuiMultiplayer, int par1) 533 { 534 return par0GuiMultiplayer.selectedServer = par1; 535 } 536 537 /** 538 * Return buttonSelect GuiButton 539 */ 540 static GuiButton getButtonSelect(GuiMultiplayer par0GuiMultiplayer) 541 { 542 return par0GuiMultiplayer.buttonSelect; 543 } 544 545 /** 546 * Return buttonEdit GuiButton 547 */ 548 static GuiButton getButtonEdit(GuiMultiplayer par0GuiMultiplayer) 549 { 550 return par0GuiMultiplayer.buttonEdit; 551 } 552 553 /** 554 * Return buttonDelete GuiButton 555 */ 556 static GuiButton getButtonDelete(GuiMultiplayer par0GuiMultiplayer) 557 { 558 return par0GuiMultiplayer.buttonDelete; 559 } 560 561 static void func_74008_b(GuiMultiplayer par0GuiMultiplayer, int par1) 562 { 563 par0GuiMultiplayer.joinServer(par1); 564 } 565 566 static int func_74010_g(GuiMultiplayer par0GuiMultiplayer) 567 { 568 return par0GuiMultiplayer.field_74039_z; 569 } 570 571 static Object func_74011_h() 572 { 573 return lock; 574 } 575 576 static int func_74012_i() 577 { 578 return threadsPending; 579 } 580 581 static int func_74021_j() 582 { 583 return threadsPending++; 584 } 585 586 static void func_82291_a(ServerData par0ServerData) throws IOException 587 { 588 func_74017_b(par0ServerData); 589 } 590 591 static int func_74018_k() 592 { 593 return threadsPending--; 594 } 595 596 static String func_74009_a(GuiMultiplayer par0GuiMultiplayer, String par1Str) 597 { 598 return par0GuiMultiplayer.lagTooltip = par1Str; 599 } 600 }