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