001package net.minecraft.server.integrated; 002 003import cpw.mods.fml.common.FMLCommonHandler; 004import cpw.mods.fml.relauncher.Side; 005import cpw.mods.fml.relauncher.SideOnly; 006import java.io.File; 007import java.io.IOException; 008import net.minecraft.client.Minecraft; 009import net.minecraft.client.multiplayer.ThreadLanServerPing; 010import net.minecraft.crash.CrashReport; 011import net.minecraft.logging.ILogAgent; 012import net.minecraft.logging.LogAgent; 013import net.minecraft.network.NetworkListenThread; 014import net.minecraft.profiler.PlayerUsageSnooper; 015import net.minecraft.server.MinecraftServer; 016import net.minecraft.util.CryptManager; 017import net.minecraft.world.EnumGameType; 018import net.minecraft.world.WorldManager; 019import net.minecraft.world.WorldServer; 020import net.minecraft.world.WorldServerMulti; 021import net.minecraft.world.WorldSettings; 022import net.minecraft.world.WorldType; 023import net.minecraft.world.demo.DemoWorldServer; 024import net.minecraft.world.storage.ISaveHandler; 025 026import net.minecraftforge.common.DimensionManager; 027import net.minecraftforge.common.MinecraftForge; 028import net.minecraftforge.event.world.WorldEvent; 029 030@SideOnly(Side.CLIENT) 031public class IntegratedServer extends MinecraftServer 032{ 033 /** The Minecraft instance. */ 034 private final Minecraft mc; 035 private final WorldSettings theWorldSettings; 036 private final ILogAgent serverLogAgent = new LogAgent("Minecraft-Server", " [SERVER]", (new File(Minecraft.getMinecraftDir(), "output-server.log")).getAbsolutePath()); 037 038 /** Instance of IntegratedServerListenThread. */ 039 private IntegratedServerListenThread theServerListeningThread; 040 private boolean isGamePaused = false; 041 private boolean isPublic; 042 private ThreadLanServerPing lanServerPing; 043 044 public IntegratedServer(Minecraft par1Minecraft, String par2Str, String par3Str, WorldSettings par4WorldSettings) 045 { 046 super(new File(Minecraft.getMinecraftDir(), "saves")); 047 this.setServerOwner(par1Minecraft.session.username); 048 this.setFolderName(par2Str); 049 this.setWorldName(par3Str); 050 this.setDemo(par1Minecraft.isDemo()); 051 this.canCreateBonusChest(par4WorldSettings.isBonusChestEnabled()); 052 this.setBuildLimit(256); 053 this.setConfigurationManager(new IntegratedPlayerList(this)); 054 this.mc = par1Minecraft; 055 this.theWorldSettings = par4WorldSettings; 056 057 try 058 { 059 this.theServerListeningThread = new IntegratedServerListenThread(this); 060 } 061 catch (IOException ioexception) 062 { 063 throw new Error(); 064 } 065 } 066 067 protected void loadAllWorlds(String par1Str, String par2Str, long par3, WorldType par5WorldType, String par6Str) 068 { 069 this.convertMapIfNeeded(par1Str); 070 ISaveHandler isavehandler = this.getActiveAnvilConverter().getSaveLoader(par1Str, true); 071 072 WorldServer overWorld = (isDemo() ? new DemoWorldServer(this, isavehandler, par2Str, 0, theProfiler, getLogAgent()) : new WorldServer(this, isavehandler, par2Str, 0, theWorldSettings, theProfiler, getLogAgent())); 073 for (int dim : DimensionManager.getStaticDimensionIDs()) 074 { 075 WorldServer world = (dim == 0 ? overWorld : new WorldServerMulti(this, isavehandler, par2Str, dim, theWorldSettings, overWorld, theProfiler, getLogAgent())); 076 world.addWorldAccess(new WorldManager(this, world)); 077 078 if (!this.isSinglePlayer()) 079 { 080 world.getWorldInfo().setGameType(this.getGameType()); 081 } 082 083 MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world)); 084 } 085 086 this.getConfigurationManager().setPlayerManager(new WorldServer[]{ overWorld }); 087 this.setDifficultyForAllWorlds(this.getDifficulty()); 088 this.initialWorldChunkLoad(); 089 } 090 091 /** 092 * Initialises the server and starts it. 093 */ 094 protected boolean startServer() throws IOException 095 { 096 this.serverLogAgent.logInfo("Starting integrated minecraft server version 1.5.1"); 097 this.setOnlineMode(false); 098 this.setCanSpawnAnimals(true); 099 this.setCanSpawnNPCs(true); 100 this.setAllowPvp(true); 101 this.setAllowFlight(true); 102 this.serverLogAgent.logInfo("Generating keypair"); 103 this.setKeyPair(CryptManager.createNewKeyPair()); 104 if (!FMLCommonHandler.instance().handleServerAboutToStart(this)) { return false; } 105 this.loadAllWorlds(this.getFolderName(), this.getWorldName(), this.theWorldSettings.getSeed(), this.theWorldSettings.getTerrainType(), this.theWorldSettings.func_82749_j()); 106 this.setMOTD(this.getServerOwner() + " - " + this.worldServers[0].getWorldInfo().getWorldName()); 107 return FMLCommonHandler.instance().handleServerStarting(this); 108 } 109 110 /** 111 * Main function called by run() every loop. 112 */ 113 public void tick() 114 { 115 boolean flag = this.isGamePaused; 116 this.isGamePaused = this.theServerListeningThread.isGamePaused(); 117 118 if (!flag && this.isGamePaused) 119 { 120 this.serverLogAgent.logInfo("Saving and pausing game..."); 121 this.getConfigurationManager().saveAllPlayerData(); 122 this.saveAllWorlds(false); 123 } 124 125 if (!this.isGamePaused) 126 { 127 super.tick(); 128 } 129 } 130 131 public boolean canStructuresSpawn() 132 { 133 return false; 134 } 135 136 public EnumGameType getGameType() 137 { 138 return this.theWorldSettings.getGameType(); 139 } 140 141 /** 142 * Defaults to "1" (Easy) for the dedicated server, defaults to "2" (Normal) on the client. 143 */ 144 public int getDifficulty() 145 { 146 return this.mc.gameSettings.difficulty; 147 } 148 149 /** 150 * Defaults to false. 151 */ 152 public boolean isHardcore() 153 { 154 return this.theWorldSettings.getHardcoreEnabled(); 155 } 156 157 protected File getDataDirectory() 158 { 159 return this.mc.mcDataDir; 160 } 161 162 public boolean isDedicatedServer() 163 { 164 return false; 165 } 166 167 /** 168 * Gets the IntergratedServerListenThread. 169 */ 170 public IntegratedServerListenThread getServerListeningThread() 171 { 172 return this.theServerListeningThread; 173 } 174 175 /** 176 * Called on exit from the main run() loop. 177 */ 178 protected void finalTick(CrashReport par1CrashReport) 179 { 180 this.mc.crashed(par1CrashReport); 181 } 182 183 /** 184 * Adds the server info, including from theWorldServer, to the crash report. 185 */ 186 public CrashReport addServerInfoToCrashReport(CrashReport par1CrashReport) 187 { 188 par1CrashReport = super.addServerInfoToCrashReport(par1CrashReport); 189 par1CrashReport.func_85056_g().addCrashSectionCallable("Type", new CallableType3(this)); 190 par1CrashReport.func_85056_g().addCrashSectionCallable("Is Modded", new CallableIsModded(this)); 191 return par1CrashReport; 192 } 193 194 public void addServerStatsToSnooper(PlayerUsageSnooper par1PlayerUsageSnooper) 195 { 196 super.addServerStatsToSnooper(par1PlayerUsageSnooper); 197 par1PlayerUsageSnooper.addData("snooper_partner", this.mc.getPlayerUsageSnooper().getUniqueID()); 198 } 199 200 /** 201 * Returns whether snooping is enabled or not. 202 */ 203 public boolean isSnooperEnabled() 204 { 205 return Minecraft.getMinecraft().isSnooperEnabled(); 206 } 207 208 /** 209 * On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections. 210 */ 211 public String shareToLAN(EnumGameType par1EnumGameType, boolean par2) 212 { 213 try 214 { 215 String s = this.theServerListeningThread.func_71755_c(); 216 this.getLogAgent().logInfo("Started on " + s); 217 this.isPublic = true; 218 this.lanServerPing = new ThreadLanServerPing(this.getMOTD(), s); 219 this.lanServerPing.start(); 220 this.getConfigurationManager().setGameType(par1EnumGameType); 221 this.getConfigurationManager().setCommandsAllowedForAll(par2); 222 return s; 223 } 224 catch (IOException ioexception) 225 { 226 return null; 227 } 228 } 229 230 public ILogAgent getLogAgent() 231 { 232 return this.serverLogAgent; 233 } 234 235 /** 236 * Saves all necessary data as preparation for stopping the server. 237 */ 238 public void stopServer() 239 { 240 super.stopServer(); 241 242 if (this.lanServerPing != null) 243 { 244 this.lanServerPing.interrupt(); 245 this.lanServerPing = null; 246 } 247 } 248 249 /** 250 * Sets the serverRunning variable to false, in order to get the server to shut down. 251 */ 252 public void initiateShutdown() 253 { 254 super.initiateShutdown(); 255 256 if (this.lanServerPing != null) 257 { 258 this.lanServerPing.interrupt(); 259 this.lanServerPing = null; 260 } 261 } 262 263 /** 264 * Returns true if this integrated server is open to LAN 265 */ 266 public boolean getPublic() 267 { 268 return this.isPublic; 269 } 270 271 /** 272 * Sets the game type for all worlds. 273 */ 274 public void setGameType(EnumGameType par1EnumGameType) 275 { 276 this.getConfigurationManager().setGameType(par1EnumGameType); 277 } 278 279 /** 280 * Return whether command blocks are enabled. 281 */ 282 public boolean isCommandBlockEnabled() 283 { 284 return true; 285 } 286 287 public NetworkListenThread getNetworkThread() 288 { 289 return this.getServerListeningThread(); 290 } 291}