diff --git a/src/main/java/cpw/mods/fml/common/FMLContainer.java b/src/main/java/cpw/mods/fml/common/FMLContainer.java index 968f57792c..c7316097ae 100644 --- a/src/main/java/cpw/mods/fml/common/FMLContainer.java +++ b/src/main/java/cpw/mods/fml/common/FMLContainer.java @@ -216,6 +216,14 @@ public class FMLContainer extends DummyModContainer implements WorldAccessContai NBTTagCompound dataTag = list.func_150305_b(i); dataList.put(dataTag.func_74779_i("K"), dataTag.func_74762_e("V")); } + + if (!tag.func_74764_b("BlockedItemIds")) // no blocked id info -> old 1.7 save + { + // old 1.7 save potentially affected by the registry mapping bug + // fix the ids the best we can... + GameData.fixBrokenIds(dataList); + } + // blocked ids int[] blockedIds = tag.func_74759_k("BlockedItemIds"); // block aliases diff --git a/src/main/java/cpw/mods/fml/common/registry/GameData.java b/src/main/java/cpw/mods/fml/common/registry/GameData.java index f4320f4522..053e993488 100644 --- a/src/main/java/cpw/mods/fml/common/registry/GameData.java +++ b/src/main/java/cpw/mods/fml/common/registry/GameData.java @@ -218,6 +218,78 @@ public class GameData { return ui; } + /** + * Fix IDs improperly allocated by early versions of the registry, best-effort. + * + * Items sharing the same ID with a block, but not sharing the same registry name will be + * mapped to an unused id. Losing items instead of blocks should minimize the damage. + * + * @param dataList List containing the IDs to fix + */ + public static void fixBrokenIds(Map dataList) + { + BitSet availabilityMap = new BitSet(32000); + + // reserve all ids occupied by blocks + for (Entry entry : dataList.entrySet()) + { + String itemName = entry.getKey(); + + if (itemName.charAt(0) == '\u0001') // is a block + { + availabilityMap.set(entry.getValue()); + } + } + + Set itemsToAllocate = new HashSet(); + + // check all ids occupied by items + for (Entry entry : dataList.entrySet()) + { + String itemName = entry.getKey(); + + if (itemName.charAt(0) != '\u0001') // is an item + { + int oldId = entry.getValue(); + + if (availabilityMap.get(oldId)) // id is already occupied + { + String realName = itemName.substring(1); + String blockName = '\u0001' + realName; + + if (!dataList.containsKey(blockName) || + !(getMain().iItemRegistry.getRaw(realName) instanceof ItemBlock)) // the slot is occupied by something else and this item is no ItemBlock + { + // relocate the item later, after all correct ids have been claimed + itemsToAllocate.add(itemName); + } + else if (dataList.get(blockName) != oldId) // occupied, but this is an ItemBlock for a different block than whatever may use its id + { + // relocate to the matching block + int newId = dataList.get(blockName); + entry.setValue(newId); + + FMLLog.warning("Fixed ItemBlock %s not using the id of its block, old id %d, new id %d.", realName, oldId, newId); + } + } + else // unused id, occupy + { + availabilityMap.set(oldId); + } + } + } + + for (String itemName : itemsToAllocate) + { + int oldId = dataList.get(itemName); + int newId = availabilityMap.nextClearBit(4096); + + dataList.put(itemName, newId); + + FMLLog.warning("Fixed Item %s conflicting with another block/item, old id %d, new id %d.", itemName.substring(1), oldId, newId); + } + } + public static List injectWorldIDMap(Map dataList, boolean injectFrozenData, boolean isLocalWorld) { return injectWorldIDMap(dataList, new int[0], new HashMap(), new HashMap(), injectFrozenData, isLocalWorld);