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