377 lines
16 KiB
Diff
377 lines
16 KiB
Diff
--- ../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
|
|
}
|