From f1d9aee0b8e1c052fff5b14e464e88ec33d15e17 Mon Sep 17 00:00:00 2001 From: SpaceToad Date: Sun, 11 May 2014 13:19:06 +0200 Subject: [PATCH] Added various levels of detection and recovery for missing blocks. Such blueprints should not be loaded in survival, as there may be inconsistencies, but it's ok to load in creative, in particular for repair if needed. Close #1779 --- .../blueprints/MappingNotFoundException.java | 15 ++++ .../api/blueprints/MappingRegistry.java | 87 +++++++++++++++---- .../api/blueprints/SchematicBlock.java | 11 ++- .../api/blueprints/SchematicEntity.java | 6 +- .../api/blueprints/SchematicFactory.java | 6 +- .../api/blueprints/SchematicTile.java | 6 +- common/buildcraft/builders/BuildingItem.java | 3 +- .../schematics/SchematicFactoryBlock.java | 4 +- .../schematics/SchematicFactoryEntity.java | 4 +- .../buildcraft/core/blueprints/Blueprint.java | 19 +++- .../core/blueprints/BptBuilderBase.java | 14 ++- .../core/blueprints/BuildingSlot.java | 3 +- .../core/blueprints/BuildingSlotBlock.java | 3 +- .../core/blueprints/BuildingSlotEntity.java | 4 +- .../transport/schematics/SchematicPipe.java | 9 +- 15 files changed, 157 insertions(+), 37 deletions(-) create mode 100755 api/buildcraft/api/blueprints/MappingNotFoundException.java diff --git a/api/buildcraft/api/blueprints/MappingNotFoundException.java b/api/buildcraft/api/blueprints/MappingNotFoundException.java new file mode 100755 index 00000000..e3e13739 --- /dev/null +++ b/api/buildcraft/api/blueprints/MappingNotFoundException.java @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2011-2014, SpaceToad and the BuildCraft Team + * http://www.mod-buildcraft.com + * + * BuildCraft is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://www.mod-buildcraft.com/MMPL-1.0.txt + */ +package buildcraft.api.blueprints; + +public class MappingNotFoundException extends Exception { + public MappingNotFoundException(String msg) { + super(msg); + } +} \ No newline at end of file diff --git a/api/buildcraft/api/blueprints/MappingRegistry.java b/api/buildcraft/api/blueprints/MappingRegistry.java index 605c22f7..9bdc6e7c 100755 --- a/api/buildcraft/api/blueprints/MappingRegistry.java +++ b/api/buildcraft/api/blueprints/MappingRegistry.java @@ -10,6 +10,7 @@ package buildcraft.api.blueprints; import java.util.ArrayList; import java.util.HashMap; +import java.util.logging.Level; import net.minecraft.block.Block; import net.minecraft.entity.Entity; @@ -21,6 +22,8 @@ import net.minecraft.nbt.NBTTagShort; import net.minecraftforge.common.util.Constants; +import buildcraft.api.core.BCLog; + public class MappingRegistry { public HashMap blockToId = new HashMap(); @@ -53,12 +56,18 @@ public class MappingRegistry { } } - public Item getItemForId(int id) { + public Item getItemForId(int id) throws MappingNotFoundException { if (id >= idToItem.size()) { - return null; + throw new MappingNotFoundException("no item mapping at position " + id); } - return idToItem.get(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) { @@ -75,18 +84,24 @@ public class MappingRegistry { return getIdForItem(item); } - public int itemIdToWorld(int id) { + public int itemIdToWorld(int id) throws MappingNotFoundException { Item item = getItemForId(id); return Item.getIdFromItem(item); } - public Block getBlockForId(int id) { + public Block getBlockForId(int id) throws MappingNotFoundException { if (id >= idToBlock.size()) { - return null; + throw new MappingNotFoundException("no block mapping at position " + id); } - return idToBlock.get(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) { @@ -103,18 +118,24 @@ public class MappingRegistry { return getIdForBlock(block); } - public int blockIdToWorld(int id) { + public int blockIdToWorld(int id) throws MappingNotFoundException { Block block = getBlockForId(id); return Block.getIdFromBlock(block); } - public Class getEntityForId(int id) { + public Class getEntityForId(int id) throws MappingNotFoundException { if (id >= idToEntity.size()) { - return null; + throw new MappingNotFoundException("no entity mapping at position " + id); } - return idToEntity.get(id); + Class result = idToEntity.get(id); + + if (result == null) { + throw new MappingNotFoundException("no entity mapping at position " + id); + } else { + return result; + } } public int getIdForEntity(Class entity) { @@ -138,7 +159,7 @@ public class MappingRegistry { * Relocates a stack nbt from the registry referential to the world * referential. */ - public void stackToWorld(NBTTagCompound nbt) { + public void stackToWorld(NBTTagCompound nbt) throws MappingNotFoundException { Item item = getItemForId(nbt.getShort("id")); nbt.setShort("id", (short) Item.getIdFromItem(item)); } @@ -180,7 +201,7 @@ public class MappingRegistry { } } - public void scanAndTranslateStacksToWorld(NBTTagCompound nbt) { + public void scanAndTranslateStacksToWorld(NBTTagCompound nbt) throws MappingNotFoundException { // First, check if this nbt is itself a stack if (isStackLayout(nbt)) { @@ -193,15 +214,23 @@ public class MappingRegistry { String key = (String) keyO; if (nbt.getTag(key) instanceof NBTTagCompound) { - scanAndTranslateStacksToWorld(nbt.getCompoundTag(key)); + 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.func_150303_d() == Constants.NBT.TAG_COMPOUND) { - for (int i = 0; i < list.tagCount(); ++i) { - scanAndTranslateStacksToWorld(list.getCompoundTagAt(i)); + for (int i = list.tagCount() - 1; i >= 0; --i) { + try { + scanAndTranslateStacksToWorld(list.getCompoundTagAt(i)); + } catch (MappingNotFoundException e) { + list.removeTag(i); + } } } } @@ -250,7 +279,14 @@ public class MappingRegistry { NBTTagCompound sub = blocksMapping.getCompoundTagAt(i); String name = sub.getString("name"); Block b = (Block) Block.blockRegistry.getObject(name); - registerBlock (b); + + if (b != null) { + registerBlock(b); + } else { + // Keeping the order correct + idToBlock.add(null); + BCLog.logger.log(Level.WARNING, "Can't load block " + name); + } } NBTTagList itemsMapping = nbt.getTagList("itemsMapping", @@ -260,7 +296,14 @@ public class MappingRegistry { NBTTagCompound sub = itemsMapping.getCompoundTagAt(i); String name = sub.getString("name"); Item item = (Item) Item.itemRegistry.getObject(name); - registerItem (item); + + if (item != null) { + registerItem(item); + } else { + // Keeping the order correct + idToItem.add(null); + BCLog.logger.log(Level.WARNING, "Can't load item " + name); + } } NBTTagList entitiesMapping = nbt.getTagList("entitiesMapping", @@ -277,7 +320,13 @@ public class MappingRegistry { e1.printStackTrace(); } - registerEntity (e); + if (e != null) { + registerEntity(e); + } else { + // Keeping the order correct + idToEntity.add(null); + BCLog.logger.log(Level.WARNING, "Can't load entity " + name); + } } } } diff --git a/api/buildcraft/api/blueprints/SchematicBlock.java b/api/buildcraft/api/blueprints/SchematicBlock.java index b14ba29e..b18130ff 100755 --- a/api/buildcraft/api/blueprints/SchematicBlock.java +++ b/api/buildcraft/api/blueprints/SchematicBlock.java @@ -109,7 +109,14 @@ public class SchematicBlock extends SchematicBlockBase { public void readFromNBT(NBTTagCompound nbt, MappingRegistry registry) { super.readFromNBT(nbt, registry); - block = registry.getBlockForId(nbt.getInteger("blockId")); + try { + block = registry.getBlockForId(nbt.getInteger("blockId")); + } catch (MappingNotFoundException e) { + defaultPermission = BuildingPermission.CREATIVE_ONLY; + + return; + } + meta = nbt.getInteger("blockMeta"); if (nbt.hasKey("rq")) { @@ -127,6 +134,8 @@ public class SchematicBlock extends SchematicBlockBase { } else { defaultPermission = BuildingPermission.CREATIVE_ONLY; } + } catch (MappingNotFoundException e) { + defaultPermission = BuildingPermission.CREATIVE_ONLY; } catch (Throwable t) { t.printStackTrace(); defaultPermission = BuildingPermission.CREATIVE_ONLY; diff --git a/api/buildcraft/api/blueprints/SchematicEntity.java b/api/buildcraft/api/blueprints/SchematicEntity.java index 61949ac4..b53cd506 100755 --- a/api/buildcraft/api/blueprints/SchematicEntity.java +++ b/api/buildcraft/api/blueprints/SchematicEntity.java @@ -82,7 +82,11 @@ public class SchematicEntity extends Schematic { @Override public void idsToWorld(MappingRegistry registry) { - registry.scanAndTranslateStacksToWorld(cpt); + try { + registry.scanAndTranslateStacksToWorld(cpt); + } catch (MappingNotFoundException e) { + cpt = new NBTTagCompound(); + } } @Override diff --git a/api/buildcraft/api/blueprints/SchematicFactory.java b/api/buildcraft/api/blueprints/SchematicFactory.java index 9572a869..e7c635de 100755 --- a/api/buildcraft/api/blueprints/SchematicFactory.java +++ b/api/buildcraft/api/blueprints/SchematicFactory.java @@ -18,13 +18,15 @@ public abstract class SchematicFactory { private static final HashMap, SchematicFactory> schematicToFactory = new HashMap, SchematicFactory>(); - protected abstract S loadSchematicFromWorldNBT (NBTTagCompound nbt, MappingRegistry registry); + protected abstract S loadSchematicFromWorldNBT(NBTTagCompound nbt, MappingRegistry registry) + throws MappingNotFoundException; public void saveSchematicToWorldNBT (NBTTagCompound nbt, S object, MappingRegistry registry) { nbt.setString("factoryID", getClass().getCanonicalName()); } - public static Schematic createSchematicFromWorldNBT (NBTTagCompound nbt, MappingRegistry registry) { + public static Schematic createSchematicFromWorldNBT(NBTTagCompound nbt, MappingRegistry registry) + throws MappingNotFoundException { String factoryName = nbt.getString("factoryID"); if (factories.containsKey(factoryName)) { diff --git a/api/buildcraft/api/blueprints/SchematicTile.java b/api/buildcraft/api/blueprints/SchematicTile.java index 0d83cb24..4e840424 100755 --- a/api/buildcraft/api/blueprints/SchematicTile.java +++ b/api/buildcraft/api/blueprints/SchematicTile.java @@ -35,7 +35,11 @@ public class SchematicTile extends SchematicBlock { @Override public void idsToWorld(MappingRegistry registry) { - registry.scanAndTranslateStacksToWorld(cpt); + try { + registry.scanAndTranslateStacksToWorld(cpt); + } catch (MappingNotFoundException e) { + cpt = new NBTTagCompound(); + } } /** diff --git a/common/buildcraft/builders/BuildingItem.java b/common/buildcraft/builders/BuildingItem.java index afd02a2d..ed5929d4 100755 --- a/common/buildcraft/builders/BuildingItem.java +++ b/common/buildcraft/builders/BuildingItem.java @@ -20,6 +20,7 @@ import net.minecraftforge.common.util.Constants; import buildcraft.BuildCraftBuilders; import buildcraft.api.blueprints.IBuilderContext; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.core.NetworkData; import buildcraft.api.core.Position; @@ -255,7 +256,7 @@ public class BuildingItem implements IBuilder { nbt.setTag("slotToBuild", slotNBT); } - public void readFromNBT (NBTTagCompound nbt) { + public void readFromNBT(NBTTagCompound nbt) throws MappingNotFoundException { origin = new Position(nbt.getCompoundTag("origin")); destination = new Position (nbt.getCompoundTag("destination")); lifetime = nbt.getDouble("lifetime"); diff --git a/common/buildcraft/builders/schematics/SchematicFactoryBlock.java b/common/buildcraft/builders/schematics/SchematicFactoryBlock.java index b23c7eb3..e67e1669 100755 --- a/common/buildcraft/builders/schematics/SchematicFactoryBlock.java +++ b/common/buildcraft/builders/schematics/SchematicFactoryBlock.java @@ -12,6 +12,7 @@ import net.minecraft.block.Block; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.blueprints.SchematicBlock; import buildcraft.api.blueprints.SchematicFactory; @@ -20,7 +21,8 @@ import buildcraft.api.blueprints.SchematicRegistry; public class SchematicFactoryBlock extends SchematicFactory { @Override - protected SchematicBlock loadSchematicFromWorldNBT (NBTTagCompound nbt, MappingRegistry registry) { + protected SchematicBlock loadSchematicFromWorldNBT(NBTTagCompound nbt, MappingRegistry registry) + throws MappingNotFoundException { int blockId = nbt.getInteger("blockId"); Block b = registry.getBlockForId(blockId); diff --git a/common/buildcraft/builders/schematics/SchematicFactoryEntity.java b/common/buildcraft/builders/schematics/SchematicFactoryEntity.java index 63c2c864..01d61b0a 100755 --- a/common/buildcraft/builders/schematics/SchematicFactoryEntity.java +++ b/common/buildcraft/builders/schematics/SchematicFactoryEntity.java @@ -10,6 +10,7 @@ package buildcraft.builders.schematics; import net.minecraft.nbt.NBTTagCompound; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.blueprints.SchematicEntity; import buildcraft.api.blueprints.SchematicFactory; @@ -18,7 +19,8 @@ import buildcraft.api.blueprints.SchematicRegistry; public class SchematicFactoryEntity extends SchematicFactory { @Override - protected SchematicEntity loadSchematicFromWorldNBT (NBTTagCompound nbt, MappingRegistry registry) { + protected SchematicEntity loadSchematicFromWorldNBT(NBTTagCompound nbt, MappingRegistry registry) + throws MappingNotFoundException { int entityId = nbt.getInteger("entityId"); SchematicEntity s = SchematicRegistry.newSchematicEntity(registry.getEntityForId(entityId)); diff --git a/common/buildcraft/core/blueprints/Blueprint.java b/common/buildcraft/core/blueprints/Blueprint.java index 84bf795c..994a01bc 100644 --- a/common/buildcraft/core/blueprints/Blueprint.java +++ b/common/buildcraft/core/blueprints/Blueprint.java @@ -22,6 +22,7 @@ import net.minecraftforge.common.util.Constants; import buildcraft.BuildCraftBuilders; import buildcraft.api.blueprints.BuildingPermission; import buildcraft.api.blueprints.IBuilderContext; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.SchematicBlock; import buildcraft.api.blueprints.SchematicEntity; import buildcraft.api.blueprints.SchematicRegistry; @@ -205,7 +206,14 @@ public class Blueprint extends BlueprintBase { index++; if (cpt.hasKey("blockId")) { - Block block = mapping.getBlockForId(cpt.getInteger("blockId")); + Block block; + + try { + block = mapping.getBlockForId(cpt.getInteger("blockId")); + } catch (MappingNotFoundException e) { + block = null; + buildingPermission = BuildingPermission.CREATIVE_ONLY; + } if (block != null) { contents[x][y][z] = SchematicRegistry.newSchematicBlock(block); @@ -242,7 +250,14 @@ public class Blueprint extends BlueprintBase { NBTTagCompound cpt = entitiesNBT.getCompoundTagAt(i); if (cpt.hasKey("entityId")) { - Class entity = mapping.getEntityForId(cpt.getInteger("entityId")); + Class entity; + + try { + entity = mapping.getEntityForId(cpt.getInteger("entityId")); + } catch (MappingNotFoundException e) { + entity = null; + buildingPermission = BuildingPermission.CREATIVE_ONLY; + } if (entity != null) { SchematicEntity s = SchematicRegistry.newSchematicEntity(entity); diff --git a/common/buildcraft/core/blueprints/BptBuilderBase.java b/common/buildcraft/core/blueprints/BptBuilderBase.java index 330055ac..22454f4b 100644 --- a/common/buildcraft/core/blueprints/BptBuilderBase.java +++ b/common/buildcraft/core/blueprints/BptBuilderBase.java @@ -11,6 +11,7 @@ package buildcraft.core.blueprints; import java.util.ArrayList; import java.util.LinkedList; import java.util.TreeSet; +import java.util.logging.Level; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; @@ -22,7 +23,9 @@ import net.minecraftforge.common.util.Constants; import buildcraft.BuildCraftBuilders; import buildcraft.api.blueprints.IBuilderContext; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.SchematicRegistry; +import buildcraft.api.core.BCLog; import buildcraft.api.core.IAreaProvider; import buildcraft.api.core.Position; import buildcraft.builders.BuildingItem; @@ -220,9 +223,14 @@ public abstract class BptBuilderBase implements IAreaProvider { for (int i = 0; i < buildingList.tagCount(); ++i) { BuildingItem item = new BuildingItem(); - item.readFromNBT(buildingList.getCompoundTagAt(i)); - item.context = getContext(); - builder.buildersInAction.add(item); + + try { + item.readFromNBT(buildingList.getCompoundTagAt(i)); + item.context = getContext(); + builder.buildersInAction.add(item); + } catch (MappingNotFoundException e) { + BCLog.logger.log(Level.WARNING, "can't load building item", e); + } } } } diff --git a/common/buildcraft/core/blueprints/BuildingSlot.java b/common/buildcraft/core/blueprints/BuildingSlot.java index 8e9616eb..ac0d083b 100755 --- a/common/buildcraft/core/blueprints/BuildingSlot.java +++ b/common/buildcraft/core/blueprints/BuildingSlot.java @@ -14,6 +14,7 @@ import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import buildcraft.api.blueprints.IBuilderContext; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.blueprints.Schematic; import buildcraft.api.core.Position; @@ -58,7 +59,7 @@ public abstract class BuildingSlot { public abstract void writeToNBT (NBTTagCompound nbt, MappingRegistry registry); - public abstract void readFromNBT (NBTTagCompound nbt, MappingRegistry registry); + public abstract void readFromNBT(NBTTagCompound nbt, MappingRegistry registry) throws MappingNotFoundException; public abstract double getEnergyRequirement(); } diff --git a/common/buildcraft/core/blueprints/BuildingSlotBlock.java b/common/buildcraft/core/blueprints/BuildingSlotBlock.java index 075ae3cf..238941a0 100755 --- a/common/buildcraft/core/blueprints/BuildingSlotBlock.java +++ b/common/buildcraft/core/blueprints/BuildingSlotBlock.java @@ -18,6 +18,7 @@ import net.minecraft.tileentity.TileEntity; import net.minecraftforge.common.util.Constants; import buildcraft.api.blueprints.IBuilderContext; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.blueprints.SchematicBlockBase; import buildcraft.api.blueprints.SchematicFactory; @@ -137,7 +138,7 @@ public class BuildingSlotBlock extends BuildingSlot { } @Override - public void readFromNBT (NBTTagCompound nbt, MappingRegistry registry) { + public void readFromNBT(NBTTagCompound nbt, MappingRegistry registry) throws MappingNotFoundException { mode = Mode.values() [nbt.getByte("mode")]; x = nbt.getInteger("x"); y = nbt.getInteger("y"); diff --git a/common/buildcraft/core/blueprints/BuildingSlotEntity.java b/common/buildcraft/core/blueprints/BuildingSlotEntity.java index d4f41166..d8e2ae49 100755 --- a/common/buildcraft/core/blueprints/BuildingSlotEntity.java +++ b/common/buildcraft/core/blueprints/BuildingSlotEntity.java @@ -13,7 +13,9 @@ import java.util.LinkedList; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.nbt.NBTTagList; + import buildcraft.api.blueprints.IBuilderContext; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.blueprints.SchematicEntity; import buildcraft.api.blueprints.SchematicFactory; @@ -74,7 +76,7 @@ public class BuildingSlotEntity extends BuildingSlot { } @Override - public void readFromNBT (NBTTagCompound nbt, MappingRegistry registry) { + public void readFromNBT(NBTTagCompound nbt, MappingRegistry registry) throws MappingNotFoundException { schematic = (SchematicEntity) SchematicFactory .createSchematicFromWorldNBT(nbt.getCompoundTag("schematic"), registry); } diff --git a/common/buildcraft/transport/schematics/SchematicPipe.java b/common/buildcraft/transport/schematics/SchematicPipe.java index e99a6868..ba81a860 100644 --- a/common/buildcraft/transport/schematics/SchematicPipe.java +++ b/common/buildcraft/transport/schematics/SchematicPipe.java @@ -20,6 +20,7 @@ import net.minecraftforge.common.util.ForgeDirection; import buildcraft.api.blueprints.BuildingPermission; import buildcraft.api.blueprints.IBuilderContext; +import buildcraft.api.blueprints.MappingNotFoundException; import buildcraft.api.blueprints.MappingRegistry; import buildcraft.api.blueprints.SchematicTile; import buildcraft.api.gates.ActionManager; @@ -157,9 +158,13 @@ public class SchematicPipe extends SchematicTile { super.idsToWorld(registry); if (cpt.hasKey("pipeId")) { - Item item = registry.getItemForId(cpt.getInteger("pipeId")); + try { + Item item = registry.getItemForId(cpt.getInteger("pipeId")); - cpt.setInteger("pipeId", Item.getIdFromItem(item)); + cpt.setInteger("pipeId", Item.getIdFromItem(item)); + } catch (MappingNotFoundException e) { + cpt.removeTag("pipeId"); + } } }