    001    package net.minecraft.src;
    002
    003    import cpw.mods.fml.common.FMLCommonHandler;
    004    import cpw.mods.fml.common.Side;
    005    import cpw.mods.fml.common.asm.SideOnly;
    006    import java.io.File;
    007    import java.io.IOException;
    008    import java.net.InetAddress;
    009    import java.util.ArrayList;
    010    import java.util.Collections;
    011    import java.util.List;
    012    import java.util.Random;
    013    import java.util.logging.Level;
    014    import net.minecraft.server.MinecraftServer;
    015
    016    public class DedicatedServer extends MinecraftServer implements IServer
    017    {
    018        private final List pendingCommandList = Collections.synchronizedList(new ArrayList());
    019        private RConThreadQuery theRConThreadQuery;
    020        private RConThreadMain theRConThreadMain;
    021        private PropertyManager settings;
    022        private boolean canSpawnStructures;
    023        private EnumGameType gameType;
    024        private NetworkListenThread networkThread;
    025        private boolean guiIsEnabled = false;
    026
    027        public DedicatedServer(File par1File)
    028        {
    029            super(par1File);
    030            new DedicatedServerSleepThread(this);
    031        }
    032
    033        /**
    034         * Initialises the server and starts it.
    035         */
    036        protected boolean startServer() throws IOException
    037        {
    038            DedicatedServerCommandThread var1 = new DedicatedServerCommandThread(this);
    039            var1.setDaemon(true);
    040            var1.start();
    041            ConsoleLogManager.init();
    042            logger.info("Starting minecraft server version 1.4.1");
    043
    044            if (Runtime.getRuntime().maxMemory() / 1024L / 1024L < 512L)
    045            {
    046                logger.warning("To start the server with more ram, launch it as \"java -Xmx1024M -Xms1024M -jar minecraft_server.jar\"");
    047            }
    048
    049            FMLCommonHandler.instance().onServerStart(this);
    050
    051            logger.info("Loading properties");
    052            this.settings = new PropertyManager(new File("server.properties"));
    053
    054            if (this.isSinglePlayer())
    055            {
    056                this.setHostname("127.0.0.1");
    057            }
    058            else
    059            {
    060                this.setOnlineMode(this.settings.getBooleanProperty("online-mode", true));
    061                this.setHostname(this.settings.getProperty("server-ip", ""));
    062            }
    063
    064            this.setCanSpawnAnimals(this.settings.getBooleanProperty("spawn-animals", true));
    065            this.setCanSpawnNPCs(this.settings.getBooleanProperty("spawn-npcs", true));
    066            this.setAllowPvp(this.settings.getBooleanProperty("pvp", true));
    067            this.setAllowFlight(this.settings.getBooleanProperty("allow-flight", false));
    068            this.setTexturePack(this.settings.getProperty("texture-pack", ""));
    069            this.setMOTD(this.settings.getProperty("motd", "A Minecraft Server"));
    070            this.canSpawnStructures = this.settings.getBooleanProperty("generate-structures", true);
    071            int var2 = this.settings.getIntProperty("gamemode", EnumGameType.SURVIVAL.getID());
    072            this.gameType = WorldSettings.getGameTypeById(var2);
    073            logger.info("Default game type: " + this.gameType);
    074            InetAddress var3 = null;
    075
    076            if (this.getServerHostname().length() > 0)
    077            {
    078                var3 = InetAddress.getByName(this.getServerHostname());
    079            }
    080
    081            if (this.getServerPort() < 0)
    082            {
    083                this.setServerPort(this.settings.getIntProperty("server-port", 25565));
    084            }
    085
    086            logger.info("Generating keypair");
    087            this.setKeyPair(CryptManager.createNewKeyPair());
    088            logger.info("Starting Minecraft server on " + (this.getServerHostname().length() == 0 ? "*" : this.getServerHostname()) + ":" + this.getServerPort());
    089
    090            try
    091            {
    092                this.networkThread = new DedicatedServerListenThread(this, var3, this.getServerPort());
    093            }
    094            catch (IOException var16)
    095            {
    096                logger.warning("**** FAILED TO BIND TO PORT!");
    097                logger.log(Level.WARNING, "The exception was: " + var16.toString());
    098                logger.warning("Perhaps a server is already running on that port?");
    099                return false;
    100            }
    101
    102            if (!this.isServerInOnlineMode())
    103            {
    104                logger.warning("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
    105                logger.warning("The server will make no attempt to authenticate usernames. Beware.");
    106                logger.warning("While this makes the game possible to play without internet access, it also opens up the ability for hackers to connect with any username they choose.");
    107                logger.warning("To change this, set \"online-mode\" to \"true\" in the server.properties file.");
    108            }
    109
    110            FMLCommonHandler.instance().onServerStarted();
    111            this.setConfigurationManager(new DedicatedPlayerList(this));
    112            long var4 = System.nanoTime();
    113
    114            if (this.getFolderName() == null)
    115            {
    116                this.setFolderName(this.settings.getProperty("level-name", "world"));
    117            }
    118
    119            String var6 = this.settings.getProperty("level-seed", "");
    120            String var7 = this.settings.getProperty("level-type", "DEFAULT");
    121            String var8 = this.settings.getProperty("generator-settings", "");
    122            long var9 = (new Random()).nextLong();
    123
    124            if (var6.length() > 0)
    125            {
    126                try
    127                {
    128                    long var11 = Long.parseLong(var6);
    129
    130                    if (var11 != 0L)
    131                    {
    132                        var9 = var11;
    133                    }
    134                }
    135                catch (NumberFormatException var15)
    136                {
    137                    var9 = (long)var6.hashCode();
    138                }
    139            }
    140
    141            WorldType var17 = WorldType.parseWorldType(var7);
    142
    143            if (var17 == null)
    144            {
    145                var17 = WorldType.DEFAULT;
    146            }
    147
    148            this.setBuildLimit(this.settings.getIntProperty("max-build-height", 256));
    149            this.setBuildLimit((this.getBuildLimit() + 8) / 16 * 16);
    150            this.setBuildLimit(MathHelper.clamp_int(this.getBuildLimit(), 64, 256));
    151            this.settings.setProperty("max-build-height", Integer.valueOf(this.getBuildLimit()));
    152            logger.info("Preparing level \"" + this.getFolderName() + "\"");
    153            this.loadAllWorlds(this.getFolderName(), this.getFolderName(), var9, var17, var8);
    154            long var12 = System.nanoTime() - var4;
    155            String var14 = String.format("%.3fs", new Object[] {Double.valueOf((double)var12 / 1.0E9D)});
    156            logger.info("Done (" + var14 + ")! For help, type \"help\" or \"?\"");
    157
    158            if (this.settings.getBooleanProperty("enable-query", false))
    159            {
    160                logger.info("Starting GS4 status listener");
    161                this.theRConThreadQuery = new RConThreadQuery(this);
    162                this.theRConThreadQuery.startThread();
    163            }
    164
    165            if (this.settings.getBooleanProperty("enable-rcon", false))
    166            {
    167                logger.info("Starting remote control listener");
    168                this.theRConThreadMain = new RConThreadMain(this);
    169                this.theRConThreadMain.startThread();
    170            }
    171            FMLCommonHandler.instance().handleServerStarting(this);
    172            return true;
    173        }
    174
    175        public boolean canStructuresSpawn()
    176        {
    177            return this.canSpawnStructures;
    178        }
    179
    180        public EnumGameType getGameType()
    181        {
    182            return this.gameType;
    183        }
    184
    185        /**
    186         * Defaults to "1" (Easy) for the dedicated server, defaults to "2" (Normal) on the client.
    187         */
    188        public int getDifficulty()
    189        {
    190            return this.settings.getIntProperty("difficulty", 1);
    191        }
    192
    193        /**
    194         * Defaults to false.
    195         */
    196        public boolean isHardcore()
    197        {
    198            return this.settings.getBooleanProperty("hardcore", false);
    199        }
    200
    201        /**
    202         * Called on exit from the main run() loop.
    203         */
    204        protected void finalTick(CrashReport par1CrashReport)
    205        {
    206            while (this.isServerRunning())
    207            {
    208                this.executePendingCommands();
    209
    210                try
    211                {
    212                    Thread.sleep(10L);
    213                }
    214                catch (InterruptedException var3)
    215                {
    216                    var3.printStackTrace();
    217                }
    218            }
    219        }
    220
    221        /**
    222         * Adds the server info, including from theWorldServer, to the crash report.
    223         */
    224        public CrashReport addServerInfoToCrashReport(CrashReport par1CrashReport)
    225        {
    226            par1CrashReport = super.addServerInfoToCrashReport(par1CrashReport);
    227            par1CrashReport.addCrashSectionCallable("Type", new CallableType(this));
    228            return par1CrashReport;
    229        }
    230
    231        /**
    232         * Directly calls System.exit(0), instantly killing the program.
    233         */
    234        protected void systemExitNow()
    235        {
    236            System.exit(0);
    237        }
    238
    239        public void updateTimeLightAndEntities()
    240        {
    241            super.updateTimeLightAndEntities();
    242            this.executePendingCommands();
    243        }
    244
    245        public boolean getAllowNether()
    246        {
    247            return this.settings.getBooleanProperty("allow-nether", true);
    248        }
    249
    250        public boolean allowSpawnMonsters()
    251        {
    252            return this.settings.getBooleanProperty("spawn-monsters", true);
    253        }
    254
    255        public void addServerStatsToSnooper(PlayerUsageSnooper par1PlayerUsageSnooper)
    256        {
    257            par1PlayerUsageSnooper.addData("whitelist_enabled", Boolean.valueOf(this.getDedicatedPlayerList().isWhiteListEnabled()));
    258            par1PlayerUsageSnooper.addData("whitelist_count", Integer.valueOf(this.getDedicatedPlayerList().getWhiteListedPlayers().size()));
    259            super.addServerStatsToSnooper(par1PlayerUsageSnooper);
    260        }
    261
    262        /**
    263         * Returns whether snooping is enabled or not.
    264         */
    265        public boolean isSnooperEnabled()
    266        {
    267            return this.settings.getBooleanProperty("snooper-enabled", true);
    268        }
    269
    270        public void addPendingCommand(String par1Str, ICommandSender par2ICommandSender)
    271        {
    272            this.pendingCommandList.add(new ServerCommand(par1Str, par2ICommandSender));
    273        }
    274
    275        public void executePendingCommands()
    276        {
    277            while (!this.pendingCommandList.isEmpty())
    278            {
    279                ServerCommand var1 = (ServerCommand)this.pendingCommandList.remove(0);
    280                this.getCommandManager().executeCommand(var1.sender, var1.command);
    281            }
    282        }
    283
    284        public boolean isDedicatedServer()
    285        {
    286            return true;
    287        }
    288
    289        public DedicatedPlayerList getDedicatedPlayerList()
    290        {
    291            return (DedicatedPlayerList)super.getConfigurationManager();
    292        }
    293
    294        public NetworkListenThread getNetworkThread()
    295        {
    296            return this.networkThread;
    297        }
    298
    299        /**
    300         * Gets an integer property. If it does not exist, set it to the specified value.
    301         */
    302        public int getIntProperty(String par1Str, int par2)
    303        {
    304            return this.settings.getIntProperty(par1Str, par2);
    305        }
    306
    307        /**
    308         * Gets a string property. If it does not exist, set it to the specified value.
    309         */
    310        public String getStringProperty(String par1Str, String par2Str)
    311        {
    312            return this.settings.getProperty(par1Str, par2Str);
    313        }
    314
    315        /**
    316         * Gets a boolean property. If it does not exist, set it to the specified value.
    317         */
    318        public boolean getBooleanProperty(String par1Str, boolean par2)
    319        {
    320            return this.settings.getBooleanProperty(par1Str, par2);
    321        }
    322
    323        /**
    324         * Saves an Object with the given property name.
    325         */
    326        public void setProperty(String par1Str, Object par2Obj)
    327        {
    328            this.settings.setProperty(par1Str, par2Obj);
    329        }
    330
    331        /**
    332         * Saves all of the server properties to the properties file.
    333         */
    334        public void saveProperties()
    335        {
    336            this.settings.saveProperties();
    337        }
    338
    339        public String getSettingsFilePath()
    340        {
    341            File var1 = this.settings.getPropertiesFile();
    342            return var1 != null ? var1.getAbsolutePath() : "No settings file";
    343        }
    344
    345        public boolean getGuiEnabled()
    346        {
    347            return this.guiIsEnabled;
    348        }
    349
    350        /**
    351         * On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections.
    352         */
    353        public String shareToLAN(EnumGameType par1EnumGameType, boolean par2)
    354        {
    355            return "";
    356        }
    357
    358        public boolean func_82356_Z()
    359        {
    360            return this.settings.getBooleanProperty("enable-command-block", false);
    361        }
    362
    363        public int func_82357_ak()
    364        {
    365            return this.settings.getIntProperty("spawn-protection", super.func_82357_ak());
    366        }
    367
    368        public ServerConfigurationManager getConfigurationManager()
    369        {
    370            return this.getDedicatedPlayerList();
    371        }
    372
    373        @SideOnly(Side.SERVER)
    374        public void func_82011_an()
    375        {
    376            ServerGUI.initGUI(this);
    377            this.guiIsEnabled = true;
    378        }
    379    }