Rework DimensionManager for new DimensionType enum, replaces the old provider registry. Also fixed save folder issues with dimensions. Closes #2570

This commit is contained in:
LexManos committed 2016-03-21 17:12:34 -07:00
1 parent bebf22c0b0
commit 6fd9a2c00e
9 files changed
+174 -84

No files matched your search

@@ -20,13 +20,11 @@ import com.google.common.collect.Multiset;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.DimensionType;
import net.minecraft.world.MinecraftException;
import net.minecraft.world.World;
import net.minecraft.world.WorldManager;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.WorldProviderEnd;
import net.minecraft.world.WorldProviderHell;
import net.minecraft.world.WorldProviderSurface;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldServerMulti;
import net.minecraft.world.storage.ISaveHandler;
@@ -37,51 +35,24 @@ import net.minecraftforge.fml.common.FMLLog;
public class DimensionManager
{
private static Hashtable<Integer, Class<? extends WorldProvider>> providers = new Hashtable<Integer, Class<? extends WorldProvider>>();
private static Hashtable<Integer, Boolean> spawnSettings = new Hashtable<Integer, Boolean>();
private static Hashtable<Integer, WorldServer> worlds = new Hashtable<Integer, WorldServer>();
private static boolean hasInit = false;
private static Hashtable<Integer, Integer> dimensions = new Hashtable<Integer, Integer>();
private static Hashtable<Integer, DimensionType> dimensions = new Hashtable<Integer, DimensionType>();
private static ArrayList<Integer> unloadQueue = new ArrayList<Integer>();
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();
public static boolean registerProviderType(int id, Class<? extends WorldProvider> provider, boolean keepLoaded)
{
if (providers.containsKey(id))
{
return false;
}
providers.put(id, provider);
spawnSettings.put(id, keepLoaded);
return true;
}
/**
* Unregisters a Provider type, and returns a array of all dimensions that are
* registered to this provider type.
* If the return size is greater then 0, it is required that the caller either
* change those dimensions's registered type, or replace this type before the
* world is attempted to load, else the loader will throw an exception.
*
* @param id The provider type ID to unreigster
* @return An array containing all dimension IDs still registered to this provider type.
* Returns a list of dimensions associated with this DimensionType.
*/
public static int[] unregisterProviderType(int id)
public static int[] getDimensions(DimensionType type)
{
if (!providers.containsKey(id))
{
return new int[0];
}
providers.remove(id);
spawnSettings.remove(id);
int[] ret = new int[dimensions.size()];
int x = 0;
for (Map.Entry<Integer, Integer> ent : dimensions.entrySet())
for (Map.Entry<Integer, DimensionType> ent : dimensions.entrySet())
{
if (ent.getValue() == id)
if (ent.getValue() == type)
{
ret[x++] = ent.getKey();
}
@@ -99,25 +70,19 @@ public class DimensionManager
hasInit = true;
registerProviderType( 0, WorldProviderSurface.class, true);
registerProviderType(-1, WorldProviderHell.class, true);
registerProviderType( 1, WorldProviderEnd.class, false);
registerDimension( 0, 0);
registerDimension(-1, -1);
registerDimension( 1, 1);
registerDimension( 0, DimensionType.OVERWORLD);
registerDimension(-1, DimensionType.NETHER);
registerDimension( 1, DimensionType.THE_END);
}
public static void registerDimension(int id, int providerType)
public static void registerDimension(int id, DimensionType type)
{
if (!providers.containsKey(providerType))
{
throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, provider type %d does not exist", id, providerType));
}
DimensionType.getById(type.getId()); //Check if type is invalid {will throw an error} No clue how it would be invalid tho...
if (dimensions.containsKey(id))
{
throw new IllegalArgumentException(String.format("Failed to register dimension for id %d, One is already registered", id));
}
dimensions.put(id, providerType);
dimensions.put(id, type);
if (id >= 0)
{
dimensionMap.set(id);
@@ -141,7 +106,7 @@ public class DimensionManager
return dimensions.containsKey(dim);
}
public static int getProviderType(int dim)
public static DimensionType getProviderType(int dim)
{
if (!dimensions.containsKey(dim))
{
@@ -264,12 +229,6 @@ public class DimensionManager
return worlds.values().toArray(new WorldServer[worlds.size()]);
}
public static boolean shouldLoadSpawn(int dim)
{
int id = getProviderType(dim);
return spawnSettings.containsKey(id) && spawnSettings.get(id);
}
static
{
init();
@@ -289,9 +248,9 @@ public class DimensionManager
{
if (dimensions.containsKey(dim))
{
WorldProvider provider = providers.get(getProviderType(dim)).newInstance();
provider.setDimension(dim);
return provider;
WorldProvider ret = getProviderType(dim).createDimension();
ret.setDimension(dim);
return ret;
}
else
{
@@ -301,7 +260,7 @@ public class DimensionManager
catch (Exception e)
{
FMLCommonHandler.instance().getFMLLogger().log(Level.ERROR, String.format("An error occured trying to create an instance of WorldProvider %d (%s)",
dim, providers.get(getProviderType(dim)).getSimpleName()),e);
dim, getProviderType(dim)),e);
throw new RuntimeException(e);
}
}
@@ -50,24 +50,37 @@ public class WorldSpecificSaveHandler implements ISaveHandler
dataDir.mkdirs();
}
File file = new File(dataDir, name + ".dat");
if (!file.exists() && name.equalsIgnoreCase("FORTRESS") && world.provider.getDimension() == -1) //Only copy over the fortress.dat for the vanilla nether.
if (!file.exists())
{
File parentFile = parent.getMapFileFromName(name);
if (parentFile.exists())
switch (world.provider.getDimension())
{
try
{
Files.copy(parentFile, file);
}
catch (IOException e)
{
FMLLog.log(Level.ERROR, e, "A critical error occured copying fortress.dat to world specific dat folder - new file will be created.");
}
case -1:
if (name.equalsIgnoreCase("FORTRESS")) copyFile(name, file);
break;
case 1:
if (name.equalsIgnoreCase("VILLAGES_END")) copyFile(name, file);
break;
}
}
return file;
}
private void copyFile(String name, File to)
{
File parentFile = parent.getMapFileFromName(name);
if (parentFile.exists())
{
try
{
Files.copy(parentFile, to);
}
catch (IOException e)
{
FMLLog.log(Level.ERROR, e, "A critical error occured copying %s to world specific dat folder - new file will be created.", parentFile.getName());
}
}
}
@Override
public TemplateManager getStructureTemplateManager()
{
@@ -2,6 +2,7 @@ package net.minecraftforge.common.network;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import net.minecraft.world.DimensionType;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.network.ForgeMessage.DimensionRegisterMessage;
import org.apache.logging.log4j.Level;
@@ -13,7 +14,7 @@ public class DimensionMessageHandler extends SimpleChannelInboundHandler<ForgeMe
{
if (!DimensionManager.isDimensionRegistered(msg.dimensionId))
{
DimensionManager.registerDimension(msg.dimensionId, msg.providerId);
DimensionManager.registerDimension(msg.dimensionId, DimensionType.valueOf(msg.providerId));
}
}
@Override
@@ -8,6 +8,7 @@ import org.apache.logging.log4j.Level;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidRegistry;
import com.google.common.base.Charsets;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.Sets;
@@ -21,10 +22,10 @@ public abstract class ForgeMessage {
/** The dimension ID to register on client */
int dimensionId;
/** The provider ID to register with dimension on client */
int providerId;
String providerId;
public DimensionRegisterMessage(){}
public DimensionRegisterMessage(int dimensionId, int providerId)
public DimensionRegisterMessage(int dimensionId, String providerId)
{
this.dimensionId = dimensionId;
this.providerId = providerId;
@@ -34,14 +35,18 @@ public abstract class ForgeMessage {
void toBytes(ByteBuf bytes)
{
bytes.writeInt(this.dimensionId);
bytes.writeInt(this.providerId);
byte[] data = this.providerId.getBytes(Charsets.UTF_8);
bytes.writeShort(data.length);
bytes.writeBytes(data);
}
@Override
void fromBytes(ByteBuf bytes)
{
dimensionId = bytes.readInt();
providerId = bytes.readInt();
byte[] data = new byte[bytes.readShort()];
bytes.readBytes(data);
providerId = new String(data, Charsets.UTF_8);
}
}
@@ -3,6 +3,9 @@ package net.minecraftforge.common.util;
import java.lang.reflect.*;
import java.util.*;
import com.google.common.collect.Lists;
import net.minecraftforge.fml.common.EnhancedRuntimeException;
import net.minecraftforge.fml.common.FMLLog;
import net.minecraft.block.BlockPressurePlate.Sensitivity;
import net.minecraft.block.material.Material;
@@ -204,8 +207,19 @@ public class EnumHelper
return null;
}
@SuppressWarnings("unchecked")
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Class<?>[] paramTypes, Object[] paramValues)
//Tests an enum is compatible with these args, throws an error if not.
public static void testEnum(Class<? extends Enum<?>> enumType, Class<?>[] paramTypes)
{
addEnum(true, enumType, null, paramTypes, (Object[])null);
}
public static <T extends Enum<? >> T addEnum(Class<T> enumType, String enumName, Class<?>[] paramTypes, Object... paramValues)
{
return addEnum(false, enumType, enumName, paramTypes, paramValues);
}
@SuppressWarnings({ "unchecked", "serial" })
private static <T extends Enum<? >> T addEnum(boolean test, final Class<T> enumType, String enumName, final Class<?>[] paramTypes, Object[] paramValues)
{
if (!isSetup)
{
@@ -243,14 +257,74 @@ public class EnumHelper
if (valuesField == null)
{
FMLLog.severe("Could not find $VALUES field for enum: %s", enumType.getName());
FMLLog.severe("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF);
FMLLog.severe("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0'));
FMLLog.severe("Fields:");
final List<String> lines = Lists.newArrayList();
lines.add(String.format("Could not find $VALUES field for enum: %s", enumType.getName()));
lines.add(String.format("Runtime Deobf: %s", FMLForgePlugin.RUNTIME_DEOBF));
lines.add(String.format("Flags: %s", String.format("%16s", Integer.toBinaryString(flags)).replace(' ', '0')));
lines.add( "Fields:");
for (Field field : fields)
{
String mods = String.format("%16s", Integer.toBinaryString(field.getModifiers())).replace(' ', '0');
FMLLog.severe(" %s %s: %s", mods, field.getName(), field.getType().getName());
lines.add(String.format(" %s %s: %s", mods, field.getName(), field.getType().getName()));
}
for (String line : lines)
FMLLog.severe(line);
if (test)
{
throw new EnhancedRuntimeException("Could not find $VALUES field for enum: " + enumType.getName())
{
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
for (String line : lines)
stream.println(line);
}
};
}
return null;
}
if (test)
{
Object ctr = null;
Exception ex = null;
try
{
ctr = getConstructorAccessor(enumType, paramTypes);
}
catch (Exception e)
{
ex = e;
}
if (ctr == null || ex != null)
{
throw new EnhancedRuntimeException(String.format("Could not find constructor for Enum %s", enumType.getName()), ex)
{
private String toString(Class<?>[] cls)
{
StringBuilder b = new StringBuilder();
for (int x = 0; x < cls.length; x++)
{
b.append(cls[x].getName());
if (x != cls.length - 1)
b.append(", ");
}
return b.toString();
}
@Override
protected void printStackTrace(WrappedPrintStream stream)
{
stream.println("Target Arguments:");
stream.println(" java.lang.String, int, " + toString(paramTypes));
stream.println("Found Constructors:");
for (Constructor<?> ctr : enumType.getDeclaredConstructors())
{
stream.println(" " + toString(ctr.getParameterTypes()));
}
}
};
}
return null;
}