You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
376 lines
16 KiB
376 lines
16 KiB
--- ../src-base/minecraft/net/minecraftforge/common/DimensionManager.java |
|
+++ ../src-work/minecraft/net/minecraftforge/common/DimensionManager.java |
|
@@ -34,6 +34,15 @@ |
|
import net.minecraft.world.storage.ISaveHandler; |
|
import net.minecraft.world.storage.SaveHandler; |
|
import net.minecraftforge.event.world.WorldEvent; |
|
+// Cauldron start |
|
+import net.minecraft.server.dedicated.DedicatedServer; |
|
+import net.minecraft.world.chunk.storage.AnvilSaveHandler; |
|
+import net.minecraftforge.cauldron.CauldronUtils; |
|
+import net.minecraftforge.common.util.EnumHelper; |
|
+import org.bukkit.World.Environment; |
|
+import org.bukkit.WorldCreator; |
|
+import org.bukkit.generator.ChunkGenerator; |
|
+// Cauldron end |
|
|
|
public class DimensionManager |
|
{ |
|
@@ -46,6 +55,11 @@ |
|
private static BitSet dimensionMap = new BitSet(Long.SIZE << 4); |
|
private static ConcurrentMap<World, World> weakWorldMap = new MapMaker().weakKeys().weakValues().<World,World>makeMap(); |
|
private static Multiset<Integer> leakedWorlds = HashMultiset.create(); |
|
+ // Cauldron start |
|
+ private static Hashtable<Class<? extends WorldProvider>, Integer> classToProviders = new Hashtable<Class<? extends WorldProvider>, Integer>(); |
|
+ private static ArrayList<Integer> bukkitDims = new ArrayList<Integer>(); // used to keep track of Bukkit dimensions |
|
+ private static final String FILE_SEPARATOR = System.getProperty("file.separator"); |
|
+ // Cauldron end |
|
|
|
public static boolean registerProviderType(int id, Class<? extends WorldProvider> provider, boolean keepLoaded) |
|
{ |
|
@@ -53,7 +67,23 @@ |
|
{ |
|
return false; |
|
} |
|
+ // Cauldron start - register provider with bukkit and add appropriate config option |
|
+ String worldType = "unknown"; |
|
+ if (id != -1 && id != 0 && id != 1) // ignore vanilla |
|
+ { |
|
+ worldType = provider.getSimpleName().toLowerCase(); |
|
+ worldType = worldType.replace("worldprovider", ""); |
|
+ worldType = worldType.replace("provider", ""); |
|
+ registerBukkitEnvironment(id, worldType); |
|
+ } |
|
+ else |
|
+ { |
|
+ worldType = Environment.getEnvironment(id).name().toLowerCase(); |
|
+ } |
|
+ keepLoaded = MinecraftServer.getServer().cauldronConfig.getBoolean("world-environment-settings." + worldType + ".keep-world-loaded", keepLoaded); |
|
+ // Cauldron end |
|
providers.put(id, provider); |
|
+ classToProviders.put(provider, id); |
|
spawnSettings.put(id, keepLoaded); |
|
return true; |
|
} |
|
@@ -157,28 +187,33 @@ |
|
|
|
public static Integer[] getIDs(boolean check) |
|
{ |
|
- if (check) |
|
+ // Cauldron start - check config option and only log world leak messages if enabled |
|
+ if (MinecraftServer.getServer().cauldronConfig.worldLeakDebug.getValue()) |
|
{ |
|
- List<World> allWorlds = Lists.newArrayList(weakWorldMap.keySet()); |
|
- allWorlds.removeAll(worlds.values()); |
|
- for (ListIterator<World> li = allWorlds.listIterator(); li.hasNext(); ) |
|
+ if (check) |
|
{ |
|
- World w = li.next(); |
|
- leakedWorlds.add(System.identityHashCode(w)); |
|
- } |
|
- for (World w : allWorlds) |
|
- { |
|
- int leakCount = leakedWorlds.count(System.identityHashCode(w)); |
|
- if (leakCount == 5) |
|
+ List<World> allWorlds = Lists.newArrayList(weakWorldMap.keySet()); |
|
+ allWorlds.removeAll(worlds.values()); |
|
+ for (ListIterator<World> li = allWorlds.listIterator(); li.hasNext(); ) |
|
{ |
|
- FMLLog.fine("The world %x (%s) may have leaked: first encounter (5 occurences).\n", System.identityHashCode(w), w.getWorldInfo().getWorldName()); |
|
+ World w = li.next(); |
|
+ leakedWorlds.add(System.identityHashCode(w)); |
|
} |
|
- else if (leakCount % 5 == 0) |
|
+ for (World w : allWorlds) |
|
{ |
|
- FMLLog.fine("The world %x (%s) may have leaked: seen %d times.\n", System.identityHashCode(w), w.getWorldInfo().getWorldName(), leakCount); |
|
+ int leakCount = leakedWorlds.count(System.identityHashCode(w)); |
|
+ if (leakCount == 5) |
|
+ { |
|
+ FMLLog.fine("The world %x (%s) may have leaked: first encounter (5 occurences). Note: This may be a caused by a mod, plugin, or just a false-positive(No memory leak). If server crashes due to OOM, report to Cauldron.\n", System.identityHashCode(w), w.getWorldInfo().getWorldName()); |
|
+ } |
|
+ else if (leakCount % 5 == 0) |
|
+ { |
|
+ FMLLog.fine("The world %x (%s) may have leaked: seen %d times. Note: This may be a caused by a mod, plugin, or just a false-positive(No memory leak). If server crashes due to OOM, report to Cauldron.\n", System.identityHashCode(w), w.getWorldInfo().getWorldName(), leakCount); |
|
+ } |
|
} |
|
} |
|
} |
|
+ // Cauldron end |
|
return getIDs(); |
|
} |
|
public static Integer[] getIDs() |
|
@@ -191,12 +226,23 @@ |
|
if (world != null) |
|
{ |
|
worlds.put(id, world); |
|
- weakWorldMap.put(world, world); |
|
+ // Cauldron start - check config option and only log world leak messages if enabled |
|
+ if (MinecraftServer.getServer().cauldronConfig.worldLeakDebug.getValue()) |
|
+ { |
|
+ weakWorldMap.put(world, world); |
|
+ } |
|
+ // handle all world adds here for Bukkit |
|
+ if (!MinecraftServer.getServer().worlds.contains(world)) |
|
+ { |
|
+ MinecraftServer.getServer().worlds.add(world); |
|
+ } |
|
+ // Cauldron end |
|
MinecraftServer.getServer().worldTickTimes.put(id, new long[100]); |
|
FMLLog.info("Loading dimension %d (%s) (%s)", id, world.getWorldInfo().getWorldName(), world.func_73046_m()); |
|
} |
|
else |
|
{ |
|
+ MinecraftServer.getServer().worlds.remove(getWorld(id)); // Cauldron - remove world from our new world arraylist |
|
worlds.remove(id); |
|
MinecraftServer.getServer().worldTickTimes.remove(id); |
|
FMLLog.info("Unloading dimension %d", id); |
|
@@ -224,6 +270,7 @@ |
|
} |
|
|
|
public static void initDimension(int dim) { |
|
+ if (dim == 0) return; // Cauldron - overworld |
|
WorldServer overworld = getWorld(0); |
|
if (overworld == null) |
|
{ |
|
@@ -231,6 +278,12 @@ |
|
} |
|
try |
|
{ |
|
+ // Cauldron start - Fixes MultiVerse issue when mods such as Twilight Forest try to hotload their dimension when using its WorldProvider |
|
+ if(net.minecraftforge.cauldron.CauldronHooks.craftWorldLoading) |
|
+ { |
|
+ return; |
|
+ } |
|
+ // Cauldron end |
|
DimensionManager.getProviderType(dim); |
|
} |
|
catch (Exception e) |
|
@@ -242,9 +295,52 @@ |
|
ISaveHandler savehandler = overworld.getSaveHandler(); |
|
WorldSettings worldSettings = new WorldSettings(overworld.getWorldInfo()); |
|
|
|
- WorldServer world = (dim == 0 ? overworld : new WorldServerMulti(mcServer, savehandler, overworld.getWorldInfo().getWorldName(), dim, worldSettings, overworld, mcServer.theProfiler)); |
|
+ // Cauldron start - handles hotloading dimensions |
|
+ String worldType; |
|
+ String name; |
|
+ String oldName = ""; |
|
+ Environment env = Environment.getEnvironment(getProviderType(dim)); |
|
+ if (dim >= -1 && dim <= 1) |
|
+ { |
|
+ if ((dim == -1 && !mcServer.getAllowNether()) || (dim == 1 && !mcServer.server.getAllowEnd())) |
|
+ return; |
|
+ worldType = env.toString().toLowerCase(); |
|
+ name = "DIM" + dim; |
|
+ } |
|
+ else |
|
+ { |
|
+ WorldProvider provider = WorldProvider.getProviderForDimension(dim); |
|
+ worldType = provider.getClass().getSimpleName().toLowerCase(); |
|
+ worldType = worldType.replace("worldprovider", ""); |
|
+ oldName = "world_" + worldType; |
|
+ worldType = worldType.replace("provider", ""); |
|
+ |
|
+ if (Environment.getEnvironment(DimensionManager.getProviderType(dim)) == null) |
|
+ env = DimensionManager.registerBukkitEnvironment(DimensionManager.getProviderType(provider.getClass()), worldType); |
|
+ |
|
+ name = provider.getSaveFolder(); |
|
+ if (name == null) name = "DIM0"; |
|
+ } |
|
+ // add ability to disable dimensions |
|
+ if (!MinecraftServer.getServer().cauldronConfig.getBoolean("world-environment-settings." + worldType + ".enabled", true)) |
|
+ return; |
|
+ |
|
+ CauldronUtils.migrateWorlds(worldType, oldName, overworld.getWorldInfo().getWorldName(), name); // Cauldron |
|
+ ChunkGenerator gen = mcServer.server.getGenerator(name); |
|
+ if (mcServer instanceof DedicatedServer) { |
|
+ worldSettings.func_82750_a(((DedicatedServer) mcServer).getStringProperty("generator-settings", "")); |
|
+ } |
|
+ WorldServer world = new WorldServerMulti(mcServer, new AnvilSaveHandler(mcServer.server.getWorldContainer(), name, true), name, dim, worldSettings, overworld, mcServer.theProfiler, env, gen); |
|
+ |
|
+ if (gen != null) |
|
+ { |
|
+ world.getWorld().getPopulators().addAll(gen.getDefaultPopulators(world.getWorld())); |
|
+ } |
|
+ mcServer.getConfigurationManager().setPlayerManager(mcServer.worlds.toArray(new WorldServer[mcServer.worlds.size()])); |
|
world.addWorldAccess(new WorldManager(mcServer, world)); |
|
MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world)); |
|
+ mcServer.server.getPluginManager().callEvent(new org.bukkit.event.world.WorldLoadEvent(world.getWorld())); |
|
+ // Cauldron end |
|
if (!mcServer.isSinglePlayer()) |
|
{ |
|
world.getWorldInfo().setGameType(mcServer.getGameType()); |
|
@@ -253,6 +349,79 @@ |
|
mcServer.func_147139_a(mcServer.func_147135_j()); |
|
} |
|
|
|
+ // Cauldron start - new method for handling creation of Bukkit dimensions. Currently supports MultiVerse |
|
+ public static WorldServer initDimension(WorldCreator creator, WorldSettings worldSettings) { |
|
+ WorldServer overworld = getWorld(0); |
|
+ if (overworld == null) { |
|
+ throw new RuntimeException("Cannot Hotload Dim: Overworld is not Loaded!"); |
|
+ } |
|
+ |
|
+ MinecraftServer mcServer = overworld.func_73046_m(); |
|
+ |
|
+ String worldType; |
|
+ String name; |
|
+ |
|
+ int providerId = 0; |
|
+ if (creator.environment() != null) |
|
+ providerId = creator.environment().getId(); |
|
+ try { |
|
+ providerId = getProviderType(providerId); |
|
+ } |
|
+ catch (IllegalArgumentException e) |
|
+ { |
|
+ // do nothing |
|
+ } |
|
+ |
|
+ Environment env = creator.environment(); |
|
+ worldType = env.name().toLowerCase(); |
|
+ name = creator.name(); |
|
+ int dim = 0; |
|
+ // Use saved dimension from level.dat if it exists. This guarantees that after a world is created, the same dimension will be used. Fixes issues with MultiVerse |
|
+ AnvilSaveHandler saveHandler = new AnvilSaveHandler(mcServer.server.getWorldContainer(), name, true); |
|
+ if (saveHandler.loadWorldInfo() != null) |
|
+ { |
|
+ int savedDim = saveHandler.loadWorldInfo().getDimension(); |
|
+ if (savedDim != 0 && savedDim != -1 && savedDim != 1) |
|
+ { |
|
+ dim = savedDim; |
|
+ } |
|
+ } |
|
+ if (dim == 0) |
|
+ { |
|
+ dim = getNextFreeDimId(); |
|
+ } |
|
+ |
|
+ if (!isDimensionRegistered(dim)) // handle reloads properly |
|
+ { |
|
+ registerDimension(dim, providerId); |
|
+ addBukkitDimension(dim); |
|
+ } |
|
+ ChunkGenerator gen = creator.generator(); |
|
+ if (mcServer instanceof DedicatedServer) { |
|
+ worldSettings.func_82750_a(((DedicatedServer) mcServer).getStringProperty("generator-settings", "")); |
|
+ } |
|
+ |
|
+ WorldServer world = new WorldServerMulti(mcServer, saveHandler, name, dim, worldSettings, overworld, mcServer.theProfiler, env, gen); |
|
+ |
|
+ if (gen != null) |
|
+ { |
|
+ world.getWorld().getPopulators().addAll(gen.getDefaultPopulators(world.getWorld())); |
|
+ } |
|
+ world.provider.dimensionId = dim; // Fix for TerrainControl injecting their own WorldProvider |
|
+ mcServer.getConfigurationManager().setPlayerManager(mcServer.worlds.toArray(new WorldServer[mcServer.worlds.size()])); |
|
+ |
|
+ world.addWorldAccess(new WorldManager(mcServer, world)); |
|
+ MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world)); |
|
+ if (!mcServer.isSinglePlayer()) |
|
+ { |
|
+ world.getWorldInfo().setGameType(mcServer.getGameType()); |
|
+ } |
|
+ mcServer.func_147139_a(mcServer.func_147135_j()); |
|
+ |
|
+ return world; |
|
+ } |
|
+ // Cauldron end |
|
+ |
|
public static WorldServer getWorld(int id) |
|
{ |
|
return worlds.get(id); |
|
@@ -266,7 +435,7 @@ |
|
public static boolean shouldLoadSpawn(int dim) |
|
{ |
|
int id = getProviderType(dim); |
|
- return spawnSettings.containsKey(id) && spawnSettings.get(id); |
|
+ return ((spawnSettings.containsKey(id) && spawnSettings.get(id)) || (getWorld(dim) != null && getWorld(dim).keepSpawnInMemory)); // Cauldron added bukkit check |
|
} |
|
|
|
static |
|
@@ -306,7 +475,8 @@ |
|
} |
|
|
|
public static void unloadWorld(int id) { |
|
- unloadQueue.add(id); |
|
+ if (!shouldLoadSpawn(id)) // Cauldron - prevent mods from force unloading if we have it disabled |
|
+ unloadQueue.add(id); |
|
} |
|
|
|
/* |
|
@@ -315,26 +485,9 @@ |
|
public static void unloadWorlds(Hashtable<Integer, long[]> worldTickTimes) { |
|
for (int id : unloadQueue) { |
|
WorldServer w = worlds.get(id); |
|
- try { |
|
- if (w != null) |
|
- { |
|
- w.saveAllChunks(true, null); |
|
- } |
|
- else |
|
- { |
|
- FMLLog.warning("Unexpected world unload - world %d is already unloaded", id); |
|
- } |
|
- } catch (MinecraftException e) { |
|
- e.printStackTrace(); |
|
- } |
|
- finally |
|
+ if (w != null) |
|
{ |
|
- if (w != null) |
|
- { |
|
- MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(w)); |
|
- w.flush(); |
|
- setWorld(id, null); |
|
- } |
|
+ MinecraftServer.getServer().server.unloadWorld(w.getWorld(), true); // Cauldron - unload through our new method for simplicity |
|
} |
|
} |
|
unloadQueue.clear(); |
|
@@ -425,4 +578,45 @@ |
|
return null; |
|
} |
|
} |
|
+ |
|
+ // Cauldron start - add registration for Bukkit Environments |
|
+ public static Environment registerBukkitEnvironment(int dim, String providerName) |
|
+ { |
|
+ Environment env = Environment.getEnvironment(dim); |
|
+ if (env == null) // Cauldron if environment not found, register one |
|
+ { |
|
+ providerName = providerName.replace("WorldProvider", ""); |
|
+ env = EnumHelper.addBukkitEnvironment(dim, providerName.toUpperCase()); |
|
+ Environment.registerEnvironment(env); |
|
+ } |
|
+ return env; |
|
+ } |
|
+ |
|
+ public static int getProviderType(Class<? extends WorldProvider> provider) |
|
+ { |
|
+ return classToProviders.get(provider); |
|
+ } |
|
+ |
|
+ public static void addBukkitDimension(int dim) |
|
+ { |
|
+ if (!bukkitDims.contains(dim)) |
|
+ bukkitDims.add(dim); |
|
+ } |
|
+ |
|
+ public static void removeBukkitDimension(int dim) |
|
+ { |
|
+ if (bukkitDims.contains(dim)) |
|
+ bukkitDims.remove(bukkitDims.indexOf(dim)); |
|
+ } |
|
+ |
|
+ public static ArrayList<Integer> getBukkitDimensionIDs() |
|
+ { |
|
+ return bukkitDims; |
|
+ } |
|
+ |
|
+ public static boolean isBukkitDimension(int dim) |
|
+ { |
|
+ return bukkitDims.contains(dim); |
|
+ } |
|
+ // Cauldron end |
|
}
|
|
|