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 listofLanServers = 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.getWasUpdated())
135            {
136                this.listofLanServers = this.localNetworkServerList.getLanServers();
137                this.localNetworkServerList.setWasNotUpdated();
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.setHideAddress(var9.isHidingAddress());
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.connectToServer(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.setHideAddress(this.theServerData.isHidingAddress());
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.connectToServer(this.internetServerList.getServerData(par1));
350            }
351            else
352            {
353                par1 -= this.internetServerList.countServers();
354    
355                if (par1 < this.listofLanServers.size())
356                {
357                    LanServer var2 = (LanServer)this.listofLanServers.get(par1);
358                    this.connectToServer(new ServerData(var2.getServerMotd(), var2.getServerIpPort()));
359                }
360            }
361        }
362    
363        private void connectToServer(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.parseIntWithDefault(var26[0], 0) == 1)
413                    {
414                        par1ServerData.serverMOTD = var26[3];
415                        par1ServerData.field_82821_f = MathHelper.parseIntWithDefault(var26[1], par1ServerData.field_82821_f);
416                        par1ServerData.gameVersion = var26[2];
417                        var8 = MathHelper.parseIntWithDefault(var26[4], 0);
418                        var9 = MathHelper.parseIntWithDefault(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 = 50;
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 = 48;
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 getInternetServerList(GuiMultiplayer par0GuiMultiplayer)
522        {
523            return par0GuiMultiplayer.internetServerList;
524        }
525    
526        static List getListOfLanServers(GuiMultiplayer par0GuiMultiplayer)
527        {
528            return par0GuiMultiplayer.listofLanServers;
529        }
530    
531        static int getSelectedServer(GuiMultiplayer par0GuiMultiplayer)
532        {
533            return par0GuiMultiplayer.selectedServer;
534        }
535    
536        static int getAndSetSelectedServer(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    }