buildcraft/common/buildcraft/core/blueprints/BptBuilderBase.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();
}
}