package net.minecraftforge.common.util;
import java.io.Serializable;
import net.minecraft.block.Block;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.DimensionManager;
import cpw.mods.fml.common.registry.GameRegistry;
import cpw.mods.fml.common.registry.GameRegistry.UniqueIdentifier;
/**
* Represents a captured snapshot of a block which will not change
* automatically.
* <p>
* Unlike Block, which only one object can exist per coordinate, BlockSnapshot
* can exist multiple times for any given Block.
*/
@SuppressWarnings("serial")
public class BlockSnapshot implements Serializable
{
private static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("forge.debugBlockSnapshot", "false"));
public final int x;
public final int y;
public final int z;
public final int dimId;
public transient Block replacedBlock;
public final int meta;
public int flag;
private final NBTTagCompound nbt;
public transient World world;
public final UniqueIdentifier blockIdentifier;
public BlockSnapshot(World world, int x, int y, int z, Block block, int meta)
{
this.world = world;
this.dimId = world.provider.dimensionId;
this.x = x;
this.y = y;
this.z = z;
this.replacedBlock = block;
this.blockIdentifier = GameRegistry.findUniqueIdentifierFor(block);
this.meta = meta;
this.flag = 3;
TileEntity te = world.getTileEntity(x, y, z);
if (te != null)
{
nbt = new NBTTagCompound();
te.writeToNBT(nbt);
}
else nbt = null;
if (DEBUG)
{
System.out.printf("Created BlockSnapshot - [World: %s ][Location: %d,%d,%d ][Block: %s ][Meta: %d ]", world.getWorldInfo().getWorldName(), x, y, z, block, meta);
}
}
public BlockSnapshot(World world, int x, int y, int z, Block block, int meta, NBTTagCompound nbt)
{
this.world = world;
this.dimId = world.provider.dimensionId;
this.x = x;
this.y = y;
this.z = z;
this.replacedBlock = block;
this.blockIdentifier = GameRegistry.findUniqueIdentifierFor(block);
this.meta = meta;
this.flag = 3;
this.nbt = nbt;
if (DEBUG)
{
System.out.printf("Created BlockSnapshot - [World: %s ][Location: %d,%d,%d ][Block: %s ][Meta: %d ]", world.getWorldInfo().getWorldName(), x, y, z, block, meta);
}
}
public BlockSnapshot(World world, int x, int y, int z, Block block, int meta, int flag)
{
this(world, x, y, z, block, meta);
this.flag = flag;
}
/**
* Raw constructor designed for serialization usages.
*/
public BlockSnapshot(int dimension, int x, int y, int z, String modid, String blockName, int meta, int flag, NBTTagCompound nbt)
{
this.dimId = dimension;
this.x = x;
this.y = y;
this.z = z;
this.meta = meta;
this.flag = flag;
this.blockIdentifier = new UniqueIdentifier(modid + ":" + blockName);
this.nbt = nbt;
}
public static BlockSnapshot getBlockSnapshot(World world, int x, int y, int z)
{
return new BlockSnapshot(world, x, y, z, world.getBlock(x, y, z), world.getBlockMetadata(x, y,z));
}
public static BlockSnapshot getBlockSnapshot(World world, int x, int y, int z, int flag)
{
return new BlockSnapshot(world, x, y, z, world.getBlock(x, y, z), world.getBlockMetadata(x, y,z), flag);
}
public static BlockSnapshot readFromNBT(NBTTagCompound tag)
{
NBTTagCompound nbt = tag.getBoolean("hasTE") ? null : tag.getCompoundTag("tileEntity");
return new BlockSnapshot(
tag.getInteger("dimension"),
tag.getInteger("posX"),
tag.getInteger("posY"),
tag.getInteger("posZ"),
tag.getString("blockMod"),
tag.getString("blockName"),
tag.getInteger("metadata"),
tag.getInteger("flag"),
nbt);
}
public Block getCurrentBlock()
{
return world.getBlock(x, y, z);
}
public World getWorld()
{
if (this.world == null)
{
this.world = DimensionManager.getWorld(dimId);
}
return this.world;
}
public Block getReplacedBlock()
{
if (this.replacedBlock == null)
{
this.replacedBlock = GameRegistry.findBlock(this.blockIdentifier.modId, this.blockIdentifier.name);
}
return this.replacedBlock;
}
public TileEntity getTileEntity()
{
if (nbt != null)
return TileEntity.createAndLoadEntity(nbt);
else return null;
}
public boolean restore()
{
return restore(false);
}
public boolean restore(boolean force)
{
return restore(force, true);
}
public boolean restore(boolean force, boolean applyPhysics)
{
if (getCurrentBlock() != getReplacedBlock() || world.getBlockMetadata(x & 15, y, z & 15) != meta)
{
if (force)
{
world.setBlock(x, y, z, getReplacedBlock(), meta, applyPhysics ? 3 : 2);
}
else
{
return false;
}
}
world.setBlockMetadataWithNotify(x, y, z, meta, applyPhysics ? 3 : 2);
world.markBlockForUpdate(x, y, z);
TileEntity te = null;
if (nbt != null)
{
te = world.getTileEntity(x, y, z);
if (te != null)
{
te.readFromNBT(nbt);
}
}
if (DEBUG)
{
System.out.printf("Restored BlockSnapshot with data [World: %s ][Location: %d,%d,%d ][Meta: %d ][Block: %s ][TileEntity: %s ][force: %s ][applyPhysics: %s]", world.getWorldInfo().getWorldName(), x, y, z, meta, getReplacedBlock(), te, force, applyPhysics);
}
return true;
}
public boolean restoreToLocation(World world, int x, int y, int z, boolean force, boolean applyPhysics)
{
if (getCurrentBlock() != getReplacedBlock() || world.getBlockMetadata(x & 15, y, z & 15) != meta)
{
if (force)
{
world.setBlock(x, y, z, getReplacedBlock(), meta, applyPhysics ? 3 : 2);
}
else
{
return false;
}
}
world.setBlockMetadataWithNotify(x, y, z, meta, applyPhysics ? 3 : 2);
world.markBlockForUpdate(x, y, z);
TileEntity te = null;
if (nbt != null)
{
te = world.getTileEntity(x, y, z);
if (te != null)
{
te.readFromNBT(nbt);
}
}
if (DEBUG)
{
System.out.printf("Restored BlockSnapshot with data [World: %s ][Location: %d,%d,%d ][Meta: %d ][Block: %s ][TileEntity: %s ][force: %s ][applyPhysics: %s]", world.getWorldInfo().getWorldName(), x, y, z, meta, getReplacedBlock(), te, force, applyPhysics);
}
return true;
}
public void writeToNBT(NBTTagCompound compound)
{
compound.setString("blockMod", blockIdentifier.modId);
compound.setString("blockName", blockIdentifier.name);
compound.setInteger("posX", x);
compound.setInteger("posY", y);
compound.setInteger("posZ", z);
compound.setInteger("flag", flag);
compound.setInteger("dimension", dimId);
compound.setInteger("metadata", meta);
compound.setBoolean("hasTE", nbt != null);
if (nbt != null)
{
compound.setTag("tileEntity", nbt);
}
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final BlockSnapshot other = (BlockSnapshot) obj;
if (this.x != other.x)
{
return false;
}
if (this.y != other.y)
{
return false;
}
if (this.z != other.z)
{
return false;
}
if (this.meta != other.meta)
{
return false;
}
if (this.dimId != other.dimId)
{
return false;
}
if (this.nbt != other.nbt && (this.nbt == null || !this.nbt.equals(other.nbt)))
{
return false;
}
if (this.world != other.world && (this.world == null || !this.world.equals(other.world)))
{
return false;
}
if (this.blockIdentifier != other.blockIdentifier && (this.blockIdentifier == null || !this.blockIdentifier.equals(other.blockIdentifier)))
{
return false;
}
return true;
}
@Override
public int hashCode()
{
int hash = 7;
hash = 73 * hash + this.x;
hash = 73 * hash + this.y;
hash = 73 * hash + this.z;
hash = 73 * hash + this.meta;
hash = 73 * hash + this.dimId;
hash = 73 * hash + (this.nbt != null ? this.nbt.hashCode() : 0);
hash = 73 * hash + (this.world != null ? this.world.hashCode() : 0);
hash = 73 * hash + (this.blockIdentifier != null ? this.blockIdentifier.hashCode() : 0);
return hash;
}
}