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.MathHelper;
022import net.minecraft.util.StatCollector;
023import net.minecraft.util.StringTranslate;
024import org.lwjgl.input.Keyboard;
025
026@SideOnly(Side.CLIENT)
027public 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}