9577c53313
Added a new concept of NetworkId, allowing to transfer ids over the network instead of strings. RPCs are now all handled the same way (except RPC Pipes, to be completed when actually used).
629 lines
14 KiB
Java
Executable file
629 lines
14 KiB
Java
Executable file
/**
|
|
* 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.core.robots;
|
|
|
|
import java.util.Date;
|
|
|
|
import io.netty.buffer.ByteBuf;
|
|
|
|
import net.minecraft.entity.player.EntityPlayer;
|
|
import net.minecraft.inventory.IInventory;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.util.ResourceLocation;
|
|
import net.minecraft.world.World;
|
|
|
|
import cpw.mods.fml.common.registry.IEntityAdditionalSpawnData;
|
|
import cpw.mods.fml.relauncher.Side;
|
|
import cpw.mods.fml.relauncher.SideOnly;
|
|
|
|
import net.minecraftforge.common.util.ForgeDirection;
|
|
|
|
import buildcraft.api.boards.RedstoneBoardNBT;
|
|
import buildcraft.api.boards.RedstoneBoardRegistry;
|
|
import buildcraft.api.boards.RedstoneBoardRobot;
|
|
import buildcraft.api.boards.RedstoneBoardRobotNBT;
|
|
import buildcraft.api.core.SafeTimeTracker;
|
|
import buildcraft.api.robots.AIRobot;
|
|
import buildcraft.api.robots.DockingStationRegistry;
|
|
import buildcraft.api.robots.EntityRobotBase;
|
|
import buildcraft.api.robots.IDockingStation;
|
|
import buildcraft.core.DefaultProps;
|
|
import buildcraft.core.LaserData;
|
|
import buildcraft.core.network.RPC;
|
|
import buildcraft.core.network.RPCHandler;
|
|
import buildcraft.core.network.RPCMessageInfo;
|
|
import buildcraft.core.network.RPCSide;
|
|
|
|
public class EntityRobot extends EntityRobotBase implements
|
|
IEntityAdditionalSpawnData, IInventory {
|
|
|
|
public static final ResourceLocation ROBOT_BASE = new ResourceLocation("buildcraft",
|
|
DefaultProps.TEXTURE_PATH_ENTITIES + "/robot_base.png");
|
|
public static final ResourceLocation ROBOT_BUILDER = new ResourceLocation("buildcraft",
|
|
DefaultProps.TEXTURE_PATH_ENTITIES + "/robot_builder.png");
|
|
public static final ResourceLocation ROBOT_TRANSPORT = new ResourceLocation("buildcraft",
|
|
DefaultProps.TEXTURE_PATH_ENTITIES + "/robot_picker.png");
|
|
public static final ResourceLocation ROBOT_FACTORY = new ResourceLocation("buildcraft",
|
|
DefaultProps.TEXTURE_PATH_ENTITIES + "/robot_factory.png");
|
|
|
|
private static ResourceLocation defaultTexture = new ResourceLocation("buildcraft", DefaultProps.TEXTURE_PATH_ENTITIES + "/robot_base.png");
|
|
|
|
public SafeTimeTracker scanForTasks = new SafeTimeTracker (40, 10);
|
|
|
|
public LaserData laser = new LaserData();
|
|
public DockingStation reservedDockingStation;
|
|
public DockingStation linkedDockingStation;
|
|
public boolean isDocked = false;
|
|
|
|
public RedstoneBoardRobot board;
|
|
public AIRobotMain mainAI;
|
|
|
|
public ItemStack itemInUse;
|
|
public float itemAngle1 = 0;
|
|
public float itemAngle2 = 0;
|
|
public boolean itemActive = false;
|
|
public float itemActiveStage = 0;
|
|
public long lastUpdateTime = 0;
|
|
|
|
private boolean needsUpdate = false;
|
|
private ItemStack[] inv = new ItemStack[6];
|
|
private String boardID;
|
|
private ResourceLocation texture;
|
|
private DockingStation currentDockingStation;
|
|
|
|
private double mjStored;
|
|
|
|
public EntityRobot(World world, NBTTagCompound boardNBT) {
|
|
this(world);
|
|
|
|
board = (RedstoneBoardRobot) RedstoneBoardRegistry.instance.getRedstoneBoard(boardNBT).create(boardNBT, this);
|
|
dataWatcher.updateObject(16, board.getNBTHandler().getID());
|
|
|
|
if (!world.isRemote) {
|
|
mainAI = new AIRobotMain(this);
|
|
mainAI.start();
|
|
}
|
|
}
|
|
|
|
public EntityRobot(World world) {
|
|
super(world);
|
|
|
|
motionX = 0;
|
|
motionY = 0;
|
|
motionZ = 0;
|
|
|
|
ignoreFrustumCheck = true;
|
|
laser.isVisible = false;
|
|
entityCollisionReduction = 1F;
|
|
|
|
width = 0.5F;
|
|
height = 0.5F;
|
|
}
|
|
|
|
@Override
|
|
protected void entityInit() {
|
|
super.entityInit();
|
|
|
|
setNullBoundingBox();
|
|
|
|
preventEntitySpawning = false;
|
|
noClip = true;
|
|
isImmuneToFire = true;
|
|
|
|
dataWatcher.addObject(12, Float.valueOf(0));
|
|
dataWatcher.addObject(13, Float.valueOf(0));
|
|
dataWatcher.addObject(14, Float.valueOf(0));
|
|
dataWatcher.addObject(15, Byte.valueOf((byte) 0));
|
|
dataWatcher.addObject(16, "");
|
|
dataWatcher.addObject(17, Float.valueOf(0));
|
|
dataWatcher.addObject(18, Float.valueOf(0));
|
|
}
|
|
|
|
protected void updateDataClient() {
|
|
laser.tail.x = dataWatcher.getWatchableObjectFloat(12);
|
|
laser.tail.y = dataWatcher.getWatchableObjectFloat(13);
|
|
laser.tail.z = dataWatcher.getWatchableObjectFloat(14);
|
|
laser.isVisible = dataWatcher.getWatchableObjectByte(15) == 1;
|
|
|
|
RedstoneBoardNBT<?> boardNBT = RedstoneBoardRegistry.instance.getRedstoneBoard(dataWatcher
|
|
.getWatchableObjectString(16));
|
|
|
|
if (boardNBT != null) {
|
|
texture = ((RedstoneBoardRobotNBT) boardNBT).getRobotTexture();
|
|
}
|
|
|
|
itemAngle1 = dataWatcher.getWatchableObjectFloat(17);
|
|
itemAngle2 = dataWatcher.getWatchableObjectFloat(18);
|
|
}
|
|
|
|
protected void updateDataServer() {
|
|
dataWatcher.updateObject(12, Float.valueOf((float) laser.tail.x));
|
|
dataWatcher.updateObject(13, Float.valueOf((float) laser.tail.y));
|
|
dataWatcher.updateObject(14, Float.valueOf((float) laser.tail.z));
|
|
dataWatcher.updateObject(15, Byte.valueOf((byte) (laser.isVisible ? 1 : 0)));
|
|
dataWatcher.updateObject(17, Float.valueOf(itemAngle1));
|
|
dataWatcher.updateObject(18, Float.valueOf(itemAngle2));
|
|
}
|
|
|
|
protected void init() {
|
|
if (worldObj.isRemote) {
|
|
RPCHandler.rpcServer(this, "requestInitialization");
|
|
}
|
|
}
|
|
|
|
public void setLaserDestination (float x, float y, float z) {
|
|
if (x != laser.tail.x || y != laser.tail.y || z != laser.tail.z) {
|
|
laser.tail.x = x;
|
|
laser.tail.y = y;
|
|
laser.tail.z = z;
|
|
|
|
needsUpdate = true;
|
|
}
|
|
}
|
|
|
|
public void showLaser() {
|
|
if (!laser.isVisible) {
|
|
laser.isVisible = true;
|
|
needsUpdate = true;
|
|
}
|
|
}
|
|
|
|
public void hideLaser() {
|
|
if (laser.isVisible) {
|
|
laser.isVisible = false;
|
|
needsUpdate = true;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void onUpdate() {
|
|
if (!worldObj.isRemote && needsUpdate) {
|
|
updateDataServer();
|
|
needsUpdate = false;
|
|
}
|
|
|
|
if (worldObj.isRemote) {
|
|
updateDataClient();
|
|
}
|
|
|
|
if (currentDockingStation != null) {
|
|
motionX = 0;
|
|
motionY = 0;
|
|
motionZ = 0;
|
|
posX = currentDockingStation.pipe.xCoord + 0.5F + currentDockingStation.side.offsetX * 0.5F;
|
|
posY = currentDockingStation.pipe.yCoord + 0.5F + currentDockingStation.side.offsetY * 0.5F;
|
|
posZ = currentDockingStation.pipe.zCoord + 0.5F + currentDockingStation.side.offsetZ * 0.5F;
|
|
}
|
|
|
|
if (!worldObj.isRemote) {
|
|
mainAI.cycle();
|
|
}
|
|
|
|
super.onUpdate();
|
|
}
|
|
|
|
public void setRegularBoundingBox() {
|
|
width = 0.5F;
|
|
height = 0.5F;
|
|
|
|
if (laser.isVisible) {
|
|
boundingBox.minX = Math.min(posX, laser.tail.x);
|
|
boundingBox.minY = Math.min(posY, laser.tail.y);
|
|
boundingBox.minZ = Math.min(posZ, laser.tail.z);
|
|
|
|
boundingBox.maxX = Math.max(posX, laser.tail.x);
|
|
boundingBox.maxY = Math.max(posY, laser.tail.y);
|
|
boundingBox.maxZ = Math.max(posZ, laser.tail.z);
|
|
|
|
boundingBox.minX--;
|
|
boundingBox.minY--;
|
|
boundingBox.minZ--;
|
|
|
|
boundingBox.maxX++;
|
|
boundingBox.maxY++;
|
|
boundingBox.maxZ++;
|
|
} else {
|
|
boundingBox.minX = posX - 0.25F;
|
|
boundingBox.minY = posY - 0.25F;
|
|
boundingBox.minZ = posZ - 0.25F;
|
|
|
|
boundingBox.maxX = posX + 0.25F;
|
|
boundingBox.maxY = posY + 0.25F;
|
|
boundingBox.maxZ = posZ + 0.25F;
|
|
}
|
|
}
|
|
|
|
public void setNullBoundingBox() {
|
|
width = 0F;
|
|
height = 0F;
|
|
|
|
boundingBox.minX = posX;
|
|
boundingBox.minY = posY;
|
|
boundingBox.minZ = posZ;
|
|
|
|
boundingBox.maxX = posX;
|
|
boundingBox.maxY = posY;
|
|
boundingBox.maxZ = posZ;
|
|
}
|
|
|
|
private void iterateBehaviorDocked() {
|
|
motionX = 0F;
|
|
motionY = 0F;
|
|
motionZ = 0F;
|
|
|
|
setNullBoundingBox ();
|
|
}
|
|
|
|
@Override
|
|
public void writeSpawnData(ByteBuf data) {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void readSpawnData(ByteBuf data) {
|
|
init();
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getHeldItem() {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public void setCurrentItemOrArmor(int i, ItemStack itemstack) {
|
|
}
|
|
|
|
@Override
|
|
public ItemStack[] getLastActiveItems() {
|
|
return new ItemStack [0];
|
|
}
|
|
|
|
|
|
@Override
|
|
protected void fall(float par1) {}
|
|
|
|
@Override
|
|
protected void updateFallState(double par1, boolean par3) {}
|
|
|
|
@Override
|
|
public void moveEntityWithHeading(float par1, float par2) {
|
|
this.setPosition(posX + motionX, posY + motionY, posZ + motionZ);
|
|
}
|
|
|
|
@Override
|
|
public boolean isOnLadder() {
|
|
return false;
|
|
}
|
|
|
|
public ResourceLocation getTexture () {
|
|
return texture;
|
|
}
|
|
|
|
@Override
|
|
public void writeEntityToNBT(NBTTagCompound nbt) {
|
|
super.writeEntityToNBT(nbt);
|
|
|
|
if (linkedDockingStation != null) {
|
|
nbt.setInteger("dockX", linkedDockingStation.pipe.xCoord);
|
|
nbt.setInteger("dockY", linkedDockingStation.pipe.yCoord);
|
|
nbt.setInteger("dockZ", linkedDockingStation.pipe.zCoord);
|
|
nbt.setInteger("dockSide", linkedDockingStation.side.ordinal());
|
|
}
|
|
|
|
NBTTagCompound nbtLaser = new NBTTagCompound();
|
|
laser.writeToNBT(nbtLaser);
|
|
nbt.setTag("laser", nbtLaser);
|
|
|
|
for (int i = 0; i < inv.length; ++i) {
|
|
NBTTagCompound stackNbt = new NBTTagCompound();
|
|
|
|
if (inv[i] != null) {
|
|
nbt.setTag("inv[" + i + "]", inv[i].writeToNBT(stackNbt));
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void readEntityFromNBT(NBTTagCompound nbt) {
|
|
super.readEntityFromNBT(nbt);
|
|
|
|
if (nbt.hasKey("dockX")) {
|
|
linkedDockingStation = (DockingStation) DockingStationRegistry.getStation(
|
|
nbt.getInteger("dockX"),
|
|
nbt.getInteger("dockY"),
|
|
nbt.getInteger("dockZ"),
|
|
ForgeDirection.values()[nbt.getInteger("dockSide")]);
|
|
}
|
|
|
|
/*
|
|
* if (nbt.hasKey("ai")) { try { nextAI = (RobotAIBase)
|
|
* Class.forName(nbt.getString("ai")).newInstance(); } catch (Throwable
|
|
* t) { t.printStackTrace(); } }
|
|
*/
|
|
|
|
laser.readFromNBT(nbt.getCompoundTag("laser"));
|
|
|
|
for (int i = 0; i < inv.length; ++i) {
|
|
inv[i] = ItemStack.loadItemStackFromNBT(nbt.getCompoundTag("inv[" + i + "]"));
|
|
}
|
|
|
|
setDead();
|
|
}
|
|
|
|
@Override
|
|
public void dock(IDockingStation station) {
|
|
currentDockingStation = (DockingStation) station;
|
|
}
|
|
|
|
@Override
|
|
public void undock() {
|
|
if (currentDockingStation != null) {
|
|
currentDockingStation.release(this);
|
|
currentDockingStation = null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public DockingStation getDockingStation() {
|
|
return currentDockingStation;
|
|
}
|
|
|
|
@Override
|
|
public boolean reserveStation(IDockingStation iStation) {
|
|
DockingStation station = (DockingStation) iStation;
|
|
|
|
if (station == null) {
|
|
if (reservedDockingStation != null) {
|
|
reservedDockingStation.release(this);
|
|
}
|
|
|
|
reservedDockingStation = null;
|
|
|
|
return true;
|
|
}
|
|
|
|
if (station.reserved() == this) {
|
|
return true;
|
|
}
|
|
|
|
if (station.reserve(this)) {
|
|
if (reservedDockingStation != null) {
|
|
reservedDockingStation.release(this);
|
|
}
|
|
|
|
reservedDockingStation = station;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public boolean linkToStation(IDockingStation iStation) {
|
|
DockingStation station = (DockingStation) iStation;
|
|
|
|
if (station.linked() == this) {
|
|
return true;
|
|
}
|
|
|
|
if (station.link(this)) {
|
|
if (linkedDockingStation != null) {
|
|
linkedDockingStation.unlink(this);
|
|
}
|
|
|
|
linkedDockingStation = station;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getEquipmentInSlot(int var1) {
|
|
return null;
|
|
}
|
|
|
|
public boolean acceptTask (IRobotTask task) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
protected boolean isAIEnabled() {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int getSizeInventory() {
|
|
return inv.length;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getStackInSlot(int var1) {
|
|
return inv[var1];
|
|
}
|
|
|
|
@Override
|
|
public ItemStack decrStackSize(int var1, int var2) {
|
|
ItemStack result = inv[var1].splitStack(var2);
|
|
|
|
if (inv[var1].stackSize == 0) {
|
|
inv[var1] = null;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getStackInSlotOnClosing(int var1) {
|
|
return inv[var1].splitStack(var1);
|
|
}
|
|
|
|
@Override
|
|
public void setInventorySlotContents(int var1, ItemStack var2) {
|
|
inv[var1] = var2;
|
|
}
|
|
|
|
@Override
|
|
public String getInventoryName() {
|
|
return null;
|
|
}
|
|
|
|
@Override
|
|
public boolean hasCustomInventoryName() {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public int getInventoryStackLimit() {
|
|
return 64;
|
|
}
|
|
|
|
@Override
|
|
public void markDirty() {
|
|
}
|
|
|
|
@Override
|
|
public boolean isUseableByPlayer(EntityPlayer var1) {
|
|
return false;
|
|
}
|
|
|
|
@Override
|
|
public void openInventory() {
|
|
}
|
|
|
|
@Override
|
|
public void closeInventory() {
|
|
}
|
|
|
|
@Override
|
|
public boolean isItemValidForSlot(int var1, ItemStack var2) {
|
|
return inv[var1] == null
|
|
|| (inv[var1].isItemEqual(var2) && inv[var1].isStackable() && inv[var1].stackSize
|
|
+ var2.stackSize <= inv[var1].getItem().getItemStackLimit());
|
|
}
|
|
|
|
@Override
|
|
public boolean isMoving() {
|
|
return motionX != 0 || motionY != 0 || motionZ != 0;
|
|
}
|
|
|
|
@Override
|
|
public void setItemInUse(ItemStack stack) {
|
|
itemInUse = stack;
|
|
RPCHandler.rpcBroadcastWorldPlayers(worldObj, this, "clientSetItemInUse", stack);
|
|
}
|
|
|
|
@RPC(RPCSide.CLIENT)
|
|
private void clientSetItemInUse(ItemStack stack) {
|
|
itemInUse = stack;
|
|
}
|
|
|
|
@RPC(RPCSide.SERVER)
|
|
public void requestInitialization(RPCMessageInfo info) {
|
|
RPCHandler.rpcPlayer(info.sender, this, "rpcInitialize", itemInUse, itemActive);
|
|
}
|
|
|
|
@RPC(RPCSide.CLIENT)
|
|
private void rpcInitialize(ItemStack stack, boolean active) {
|
|
itemInUse = stack;
|
|
itemActive = active;
|
|
}
|
|
|
|
@Override
|
|
public void setHealth(float par1) {
|
|
// deactivate healh management
|
|
}
|
|
|
|
@Override
|
|
public void aimItemAt(int x, int y, int z) {
|
|
itemAngle1 = (float) Math.atan2(z - Math.floor(posZ),
|
|
x - Math.floor(posX));
|
|
|
|
itemAngle2 = 0;
|
|
|
|
if (Math.floor(posY) < y) {
|
|
itemAngle2 = (float) -Math.PI / 4;
|
|
|
|
if (Math.floor(posX) == x && Math.floor(posZ) == z) {
|
|
itemAngle2 -= (float) Math.PI / 4;
|
|
}
|
|
} else if (Math.floor(posY) > y) {
|
|
itemAngle2 = (float) Math.PI / 2;
|
|
|
|
if (Math.floor(posX) == x && Math.floor(posZ) == z) {
|
|
itemAngle2 += (float) Math.PI / 4;
|
|
}
|
|
}
|
|
|
|
updateDataServer();
|
|
}
|
|
|
|
@Override
|
|
public void setItemActive(boolean isActive) {
|
|
RPCHandler.rpcBroadcastWorldPlayers(worldObj, this, "rpcSetItemActive", isActive);
|
|
}
|
|
|
|
@RPC(RPCSide.CLIENT)
|
|
private void rpcSetItemActive(boolean isActive) {
|
|
itemActive = isActive;
|
|
itemActiveStage = 0;
|
|
lastUpdateTime = new Date().getTime();
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getItemInUse() {
|
|
return itemInUse;
|
|
}
|
|
|
|
@Override
|
|
public RedstoneBoardRobot getBoard() {
|
|
return board;
|
|
}
|
|
|
|
@Override
|
|
public DockingStation getLinkedStation() {
|
|
return linkedDockingStation;
|
|
}
|
|
|
|
@SideOnly(Side.CLIENT)
|
|
@Override
|
|
public boolean isInRangeToRenderDist(double par1) {
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public double getEnergy() {
|
|
return mjStored;
|
|
}
|
|
|
|
@Override
|
|
public void setEnergy(double energy) {
|
|
mjStored = energy;
|
|
|
|
if (mjStored > MAX_ENERGY) {
|
|
mjStored = MAX_ENERGY;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected boolean canDespawn() {
|
|
return false;
|
|
}
|
|
|
|
public AIRobot getOverridingAI() {
|
|
return mainAI.getOverridingAI();
|
|
}
|
|
|
|
public void overrideAI(AIRobot ai) {
|
|
mainAI.setOverridingAI(ai);
|
|
}
|
|
|
|
}
|