package com.amadornes.framez.movement;
import java.util.ArrayList;
import java.util.List;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import uk.co.qmunity.lib.vec.Vec3i;
import com.amadornes.framez.api.movement.IFrame;
import com.amadornes.framez.api.movement.IMovable;
import com.amadornes.framez.api.movement.IMovement.IMovementSlide;
import com.amadornes.framez.api.movement.IMovingBlock;
import com.amadornes.framez.init.FramezBlocks;
import com.amadornes.framez.tile.TileMoving;
import com.amadornes.framez.util.BlockUtils;
import com.amadornes.framez.util.Graph.INode;
import com.amadornes.framez.world.FakeWorld;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
public class MovingBlock implements IMovingBlock, INode {
private Vec3i location;
private MovingStructure structure;
private Block block = Blocks.air;
private int meta;
private TileEntity te;
private List<IMovable> movables = new ArrayList<IMovable>();
private List<IFrame> frames = null;
private TileMoving placeholder;
public MovingBlock(Vec3i location, MovingStructure structure, List<IFrame> frames) {
this.location = location;
this.structure = structure;
this.frames = frames;
}
@Override
public World getWorld() {
return location.getWorld();
}
@Override
public int getX() {
return location.getX();
}
@Override
public int getY() {
return location.getY();
}
@Override
public int getZ() {
return location.getZ();
}
@Override
public MovingStructure getStructure() {
return structure;
}
public void setStructure(MovingStructure structure) {
this.structure = structure;
}
@Override
public Block getBlock() {
return block;
}
@Override
public int getMetadata() {
return meta;
}
@Override
public TileEntity getTileEntity() {
return te;
}
@Override
public MovingBlock setBlock(Block block) {
this.block = block;
return this;
}
@Override
public MovingBlock setMetadata(int metadata) {
meta = metadata;
return this;
}
@Override
public MovingBlock setTileEntity(TileEntity tileentity) {
te = tileentity;
return this;
}
@Override
public MovingBlock snapshot() {
block = location.getBlock();
meta = location.getBlockMeta();
te = location.getTileEntity();
movables = FrameMovementRegistry.instance().findMovables(getWorld(), getX(), getY(), getZ());
return this;
}
protected void remove() {
snapshot();
boolean handled = false;
for (IMovable movable : movables) {
if (movable.startMoving(this)) {
handled = true;
break;
}
}
if (!handled)
startMoving(true, true);
// Place placeholder
if (getStructure().getMovement() instanceof IMovementSlide) {
ForgeDirection direction = ((IMovementSlide) getStructure().getMovement()).getDirection();
getWorld().setBlock(getX(), getY(), getZ(), FramezBlocks.moving, 0, 0);
TileMoving ph1 = null;
if (placeholder != null)
ph1 = placeholder;
else
ph1 = placeholder = new TileMoving();
ph1.setBlockA(this);
getWorld().setTileEntity(getX(), getY(), getZ(), ph1);
TileMoving ph2 = null;
MovingBlock b = structure.getBlock(getX() + direction.offsetX, getY() + direction.offsetY, getZ() + direction.offsetZ);
if (b != null) {
if (b.placeholder == null)
ph2 = b.placeholder = new TileMoving();
else
ph2 = b.placeholder;
} else {
getWorld().setBlock(getX() + direction.offsetX, getY() + direction.offsetY, getZ() + direction.offsetZ,
FramezBlocks.moving, 0, 0);
getWorld().setTileEntity(getX() + direction.offsetX, getY() + direction.offsetY, getZ() + direction.offsetZ,
ph2 = new TileMoving());
}
ph2.setBlockB(this);
}
}
@Override
public void startMoving(boolean invalidate, boolean validate) {
TileEntity te = getTileEntity();
if (te != null) {
if (invalidate)
te.invalidate();
}
if (!getWorld().isRemote) {
BlockUtils.setBlockSneaky(getWorld(), getX(), getY(), getZ(), Blocks.air);
getWorld().setBlockMetadataWithNotify(getX(), getY(), getZ(), 0, 2);
}
if (te != null)
BlockUtils.removeTileEntity(getWorld(), getX(), getY(), getZ());
if (te != null && validate) {
te.setWorldObj(FakeWorld.getFakeWorld(this));
te.validate();
}
}
protected void notifyRemoval() {
if (!getWorld().isRemote) {
getWorld().notifyBlocksOfNeighborChange(getX(), getY(), getZ(), getBlock());
FakeWorld.getFakeWorld(this).notifyBlockOfNeighborChange(getX(), getY(), getZ(), getBlock());
} else {
getWorld().func_147479_m(getX(), getY(), getZ());
}
}
protected void place() {
// // Remove placeholder
// if (getStructure().getMovement() instanceof IMovementSlide) {
// ForgeDirection direction = ((IMovementSlide) getStructure().getMovement()).getDirection();
//
// if (placeholder != null) {
// placeholder.setBlockA(null);
// MovingBlock b = structure.getBlock(getX() + direction.offsetX, getY() + direction.offsetY, getZ() + direction.offsetZ);
// if (b != null)
// b.placeholder.setBlockB(null);
// }
// }
boolean handled = false;
for (IMovable movable : movables) {
if (movable.finishMoving(this)) {
handled = true;
break;
}
}
if (!handled)
finishMoving(true, true);
}
@Override
public void finishMoving(boolean invalidate, boolean validate) {
Vec3i newLocation = getStructure().getMovement().transform(new Vec3i(this));
TileEntity te = getTileEntity();
if (te != null && invalidate)
te.invalidate();
// if (!newLocation.getWorld().isRemote) {
if (getWorld().isRemote) {
newLocation.getWorld().setBlock(newLocation.getX(), newLocation.getY(), newLocation.getZ(), getBlock(), 0, 0);
} else {
BlockUtils.setBlockSneaky(newLocation.getWorld(), newLocation.getX(), newLocation.getY(), newLocation.getZ(), getBlock());
}
newLocation.getWorld().setBlockMetadataWithNotify(newLocation.getX(), newLocation.getY(), newLocation.getZ(), getMetadata(), 2);
// }
if (te != null) {
te.setWorldObj(newLocation.getWorld());
te.xCoord = newLocation.getX();
te.yCoord = newLocation.getY();
te.zCoord = newLocation.getZ();
if (validate)
te.validate();
BlockUtils.setTileEntity(newLocation.getWorld(), newLocation.getX(), newLocation.getY(), newLocation.getZ(), te);
}
}
protected void notifyPlacement() {
Vec3i newLocation = getStructure().getMovement().transform(new Vec3i(this));
if (!newLocation.getWorld().isRemote) {
newLocation.getWorld().notifyBlocksOfNeighborChange(newLocation.getX(), newLocation.getY(), newLocation.getZ(), getBlock());
newLocation.getWorld().notifyBlockOfNeighborChange(newLocation.getX(), newLocation.getY(), newLocation.getZ(), getBlock());
}
newLocation.getWorld().markBlockRangeForRenderUpdate(newLocation.getX(), newLocation.getY(), newLocation.getZ(),
newLocation.getX(), newLocation.getY(), newLocation.getZ());
}
@Override
public String toString() {
return "MovingBlock [location=" + location + ", block=" + block + ", meta=" + meta + ", te=" + te + "]";
}
@Override
public boolean equals(Object obj) {
if (obj instanceof MovingBlock) {
MovingBlock b = (MovingBlock) obj;
return b.getX() == getX() && b.getY() == getY() && b.getZ() == getZ();
}
return false;
}
@Override
public int hashCode() {
return getX() + getY() << 8 + getZ() << 16;
}
@Override
public int getMaxNeighbors() {
if (frames != null) {
int max = 0;
for (IFrame f : frames)
max = Math.max(max, f.getMaxMovedBlocks());
return max;
}
return 0;
}
public int getMaxMultiparts() {
if (frames != null) {
int max = 0;
for (IFrame f : frames)
max = Math.max(max, f.getMaxMultiparts());
return max;
}
return 0;
}
public int getMultiparts() {
if (frames != null) {
int max = 0;
for (IFrame f : frames)
max = Math.max(max, f.getMultiparts());
return max;
}
return 0;
}
// Clientside stuff (rendering, mostly)
private int renderList = -1;
@SideOnly(Side.CLIENT)
public void scheduleReRender() {
renderList = -1;
}
@SideOnly(Side.CLIENT)
public int getRenderList() {
return renderList;
}
@SideOnly(Side.CLIENT)
public void setRenderList(int renderList) {
this.renderList = renderList;
}
}