/** Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team http://www.mod-buildcraft.com * * The BuildCraft API is distributed under the terms of the MIT License. Please check the contents of the license, which * should be located as "LICENSE.API" in the BuildCraft source code distribution. */ package buildcraft.api.blueprints; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map.Entry; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import org.apache.logging.log4j.Level; import net.minecraft.block.Block; import net.minecraft.crash.CrashReportCategory; import net.minecraft.entity.Entity; import net.minecraft.item.Item; import net.minecraft.nbt.NBTTagByte; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagShort; import net.minecraft.util.ResourceLocation; import net.minecraftforge.common.util.Constants; import net.minecraftforge.fml.common.FMLModContainer; import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.event.FMLMissingMappingsEvent; import net.minecraftforge.fml.common.registry.GameRegistry; import buildcraft.api.core.BCLog; public class MappingRegistry { public HashMap<Block, Integer> blockToId = new HashMap<Block, Integer>(); public ArrayList<Block> idToBlock = new ArrayList<Block>(); public HashMap<Item, Integer> itemToId = new HashMap<Item, Integer>(); public ArrayList<Item> idToItem = new ArrayList<Item>(); public HashMap<Class<? extends Entity>, Integer> entityToId = new HashMap<Class<? extends Entity>, Integer>(); public ArrayList<Class<? extends Entity>> idToEntity = new ArrayList<Class<? extends Entity>>(); private void registerItem(Item item) { if (item == null) throw new IllegalArgumentException("Cannot register a null item!"); if (!itemToId.containsKey(item)) { idToItem.add(item); itemToId.put(item, idToItem.size() - 1); } } private void registerBlock(Block block) { if (block == null) throw new IllegalArgumentException("Cannot register a null block!"); if (!blockToId.containsKey(block)) { idToBlock.add(block); blockToId.put(block, idToBlock.size() - 1); } } private void registerEntity(Class<? extends Entity> entityClass) { if (entityClass == null) throw new IllegalArgumentException("Cannot register a null entityClass!"); if (!entityToId.containsKey(entityClass)) { idToEntity.add(entityClass); entityToId.put(entityClass, idToEntity.size() - 1); } } public Item getItemForId(int id) throws MappingNotFoundException { if (id >= idToItem.size()) { throw new MappingNotFoundException("no item mapping at position " + id); } Item result = idToItem.get(id); if (result == null) { throw new MappingNotFoundException("no item mapping at position " + id); } else { return result; } } public int getIdForItem(Item item) { if (item == null) throw new NullPointerException("item"); if (!itemToId.containsKey(item)) { registerItem(item); } return itemToId.get(item); } public int itemIdToRegistry(int id) { Item item = Item.getItemById(id); return getIdForItem(item); } public ResourceLocation itemIdToWorld(int id) throws MappingNotFoundException { Item item = getItemForId(id); return Item.itemRegistry.getNameForObject(item); } public Block getBlockForId(int id) throws MappingNotFoundException { if (id >= idToBlock.size()) { throw new MappingNotFoundException("no block mapping at position " + id); } Block result = idToBlock.get(id); if (result == null) { throw new MappingNotFoundException("no block mapping at position " + id); } else { return result; } } public int getIdForBlock(Block block) { if (!blockToId.containsKey(block)) { registerBlock(block); } return blockToId.get(block); } public int blockIdToRegistry(int id) { Block block = Block.getBlockById(id); return getIdForBlock(block); } public ResourceLocation blockIdToWorld(int id) throws MappingNotFoundException { Block block = getBlockForId(id); return Block.blockRegistry.getNameForObject(block); } public Class<? extends Entity> getEntityForId(int id) throws MappingNotFoundException { if (id >= idToEntity.size()) { throw new MappingNotFoundException("no entity mapping at position " + id); } Class<? extends Entity> result = idToEntity.get(id); if (result == null) { throw new MappingNotFoundException("no entity mapping at position " + id); } else { return result; } } public int getIdForEntity(Class<? extends Entity> entity) { if (!entityToId.containsKey(entity)) { registerEntity(entity); } return entityToId.get(entity); } /** Relocates a stack nbt from the registry referential to the world referential. */ public void stackToWorld(NBTTagCompound nbt) throws MappingNotFoundException { // 1.7.10 back-compat if (nbt.hasKey("id", Constants.NBT.TAG_SHORT)) { Item item = getItemForId(nbt.getShort("id")); nbt.setString("id", (Item.itemRegistry.getNameForObject(item).toString())); } } // versions before 1.8 saved stacks with an Item ID as a short private boolean isOldStackLayout(NBTTagCompound nbt) { return nbt.hasKey("id") && nbt.hasKey("Count") && nbt.hasKey("Damage") && nbt.getTag("id") instanceof NBTTagShort && nbt.getTag( "Count") instanceof NBTTagByte && nbt.getTag("Damage") instanceof NBTTagShort; } // 1.7.10 Back compat public void scanAndTranslateStacksToWorld(NBTTagCompound nbt) throws MappingNotFoundException { // First, check if this nbt is itself a stack if (isOldStackLayout(nbt)) { stackToWorld(nbt); } // Then, look at the nbt compound contained in this nbt (even if it's a // stack) and checks for stacks in it. for (String key : (Collection<String>) nbt.getKeySet()) { if (nbt.getTag(key) instanceof NBTTagCompound) { try { scanAndTranslateStacksToWorld(nbt.getCompoundTag(key)); } catch (MappingNotFoundException e) { nbt.removeTag(key); } } if (nbt.getTag(key) instanceof NBTTagList) { NBTTagList list = (NBTTagList) nbt.getTag(key); if (list.getTagType() == Constants.NBT.TAG_COMPOUND) { for (int i = list.tagCount() - 1; i >= 0; --i) { try { scanAndTranslateStacksToWorld(list.getCompoundTagAt(i)); } catch (MappingNotFoundException e) { list.removeTag(i); } } } } } } public void write(NBTTagCompound nbt) { NBTTagList blocksMapping = new NBTTagList(); for (Block b : idToBlock) { NBTTagCompound sub = new NBTTagCompound(); if (b != null) { Object obj = Block.blockRegistry.getNameForObject(b); if (obj == null) { BCLog.logger.error("Block " + b.getUnlocalizedName() + " (" + b.getClass().getName() + ") does not have a registry name! This is a bug!"); } else { String name = obj.toString(); if (name == null || name.length() == 0) { BCLog.logger.error("Block " + b.getUnlocalizedName() + " (" + b.getClass().getName() + ") has an empty registry name! This is a bug!"); } else { sub.setString("name", name); } } } else { throw new IllegalArgumentException("Found a null block!"); } blocksMapping.appendTag(sub); } nbt.setTag("blocksMapping", blocksMapping); NBTTagList itemsMapping = new NBTTagList(); for (Item i : idToItem) { NBTTagCompound sub = new NBTTagCompound(); if (i != null) { ResourceLocation obj = Item.itemRegistry.getNameForObject(i); if (obj == null) { BCLog.logger.error("Item " + i.getUnlocalizedName() + " (" + i.getClass().getName() + ") does not have a registry name! This is a bug!"); } else { String name = obj.toString(); if (name == null || name.length() == 0) { BCLog.logger.error("Item " + i.getUnlocalizedName() + " (" + i.getClass().getName() + ") has an empty registry name! This is a bug!"); } else { sub.setString("name", name); } } } else { throw new IllegalArgumentException("Found a null item!"); } itemsMapping.appendTag(sub); } nbt.setTag("itemsMapping", itemsMapping); NBTTagList entitiesMapping = new NBTTagList(); for (Class<? extends Entity> e : idToEntity) { NBTTagCompound sub = new NBTTagCompound(); sub.setString("name", e.getCanonicalName()); entitiesMapping.appendTag(sub); } nbt.setTag("entitiesMapping", entitiesMapping); // System.out.println("[W] idToItem size : " + idToItem.size()); // for (Item i : idToItem) { // System.out.println("- " + (i != null ? i.toString() : "null")); // } } private Object getMissingMappingFromFML(boolean isBlock, String name, int i) { ResourceLocation location = new ResourceLocation(name); String modName = name.split(":")[0]; if (Loader.isModLoaded(modName)) { try { FMLMissingMappingsEvent.MissingMapping mapping = new FMLMissingMappingsEvent.MissingMapping(isBlock ? GameRegistry.Type.BLOCK : GameRegistry.Type.ITEM, location, i); ListMultimap<String, FMLMissingMappingsEvent.MissingMapping> missingMapping = ArrayListMultimap.create(); missingMapping.put(modName, mapping); FMLMissingMappingsEvent event = new FMLMissingMappingsEvent(missingMapping); for (ModContainer container : Loader.instance().getModList()) { if (container instanceof FMLModContainer) { event.applyModContainer(container); ((FMLModContainer) container).handleModStateEvent(event); if (mapping.getAction() != FMLMissingMappingsEvent.Action.DEFAULT) { break; } } } if (mapping.getAction() == FMLMissingMappingsEvent.Action.REMAP) { return mapping.getTarget(); } } catch (Exception e) { e.printStackTrace(); } } return null; } public void read(NBTTagCompound nbt) { NBTTagList blocksMapping = nbt.getTagList("blocksMapping", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < blocksMapping.tagCount(); ++i) { NBTTagCompound sub = blocksMapping.getCompoundTagAt(i); if (!sub.hasKey("name")) { // Keeping the order correct idToBlock.add(null); BCLog.logger.log(Level.WARN, "Can't load a block - corrupt blueprint!"); continue; } String name = sub.getString("name"); ResourceLocation location = new ResourceLocation(name); Block b = null; if (!Block.blockRegistry.containsKey(location) && name.contains(":")) { b = (Block) getMissingMappingFromFML(true, name, i); if (b != null) { BCLog.logger.info("Remapped " + name + " to " + Block.blockRegistry.getNameForObject(b)); } } if (b == null && Block.blockRegistry.containsKey(location)) { b = (Block) Block.blockRegistry.getObject(location); } if (b != null) { registerBlock(b); } else { // Keeping the order correct idToBlock.add(null); BCLog.logger.log(Level.WARN, "Can't load block " + name); } } NBTTagList itemsMapping = nbt.getTagList("itemsMapping", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < itemsMapping.tagCount(); ++i) { NBTTagCompound sub = itemsMapping.getCompoundTagAt(i); if (!sub.hasKey("name")) { // Keeping the order correct idToItem.add(null); BCLog.logger.log(Level.WARN, "Can't load an item - corrupt blueprint!"); continue; } String name = sub.getString("name"); ResourceLocation location = new ResourceLocation(name); Item item = null; if (!Item.itemRegistry.containsKey(location) && name.contains(":")) { item = (Item) getMissingMappingFromFML(false, name, i); if (item != null) { BCLog.logger.info("Remapped " + name + " to " + Item.itemRegistry.getNameForObject(item)); } } if (item == null && Item.itemRegistry.containsKey(location)) { item = (Item) Item.itemRegistry.getObject(location); } if (item != null) { registerItem(item); } else { // Keeping the order correct idToItem.add(null); BCLog.logger.log(Level.WARN, "Can't load item " + name); } } NBTTagList entitiesMapping = nbt.getTagList("entitiesMapping", Constants.NBT.TAG_COMPOUND); for (int i = 0; i < entitiesMapping.tagCount(); ++i) { NBTTagCompound sub = entitiesMapping.getCompoundTagAt(i); String name = sub.getString("name"); Class<? extends Entity> e = null; try { e = (Class<? extends Entity>) Class.forName(name); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } if (e != null) { registerEntity(e); } else { // Keeping the order correct idToEntity.add(null); BCLog.logger.log(Level.WARN, "Can't load entity " + name); } } // System.out.println("[R] idToItem size : " + idToItem.size()); // for (Item i : idToItem) { // System.out.println("- " + (i != null ? i.toString() : "null")); // } } public void addToCrashReport(CrashReportCategory cat) { cat.addCrashSection("Item Map Count", itemToId.size()); for (Entry<Item, Integer> e : itemToId.entrySet()) { cat.addCrashSection(" - ID " + e.getValue(), Item.itemRegistry.getNameForObject(e.getKey())); } cat.addCrashSection("Block Map Count", blockToId.size()); for (Entry<Block, Integer> e : blockToId.entrySet()) { cat.addCrashSection(" - ID " + e.getValue(), Block.blockRegistry.getNameForObject(e.getKey())); } cat.addCrashSection("Entity Map Count", entityToId.size()); for (Entry<Class<? extends Entity>, Integer> e : entityToId.entrySet()) { cat.addCrashSection(" - ID " + e.getValue(), e.getKey()); } } }