853 lines
23 KiB
Java
853 lines
23 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.ArrayList;
|
|
import java.util.Collections;
|
|
import java.util.Comparator;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.LinkedList;
|
|
import java.util.List;
|
|
import java.util.ListIterator;
|
|
import java.util.Map.Entry;
|
|
|
|
import net.minecraft.init.Blocks;
|
|
import net.minecraft.inventory.IInventory;
|
|
import net.minecraft.item.Item;
|
|
import net.minecraft.item.ItemBlock;
|
|
import net.minecraft.item.ItemStack;
|
|
import net.minecraft.nbt.NBTTagCompound;
|
|
import net.minecraft.world.World;
|
|
import net.minecraft.world.WorldSettings.GameType;
|
|
|
|
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.blueprints.BuilderAPI;
|
|
import buildcraft.api.blueprints.Schematic;
|
|
import buildcraft.api.blueprints.SchematicBlock;
|
|
import buildcraft.api.blueprints.SchematicEntity;
|
|
import buildcraft.api.core.BCLog;
|
|
import buildcraft.api.core.BlockIndex;
|
|
import buildcraft.api.core.BuildCraftAPI;
|
|
import buildcraft.api.core.IInvSlot;
|
|
import buildcraft.api.core.StackKey;
|
|
import buildcraft.core.builders.BuilderItemMetaPair;
|
|
import buildcraft.core.builders.BuildingSlot;
|
|
import buildcraft.core.builders.BuildingSlotBlock;
|
|
import buildcraft.core.builders.BuildingSlotBlock.Mode;
|
|
import buildcraft.core.builders.BuildingSlotEntity;
|
|
import buildcraft.core.builders.IBuildingItemsProvider;
|
|
import buildcraft.core.builders.TileAbstractBuilder;
|
|
import buildcraft.core.lib.inventory.InventoryCopy;
|
|
import buildcraft.core.lib.inventory.InventoryIterator;
|
|
import buildcraft.core.lib.utils.BlockUtils;
|
|
|
|
public class BptBuilderBlueprint extends BptBuilderBase {
|
|
protected HashSet<Integer> builtEntities = new HashSet<Integer>();
|
|
protected HashMap<BuilderItemMetaPair, List<BuildingSlotBlock>> buildList = new HashMap<BuilderItemMetaPair, List<BuildingSlotBlock>>();
|
|
protected int[] buildStageOccurences;
|
|
|
|
private ArrayList<RequirementItemStack> neededItems = new ArrayList<RequirementItemStack>();
|
|
|
|
private LinkedList<BuildingSlotEntity> entityList = new LinkedList<BuildingSlotEntity>();
|
|
private LinkedList<BuildingSlot> postProcessing = new LinkedList<BuildingSlot>();
|
|
private BuildingSlotMapIterator iterator;
|
|
private IndexRequirementMap requirementMap = new IndexRequirementMap();
|
|
|
|
public BptBuilderBlueprint(Blueprint bluePrint, World world, int x, int y, int z) {
|
|
super(bluePrint, world, x, y, z);
|
|
}
|
|
|
|
@Override
|
|
protected void internalInit() {
|
|
for (int j = blueprint.sizeY - 1; j >= 0; --j) {
|
|
int yCoord = j + y - blueprint.anchorY;
|
|
|
|
if (yCoord < 0 || yCoord >= context.world.getHeight()) {
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; i < blueprint.sizeX; ++i) {
|
|
int xCoord = i + x - blueprint.anchorX;
|
|
|
|
for (int k = 0; k < blueprint.sizeZ; ++k) {
|
|
int zCoord = k + z - blueprint.anchorZ;
|
|
|
|
if (!isLocationUsed(xCoord, yCoord, zCoord)) {
|
|
SchematicBlock slot = (SchematicBlock) blueprint.get(i, j, k);
|
|
|
|
if (slot == null && !blueprint.excavate) {
|
|
continue;
|
|
}
|
|
|
|
if (slot == null) {
|
|
slot = new SchematicBlock();
|
|
slot.meta = 0;
|
|
slot.block = Blocks.air;
|
|
}
|
|
|
|
if (!SchematicRegistry.INSTANCE.isAllowedForBuilding(slot.block, slot.meta)) {
|
|
continue;
|
|
}
|
|
|
|
BuildingSlotBlock b = new BuildingSlotBlock();
|
|
b.schematic = slot;
|
|
b.x = xCoord;
|
|
b.y = yCoord;
|
|
b.z = zCoord;
|
|
b.mode = Mode.ClearIfInvalid;
|
|
b.buildStage = 0;
|
|
|
|
addToBuildList(b);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
LinkedList<BuildingSlotBlock> tmpStandalone = new LinkedList<BuildingSlotBlock>();
|
|
LinkedList<BuildingSlotBlock> tmpExpanding = new LinkedList<BuildingSlotBlock>();
|
|
|
|
for (int j = 0; j < blueprint.sizeY; ++j) {
|
|
int yCoord = j + y - blueprint.anchorY;
|
|
|
|
if (yCoord < 0 || yCoord >= context.world.getHeight()) {
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; i < blueprint.sizeX; ++i) {
|
|
int xCoord = i + x - blueprint.anchorX;
|
|
|
|
for (int k = 0; k < blueprint.sizeZ; ++k) {
|
|
int zCoord = k + z - blueprint.anchorZ;
|
|
|
|
SchematicBlock slot = (SchematicBlock) blueprint.get(i, j, k);
|
|
|
|
if (slot == null) {
|
|
continue;
|
|
}
|
|
|
|
if (!SchematicRegistry.INSTANCE.isAllowedForBuilding(slot.block, slot.meta)) {
|
|
continue;
|
|
}
|
|
|
|
BuildingSlotBlock b = new BuildingSlotBlock();
|
|
b.schematic = slot;
|
|
b.x = xCoord;
|
|
b.y = yCoord;
|
|
b.z = zCoord;
|
|
b.mode = Mode.Build;
|
|
|
|
if (!isLocationUsed(xCoord, yCoord, zCoord)) {
|
|
switch (slot.getBuildStage()) {
|
|
case STANDALONE:
|
|
tmpStandalone.add(b);
|
|
b.buildStage = 1;
|
|
break;
|
|
case EXPANDING:
|
|
tmpExpanding.add(b);
|
|
b.buildStage = 2;
|
|
break;
|
|
}
|
|
} else {
|
|
postProcessing.add(b);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (BuildingSlotBlock b : tmpStandalone) {
|
|
addToBuildList(b);
|
|
}
|
|
for (BuildingSlotBlock b : tmpExpanding) {
|
|
addToBuildList(b);
|
|
}
|
|
|
|
int seqId = 0;
|
|
|
|
for (SchematicEntity e : ((Blueprint) blueprint).entities) {
|
|
|
|
BuildingSlotEntity b = new BuildingSlotEntity();
|
|
b.schematic = e;
|
|
b.sequenceNumber = seqId;
|
|
|
|
if (!builtEntities.contains(seqId)) {
|
|
entityList.add(b);
|
|
} else {
|
|
postProcessing.add(b);
|
|
}
|
|
|
|
seqId++;
|
|
}
|
|
|
|
recomputeNeededItems();
|
|
}
|
|
|
|
public void deploy() {
|
|
initialize();
|
|
|
|
for (List<BuildingSlotBlock> lb : buildList.values()) {
|
|
for (BuildingSlotBlock b : lb) {
|
|
if (b.mode == Mode.ClearIfInvalid) {
|
|
context.world.setBlockToAir(b.x, b.y, b.z);
|
|
} else if (!b.schematic.doNotBuild()) {
|
|
b.stackConsumed = new LinkedList<ItemStack>();
|
|
|
|
try {
|
|
for (ItemStack stk : b.getRequirements(context)) {
|
|
if (stk != null) {
|
|
b.stackConsumed.add(stk.copy());
|
|
}
|
|
}
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
b.writeToWorld(context);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (BuildingSlotEntity e : entityList) {
|
|
e.stackConsumed = new LinkedList<ItemStack>();
|
|
|
|
try {
|
|
for (ItemStack stk : e.getRequirements(context)) {
|
|
if (stk != null) {
|
|
e.stackConsumed.add(stk.copy());
|
|
}
|
|
}
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
e.writeToWorld(context);
|
|
}
|
|
|
|
for (List<BuildingSlotBlock> lb : buildList.values()) {
|
|
for (BuildingSlotBlock b : lb) {
|
|
if (b.mode != Mode.ClearIfInvalid) {
|
|
b.postProcessing(context);
|
|
}
|
|
}
|
|
}
|
|
|
|
for (BuildingSlotEntity e : entityList) {
|
|
e.postProcessing(context);
|
|
}
|
|
}
|
|
|
|
private void checkDone() {
|
|
if (getBuildListCount() == 0 && entityList.size() == 0) {
|
|
done = true;
|
|
} else {
|
|
done = false;
|
|
}
|
|
}
|
|
|
|
private int getBuildListCount() {
|
|
int out = 0;
|
|
if (buildStageOccurences != null) {
|
|
for (int i = 0; i < buildStageOccurences.length; i++) {
|
|
out += buildStageOccurences[i];
|
|
}
|
|
}
|
|
return out;
|
|
}
|
|
|
|
@Override
|
|
public BuildingSlot reserveNextBlock(World world) {
|
|
if (getBuildListCount() != 0) {
|
|
BuildingSlot slot = internalGetNextBlock(world, null);
|
|
checkDone();
|
|
|
|
if (slot != null) {
|
|
slot.reserved = true;
|
|
}
|
|
|
|
return slot;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private void addToBuildList(BuildingSlotBlock b) {
|
|
if (b != null) {
|
|
BuilderItemMetaPair imp = new BuilderItemMetaPair(context, b);
|
|
if (!buildList.containsKey(imp)) {
|
|
buildList.put(imp, new ArrayList<BuildingSlotBlock>());
|
|
}
|
|
buildList.get(imp).add(b);
|
|
|
|
if (buildStageOccurences == null) {
|
|
buildStageOccurences = new int[Math.max(3, b.buildStage + 1)];
|
|
} else if (buildStageOccurences.length <= b.buildStage) {
|
|
int[] newBSO = new int[b.buildStage + 1];
|
|
System.arraycopy(buildStageOccurences, 0, newBSO, 0, buildStageOccurences.length);
|
|
buildStageOccurences = newBSO;
|
|
}
|
|
buildStageOccurences[b.buildStage]++;
|
|
|
|
if (b.mode == Mode.Build) {
|
|
requirementMap.add(b, context);
|
|
b.internalRequirementRemovalListener = requirementMap;
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public BuildingSlot getNextBlock(World world, TileAbstractBuilder inv) {
|
|
if (getBuildListCount() != 0) {
|
|
BuildingSlot slot = internalGetNextBlock(world, inv);
|
|
checkDone();
|
|
return slot;
|
|
}
|
|
|
|
if (entityList.size() != 0) {
|
|
BuildingSlot slot = internalGetNextEntity(world, inv);
|
|
checkDone();
|
|
return slot;
|
|
}
|
|
|
|
checkDone();
|
|
return null;
|
|
}
|
|
|
|
protected boolean readyForSlotLookup(TileAbstractBuilder builder) {
|
|
return builder == null || builder.energyAvailable() >= BuilderAPI.BREAK_ENERGY;
|
|
}
|
|
|
|
/**
|
|
* Gets the next available block. If builder is not null, then building will
|
|
* be verified and performed. Otherwise, the next possible building slot is
|
|
* returned, possibly for reservation, with no building.
|
|
*/
|
|
private BuildingSlot internalGetNextBlock(World world, TileAbstractBuilder builder) {
|
|
if (!readyForSlotLookup(builder)) {
|
|
return null;
|
|
}
|
|
|
|
if (iterator == null) {
|
|
iterator = new BuildingSlotMapIterator(this, builder);
|
|
}
|
|
|
|
BuildingSlotBlock slot;
|
|
iterator.refresh(builder);
|
|
|
|
while (readyForSlotLookup(builder) && (slot = iterator.next()) != null) {
|
|
if (!world.blockExists(slot.x, slot.y, slot.z)) {
|
|
continue;
|
|
}
|
|
|
|
boolean skipped = false;
|
|
|
|
for (int i = 0; i < slot.buildStage; i++) {
|
|
if (buildStageOccurences[i] > 0) {
|
|
iterator.skipKey();
|
|
skipped = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (skipped) {
|
|
continue;
|
|
}
|
|
|
|
if (slot.built) {
|
|
iterator.remove();
|
|
markLocationUsed(slot.x, slot.y, slot.z);
|
|
postProcessing.add(slot);
|
|
|
|
continue;
|
|
}
|
|
|
|
if (slot.reserved) {
|
|
continue;
|
|
}
|
|
|
|
try {
|
|
if (slot.isAlreadyBuilt(context)) {
|
|
if (slot.mode == Mode.Build) {
|
|
requirementMap.remove(slot);
|
|
|
|
// Even slots that considered already built may need
|
|
// post processing calls. For example, flowing water
|
|
// may need to be adjusted, engines may need to be
|
|
// turned to the right direction, etc.
|
|
postProcessing.add(slot);
|
|
}
|
|
|
|
iterator.remove();
|
|
continue;
|
|
}
|
|
|
|
if (BlockUtils.isUnbreakableBlock(world, slot.x, slot.y, slot.z)) {
|
|
// if the block can't be broken, just forget this iterator
|
|
iterator.remove();
|
|
markLocationUsed(slot.x, slot.y, slot.z);
|
|
requirementMap.remove(slot);
|
|
} else {
|
|
if (slot.mode == Mode.ClearIfInvalid) {
|
|
if (BuildCraftAPI.isSoftBlock(world, slot.x, slot.y,
|
|
slot.z)
|
|
|| isBlockBreakCanceled(world, slot.x, slot.y, slot.z)) {
|
|
iterator.remove();
|
|
markLocationUsed(slot.x, slot.y, slot.z);
|
|
} else {
|
|
if (builder == null) {
|
|
createDestroyItems(slot);
|
|
return slot;
|
|
} else if (canDestroy(builder, context, slot)) {
|
|
consumeEnergyToDestroy(builder, slot);
|
|
createDestroyItems(slot);
|
|
|
|
iterator.remove();
|
|
markLocationUsed(slot.x, slot.y, slot.z);
|
|
return slot;
|
|
}
|
|
}
|
|
} else if (!slot.schematic.doNotBuild()) {
|
|
if (builder == null) {
|
|
return slot;
|
|
} else if (checkRequirements(builder, slot.schematic)) {
|
|
if (!BuildCraftAPI.isSoftBlock(world, slot.x, slot.y,
|
|
slot.z) || requirementMap.contains(new BlockIndex(slot.x, slot.y, slot.z))) {
|
|
continue; // Can't build yet, wait (#2751)
|
|
} else if (isBlockPlaceCanceled(world, slot.x, slot.y, slot.z, slot.schematic)) {
|
|
// Forge does not allow us to place a block in
|
|
// this position.
|
|
iterator.remove();
|
|
requirementMap.remove(slot);
|
|
markLocationUsed(slot.x, slot.y, slot.z);
|
|
continue;
|
|
}
|
|
|
|
// At this stage, regardless of the fact that the
|
|
// block can actually be built or not, we'll try.
|
|
// When the item reaches the actual block, we'll
|
|
// verify that the location is indeed clear, and
|
|
// avoid building otherwise.
|
|
builder.consumeEnergy(slot.getEnergyRequirement());
|
|
useRequirements(builder, slot);
|
|
|
|
iterator.remove();
|
|
markLocationUsed(slot.x, slot.y, slot.z);
|
|
postProcessing.add(slot);
|
|
return slot;
|
|
}
|
|
} else {
|
|
// Even slots that don't need to be build may need
|
|
// post processing, see above for the argument.
|
|
postProcessing.add(slot);
|
|
requirementMap.remove(slot);
|
|
iterator.remove();
|
|
}
|
|
}
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
iterator.remove();
|
|
requirementMap.remove(slot);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
// TODO: Remove recomputeNeededItems() and replace with something more efficient
|
|
private BuildingSlot internalGetNextEntity(World world, TileAbstractBuilder builder) {
|
|
Iterator<BuildingSlotEntity> it = entityList.iterator();
|
|
|
|
while (it.hasNext()) {
|
|
BuildingSlotEntity slot = it.next();
|
|
|
|
if (slot.isAlreadyBuilt(context)) {
|
|
it.remove();
|
|
recomputeNeededItems();
|
|
} else {
|
|
if (checkRequirements(builder, slot.schematic)) {
|
|
builder.consumeEnergy(slot.getEnergyRequirement());
|
|
useRequirements(builder, slot);
|
|
|
|
it.remove();
|
|
recomputeNeededItems();
|
|
postProcessing.add(slot);
|
|
builtEntities.add(slot.sequenceNumber);
|
|
return slot;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public boolean checkRequirements(TileAbstractBuilder builder, Schematic slot) {
|
|
LinkedList<ItemStack> tmpReq = new LinkedList<ItemStack>();
|
|
|
|
try {
|
|
LinkedList<ItemStack> req = new LinkedList<ItemStack>();
|
|
|
|
slot.getRequirementsForPlacement(context, req);
|
|
|
|
for (ItemStack stk : req) {
|
|
if (stk != null) {
|
|
tmpReq.add(stk.copy());
|
|
}
|
|
}
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
LinkedList<ItemStack> stacksUsed = new LinkedList<ItemStack>();
|
|
|
|
if (context.world().getWorldInfo().getGameType() == GameType.CREATIVE) {
|
|
for (ItemStack s : tmpReq) {
|
|
stacksUsed.add(s);
|
|
}
|
|
|
|
return !(builder.energyAvailable() < slot.getEnergyRequirement(stacksUsed));
|
|
}
|
|
|
|
IInventory invCopy = new InventoryCopy(builder);
|
|
|
|
for (ItemStack reqStk : tmpReq) {
|
|
boolean itemBlock = reqStk.getItem() instanceof ItemBlock;
|
|
Fluid fluid = itemBlock ? FluidRegistry.lookupFluidForBlock(((ItemBlock) reqStk.getItem()).field_150939_a) : null;
|
|
|
|
if (fluid != null && builder.drainBuild(new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME), true)) {
|
|
continue;
|
|
}
|
|
|
|
for (IInvSlot slotInv : InventoryIterator.getIterable(invCopy, ForgeDirection.UNKNOWN)) {
|
|
if (!builder.isBuildingMaterialSlot(slotInv.getIndex())) {
|
|
continue;
|
|
}
|
|
|
|
ItemStack invStk = slotInv.getStackInSlot();
|
|
if (invStk == null || invStk.stackSize == 0) {
|
|
continue;
|
|
}
|
|
|
|
FluidStack fluidStack = fluid != null ? FluidContainerRegistry.getFluidForFilledItem(invStk) : null;
|
|
boolean compatibleContainer = fluidStack != null && fluidStack.getFluid() == fluid && fluidStack.amount >= FluidContainerRegistry.BUCKET_VOLUME;
|
|
|
|
if (slot.isItemMatchingRequirement(invStk, reqStk) || compatibleContainer) {
|
|
try {
|
|
stacksUsed.add(slot.useItem(context, reqStk, slotInv));
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
if (reqStk.stackSize == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (reqStk.stackSize != 0) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return builder.energyAvailable() >= slot.getEnergyRequirement(stacksUsed);
|
|
}
|
|
|
|
@Override
|
|
public void useRequirements(IInventory inv, BuildingSlot slot) {
|
|
if (slot instanceof BuildingSlotBlock && ((BuildingSlotBlock) slot).mode == Mode.ClearIfInvalid) {
|
|
return;
|
|
}
|
|
|
|
LinkedList<ItemStack> tmpReq = new LinkedList<ItemStack>();
|
|
|
|
try {
|
|
for (ItemStack stk : slot.getRequirements(context)) {
|
|
if (stk != null) {
|
|
tmpReq.add(stk.copy());
|
|
}
|
|
}
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
|
|
}
|
|
|
|
if (context.world().getWorldInfo().getGameType() == GameType.CREATIVE) {
|
|
for (ItemStack s : tmpReq) {
|
|
slot.addStackConsumed(s);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
ListIterator<ItemStack> itr = tmpReq.listIterator();
|
|
|
|
while (itr.hasNext()) {
|
|
ItemStack reqStk = itr.next();
|
|
boolean smallStack = reqStk.stackSize == 1;
|
|
ItemStack usedStack = reqStk;
|
|
|
|
boolean itemBlock = reqStk.getItem() instanceof ItemBlock;
|
|
Fluid fluid = itemBlock ? FluidRegistry.lookupFluidForBlock(((ItemBlock) reqStk.getItem()).field_150939_a) : null;
|
|
|
|
if (fluid != null
|
|
&& inv instanceof TileAbstractBuilder
|
|
&& ((TileAbstractBuilder) inv).drainBuild(new FluidStack(fluid, FluidContainerRegistry.BUCKET_VOLUME), true)) {
|
|
continue;
|
|
}
|
|
|
|
for (IInvSlot slotInv : InventoryIterator.getIterable(inv, ForgeDirection.UNKNOWN)) {
|
|
if (inv instanceof TileAbstractBuilder &&
|
|
!((TileAbstractBuilder) inv).isBuildingMaterialSlot(slotInv.getIndex())) {
|
|
continue;
|
|
}
|
|
|
|
ItemStack invStk = slotInv.getStackInSlot();
|
|
|
|
if (invStk == null || invStk.stackSize == 0) {
|
|
continue;
|
|
}
|
|
|
|
FluidStack fluidStack = fluid != null ? FluidContainerRegistry.getFluidForFilledItem(invStk) : null;
|
|
boolean fluidFound = fluidStack != null && fluidStack.getFluid() == fluid && fluidStack.amount >= FluidContainerRegistry.BUCKET_VOLUME;
|
|
|
|
if (fluidFound || slot.getSchematic().isItemMatchingRequirement(invStk, reqStk)) {
|
|
try {
|
|
usedStack = slot.getSchematic().useItem(context, reqStk, slotInv);
|
|
slot.addStackConsumed(usedStack);
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
if (reqStk.stackSize == 0) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (reqStk.stackSize != 0) {
|
|
return;
|
|
}
|
|
|
|
if (smallStack) {
|
|
itr.set(usedStack); // set to the actual item used.
|
|
}
|
|
}
|
|
}
|
|
|
|
public List<RequirementItemStack> getNeededItems() {
|
|
return neededItems;
|
|
}
|
|
|
|
protected void onRemoveBuildingSlotBlock(BuildingSlotBlock slot) {
|
|
buildStageOccurences[slot.buildStage]--;
|
|
LinkedList<ItemStack> stacks = new LinkedList<ItemStack>();
|
|
|
|
try {
|
|
stacks = slot.getRequirements(context);
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
HashMap<StackKey, Integer> computeStacks = new HashMap<StackKey, Integer>();
|
|
|
|
for (ItemStack stack : stacks) {
|
|
if (stack == null || stack.getItem() == null || stack.stackSize == 0) {
|
|
continue;
|
|
}
|
|
|
|
StackKey key = new StackKey(stack);
|
|
|
|
if (!computeStacks.containsKey(key)) {
|
|
computeStacks.put(key, stack.stackSize);
|
|
} else {
|
|
Integer num = computeStacks.get(key);
|
|
num += stack.stackSize;
|
|
computeStacks.put(key, num);
|
|
}
|
|
}
|
|
|
|
for (RequirementItemStack ris : neededItems) {
|
|
StackKey stackKey = new StackKey(ris.stack);
|
|
if (computeStacks.containsKey(stackKey)) {
|
|
Integer num = computeStacks.get(stackKey);
|
|
if (ris.size <= num) {
|
|
recomputeNeededItems();
|
|
return;
|
|
} else {
|
|
neededItems.set(neededItems.indexOf(ris), new RequirementItemStack(ris.stack, ris.size - num));
|
|
}
|
|
}
|
|
}
|
|
|
|
sortNeededItems();
|
|
}
|
|
|
|
private void sortNeededItems() {
|
|
Collections.sort(neededItems, new Comparator<RequirementItemStack>() {
|
|
@Override
|
|
public int compare(RequirementItemStack o1, RequirementItemStack o2) {
|
|
if (o1.size != o2.size) {
|
|
return o1.size < o2.size ? 1 : -1;
|
|
} else {
|
|
ItemStack os1 = o1.stack;
|
|
ItemStack os2 = o2.stack;
|
|
if (Item.getIdFromItem(os1.getItem()) > Item.getIdFromItem(os2.getItem())) {
|
|
return -1;
|
|
} else if (Item.getIdFromItem(os1.getItem()) < Item.getIdFromItem(os2.getItem())) {
|
|
return 1;
|
|
} else if (os1.getItemDamage() > os2.getItemDamage()) {
|
|
return -1;
|
|
} else if (os1.getItemDamage() < os2.getItemDamage()) {
|
|
return 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
private void recomputeNeededItems() {
|
|
neededItems.clear();
|
|
|
|
HashMap<StackKey, Integer> computeStacks = new HashMap<StackKey, Integer>();
|
|
|
|
for (List<BuildingSlotBlock> lb : buildList.values()) {
|
|
for (BuildingSlotBlock slot : lb) {
|
|
if (slot == null) {
|
|
continue;
|
|
}
|
|
|
|
LinkedList<ItemStack> stacks = new LinkedList<ItemStack>();
|
|
|
|
try {
|
|
stacks = slot.getRequirements(context);
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
for (ItemStack stack : stacks) {
|
|
if (stack == null || stack.getItem() == null || stack.stackSize == 0) {
|
|
continue;
|
|
}
|
|
|
|
StackKey key = new StackKey(stack);
|
|
|
|
if (!computeStacks.containsKey(key)) {
|
|
computeStacks.put(key, stack.stackSize);
|
|
} else {
|
|
Integer num = computeStacks.get(key);
|
|
num += stack.stackSize;
|
|
|
|
computeStacks.put(key, num);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (BuildingSlotEntity slot : entityList) {
|
|
LinkedList<ItemStack> stacks = new LinkedList<ItemStack>();
|
|
|
|
try {
|
|
stacks = slot.getRequirements(context);
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
|
|
for (ItemStack stack : stacks) {
|
|
if (stack == null || stack.getItem() == null || stack.stackSize == 0) {
|
|
continue;
|
|
}
|
|
|
|
StackKey key = new StackKey(stack);
|
|
|
|
if (!computeStacks.containsKey(key)) {
|
|
computeStacks.put(key, stack.stackSize);
|
|
} else {
|
|
Integer num = computeStacks.get(key);
|
|
num += stack.stackSize;
|
|
|
|
computeStacks.put(key, num);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
for (Entry<StackKey, Integer> e : computeStacks.entrySet()) {
|
|
neededItems.add(new RequirementItemStack(e.getKey().stack.copy(), e.getValue()));
|
|
}
|
|
|
|
sortNeededItems();
|
|
}
|
|
|
|
@Override
|
|
public void postProcessing(World world) {
|
|
for (BuildingSlot s : postProcessing) {
|
|
try {
|
|
s.postProcessing(context);
|
|
} catch (Throwable t) {
|
|
// Defensive code against errors in implementers
|
|
t.printStackTrace();
|
|
BCLog.logger.throwing(t);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void saveBuildStateToNBT(NBTTagCompound nbt, IBuildingItemsProvider builder) {
|
|
super.saveBuildStateToNBT(nbt, builder);
|
|
|
|
int[] entitiesBuiltArr = new int[builtEntities.size()];
|
|
|
|
int id = 0;
|
|
|
|
for (Integer i : builtEntities) {
|
|
entitiesBuiltArr[id] = i;
|
|
id++;
|
|
}
|
|
|
|
nbt.setIntArray("builtEntities", entitiesBuiltArr);
|
|
}
|
|
|
|
@Override
|
|
public void loadBuildStateToNBT(NBTTagCompound nbt, IBuildingItemsProvider builder) {
|
|
super.loadBuildStateToNBT(nbt, builder);
|
|
|
|
int[] entitiesBuiltArr = nbt.getIntArray("builtEntities");
|
|
|
|
for (int i = 0; i < entitiesBuiltArr.length; ++i) {
|
|
builtEntities.add(i);
|
|
}
|
|
}
|
|
}
|