--- ../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
 }
