/**
* Copyright (c) 2011-2015, SpaceToad and the BuildCraft Team
* http://www.mod-buildcraft.com
* <p/>
* 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.core;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.World;
import buildcraft.BuildCraftCore;
import buildcraft.api.core.ISerializable;
import buildcraft.api.core.Position;
import buildcraft.api.tiles.ITileAreaProvider;
import buildcraft.core.lib.EntityBlock;
import buildcraft.core.lib.block.TileBuildCraft;
import buildcraft.core.lib.utils.LaserUtils;
import buildcraft.core.proxy.CoreProxy;
public class TileMarker extends TileBuildCraft implements ITileAreaProvider {
public static class TileWrapper implements ISerializable {
public int x, y, z;
private TileMarker marker;
public TileWrapper() {
x = Integer.MAX_VALUE;
y = Integer.MAX_VALUE;
z = Integer.MAX_VALUE;
}
public TileWrapper(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
public boolean isSet() {
return x != Integer.MAX_VALUE;
}
public TileMarker getMarker(World world) {
if (!isSet()) {
return null;
}
if (marker == null) {
TileEntity tile = world.getTileEntity(x, y, z);
if (tile instanceof TileMarker) {
marker = (TileMarker) tile;
}
}
return marker;
}
public void reset() {
x = Integer.MAX_VALUE;
y = Integer.MAX_VALUE;
z = Integer.MAX_VALUE;
}
@Override
public void readData(ByteBuf stream) {
x = stream.readInt();
if (isSet()) {
y = stream.readShort();
z = stream.readInt();
}
}
@Override
public void writeData(ByteBuf stream) {
stream.writeInt(x);
if (isSet()) {
// Only X is used for checking if a vector is set, so we can save space on the Y coordinate.
stream.writeShort(y);
stream.writeInt(z);
}
}
}
public static class Origin implements ISerializable {
public TileWrapper vectO = new TileWrapper();
public TileWrapper[] vect = {new TileWrapper(), new TileWrapper(), new TileWrapper()};
public int xMin, yMin, zMin, xMax, yMax, zMax;
public boolean isSet() {
return vectO.isSet();
}
@Override
public void writeData(ByteBuf stream) {
vectO.writeData(stream);
for (TileWrapper tw : vect) {
tw.writeData(stream);
}
stream.writeInt(xMin);
stream.writeShort(yMin);
stream.writeInt(zMin);
stream.writeInt(xMax);
stream.writeShort(yMax);
stream.writeInt(zMax);
}
@Override
public void readData(ByteBuf stream) {
vectO.readData(stream);
for (TileWrapper tw : vect) {
tw.readData(stream);
}
xMin = stream.readInt();
yMin = stream.readShort();
zMin = stream.readInt();
xMax = stream.readInt();
yMax = stream.readShort();
zMax = stream.readInt();
}
}
public Origin origin = new Origin();
public boolean showSignals = false;
private Position initVectO;
private Position[] initVect;
private EntityBlock[] lasers;
private EntityBlock[] signals;
public void updateSignals() {
if (!worldObj.isRemote) {
showSignals = worldObj.isBlockIndirectlyGettingPowered(xCoord, yCoord, zCoord);
sendNetworkUpdate();
}
}
private void switchSignals() {
if (signals != null) {
for (EntityBlock b : signals) {
if (b != null) {
CoreProxy.proxy.removeEntity(b);
}
}
signals = null;
}
if (showSignals) {
signals = new EntityBlock[6];
if (!origin.isSet() || !origin.vect[0].isSet()) {
signals[0] = LaserUtils.createLaser(worldObj, new Position(xCoord, yCoord, zCoord), new Position(xCoord + DefaultProps.MARKER_RANGE - 1, yCoord, zCoord),
LaserKind.Blue);
signals[1] = LaserUtils.createLaser(worldObj, new Position(xCoord - DefaultProps.MARKER_RANGE + 1, yCoord, zCoord), new Position(xCoord, yCoord, zCoord),
LaserKind.Blue);
}
if (!origin.isSet() || !origin.vect[1].isSet()) {
signals[2] = LaserUtils.createLaser(worldObj, new Position(xCoord, yCoord, zCoord), new Position(xCoord, yCoord + DefaultProps.MARKER_RANGE - 1, zCoord),
LaserKind.Blue);
signals[3] = LaserUtils.createLaser(worldObj, new Position(xCoord, yCoord - DefaultProps.MARKER_RANGE + 1, zCoord), new Position(xCoord, yCoord, zCoord),
LaserKind.Blue);
}
if (!origin.isSet() || !origin.vect[2].isSet()) {
signals[4] = LaserUtils.createLaser(worldObj, new Position(xCoord, yCoord, zCoord), new Position(xCoord, yCoord, zCoord + DefaultProps.MARKER_RANGE - 1),
LaserKind.Blue);
signals[5] = LaserUtils.createLaser(worldObj, new Position(xCoord, yCoord, zCoord - DefaultProps.MARKER_RANGE + 1), new Position(xCoord, yCoord, zCoord),
LaserKind.Blue);
}
}
}
@Override
public void initialize() {
super.initialize();
updateSignals();
if (initVectO != null) {
origin = new Origin();
origin.vectO = new TileWrapper((int) initVectO.x, (int) initVectO.y, (int) initVectO.z);
for (int i = 0; i < 3; ++i) {
if (initVect[i] != null) {
linkTo((TileMarker) worldObj.getTileEntity((int) initVect[i].x, (int) initVect[i].y, (int) initVect[i].z), i);
}
}
}
}
public void tryConnection() {
if (worldObj.isRemote) {
return;
}
for (int j = 0; j < 3; ++j) {
if (!origin.isSet() || !origin.vect[j].isSet()) {
setVect(j);
}
}
sendNetworkUpdate();
}
void setVect(int n) {
int[] coords = new int[3];
coords[0] = xCoord;
coords[1] = yCoord;
coords[2] = zCoord;
if (!origin.isSet() || !origin.vect[n].isSet()) {
for (int j = 1; j < DefaultProps.MARKER_RANGE; ++j) {
coords[n] += j;
Block block = worldObj.getBlock(coords[0], coords[1], coords[2]);
if (block == BuildCraftCore.markerBlock) {
TileMarker marker = (TileMarker) worldObj.getTileEntity(coords[0], coords[1], coords[2]);
if (linkTo(marker, n)) {
break;
}
}
coords[n] -= j;
coords[n] -= j;
block = worldObj.getBlock(coords[0], coords[1], coords[2]);
if (block == BuildCraftCore.markerBlock) {
TileMarker marker = (TileMarker) worldObj.getTileEntity(coords[0], coords[1], coords[2]);
if (linkTo(marker, n)) {
break;
}
}
coords[n] += j;
}
}
}
private boolean linkTo(TileMarker marker, int n) {
if (marker == null) {
return false;
}
if (origin.isSet() && marker.origin.isSet()) {
return false;
}
if (!origin.isSet() && !marker.origin.isSet()) {
origin = new Origin();
marker.origin = origin;
origin.vectO = new TileWrapper(xCoord, yCoord, zCoord);
origin.vect[n] = new TileWrapper(marker.xCoord, marker.yCoord, marker.zCoord);
} else if (!origin.isSet()) {
origin = marker.origin;
origin.vect[n] = new TileWrapper(xCoord, yCoord, zCoord);
} else {
marker.origin = origin;
origin.vect[n] = new TileWrapper(marker.xCoord, marker.yCoord, marker.zCoord);
}
origin.vectO.getMarker(worldObj).createLasers();
updateSignals();
marker.updateSignals();
return true;
}
private void createLasers() {
if (lasers != null) {
for (EntityBlock entity : lasers) {
if (entity != null) {
CoreProxy.proxy.removeEntity(entity);
}
}
}
lasers = new EntityBlock[12];
Origin o = origin;
if (!origin.vect[0].isSet()) {
o.xMin = origin.vectO.x;
o.xMax = origin.vectO.x;
} else if (origin.vect[0].x < xCoord) {
o.xMin = origin.vect[0].x;
o.xMax = xCoord;
} else {
o.xMin = xCoord;
o.xMax = origin.vect[0].x;
}
if (!origin.vect[1].isSet()) {
o.yMin = origin.vectO.y;
o.yMax = origin.vectO.y;
} else if (origin.vect[1].y < yCoord) {
o.yMin = origin.vect[1].y;
o.yMax = yCoord;
} else {
o.yMin = yCoord;
o.yMax = origin.vect[1].y;
}
if (!origin.vect[2].isSet()) {
o.zMin = origin.vectO.z;
o.zMax = origin.vectO.z;
} else if (origin.vect[2].z < zCoord) {
o.zMin = origin.vect[2].z;
o.zMax = zCoord;
} else {
o.zMin = zCoord;
o.zMax = origin.vect[2].z;
}
lasers = LaserUtils.createLaserBox(worldObj, o.xMin, o.yMin, o.zMin, o.xMax, o.yMax, o.zMax, LaserKind.Red);
}
@Override
public int xMin() {
if (origin.isSet()) {
return origin.xMin;
}
return xCoord;
}
@Override
public int yMin() {
if (origin.isSet()) {
return origin.yMin;
}
return yCoord;
}
@Override
public int zMin() {
if (origin.isSet()) {
return origin.zMin;
}
return zCoord;
}
@Override
public int xMax() {
if (origin.isSet()) {
return origin.xMax;
}
return xCoord;
}
@Override
public int yMax() {
if (origin.isSet()) {
return origin.yMax;
}
return yCoord;
}
@Override
public int zMax() {
if (origin.isSet()) {
return origin.zMax;
}
return zCoord;
}
@Override
public void invalidate() {
super.invalidate();
destroy();
}
@Override
public void destroy() {
TileMarker markerOrigin = null;
if (origin.isSet()) {
markerOrigin = origin.vectO.getMarker(worldObj);
Origin o = origin;
if (markerOrigin != null && markerOrigin.lasers != null) {
for (EntityBlock entity : markerOrigin.lasers) {
if (entity != null) {
entity.setDead();
}
}
markerOrigin.lasers = null;
}
for (TileWrapper m : o.vect) {
TileMarker mark = m.getMarker(worldObj);
if (mark != null) {
if (mark.lasers != null) {
for (EntityBlock entity : mark.lasers) {
if (entity != null) {
entity.setDead();
}
}
mark.lasers = null;
}
if (mark != this) {
mark.origin = new Origin();
}
}
}
if (markerOrigin != this && markerOrigin != null) {
markerOrigin.origin = new Origin();
}
for (TileWrapper wrapper : o.vect) {
TileMarker mark = wrapper.getMarker(worldObj);
if (mark != null) {
mark.updateSignals();
}
}
if (markerOrigin != null) {
markerOrigin.updateSignals();
}
}
if (signals != null) {
for (EntityBlock block : signals) {
if (block != null) {
block.setDead();
}
}
}
signals = null;
if (!worldObj.isRemote && markerOrigin != null && markerOrigin != this) {
markerOrigin.sendNetworkUpdate();
}
}
@Override
public void removeFromWorld() {
if (!origin.isSet()) {
return;
}
Origin o = origin;
for (TileWrapper m : o.vect.clone()) {
if (m.isSet()) {
worldObj.setBlockToAir(m.x, m.y, m.z);
BuildCraftCore.markerBlock.dropBlockAsItem(worldObj, m.x, m.y, m.z, 0, 0);
}
}
worldObj.setBlockToAir(o.vectO.x, o.vectO.y, o.vectO.z);
BuildCraftCore.markerBlock.dropBlockAsItem(worldObj, o.vectO.x, o.vectO.y, o.vectO.z, 0, 0);
}
@Override
public void readFromNBT(NBTTagCompound nbttagcompound) {
super.readFromNBT(nbttagcompound);
if (nbttagcompound.hasKey("vectO")) {
initVectO = new Position(nbttagcompound.getCompoundTag("vectO"));
initVect = new Position[3];
for (int i = 0; i < 3; ++i) {
if (nbttagcompound.hasKey("vect" + i)) {
initVect[i] = new Position(nbttagcompound.getCompoundTag("vect" + i));
}
}
}
}
@Override
public void writeToNBT(NBTTagCompound nbttagcompound) {
super.writeToNBT(nbttagcompound);
if (origin.isSet() && origin.vectO.getMarker(worldObj) == this) {
NBTTagCompound vectO = new NBTTagCompound();
new Position(origin.vectO.getMarker(worldObj)).writeToNBT(vectO);
nbttagcompound.setTag("vectO", vectO);
for (int i = 0; i < 3; ++i) {
if (origin.vect[i].isSet()) {
NBTTagCompound vect = new NBTTagCompound();
new Position(origin.vect[i].x, origin.vect[i].y, origin.vect[i].z).writeToNBT(vect);
nbttagcompound.setTag("vect" + i, vect);
}
}
}
}
@Override
public void writeData(ByteBuf stream) {
origin.writeData(stream);
stream.writeBoolean(showSignals);
}
@Override
public void readData(ByteBuf stream) {
origin.readData(stream);
showSignals = stream.readBoolean();
switchSignals();
if (origin.vectO.isSet() && origin.vectO.getMarker(worldObj) != null) {
origin.vectO.getMarker(worldObj).updateSignals();
for (TileWrapper w : origin.vect) {
TileMarker m = w.getMarker(worldObj);
if (m != null) {
m.updateSignals();
}
}
}
createLasers();
}
@Override
public boolean isValidFromLocation(int x, int y, int z) {
// Rules:
// - one or two, but not three, of the coordinates must be equal to the marker's location
// - one of the coordinates must be either -1 or 1 away
// - it must be physically touching the box
// - however, it cannot be INSIDE the box
int equal = (x == xCoord ? 1 : 0) + (y == yCoord ? 1 : 0) + (z == zCoord ? 1 : 0);
int touching = 0;
if (equal == 0 || equal == 3) {
return false;
}
if (x < (xMin() - 1) || x > (xMax() + 1) || y < (yMin() - 1) || y > (yMax() + 1)
|| z < (zMin() - 1) || z > (zMax() + 1)) {
return false;
}
if (x >= xMin() && x <= xMax() && y >= yMin() && y <= yMax() && z >= zMin() && z <= zMax()) {
return false;
}
if (xMin() - x == 1 || x - xMax() == 1) {
touching++;
}
if (yMin() - y == 1 || y - yMax() == 1) {
touching++;
}
if (zMin() - z == 1 || z - zMax() == 1) {
touching++;
}
return touching == 1;
}
}