Registry: Implement support for remapping blocks/items to a new name.

This commit is contained in:
Player 2014-03-25 00:36:37 +01:00
parent 180c605570
commit ac44af863b
5 changed files with 330 additions and 113 deletions

View file

@ -15,6 +15,7 @@ package cpw.mods.fml.common;
import java.io.File; import java.io.File;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -101,6 +102,7 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
list.func_74742_a(mod); list.func_74742_a(mod);
} }
fmlData.func_74782_a("ModList", list); fmlData.func_74782_a("ModList", list);
// name <-> id mappings
NBTTagList dataList = new NBTTagList(); NBTTagList dataList = new NBTTagList();
FMLLog.fine("Gathering id map for writing to world save %s", info.func_76065_j()); FMLLog.fine("Gathering id map for writing to world save %s", info.func_76065_j());
Map<String,Integer> itemList = GameData.buildItemDataList(); Map<String,Integer> itemList = GameData.buildItemDataList();
@ -112,7 +114,29 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
dataList.func_74742_a(tag); dataList.func_74742_a(tag);
} }
fmlData.func_74782_a("ItemData", dataList); fmlData.func_74782_a("ItemData", dataList);
fmlData.func_74783_a("BlockedIds", GameData.getBlockedIds()); // blocked ids
fmlData.func_74783_a("BlockedItemIds", GameData.getBlockedIds());
// block aliases
NBTTagList blockAliasList = new NBTTagList();
for (Entry<String, String> entry : GameData.getBlockRegistry().getAliases().entrySet())
{
NBTTagCompound tag = new NBTTagCompound();
tag.func_74778_a("K", entry.getKey());
tag.func_74778_a("V", entry.getValue());
blockAliasList.func_74742_a(tag);
}
fmlData.func_74782_a("BlockAliases", blockAliasList);
// item aliases
NBTTagList itemAliasList = new NBTTagList();
for (Entry<String, String> entry : GameData.getItemRegistry().getAliases().entrySet())
{
NBTTagCompound tag = new NBTTagCompound();
tag.func_74778_a("K", entry.getKey());
tag.func_74778_a("V", entry.getValue());
itemAliasList.func_74742_a(tag);
}
fmlData.func_74782_a("ItemAliases", itemAliasList);
return fmlData; return fmlData;
} }
@ -187,18 +211,34 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai
} }
else if (tag.func_74764_b("ItemData")) else if (tag.func_74764_b("ItemData"))
{ {
// read name <-> id mappings // name <-> id mappings
NBTTagList list = tag.func_150295_c("ItemData", (byte)10); NBTTagList list = tag.func_150295_c("ItemData", 10);
Map<String,Integer> dataList = Maps.newLinkedHashMap(); Map<String,Integer> dataList = Maps.newLinkedHashMap();
for (int i = 0; i < list.func_74745_c(); i++) for (int i = 0; i < list.func_74745_c(); i++)
{ {
NBTTagCompound dataTag = list.func_150305_b(i); NBTTagCompound dataTag = list.func_150305_b(i);
dataList.put(dataTag.func_74779_i("K"), dataTag.func_74762_e("V")); dataList.put(dataTag.func_74779_i("K"), dataTag.func_74762_e("V"));
} }
// read blocked ids // blocked ids
int[] blockedIds = tag.func_74759_k("BlockedIds"); int[] blockedIds = tag.func_74759_k("BlockedItemIds");
// block aliases
Map<String, String> blockAliases = new HashMap<String, String>();
list = tag.func_150295_c("BlockAliases", 10);
for (int i = 0; i < list.func_74745_c(); i++)
{
NBTTagCompound dataTag = list.func_150305_b(i);
blockAliases.put(dataTag.func_74779_i("K"), dataTag.func_74779_i("V"));
}
// item aliases
Map<String, String> itemAliases = new HashMap<String, String>();
list = tag.func_150295_c("ItemAliases", 10);
for (int i = 0; i < list.func_74745_c(); i++)
{
NBTTagCompound dataTag = list.func_150305_b(i);
itemAliases.put(dataTag.func_74779_i("K"), dataTag.func_74779_i("V"));
}
List<String> failedElements = GameData.injectWorldIDMap(dataList, blockedIds, true, true); List<String> failedElements = GameData.injectWorldIDMap(dataList, blockedIds, blockAliases, itemAliases, true, true);
if (!failedElements.isEmpty()) if (!failedElements.isEmpty())
{ {
throw new GameRegistryException("Failed to load the world - there are fatal block and item id issues", failedElements); throw new GameRegistryException("Failed to load the world - there are fatal block and item id issues", failedElements);

View file

@ -856,7 +856,7 @@ public class Loader
* @param gameData GameData instance where the new map's config is to be loaded into. * @param gameData GameData instance where the new map's config is to be loaded into.
* @return List with the mapping results. * @return List with the mapping results.
*/ */
public List<String> fireMissingMappingEvent(LinkedHashMap<String, Integer> missing, boolean isLocalWorld, GameData gameData) public List<String> fireMissingMappingEvent(LinkedHashMap<String, Integer> missing, boolean isLocalWorld, GameData gameData, Map<String, Integer[]> remaps)
{ {
if (missing.isEmpty()) // nothing to do if (missing.isEmpty()) // nothing to do
{ {
@ -868,10 +868,9 @@ public class Loader
for (Map.Entry<String, Integer> mapping : missing.entrySet()) for (Map.Entry<String, Integer> mapping : missing.entrySet())
{ {
String itemName = mapping.getKey();
int id = mapping.getValue(); int id = mapping.getValue();
MissingMapping m = new MissingMapping(itemName, id); MissingMapping m = new MissingMapping(mapping.getKey(), id);
missingMappings.put(itemName.substring(0, itemName.indexOf(':')), m); missingMappings.put(m.name.substring(0, m.name.indexOf(':')), m);
} }
FMLMissingMappingsEvent missingEvent = new FMLMissingMappingsEvent(missingMappings); FMLMissingMappingsEvent missingEvent = new FMLMissingMappingsEvent(missingMappings);
@ -913,7 +912,7 @@ public class Loader
} }
} }
return GameData.processIdRematches(missingMappings.values(), isLocalWorld, gameData); return GameData.processIdRematches(missingMappings.values(), isLocalWorld, gameData, remaps);
} }
public void fireRemapEvent(Map<String, Integer[]> remaps) public void fireRemapEvent(Map<String, Integer[]> remaps)

View file

@ -2,11 +2,14 @@ package cpw.mods.fml.common.event;
import java.util.List; import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ListMultimap; import com.google.common.collect.ListMultimap;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.registry.GameData;
import cpw.mods.fml.common.registry.GameRegistry; import cpw.mods.fml.common.registry.GameRegistry;
/** /**
@ -28,49 +31,102 @@ public class FMLMissingMappingsEvent extends FMLEvent {
* @author cpw * @author cpw
* *
*/ */
public static enum Action { DEFAULT, IGNORE, WARN, FAIL } public static enum Action { DEFAULT, IGNORE, WARN, FAIL, REMAP }
public static class MissingMapping { public static class MissingMapping {
public final GameRegistry.Type type; public final GameRegistry.Type type;
public final String name; public final String name;
public final int id; public final int id;
private Action action = Action.DEFAULT; private Action action = Action.DEFAULT;
private Object target;
public MissingMapping(String name, int id) public MissingMapping(String name, int id)
{ {
this.type = name.charAt(0) == '\u0001' ? GameRegistry.Type.BLOCK : GameRegistry.Type.ITEM; this.type = name.charAt(0) == '\u0001' ? GameRegistry.Type.BLOCK : GameRegistry.Type.ITEM;
this.name = name; this.name = name.substring(1);
this.id = id; this.id = id;
} }
/** /**
* @deprecated use ignore(), warn() or fail() instead * @deprecated use ignore(), warn(), fail() or remap() instead
*/ */
@Deprecated @Deprecated
public void setAction(Action target) public void setAction(Action target)
{ {
if (target == Action.DEFAULT) throw new IllegalArgumentException(); if (target == Action.DEFAULT || target == Action.REMAP) throw new IllegalArgumentException();
this.action = target; this.action = target;
} }
/**
* Ignore the missing item.
*/
public void ignore() public void ignore()
{ {
this.action = Action.IGNORE; action = Action.IGNORE;
} }
/**
* Warn the user about the missing item.
*/
public void warn() public void warn()
{ {
this.action = Action.WARN; action = Action.WARN;
} }
/**
* Prevent the world from loading due to the missing item.
*/
public void fail() public void fail()
{ {
this.action = Action.FAIL; action = Action.FAIL;
} }
/**
* Remap the missing item to the specified Block.
*
* Use this if you have renamed a Block, don't forget to handle the ItemBlock.
* Existing references using the old name will point to the new one.
*
* @param target Block to remap to.
*/
public void remap(Block target)
{
if (type != GameRegistry.Type.BLOCK) throw new IllegalArgumentException("Can't remap an item to a block.");
if (target == null) throw new NullPointerException("remap target is null");
if (GameData.getBlockRegistry().getId(target) < 0) throw new IllegalArgumentException(String.format("The specified block %s hasn't been registered at startup.", target));
action = Action.REMAP;
this.target = target;
}
/**
* Remap the missing item to the specified Item.
*
* Use this if you have renamed an Item.
* Existing references using the old name will point to the new one.
*
* @param target Item to remap to.
*/
public void remap(Item target)
{
if (type != GameRegistry.Type.ITEM) throw new IllegalArgumentException("Can't remap a block to an item.");
if (target == null) throw new NullPointerException("remap target is null");
if (GameData.getItemRegistry().getId(target) < 0) throw new IllegalArgumentException(String.format("The specified item %s hasn't been registered at startup.", target));
action = Action.REMAP;
this.target = target;
}
// internal
public Action getAction() public Action getAction()
{ {
return this.action; return this.action;
} }
public Object getTarget()
{
return target;
}
} }
private ListMultimap<String,MissingMapping> missing; private ListMultimap<String,MissingMapping> missing;
private ModContainer activeContainer; private ModContainer activeContainer;

View file

@ -15,6 +15,7 @@ import net.minecraft.util.RegistryNamespaced;
import com.google.common.collect.BiMap; import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import cpw.mods.fml.common.FMLLog; import cpw.mods.fml.common.FMLLog;
@ -25,10 +26,11 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
private final Class<I> superType; private final Class<I> superType;
private String optionalDefaultName; private String optionalDefaultName;
private I optionalDefaultObject; private I optionalDefaultObject;
private int maxId;
int maxId;
private int minId; private int minId;
private char discriminator; private char discriminator;
// aliases redirecting legacy names to the actual name, may need recursive application to find the final name
private final Map<String, String> aliases = new HashMap<String, String>();
FMLControlledNamespacedRegistry(String optionalDefault, int maxIdValue, int minIdValue, Class<I> type, char discriminator) FMLControlledNamespacedRegistry(String optionalDefault, int maxIdValue, int minIdValue, Class<I> type, char discriminator)
{ {
@ -47,6 +49,7 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
this.optionalDefaultName = registry.optionalDefaultName; this.optionalDefaultName = registry.optionalDefaultName;
this.maxId = registry.maxId; this.maxId = registry.maxId;
this.minId = registry.minId; this.minId = registry.minId;
this.aliases.putAll(registry.aliases);
field_148759_a = new ObjectIntIdentityMap(); field_148759_a = new ObjectIntIdentityMap();
field_82596_a.clear(); field_82596_a.clear();
@ -58,6 +61,8 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
} }
} }
// public api
/** /**
* Add an object to the registry, trying to use the specified id. * Add an object to the registry, trying to use the specified id.
* *
@ -70,6 +75,137 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
GameData.getMain().register(thing, name, id); GameData.getMain().register(thing, name, id);
} }
@Override
public I func_82594_a(String name)
{
I object = getRaw(name);
return object == null ? this.optionalDefaultObject : object;
}
@Override
public I func_148754_a(int id)
{
I object = getRaw(id);
return object == null ? this.optionalDefaultObject : object;
}
/**
* Get the object identified by the specified id.
*
* The default object is the air block for the block registry or null for the item registry.
*
* @param id Block/Item id.
* @return Block/Item object or the default object if it wasn't found.
*/
public I get(int id)
{
return func_148754_a(id);
}
/**
* Get the object identified by the specified name.
*
* The default object is the air block for the block registry or null for the item registry.
*
* @param name Block/Item name.
* @return Block/Item object or the default object if it wasn't found.
*/
public I get(String name)
{
return func_82594_a(name);
}
/**
* Get the id for the specified object.
*
* Don't hold onto the id across the world, it's being dynamically re-mapped as needed.
*
* Usually the name should be used instead of the id, if using the Block/Item object itself is
* not suitable for the task.
*
* @param think Block/Item object.
* @return Block/Item id or -1 if it wasn't found.
*/
public int getId(I thing)
{
return func_148757_b(thing);
}
/**
* Get the object identified by the specified id.
*
* @param id Block/Item id.
* @return Block/Item object or null if it wasn't found.
*/
public I getRaw(int id)
{
return superType.cast(super.func_148754_a(id));
}
/**
* Get the object identified by the specified name.
*
* @param name Block/Item name.
* @return Block/Item object or null if it wasn't found.
*/
public I getRaw(String name)
{
I ret = superType.cast(super.func_82594_a(name));
if (ret == null) // no match, try aliases recursively
{
name = aliases.get(name);
if (name != null) return getRaw(name);
}
return ret;
}
@Override
public boolean func_148741_d(String name)
{
boolean ret = super.func_148741_d(name);
if (!ret) // no match, try aliases recursively
{
name = aliases.get(name);
if (name != null) return func_148741_d(name);
}
return ret;
}
public int getId(String itemName)
{
I obj = getRaw(itemName);
if (obj == null) return -1;
return getId(obj);
}
public boolean contains(String itemName)
{
return func_148741_d(itemName);
}
// internal
public void serializeInto(Map<String, Integer> idMapping)
{
for (Iterator<Object> it = iterator(); it.hasNext(); )
{
I thing = (I) it.next();
idMapping.put(discriminator+func_148750_c(thing), getId(thing));
}
}
public Map<String, String> getAliases()
{
return ImmutableMap.copyOf(aliases);
}
int add(int id, String name, I thing, BitSet availabilityMap) int add(int id, String name, I thing, BitSet availabilityMap)
{ {
if (name.equals(optionalDefaultName)) if (name.equals(optionalDefaultName))
@ -98,30 +234,9 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
return idToUse; return idToUse;
} }
@Override void addAlias(String from, String to)
public I func_82594_a(String name)
{ {
I object = superType.cast(super.func_82594_a(name)); aliases.put(from, to);
return object == null ? this.optionalDefaultObject : object;
}
@Override
public I func_148754_a(int id)
{
I object = superType.cast(super.func_148754_a(id));
return object == null ? this.optionalDefaultObject : object;
}
private ObjectIntIdentityMap idMap()
{
return field_148759_a;
}
@SuppressWarnings("unchecked")
private BiMap<String,I> nameMap()
{
return (BiMap<String,I>) field_82596_a;
} }
Map<String,Integer> getEntriesNotIn(FMLControlledNamespacedRegistry<I> registry) Map<String,Integer> getEntriesNotIn(FMLControlledNamespacedRegistry<I> registry)
@ -137,53 +252,6 @@ public class FMLControlledNamespacedRegistry<I> extends RegistryNamespaced {
return ret; return ret;
} }
public I get(int id)
{
return func_148754_a(id);
}
public I get(String name)
{
return func_82594_a(name);
}
public int getId(I thing)
{
return func_148757_b(thing);
}
public I getRaw(int id)
{
return superType.cast(super.func_148754_a(id));
}
public I getRaw(String name)
{
return superType.cast(super.func_82594_a(name));
}
public void serializeInto(Map<String, Integer> idMapping)
{
for (Iterator<Object> it = iterator(); it.hasNext(); )
{
I thing = (I) it.next();
idMapping.put(discriminator+func_148750_c(thing), getId(thing));
}
}
public int getId(String itemName)
{
I obj = getRaw(itemName);
if (obj == null) return -1;
return getId(obj);
}
public boolean contains(String itemName)
{
return field_82596_a.containsKey(itemName);
}
void dump() void dump()
{ {
List<Integer> ids = new ArrayList<Integer>(); List<Integer> ids = new ArrayList<Integer>();

View file

@ -15,6 +15,7 @@ package cpw.mods.fml.common.registry;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.BitSet; import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@ -47,6 +48,7 @@ import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.ModContainer; import cpw.mods.fml.common.ModContainer;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent; import cpw.mods.fml.common.event.FMLMissingMappingsEvent;
import cpw.mods.fml.common.event.FMLMissingMappingsEvent.MissingMapping; import cpw.mods.fml.common.event.FMLMissingMappingsEvent.MissingMapping;
import cpw.mods.fml.common.registry.GameRegistry.Type;
import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier; import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier;
public class GameData { public class GameData {
@ -205,10 +207,10 @@ public class GameData {
public static List<String> injectWorldIDMap(Map<String, Integer> dataList, boolean injectFrozenData, boolean isLocalWorld) public static List<String> injectWorldIDMap(Map<String, Integer> dataList, boolean injectFrozenData, boolean isLocalWorld)
{ {
return injectWorldIDMap(dataList, new int[0], injectFrozenData, isLocalWorld); return injectWorldIDMap(dataList, new int[0], new HashMap<String, String>(), new HashMap<String, String>(), injectFrozenData, isLocalWorld);
} }
public static List<String> injectWorldIDMap(Map<String, Integer> dataList, int[] blockedIds, boolean injectFrozenData, boolean isLocalWorld) public static List<String> injectWorldIDMap(Map<String, Integer> dataList, int[] blockedIds, Map<String, String> blockAliases, Map<String, String> itemAliases, boolean injectFrozenData, boolean isLocalWorld)
{ {
FMLLog.info("Injecting existing block and item data into this %s instance", FMLCommonHandler.instance().getEffectiveSide().isServer() ? "server" : "client"); FMLLog.info("Injecting existing block and item data into this %s instance", FMLCommonHandler.instance().getEffectiveSide().isServer() ? "server" : "client");
Map<String, Integer[]> remaps = Maps.newHashMap(); Map<String, Integer[]> remaps = Maps.newHashMap();
@ -224,6 +226,16 @@ public class GameData {
newData.block(id); newData.block(id);
} }
for (Map.Entry<String, String> entry : blockAliases.entrySet())
{
newData.iBlockRegistry.addAlias(entry.getKey(), entry.getValue());
}
for (Map.Entry<String, String> entry : itemAliases.entrySet())
{
newData.iItemRegistry.addAlias(entry.getKey(), entry.getValue());
}
// process blocks and items in the world, blocks in the first pass, items in the second // process blocks and items in the world, blocks in the first pass, items in the second
// blocks need to be added first for proper ItemBlock handling // blocks need to be added first for proper ItemBlock handling
for (int pass = 0; pass < 2; pass++) for (int pass = 0; pass < 2; pass++)
@ -244,7 +256,7 @@ public class GameData {
if (currId == -1) if (currId == -1)
{ {
FMLLog.info("Found a missing id from the world %s", itemName); FMLLog.info("Found a missing id from the world %s", itemName);
missingMappings.put(itemName, newId); missingMappings.put(entry.getKey(), newId);
continue; // no block/item -> nothing to add continue; // no block/item -> nothing to add
} }
else if (currId != newId) else if (currId != newId)
@ -279,7 +291,7 @@ public class GameData {
} }
} }
List<String> missedMappings = Loader.instance().fireMissingMappingEvent(missingMappings, isLocalWorld, newData); List<String> missedMappings = Loader.instance().fireMissingMappingEvent(missingMappings, isLocalWorld, newData, remaps);
if (!missedMappings.isEmpty()) return missedMappings; if (!missedMappings.isEmpty()) return missedMappings;
if (injectFrozenData) // add blocks + items missing from the map if (injectFrozenData) // add blocks + items missing from the map
@ -327,15 +339,52 @@ public class GameData {
return ImmutableList.of(); return ImmutableList.of();
} }
public static List<String> processIdRematches(Iterable<MissingMapping> remaps, boolean isLocalWorld, GameData gameData) public static List<String> processIdRematches(Iterable<MissingMapping> missedMappings, boolean isLocalWorld, GameData gameData, Map<String, Integer[]> remaps)
{ {
List<String> failed = Lists.newArrayList(); List<String> failed = Lists.newArrayList();
List<String> ignored = Lists.newArrayList(); List<String> ignored = Lists.newArrayList();
List<String> warned = Lists.newArrayList(); List<String> warned = Lists.newArrayList();
for (MissingMapping remap : remaps) for (MissingMapping remap : missedMappings)
{ {
FMLMissingMappingsEvent.Action action = remap.getAction(); FMLMissingMappingsEvent.Action action = remap.getAction();
if (action == FMLMissingMappingsEvent.Action.REMAP)
{
// block/item re-mapped, finish the registration with the new name/object, but the old id
int currId, newId;
String newName;
if (remap.type == Type.BLOCK)
{
currId = getMain().iBlockRegistry.getId((Block) remap.getTarget());
newName = getMain().iBlockRegistry.func_148750_c(remap.getTarget());
FMLLog.fine("The Block %s is being remapped to %s.", remap.name, newName);
newId = gameData.registerBlock((Block) remap.getTarget(), newName, null, remap.id);
gameData.iBlockRegistry.addAlias(remap.name, newName);
}
else
{
currId = getMain().iItemRegistry.getId((Item) remap.getTarget());
newName = getMain().iItemRegistry.func_148750_c(remap.getTarget());
FMLLog.fine("The Item %s is being remapped to %s.", remap.name, newName);
newId = gameData.registerItem((Item) remap.getTarget(), newName, null, remap.id);
gameData.iItemRegistry.addAlias(remap.name, newName);
}
if (newId != remap.id) throw new IllegalStateException();
if (currId != newId)
{
FMLLog.info("Found %s id mismatch %s : %d (was %d)", remap.type == Type.BLOCK ? "block" : "item", newName, currId, newId);
remaps.put(newName, new Integer[] { currId, newId });
}
}
else
{
// block item missing, warn as requested and block the id
if (action == FMLMissingMappingsEvent.Action.DEFAULT) if (action == FMLMissingMappingsEvent.Action.DEFAULT)
{ {
action = FMLCommonHandler.instance().getDefaultMissingAction(); action = FMLCommonHandler.instance().getDefaultMissingAction();
@ -353,9 +402,14 @@ public class GameData {
{ {
warned.add(remap.name); warned.add(remap.name);
} }
else
{
throw new RuntimeException(String.format("Invalid default missing id action specified: %s", action.name()));
}
gameData.block(remap.id); // prevent the id from being reused later gameData.block(remap.id); // prevent the id from being reused later
} }
}
if (!failed.isEmpty()) if (!failed.isEmpty())
{ {
FMLLog.severe("This world contains blocks and items that refuse to be remapped. The world will not be loaded"); FMLLog.severe("This world contains blocks and items that refuse to be remapped. The world will not be loaded");