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.func_98033_al().func_98236_b("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}