Implemented pump robot, close #1985.

Fixed race conditions with robot registry.
This commit is contained in:
SpaceToad 2014-08-18 23:32:11 +02:00
parent fb83ca8e99
commit f9b769bdde
10 changed files with 379 additions and 40 deletions

View file

@ -29,6 +29,7 @@ public final class BuildCraftAPI {
public static IWorldProperty isFarmlandProperty;
public static IWorldProperty isDirtProperty;
public static IWorldProperty isShoveled;
public static IWorldProperty isFluidSource;
/**
* Deactivate constructor

View file

@ -16,6 +16,7 @@ buildcraft.boardRobotButcher=Butcher
buildcraft.boardRobotBuilder=Builder
buildcraft.boardRobotCrafter=Crafter
buildcraft.boardRobotDelivery=Delivery
buildcraft.boardRobotPump=Pump
chat.pipe.power.iron.mode=Switched to %d MJ/t limit
chat.pipe.power.energyConverter=Energy conversion: %s

View file

@ -115,6 +115,7 @@ import buildcraft.core.triggers.TriggerRedstoneInput;
import buildcraft.core.utils.CraftingHandler;
import buildcraft.core.utils.WorldPropertyIsDirt;
import buildcraft.core.utils.WorldPropertyIsFarmland;
import buildcraft.core.utils.WorldPropertyIsFluidSource;
import buildcraft.core.utils.WorldPropertyIsHarvestable;
import buildcraft.core.utils.WorldPropertyIsLeave;
import buildcraft.core.utils.WorldPropertyIsOre;
@ -418,6 +419,7 @@ public class BuildCraftCore extends BuildCraftMod {
BuildCraftAPI.isFarmlandProperty = new WorldPropertyIsFarmland();
BuildCraftAPI.isShoveled = new WorldPropertyIsShoveled();
BuildCraftAPI.isDirtProperty = new WorldPropertyIsDirt();
BuildCraftAPI.isFluidSource = new WorldPropertyIsFluidSource();
}
@Mod.EventHandler

View file

@ -62,6 +62,7 @@ import buildcraft.core.robots.boards.BoardRobotLumberjackNBT;
import buildcraft.core.robots.boards.BoardRobotMinerNBT;
import buildcraft.core.robots.boards.BoardRobotPickerNBT;
import buildcraft.core.robots.boards.BoardRobotPlanterNBT;
import buildcraft.core.robots.boards.BoardRobotPumpNBT;
import buildcraft.core.robots.boards.BoardRobotShovelmanNBT;
import buildcraft.core.science.TechnoRobot;
import buildcraft.core.science.TechnoSimpleItem;
@ -226,6 +227,7 @@ public class BuildCraftSilicon extends BuildCraftMod {
RedstoneBoardRegistry.instance.registerBoardClass(BoardRobotShovelmanNBT.instance, 5);
RedstoneBoardRegistry.instance.registerBoardClass(BoardRobotCrafterNBT.instance, 5);
RedstoneBoardRegistry.instance.registerBoardClass(BoardRobotDeliveryNBT.instance, 5);
RedstoneBoardRegistry.instance.registerBoardClass(BoardRobotPumpNBT.instance, 5);
RedstoneBoardRegistry.instance.registerBoardClass(BoardRobotKnightNBT.instance, 1);
RedstoneBoardRegistry.instance.registerBoardClass(BoardRobotBomberNBT.instance, 1);

View file

@ -0,0 +1,78 @@
/**
* 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 net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import buildcraft.api.core.BlockIndex;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
public class AIRobotPumpBlock extends AIRobot {
public BlockIndex blockToPump;
public long waited = 0;
int pumped = 0;
public AIRobotPumpBlock(EntityRobotBase iRobot) {
super(iRobot);
}
public AIRobotPumpBlock(EntityRobotBase iRobot, BlockIndex iBlockToPump) {
super(iRobot);
blockToPump = iBlockToPump;
}
@Override
public void start() {
robot.aimItemAt(blockToPump.x, blockToPump.y, blockToPump.z);
}
@Override
public void update() {
if (waited < 40) {
waited++;
} else {
Fluid fluid = FluidRegistry.lookupFluidForBlock(robot.worldObj.getBlock(blockToPump.x, blockToPump.y,
blockToPump.z));
if (fluid != null) {
pumped = robot.fill(ForgeDirection.UNKNOWN,
new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME), true);
if (pumped > 0) {
robot.worldObj.setBlockToAir(blockToPump.x, blockToPump.y, blockToPump.z);
}
}
terminate();
}
}
@Override
public void end() {
robot.aimItemAt(0, 1, 0);
}
@Override
public double getEnergyCost() {
return 2;
}
@Override
public boolean success() {
return pumped > 0;
}
}

View file

@ -84,12 +84,12 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public boolean isTaken(ResourceId resourceId) {
public synchronized boolean isTaken(ResourceId resourceId) {
return robotIdTaking(resourceId) != EntityRobotBase.NULL_ROBOT_ID;
}
@Override
public long robotIdTaking(ResourceId resourceId) {
public synchronized long robotIdTaking(ResourceId resourceId) {
if (!resourcesTaken.containsKey(resourceId)) {
return EntityRobotBase.NULL_ROBOT_ID;
}
@ -107,7 +107,7 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public EntityRobot robotTaking(ResourceId resourceId) {
public synchronized EntityRobot robotTaking(ResourceId resourceId) {
long robotId = robotIdTaking(resourceId);
if (robotId == EntityRobotBase.NULL_ROBOT_ID || !robotsLoaded.containsKey(robotId)) {
@ -118,14 +118,14 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public boolean take(ResourceId resourceId, EntityRobotBase robot) {
public synchronized boolean take(ResourceId resourceId, EntityRobotBase robot) {
markDirty();
return take(resourceId, robot.getRobotId());
}
@Override
public boolean take(ResourceId resourceId, long robotId) {
public synchronized boolean take(ResourceId resourceId, long robotId) {
if (resourceId == null) {
return false;
}
@ -150,7 +150,7 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public void release(ResourceId resourceId) {
public synchronized void release(ResourceId resourceId) {
if (resourceId == null) {
return;
}
@ -167,11 +167,11 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public void releaseResources(EntityRobotBase robot) {
public synchronized void releaseResources(EntityRobotBase robot) {
releaseResources(robot, false);
}
private void releaseResources(EntityRobotBase robot, boolean forceAll) {
private synchronized void releaseResources(EntityRobotBase robot, boolean forceAll) {
markDirty();
if (resourcesTakenByRobot.containsKey(robot.getRobotId())) {
@ -210,7 +210,7 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public IDockingStation getStation(int x, int y, int z, ForgeDirection side) {
public synchronized IDockingStation getStation(int x, int y, int z, ForgeDirection side) {
StationIndex index = new StationIndex(side, x, y, z);
if (stations.containsKey(index)) {
@ -221,12 +221,12 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public Collection<IDockingStation> getStations() {
public synchronized Collection<IDockingStation> getStations() {
return stations.values();
}
@Override
public void registerStation(IDockingStation station) {
public synchronized void registerStation(IDockingStation station) {
markDirty();
StationIndex index = new StationIndex(station);
@ -239,7 +239,7 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public void removeStation(IDockingStation station) {
public synchronized void removeStation(IDockingStation station) {
markDirty();
StationIndex index = new StationIndex(station);
@ -254,7 +254,7 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public void take(IDockingStation station, long robotId) {
public synchronized void take(IDockingStation station, long robotId) {
if (!stationsTakenByRobot.containsKey(robotId)) {
stationsTakenByRobot.put(robotId, new HashSet<StationIndex>());
}
@ -263,13 +263,13 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public void release(IDockingStation station, long robotId) {
public synchronized void release(IDockingStation station, long robotId) {
if (stationsTakenByRobot.containsKey(robotId)) {
stationsTakenByRobot.get(robotId).remove(new StationIndex(station));
}
}
public static RobotRegistry getRegistry (World world) {
public static synchronized RobotRegistry getRegistry(World world) {
if (registries[world.provider.dimensionId] == null
|| registries[world.provider.dimensionId].world != world) {
@ -293,7 +293,7 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public void writeToNBT(NBTTagCompound nbt) {
public synchronized void writeToNBT(NBTTagCompound nbt) {
nbt.setLong("nextRobotID", nextRobotID);
NBTTagList resourceList = new NBTTagList();
@ -322,7 +322,7 @@ public class RobotRegistry extends WorldSavedData implements IRobotRegistry {
}
@Override
public void readFromNBT(NBTTagCompound nbt) {
public synchronized void readFromNBT(NBTTagCompound nbt) {
nextRobotID = nbt.getLong("nextRobotID");
NBTTagList resourceList = nbt.getTagList("resourceList", Constants.NBT.TAG_COMPOUND);

View file

@ -55,27 +55,6 @@ public abstract class BoardRobotGenericBreakBlock extends RedstoneBoardRobot {
*/
public abstract boolean isExpectedBlock(World world, int x, int y, int z);
@Override
public final void start() {
DockingStation station = (DockingStation) robot.getLinkedStation();
for (ActionSlot slot : new ActionIterator(station.getPipe().pipe)) {
if (slot.action instanceof ActionRobotFilter) {
for (IActionParameter p : slot.parameters) {
if (p != null && p instanceof ActionParameterItemStack) {
ActionParameterItemStack param = (ActionParameterItemStack) p;
ItemStack stack = param.getItemStackToDraw();
if (stack != null && stack.getItem() instanceof ItemBlock) {
blockFilter.add(((ItemBlock) stack.getItem()).field_150939_a);
metaFilter.add(stack.getItemDamage());
}
}
}
}
}
}
public final void preemt(AIRobot ai) {
if (ai instanceof AIRobotSearchBlock) {
BlockIndex index = ((AIRobotSearchBlock) ai).blockFound;
@ -96,11 +75,13 @@ public abstract class BoardRobotGenericBreakBlock extends RedstoneBoardRobot {
}
}));
} else {
updateFilter();
startDelegateAI(new AIRobotSearchBlock(robot, new IBlockFilter() {
@Override
public boolean matches(World world, int x, int y, int z) {
if (isExpectedBlock(world, x, y, z) && matchesGateFilter(world, x, y, z)) {
return !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z));
if (isExpectedBlock(world, x, y, z) && !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z))) {
return matchesGateFilter(world, x, y, z);
} else {
return false;
}
@ -140,6 +121,29 @@ public abstract class BoardRobotGenericBreakBlock extends RedstoneBoardRobot {
}
}
public final void updateFilter() {
blockFilter.clear();
metaFilter.clear();
DockingStation station = (DockingStation) robot.getLinkedStation();
for (ActionSlot slot : new ActionIterator(station.getPipe().pipe)) {
if (slot.action instanceof ActionRobotFilter) {
for (IActionParameter p : slot.parameters) {
if (p != null && p instanceof ActionParameterItemStack) {
ActionParameterItemStack param = (ActionParameterItemStack) p;
ItemStack stack = param.getItemStackToDraw();
if (stack != null && stack.getItem() instanceof ItemBlock) {
blockFilter.add(((ItemBlock) stack.getItem()).field_150939_a);
metaFilter.add(stack.getItemDamage());
}
}
}
}
}
}
private boolean matchesGateFilter(World world, int x, int y, int z) {
if (blockFilter.size() == 0) {
return true;

View file

@ -0,0 +1,163 @@
/**
* 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.boards;
import java.util.ArrayList;
import net.minecraft.block.Block;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;
import net.minecraftforge.common.util.ForgeDirection;
import net.minecraftforge.fluids.Fluid;
import net.minecraftforge.fluids.FluidContainerRegistry;
import net.minecraftforge.fluids.FluidRegistry;
import net.minecraftforge.fluids.FluidStack;
import buildcraft.api.boards.RedstoneBoardRobot;
import buildcraft.api.boards.RedstoneBoardRobotNBT;
import buildcraft.api.core.BlockIndex;
import buildcraft.api.core.BuildCraftAPI;
import buildcraft.api.gates.ActionParameterItemStack;
import buildcraft.api.gates.IActionParameter;
import buildcraft.api.robots.AIRobot;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.core.TickHandlerCore;
import buildcraft.core.robots.AIRobotGotoBlock;
import buildcraft.core.robots.AIRobotGotoSleep;
import buildcraft.core.robots.AIRobotGotoStationAndUnloadFluids;
import buildcraft.core.robots.AIRobotPumpBlock;
import buildcraft.core.robots.AIRobotSearchBlock;
import buildcraft.core.robots.DockingStation;
import buildcraft.core.robots.IBlockFilter;
import buildcraft.core.robots.ResourceIdBlock;
import buildcraft.silicon.statements.ActionRobotFilter;
import buildcraft.transport.gates.ActionIterator;
import buildcraft.transport.gates.ActionSlot;
public class BoardRobotPump extends RedstoneBoardRobot {
private BlockIndex blockFound;
private ArrayList<Fluid> fluidFilter = new ArrayList<Fluid>();
public BoardRobotPump(EntityRobotBase iRobot) {
super(iRobot);
}
@Override
public RedstoneBoardRobotNBT getNBTHandler() {
return BoardRobotPumpNBT.instance;
}
@Override
public void update() {
FluidStack tank = robot.getTankInfo(ForgeDirection.UNKNOWN)[0].fluid;
if (tank != null && tank.amount > 0) {
startDelegateAI(new AIRobotGotoStationAndUnloadFluids(robot, robot.getZoneToWork()));
} else {
updateFilter();
startDelegateAI(new AIRobotSearchBlock(robot, new IBlockFilter() {
@Override
public boolean matches(World world, int x, int y, int z) {
if (BuildCraftAPI.isFluidSource.get(world, x, y, z)
&& !robot.getRegistry().isTaken(new ResourceIdBlock(x, y, z))) {
return matchesGateFilter(world, x, y, z);
} else {
return false;
}
}
}));
}
}
@Override
public void delegateAIEnded(AIRobot ai) {
if (ai instanceof AIRobotSearchBlock) {
if (!ai.success()) {
startDelegateAI(new AIRobotGotoSleep(robot));
} else {
blockFound = ((AIRobotSearchBlock) ai).blockFound;
if (!robot.getRegistry().take(new ResourceIdBlock (blockFound), robot)) {
blockFound = null;
startDelegateAI(new AIRobotGotoSleep(robot));
} else {
startDelegateAI(new AIRobotGotoBlock(robot, ((AIRobotSearchBlock) ai).path));
}
}
} else if (ai instanceof AIRobotGotoBlock) {
if (!ai.success()) {
startDelegateAI(new AIRobotGotoSleep(robot));
} else {
startDelegateAI(new AIRobotPumpBlock(robot, blockFound));
}
} else if (ai instanceof AIRobotGotoStationAndUnloadFluids) {
robot.getRegistry().take(new ResourceIdBlock (blockFound), robot);
if (!ai.success()) {
startDelegateAI(new AIRobotGotoSleep(robot));
}
}
}
public void updateFilter() {
fluidFilter.clear();
DockingStation station = (DockingStation) robot.getLinkedStation();
for (ActionSlot slot : new ActionIterator(station.getPipe().pipe)) {
if (slot.action instanceof ActionRobotFilter) {
for (IActionParameter p : slot.parameters) {
if (p != null && p instanceof ActionParameterItemStack) {
ActionParameterItemStack param = (ActionParameterItemStack) p;
ItemStack stack = param.getItemStackToDraw();
if (stack != null) {
FluidStack fluid = FluidContainerRegistry.getFluidForFilledItem(stack);
if (fluid != null) {
fluidFilter.add(fluid.getFluid());
}
}
}
}
}
}
}
private boolean matchesGateFilter(World world, int x, int y, int z) {
if (fluidFilter.size() == 0) {
return true;
}
synchronized (TickHandlerCore.startSynchronousComputation) {
try {
TickHandlerCore.startSynchronousComputation.wait();
Block block = world.getBlock(x, y, z);
Fluid fluid = FluidRegistry.lookupFluidForBlock(block);
for (Fluid f : fluidFilter) {
if (f.getID() == fluid.getID()) {
return true;
}
}
return false;
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
}
}
}

View file

@ -0,0 +1,64 @@
/**
* 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.boards;
import java.util.List;
import net.minecraft.client.renderer.texture.IIconRegister;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.IIcon;
import net.minecraft.util.ResourceLocation;
import buildcraft.api.boards.RedstoneBoardRobot;
import buildcraft.api.boards.RedstoneBoardRobotNBT;
import buildcraft.api.robots.EntityRobotBase;
import buildcraft.core.DefaultProps;
import buildcraft.core.utils.StringUtils;
public final class BoardRobotPumpNBT extends RedstoneBoardRobotNBT {
public static BoardRobotPumpNBT instance = new BoardRobotPumpNBT();
private static final ResourceLocation TEXTURE = new ResourceLocation("buildcraft",
DefaultProps.TEXTURE_PATH_ENTITIES + "/robot_pump.png");
private IIcon icon;
@Override
public RedstoneBoardRobot create(NBTTagCompound nbt, EntityRobotBase robot) {
return new BoardRobotPump(robot);
}
@Override
public ResourceLocation getRobotTexture() {
return TEXTURE;
}
@Override
public String getID() {
return "buildcraft:boardRobotPump";
}
@Override
public void addInformation(ItemStack stack, EntityPlayer player, List list, boolean advanced) {
list.add(StringUtils.localize("buildcraft.boardRobotPump"));
}
@Override
public void registerIcons(IIconRegister iconRegister) {
icon = iconRegister.registerIcon("buildcraft:board_blue");
}
@Override
public IIcon getIcon(NBTTagCompound nbt) {
return icon;
}
}

View file

@ -0,0 +1,24 @@
/**
* 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.utils;
import net.minecraft.block.Block;
import net.minecraft.block.BlockLiquid;
import net.minecraft.world.IBlockAccess;
import net.minecraftforge.fluids.BlockFluidBase;
public class WorldPropertyIsFluidSource extends WorldProperty {
@Override
public boolean get(IBlockAccess blockAccess, Block block, int meta, int x, int y, int z) {
return (block instanceof BlockLiquid || block instanceof BlockFluidBase)
&& meta == 0;
}
}