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 field_71342_m;
020        private RConThreadMain field_71339_n;
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.3.2");
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.getHostName("127.0.0.1");
057            }
058            else
059            {
060                this.setOnlineMode(this.settings.getOrSetBoolProperty("online-mode", true));
061                this.getHostName(this.settings.getOrSetProperty("server-ip", ""));
062            }
063    
064            this.setSpawnAnimals(this.settings.getOrSetBoolProperty("spawn-animals", true));
065            this.setSpawnNpcs(this.settings.getOrSetBoolProperty("spawn-npcs", true));
066            this.setAllowPvp(this.settings.getOrSetBoolProperty("pvp", true));
067            this.setAllowFlight(this.settings.getOrSetBoolProperty("allow-flight", false));
068            this.setTexturePack(this.settings.getOrSetProperty("texture-pack", ""));
069            this.setMOTD(this.settings.getOrSetProperty("motd", "A Minecraft Server"));
070            spawnProtectionSize = this.settings.getOrSetIntProperty("spawn-protection-size", 16);
071            this.canSpawnStructures = this.settings.getOrSetBoolProperty("generate-structures", true);
072            int var2 = this.settings.getOrSetIntProperty("gamemode", EnumGameType.SURVIVAL.getID());
073            this.gameType = WorldSettings.getGameTypeById(var2);
074            logger.info("Default game type: " + this.gameType);
075            InetAddress var3 = null;
076    
077            if (this.getHostname().length() > 0)
078            {
079                var3 = InetAddress.getByName(this.getHostname());
080            }
081    
082            if (this.getServerPort() < 0)
083            {
084                this.setServerPort(this.settings.getOrSetIntProperty("server-port", 25565));
085            }
086    
087            logger.info("Generating keypair");
088            this.setKeyPair(CryptManager.createNewKeyPair());
089            logger.info("Starting Minecraft server on " + (this.getHostname().length() == 0 ? "*" : this.getHostname()) + ":" + this.getServerPort());
090    
091            try
092            {
093                this.networkThread = new DedicatedServerListenThread(this, var3, this.getServerPort());
094            }
095            catch (IOException var15)
096            {
097                logger.warning("**** FAILED TO BIND TO PORT!");
098                logger.log(Level.WARNING, "The exception was: " + var15.toString());
099                logger.warning("Perhaps a server is already running on that port?");
100                return false;
101            }
102    
103            if (!this.isServerInOnlineMode())
104            {
105                logger.warning("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!");
106                logger.warning("The server will make no attempt to authenticate usernames. Beware.");
107                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.");
108                logger.warning("To change this, set \"online-mode\" to \"true\" in the server.properties file.");
109            }
110    
111            FMLCommonHandler.instance().onServerStarted();
112            this.setConfigurationManager(new DedicatedPlayerList(this));
113            long var4 = System.nanoTime();
114    
115            if (this.getFolderName() == null)
116            {
117                this.setFolderName(this.settings.getOrSetProperty("level-name", "world"));
118            }
119    
120            String var6 = this.settings.getOrSetProperty("level-seed", "");
121            String var7 = this.settings.getOrSetProperty("level-type", "DEFAULT");
122            long var8 = (new Random()).nextLong();
123    
124            if (var6.length() > 0)
125            {
126                try
127                {
128                    long var10 = Long.parseLong(var6);
129    
130                    if (var10 != 0L)
131                    {
132                        var8 = var10;
133                    }
134                }
135                catch (NumberFormatException var14)
136                {
137                    var8 = (long)var6.hashCode();
138                }
139            }
140    
141            WorldType var16 = WorldType.parseWorldType(var7);
142    
143            if (var16 == null)
144            {
145                var16 = WorldType.DEFAULT;
146            }
147    
148            this.setBuildLimit(this.settings.getOrSetIntProperty("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.setArbitraryProperty("max-build-height", Integer.valueOf(this.getBuildLimit()));
152            logger.info("Preparing level \"" + this.getFolderName() + "\"");
153            this.loadAllDimensions(this.getFolderName(), this.getFolderName(), var8, var16);
154            long var11 = System.nanoTime() - var4;
155            String var13 = String.format("%.3fs", new Object[] {Double.valueOf((double)var11 / 1.0E9D)});
156            logger.info("Done (" + var13 + ")! For help, type \"help\" or \"?\"");
157    
158            if (this.settings.getOrSetBoolProperty("enable-query", false))
159            {
160                logger.info("Starting GS4 status listener");
161                this.field_71342_m = new RConThreadQuery(this);
162                this.field_71342_m.startThread();
163            }
164    
165            if (this.settings.getOrSetBoolProperty("enable-rcon", false))
166            {
167                logger.info("Starting remote control listener");
168                this.field_71339_n = new RConThreadMain(this);
169                this.field_71339_n.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" for the dedicated server
187         */
188        public int getDifficulty()
189        {
190            return this.settings.getOrSetIntProperty("difficulty", 1);
191        }
192    
193        /**
194         * defaults to false
195         */
196        public boolean isHardcore()
197        {
198            return this.settings.getOrSetBoolProperty("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         * iterates the worldServers and adds their info also
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, 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.getOrSetBoolProperty("allow-nether", true);
248        }
249    
250        public boolean allowSpawnMonsters()
251        {
252            return this.settings.getOrSetBoolProperty("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().getIPWhiteList().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.getOrSetBoolProperty("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        public int getOrSetIntProperty(String par1Str, int par2)
300        {
301            return this.settings.getOrSetIntProperty(par1Str, par2);
302        }
303    
304        public String getOrSetProperty(String par1Str, String par2Str)
305        {
306            return this.settings.getOrSetProperty(par1Str, par2Str);
307        }
308    
309        public boolean getOrSetBoolProperty(String par1Str, boolean par2)
310        {
311            return this.settings.getOrSetBoolProperty(par1Str, par2);
312        }
313    
314        public void setArbitraryProperty(String par1Str, Object par2Obj)
315        {
316            this.settings.setArbitraryProperty(par1Str, par2Obj);
317        }
318    
319        public void saveSettingsToFile()
320        {
321            this.settings.saveSettingsToFile();
322        }
323    
324        public String getSettingsFilePath()
325        {
326            File var1 = this.settings.getFile();
327            return var1 != null ? var1.getAbsolutePath() : "No settings file";
328        }
329    
330        public boolean getGuiEnabled()
331        {
332            return this.guiIsEnabled;
333        }
334    
335        /**
336         * does nothing on dedicated. on integrated, sets commandsAllowedForAll and gameType and allows external connections
337         */
338        public String shareToLAN(EnumGameType par1EnumGameType, boolean par2)
339        {
340            return "";
341        }
342    
343        public ServerConfigurationManager getConfigurationManager()
344        {
345            return this.getDedicatedPlayerList();
346        }
347    
348        @SideOnly(Side.SERVER)
349        public void func_79001_aj()
350        {
351            ServerGUI.func_79003_a(this);
352            this.guiIsEnabled = true;
353        }
354    }