001    package net.minecraft.client.gui;
002    
003    import cpw.mods.fml.relauncher.Side;
004    import cpw.mods.fml.relauncher.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 net.minecraft.client.multiplayer.GuiConnecting;
013    import net.minecraft.client.multiplayer.LanServer;
014    import net.minecraft.client.multiplayer.LanServerList;
015    import net.minecraft.client.multiplayer.ServerAddress;
016    import net.minecraft.client.multiplayer.ServerData;
017    import net.minecraft.client.multiplayer.ServerList;
018    import net.minecraft.client.multiplayer.ThreadLanServerFind;
019    import net.minecraft.network.packet.Packet;
020    import net.minecraft.util.ChatAllowedCharacters;
021    import net.minecraft.util.MathHelper;
022    import net.minecraft.util.StatCollector;
023    import net.minecraft.util.StringTranslate;
024    import org.lwjgl.input.Keyboard;
025    
026    @SideOnly(Side.CLIENT)
027    public 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    }