    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}