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 field_74030_m;
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        private ServerData field_74031_w = null;
059        private LanServerList field_74041_x;
060        private ThreadLanServerFind field_74040_y;
061        private int field_74039_z;
062        private boolean field_74024_A;
063        private List field_74026_B = Collections.emptyList();
064    
065        public GuiMultiplayer(GuiScreen par1GuiScreen)
066        {
067            this.parentScreen = par1GuiScreen;
068        }
069    
070        /**
071         * Adds the buttons (and other controls) to the screen in question.
072         */
073        public void initGui()
074        {
075            Keyboard.enableRepeatEvents(true);
076            this.controlList.clear();
077    
078            if (!this.field_74024_A)
079            {
080                this.field_74024_A = true;
081                this.field_74030_m = new ServerList(this.mc);
082                this.field_74030_m.loadServerList();
083                this.field_74041_x = new LanServerList();
084    
085                try
086                {
087                    this.field_74040_y = new ThreadLanServerFind(this.field_74041_x);
088                    this.field_74040_y.start();
089                }
090                catch (Exception var2)
091                {
092                    System.out.println("Unable to start LAN server detection: " + var2.getMessage());
093                }
094    
095                this.serverSlotContainer = new GuiSlotServer(this);
096            }
097            else
098            {
099                this.serverSlotContainer.func_77207_a(this.width, this.height, 32, this.height - 64);
100            }
101    
102            this.initGuiControls();
103        }
104    
105        /**
106         * Populate the GuiScreen controlList
107         */
108        public void initGuiControls()
109        {
110            StringTranslate var1 = StringTranslate.getInstance();
111            this.controlList.add(this.buttonEdit = new GuiButton(7, this.width / 2 - 154, this.height - 28, 70, 20, var1.translateKey("selectServer.edit")));
112            this.controlList.add(this.buttonDelete = new GuiButton(2, this.width / 2 - 74, this.height - 28, 70, 20, var1.translateKey("selectServer.delete")));
113            this.controlList.add(this.buttonSelect = new GuiButton(1, this.width / 2 - 154, this.height - 52, 100, 20, var1.translateKey("selectServer.select")));
114            this.controlList.add(new GuiButton(4, this.width / 2 - 50, this.height - 52, 100, 20, var1.translateKey("selectServer.direct")));
115            this.controlList.add(new GuiButton(3, this.width / 2 + 4 + 50, this.height - 52, 100, 20, var1.translateKey("selectServer.add")));
116            this.controlList.add(new GuiButton(8, this.width / 2 + 4, this.height - 28, 70, 20, var1.translateKey("selectServer.refresh")));
117            this.controlList.add(new GuiButton(0, this.width / 2 + 4 + 76, this.height - 28, 75, 20, var1.translateKey("gui.cancel")));
118            boolean var2 = this.selectedServer >= 0 && this.selectedServer < this.serverSlotContainer.getSize();
119            this.buttonSelect.enabled = var2;
120            this.buttonEdit.enabled = var2;
121            this.buttonDelete.enabled = var2;
122        }
123    
124        /**
125         * Called from the main game loop to update the screen.
126         */
127        public void updateScreen()
128        {
129            super.updateScreen();
130            ++this.field_74039_z;
131    
132            if (this.field_74041_x.func_77553_a())
133            {
134                this.field_74026_B = this.field_74041_x.func_77554_c();
135                this.field_74041_x.func_77552_b();
136            }
137        }
138    
139        /**
140         * Called when the screen is unloaded. Used to disable keyboard repeat events
141         */
142        public void onGuiClosed()
143        {
144            Keyboard.enableRepeatEvents(false);
145    
146            if (this.field_74040_y != null)
147            {
148                this.field_74040_y.interrupt();
149                this.field_74040_y = null;
150            }
151        }
152    
153        /**
154         * Fired when a control is clicked. This is the equivalent of ActionListener.actionPerformed(ActionEvent e).
155         */
156        protected void actionPerformed(GuiButton par1GuiButton)
157        {
158            if (par1GuiButton.enabled)
159            {
160                if (par1GuiButton.id == 2)
161                {
162                    String var2 = this.field_74030_m.getServerData(this.selectedServer).serverName;
163    
164                    if (var2 != null)
165                    {
166                        this.deleteClicked = true;
167                        StringTranslate var3 = StringTranslate.getInstance();
168                        String var4 = var3.translateKey("selectServer.deleteQuestion");
169                        String var5 = "\'" + var2 + "\' " + var3.translateKey("selectServer.deleteWarning");
170                        String var6 = var3.translateKey("selectServer.deleteButton");
171                        String var7 = var3.translateKey("gui.cancel");
172                        GuiYesNo var8 = new GuiYesNo(this, var4, var5, var6, var7, this.selectedServer);
173                        this.mc.displayGuiScreen(var8);
174                    }
175                }
176                else if (par1GuiButton.id == 1)
177                {
178                    this.joinServer(this.selectedServer);
179                }
180                else if (par1GuiButton.id == 4)
181                {
182                    this.directClicked = true;
183                    this.mc.displayGuiScreen(new GuiScreenServerList(this, this.field_74031_w = new ServerData(StatCollector.translateToLocal("selectServer.defaultName"), "")));
184                }
185                else if (par1GuiButton.id == 3)
186                {
187                    this.addClicked = true;
188                    this.mc.displayGuiScreen(new GuiScreenAddServer(this, this.field_74031_w = new ServerData(StatCollector.translateToLocal("selectServer.defaultName"), "")));
189                }
190                else if (par1GuiButton.id == 7)
191                {
192                    this.editClicked = true;
193                    ServerData var9 = this.field_74030_m.getServerData(this.selectedServer);
194                    this.mc.displayGuiScreen(new GuiScreenAddServer(this, this.field_74031_w = new ServerData(var9.serverName, var9.serverIP)));
195                }
196                else if (par1GuiButton.id == 0)
197                {
198                    this.mc.displayGuiScreen(this.parentScreen);
199                }
200                else if (par1GuiButton.id == 8)
201                {
202                    this.mc.displayGuiScreen(new GuiMultiplayer(this.parentScreen));
203                }
204                else
205                {
206                    this.serverSlotContainer.actionPerformed(par1GuiButton);
207                }
208            }
209        }
210    
211        public void confirmClicked(boolean par1, int par2)
212        {
213            if (this.deleteClicked)
214            {
215                this.deleteClicked = false;
216    
217                if (par1)
218                {
219                    this.field_74030_m.removeServerData(par2);
220                    this.field_74030_m.saveServerList();
221                    this.selectedServer = -1;
222                }
223    
224                this.mc.displayGuiScreen(this);
225            }
226            else if (this.directClicked)
227            {
228                this.directClicked = false;
229    
230                if (par1)
231                {
232                    this.func_74002_a(this.field_74031_w);
233                }
234                else
235                {
236                    this.mc.displayGuiScreen(this);
237                }
238            }
239            else if (this.addClicked)
240            {
241                this.addClicked = false;
242    
243                if (par1)
244                {
245                    this.field_74030_m.addServerData(this.field_74031_w);
246                    this.field_74030_m.saveServerList();
247                    this.selectedServer = -1;
248                }
249    
250                this.mc.displayGuiScreen(this);
251            }
252            else if (this.editClicked)
253            {
254                this.editClicked = false;
255    
256                if (par1)
257                {
258                    ServerData var3 = this.field_74030_m.getServerData(this.selectedServer);
259                    var3.serverName = this.field_74031_w.serverName;
260                    var3.serverIP = this.field_74031_w.serverIP;
261                    this.field_74030_m.saveServerList();
262                }
263    
264                this.mc.displayGuiScreen(this);
265            }
266        }
267    
268        /**
269         * Fired when a key is typed. This is the equivalent of KeyListener.keyTyped(KeyEvent e).
270         */
271        protected void keyTyped(char par1, int par2)
272        {
273            int var3 = this.selectedServer;
274    
275            if (par2 == 59)
276            {
277                this.mc.gameSettings.field_80005_w = !this.mc.gameSettings.field_80005_w;
278                this.mc.gameSettings.saveOptions();
279            }
280            else
281            {
282                if (isShiftKeyDown() && par2 == 200)
283                {
284                    if (var3 > 0 && var3 < this.field_74030_m.countServers())
285                    {
286                        this.field_74030_m.swapServers(var3, var3 - 1);
287                        --this.selectedServer;
288    
289                        if (var3 < this.field_74030_m.countServers() - 1)
290                        {
291                            this.serverSlotContainer.func_77208_b(-this.serverSlotContainer.slotHeight);
292                        }
293                    }
294                }
295                else if (isShiftKeyDown() && par2 == 208)
296                {
297                    if (var3 < this.field_74030_m.countServers() - 1)
298                    {
299                        this.field_74030_m.swapServers(var3, var3 + 1);
300                        ++this.selectedServer;
301    
302                        if (var3 > 0)
303                        {
304                            this.serverSlotContainer.func_77208_b(this.serverSlotContainer.slotHeight);
305                        }
306                    }
307                }
308                else if (par1 == 13)
309                {
310                    this.actionPerformed((GuiButton)this.controlList.get(2));
311                }
312            }
313        }
314    
315        /**
316         * Draws the screen and all the components in it.
317         */
318        public void drawScreen(int par1, int par2, float par3)
319        {
320            this.lagTooltip = null;
321            StringTranslate var4 = StringTranslate.getInstance();
322            this.drawDefaultBackground();
323            this.serverSlotContainer.drawScreen(par1, par2, par3);
324            this.drawCenteredString(this.fontRenderer, var4.translateKey("multiplayer.title"), this.width / 2, 20, 16777215);
325            super.drawScreen(par1, par2, par3);
326    
327            if (this.lagTooltip != null)
328            {
329                this.func_74007_a(this.lagTooltip, par1, par2);
330            }
331        }
332    
333        /**
334         * Join server by slot index
335         */
336        private void joinServer(int par1)
337        {
338            if (par1 < this.field_74030_m.countServers())
339            {
340                this.func_74002_a(this.field_74030_m.getServerData(par1));
341            }
342            else
343            {
344                par1 -= this.field_74030_m.countServers();
345    
346                if (par1 < this.field_74026_B.size())
347                {
348                    LanServer var2 = (LanServer)this.field_74026_B.get(par1);
349                    this.func_74002_a(new ServerData(var2.func_77487_a(), var2.func_77488_b()));
350                }
351            }
352        }
353    
354        private void func_74002_a(ServerData par1ServerData)
355        {
356            this.mc.displayGuiScreen(new GuiConnecting(this.mc, par1ServerData));
357        }
358    
359        private void func_74017_b(ServerData par1ServerData) throws IOException
360        {
361            ServerAddress var2 = ServerAddress.func_78860_a(par1ServerData.serverIP);
362            Socket var3 = null;
363            DataInputStream var4 = null;
364            DataOutputStream var5 = null;
365    
366            try
367            {
368                var3 = new Socket();
369                var3.setSoTimeout(3000);
370                var3.setTcpNoDelay(true);
371                var3.setTrafficClass(18);
372                var3.connect(new InetSocketAddress(var2.getIP(), var2.getPort()), 3000);
373                var4 = new DataInputStream(var3.getInputStream());
374                var5 = new DataOutputStream(var3.getOutputStream());
375                var5.write(254);
376    
377                if (var4.read() != 255)
378                {
379                    throw new IOException("Bad message");
380                }
381    
382                String var6 = Packet.readString(var4, 256);
383                char[] var7 = var6.toCharArray();
384    
385                for (int var8 = 0; var8 < var7.length; ++var8)
386                {
387                    if (var7[var8] != 167 && ChatAllowedCharacters.allowedCharacters.indexOf(var7[var8]) < 0)
388                    {
389                        var7[var8] = 63;
390                    }
391                }
392    
393                var6 = new String(var7);
394                String[] var27 = var6.split("\u00a7");
395                var6 = var27[0];
396                int var9 = -1;
397                int var10 = -1;
398    
399                try
400                {
401                    var9 = Integer.parseInt(var27[1]);
402                    var10 = Integer.parseInt(var27[2]);
403                }
404                catch (Exception var25)
405                {
406                    ;
407                }
408    
409                par1ServerData.serverMOTD = "\u00a77" + var6;
410    
411                if (var9 >= 0 && var10 > 0)
412                {
413                    par1ServerData.field_78846_c = "\u00a77" + var9 + "\u00a78/\u00a77" + var10;
414                }
415                else
416                {
417                    par1ServerData.field_78846_c = "\u00a78???";
418                }
419            }
420            finally
421            {
422                try
423                {
424                    if (var4 != null)
425                    {
426                        var4.close();
427                    }
428                }
429                catch (Throwable var24)
430                {
431                    ;
432                }
433    
434                try
435                {
436                    if (var5 != null)
437                    {
438                        var5.close();
439                    }
440                }
441                catch (Throwable var23)
442                {
443                    ;
444                }
445    
446                try
447                {
448                    if (var3 != null)
449                    {
450                        var3.close();
451                    }
452                }
453                catch (Throwable var22)
454                {
455                    ;
456                }
457            }
458        }
459    
460        protected void func_74007_a(String par1Str, int par2, int par3)
461        {
462            if (par1Str != null)
463            {
464                int var4 = par2 + 12;
465                int var5 = par3 - 12;
466                int var6 = this.fontRenderer.getStringWidth(par1Str);
467                this.drawGradientRect(var4 - 3, var5 - 3, var4 + var6 + 3, var5 + 8 + 3, -1073741824, -1073741824);
468                this.fontRenderer.drawStringWithShadow(par1Str, var4, var5, -1);
469            }
470        }
471    
472        static ServerList func_74006_a(GuiMultiplayer par0GuiMultiplayer)
473        {
474            return par0GuiMultiplayer.field_74030_m;
475        }
476    
477        static List func_74003_b(GuiMultiplayer par0GuiMultiplayer)
478        {
479            return par0GuiMultiplayer.field_74026_B;
480        }
481    
482        static int func_74020_c(GuiMultiplayer par0GuiMultiplayer)
483        {
484            return par0GuiMultiplayer.selectedServer;
485        }
486    
487        static int func_74015_a(GuiMultiplayer par0GuiMultiplayer, int par1)
488        {
489            return par0GuiMultiplayer.selectedServer = par1;
490        }
491    
492        /**
493         * Return buttonEdit GuiButton
494         */
495        static GuiButton getButtonEdit(GuiMultiplayer par0GuiMultiplayer)
496        {
497            return par0GuiMultiplayer.buttonSelect;
498        }
499    
500        /**
501         * Return buttonDelete GuiButton
502         */
503        static GuiButton getButtonDelete(GuiMultiplayer par0GuiMultiplayer)
504        {
505            return par0GuiMultiplayer.buttonEdit;
506        }
507    
508        static GuiButton func_74019_f(GuiMultiplayer par0GuiMultiplayer)
509        {
510            return par0GuiMultiplayer.buttonDelete;
511        }
512    
513        static void func_74008_b(GuiMultiplayer par0GuiMultiplayer, int par1)
514        {
515            par0GuiMultiplayer.joinServer(par1);
516        }
517    
518        static int func_74010_g(GuiMultiplayer par0GuiMultiplayer)
519        {
520            return par0GuiMultiplayer.field_74039_z;
521        }
522    
523        static Object func_74011_h()
524        {
525            return lock;
526        }
527    
528        static int func_74012_i()
529        {
530            return threadsPending;
531        }
532    
533        static int func_74021_j()
534        {
535            return threadsPending++;
536        }
537    
538        static void func_74013_a(GuiMultiplayer par0GuiMultiplayer, ServerData par1ServerData) throws IOException
539        {
540            par0GuiMultiplayer.func_74017_b(par1ServerData);
541        }
542    
543        static int func_74018_k()
544        {
545            return threadsPending--;
546        }
547    
548        static String func_74009_a(GuiMultiplayer par0GuiMultiplayer, String par1Str)
549        {
550            return par0GuiMultiplayer.lagTooltip = par1Str;
551        }
552    }