303 lines
8.7 KiB
Java
303 lines
8.7 KiB
Java
/**
|
|
* 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.blueprints;
|
|
|
|
import java.util.BitSet;
|
|
|
|
import org.apache.logging.log4j.Level;
|
|
|
|
import net.minecraft.block.Block;
|
|
import net.minecraft.init.Blocks;
|
|
import net.minecraft.inventory.IInventory;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.nbt.NBTTagList;
|
|
import net.minecraft.util.AxisAlignedBB;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.WorldServer;
|
|
|
|
import net.minecraftforge.common.MinecraftForge;
|
|
import net.minecraftforge.common.util.BlockSnapshot;
|
|
import net.minecraftforge.common.util.Constants;
|
|
import net.minecraftforge.event.world.BlockEvent;
|
|
|
|
import buildcraft.BuildCraftCore;
|
|
import buildcraft.api.blueprints.BuilderAPI;
|
|
import buildcraft.api.blueprints.IBuilderContext;
|
|
import buildcraft.api.blueprints.MappingNotFoundException;
|
|
import buildcraft.api.blueprints.SchematicBlock;
|
|
import buildcraft.api.blueprints.SchematicBlockBase;
|
|
import buildcraft.api.core.BCLog;
|
|
import buildcraft.api.core.BlockIndex;
|
|
import buildcraft.api.core.IAreaProvider;
|
|
import buildcraft.api.core.Position;
|
|
import buildcraft.core.Box;
|
|
import buildcraft.core.builders.BuildingItem;
|
|
import buildcraft.core.builders.BuildingSlot;
|
|
import buildcraft.core.builders.BuildingSlotBlock;
|
|
import buildcraft.core.builders.IBuildingItemsProvider;
|
|
import buildcraft.core.builders.TileAbstractBuilder;
|
|
import buildcraft.core.lib.utils.BitSetUtils;
|
|
import buildcraft.core.lib.utils.BlockUtils;
|
|
import buildcraft.core.proxy.CoreProxy;
|
|
|
|
public abstract class BptBuilderBase implements IAreaProvider {
|
|
|
|
public BlueprintBase blueprint;
|
|
public BptContext context;
|
|
protected BitSet usedLocations;
|
|
protected boolean done;
|
|
protected int x, y, z;
|
|
protected boolean initialized = false;
|
|
|
|
private long nextBuildDate = 0;
|
|
|
|
public BptBuilderBase(BlueprintBase bluePrint, World world, int x, int y, int z) {
|
|
this.blueprint = bluePrint;
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
this.usedLocations = new BitSet(bluePrint.sizeX * bluePrint.sizeY * bluePrint.sizeZ);
|
|
done = false;
|
|
|
|
Box box = new Box();
|
|
box.initialize(this);
|
|
|
|
context = bluePrint.getContext(world, box);
|
|
}
|
|
|
|
protected boolean isLocationUsed(int i, int j, int k) {
|
|
int xCoord = i - x + blueprint.anchorX;
|
|
int yCoord = j - y + blueprint.anchorY;
|
|
int zCoord = k - z + blueprint.anchorZ;
|
|
return usedLocations.get((zCoord * blueprint.sizeY + yCoord) * blueprint.sizeX + xCoord);
|
|
}
|
|
|
|
protected void markLocationUsed(int i, int j, int k) {
|
|
int xCoord = i - x + blueprint.anchorX;
|
|
int yCoord = j - y + blueprint.anchorY;
|
|
int zCoord = k - z + blueprint.anchorZ;
|
|
usedLocations.set((zCoord * blueprint.sizeY + yCoord) * blueprint.sizeX + xCoord, true);
|
|
}
|
|
|
|
public void initialize() {
|
|
if (!initialized) {
|
|
internalInit();
|
|
initialized = true;
|
|
}
|
|
}
|
|
|
|
protected abstract void internalInit();
|
|
|
|
protected abstract BuildingSlot reserveNextBlock(World world);
|
|
|
|
protected abstract BuildingSlot getNextBlock(World world, TileAbstractBuilder inv);
|
|
|
|
public boolean buildNextSlot(World world, TileAbstractBuilder builder, double x, double y, double z) {
|
|
initialize();
|
|
|
|
if (world.getTotalWorldTime() < nextBuildDate) {
|
|
return false;
|
|
}
|
|
|
|
BuildingSlot slot = getNextBlock(world, builder);
|
|
|
|
if (buildSlot(world, builder, slot, x + 0.5F, y + 0.5F, z + 0.5F)) {
|
|
nextBuildDate = world.getTotalWorldTime() + slot.buildTime();
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public boolean buildSlot(World world, IBuildingItemsProvider builder, BuildingSlot slot, double x, double y,
|
|
double z) {
|
|
initialize();
|
|
|
|
if (slot != null) {
|
|
slot.built = true;
|
|
BuildingItem i = new BuildingItem();
|
|
i.origin = new Position(x, y, z);
|
|
i.destination = slot.getDestination();
|
|
i.slotToBuild = slot;
|
|
i.context = getContext();
|
|
i.setStacksToDisplay(slot.getStacksToDisplay());
|
|
builder.addAndLaunchBuildingItem(i);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public BuildingSlot reserveNextSlot(World world) {
|
|
initialize();
|
|
|
|
return reserveNextBlock(world);
|
|
}
|
|
|
|
@Override
|
|
public int xMin() {
|
|
return x - blueprint.anchorX;
|
|
}
|
|
|
|
@Override
|
|
public int yMin() {
|
|
return y - blueprint.anchorY;
|
|
}
|
|
|
|
@Override
|
|
public int zMin() {
|
|
return z - blueprint.anchorZ;
|
|
}
|
|
|
|
@Override
|
|
public int xMax() {
|
|
return x + blueprint.sizeX - blueprint.anchorX - 1;
|
|
}
|
|
|
|
@Override
|
|
public int yMax() {
|
|
return y + blueprint.sizeY - blueprint.anchorY - 1;
|
|
}
|
|
|
|
@Override
|
|
public int zMax() {
|
|
return z + blueprint.sizeZ - blueprint.anchorZ - 1;
|
|
}
|
|
|
|
@Override
|
|
public void removeFromWorld() {
|
|
|
|
}
|
|
|
|
public AxisAlignedBB getBoundingBox() {
|
|
return AxisAlignedBB.getBoundingBox(xMin(), yMin(), zMin(), xMax(), yMax(), zMax());
|
|
}
|
|
|
|
public void postProcessing(World world) {
|
|
|
|
}
|
|
|
|
public BptContext getContext() {
|
|
return context;
|
|
}
|
|
|
|
public boolean isDone(IBuildingItemsProvider builder) {
|
|
return done && builder.getBuilders().size() == 0;
|
|
}
|
|
|
|
private int getBlockBreakEnergy(BuildingSlotBlock slot) {
|
|
return BlockUtils.computeBlockBreakEnergy(context.world(), slot.x, slot.y, slot.z);
|
|
}
|
|
|
|
protected final boolean canDestroy(TileAbstractBuilder builder, IBuilderContext context, BuildingSlotBlock slot) {
|
|
return builder.energyAvailable() >= getBlockBreakEnergy(slot);
|
|
}
|
|
|
|
public void consumeEnergyToDestroy(TileAbstractBuilder builder, BuildingSlotBlock slot) {
|
|
builder.consumeEnergy(getBlockBreakEnergy(slot));
|
|
}
|
|
|
|
public void createDestroyItems(BuildingSlotBlock slot) {
|
|
int hardness = (int) Math.ceil((double) getBlockBreakEnergy(slot) / BuilderAPI.BREAK_ENERGY);
|
|
|
|
for (int i = 0; i < hardness; ++i) {
|
|
slot.addStackConsumed(new ItemStack(BuildCraftCore.buildToolBlock));
|
|
}
|
|
}
|
|
|
|
public void useRequirements(IInventory inv, BuildingSlot slot) {
|
|
|
|
}
|
|
|
|
public void saveBuildStateToNBT(NBTTagCompound nbt, IBuildingItemsProvider builder) {
|
|
nbt.setByteArray("usedLocationList", BitSetUtils.toByteArray(usedLocations));
|
|
|
|
NBTTagList buildingList = new NBTTagList();
|
|
|
|
for (BuildingItem item : builder.getBuilders()) {
|
|
NBTTagCompound sub = new NBTTagCompound();
|
|
item.writeToNBT(sub);
|
|
buildingList.appendTag(sub);
|
|
}
|
|
|
|
nbt.setTag("buildersInAction", buildingList);
|
|
}
|
|
|
|
public void loadBuildStateToNBT(NBTTagCompound nbt, IBuildingItemsProvider builder) {
|
|
if (nbt.hasKey("usedLocationList")) {
|
|
usedLocations = BitSetUtils.fromByteArray(nbt.getByteArray("usedLocationList"));
|
|
}
|
|
|
|
NBTTagList buildingList = nbt
|
|
.getTagList("buildersInAction",
|
|
Constants.NBT.TAG_COMPOUND);
|
|
|
|
for (int i = 0; i < buildingList.tagCount(); ++i) {
|
|
BuildingItem item = new BuildingItem();
|
|
|
|
try {
|
|
item.readFromNBT(buildingList.getCompoundTagAt(i));
|
|
item.context = getContext();
|
|
builder.getBuilders().add(item);
|
|
} catch (MappingNotFoundException e) {
|
|
BCLog.logger.log(Level.WARN, "can't load building item", e);
|
|
}
|
|
}
|
|
|
|
// 6.4.6 and below migration
|
|
|
|
if (nbt.hasKey("clearList")) {
|
|
NBTTagList clearList = nbt.getTagList("clearList", Constants.NBT.TAG_COMPOUND);
|
|
|
|
for (int i = 0; i < clearList.tagCount(); ++i) {
|
|
NBTTagCompound cpt = clearList.getCompoundTagAt(i);
|
|
BlockIndex o = new BlockIndex(cpt);
|
|
markLocationUsed(o.x, o.y, o.z);
|
|
}
|
|
}
|
|
|
|
if (nbt.hasKey("builtList")) {
|
|
NBTTagList builtList = nbt.getTagList("builtList", Constants.NBT.TAG_COMPOUND);
|
|
|
|
for (int i = 0; i < builtList.tagCount(); ++i) {
|
|
NBTTagCompound cpt = builtList.getCompoundTagAt(i);
|
|
BlockIndex o = new BlockIndex(cpt);
|
|
markLocationUsed(o.x, o.y, o.z);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected boolean isBlockBreakCanceled(World world, int x, int y, int z) {
|
|
if (!world.isAirBlock(x, y, z)) {
|
|
BlockEvent.BreakEvent breakEvent = new BlockEvent.BreakEvent(x, y, z, world, world.getBlock(x, y, z),
|
|
world.getBlockMetadata(x, y, z),
|
|
CoreProxy.proxy.getBuildCraftPlayer((WorldServer) world, this.x, this.y, this.z).get());
|
|
MinecraftForge.EVENT_BUS.post(breakEvent);
|
|
return breakEvent.isCanceled();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected boolean isBlockPlaceCanceled(World world, int x, int y, int z, SchematicBlockBase schematic) {
|
|
Block block = schematic instanceof SchematicBlock ? ((SchematicBlock) schematic).block : Blocks.stone;
|
|
int meta = schematic instanceof SchematicBlock ? ((SchematicBlock) schematic).meta : 0;
|
|
|
|
BlockEvent.PlaceEvent placeEvent = new BlockEvent.PlaceEvent(
|
|
new BlockSnapshot(world, x, y, z, block, meta),
|
|
Blocks.air,
|
|
CoreProxy.proxy.getBuildCraftPlayer((WorldServer) world, this.x, this.y, this.z).get()
|
|
);
|
|
|
|
MinecraftForge.EVENT_BUS.post(placeEvent);
|
|
return placeEvent.isCanceled();
|
|
}
|
|
}
|