Crude basin fluid support

- basin can now store fluid
- fluid stored in basin will be bundled together with item in a MultiIngredientTypeList supporting both items and fluids
This commit is contained in:
LordGrimmauld 2020-07-08 18:20:49 +02:00
parent 6511cbcd7b
commit 3bcdac6080
7 changed files with 306 additions and 110 deletions

View file

@ -1,6 +1,7 @@
package com.simibubi.create.content.contraptions.components.mixer; package com.simibubi.create.content.contraptions.components.mixer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
@ -32,7 +33,7 @@ import net.minecraftforge.items.IItemHandler;
public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
private static Object shapelessOrMixingRecipesKey = new Object(); private static final Object shapelessOrMixingRecipesKey = new Object();
public int runningTicks; public int runningTicks;
public int processingTicks; public int processingTicks;
@ -47,15 +48,15 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
@Override @Override
public void addBehaviours(List<TileEntityBehaviour> behaviours) { public void addBehaviours(List<TileEntityBehaviour> behaviours) {
super.addBehaviours(behaviours); super.addBehaviours(behaviours);
CenteredSideValueBoxTransform slot = CenteredSideValueBoxTransform slot = new CenteredSideValueBoxTransform((state, direction) -> direction.getAxis()
new CenteredSideValueBoxTransform((state, direction) -> direction.getAxis().isHorizontal()) { .isHorizontal()) {
@Override @Override
protected Vec3d getSouthLocation() { protected Vec3d getSouthLocation() {
return super.getSouthLocation().add(0, 4 / 16f, 0); return super.getSouthLocation().add(0, 4 / 16f, 0);
} }
}; };
minIngredients = new ScrollValueBehaviour(Lang.translate("mechanical_mixer.min_ingredients"), this, slot); minIngredients = new ScrollValueBehaviour(Lang.translate("mechanical_mixer.min_ingredients"), this, slot);
minIngredients.between(1, 9); minIngredients.between(1, 9);
minIngredients.withCallback(i -> basinChecker.scheduleUpdate()); minIngredients.withCallback(i -> basinChecker.scheduleUpdate());
@ -74,7 +75,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
offset = num - .5f; offset = num - .5f;
} else if (runningTicks <= 20) { } else if (runningTicks <= 20) {
offset = 1; offset = 1;
} else if (runningTicks > 20) { } else {
localTick = 40 - runningTicks; localTick = 40 - runningTicks;
float num = (localTick - partialTicks) / 20f; float num = (localTick - partialTicks) / 20f;
num = ((2 - MathHelper.cos((float) (num * Math.PI))) / 2); num = ((2 - MathHelper.cos((float) (num * Math.PI))) / 2);
@ -93,9 +94,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
if (runningTicks <= 20) { if (runningTicks <= 20) {
return speed * 2; return speed * 2;
} }
if (runningTicks > 20) { return speed;
return speed;
}
} }
return speed / 2; return speed / 2;
} }
@ -130,7 +129,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
} }
float speed = Math.abs(getSpeed()); float speed = Math.abs(getSpeed());
if (running) { if (running && world != null) {
if (world.isRemote && runningTicks == 20) if (world.isRemote && runningTicks == 20)
renderParticles(); renderParticles();
@ -155,52 +154,53 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity {
} }
public void renderParticles() { public void renderParticles() {
IItemHandler itemHandler = basinInv.orElse(null); IItemHandler itemHandler = basinItemInv.orElse(null);
if (itemHandler != null) { BasinInventory inv = (BasinInventory) itemHandler;
BasinInventory inv = (BasinInventory) itemHandler;
for (int slot = 0; slot < inv.getInputHandler().getSlots(); slot++) { for (int slot = 0; slot < inv.getInputHandler()
ItemStack stackInSlot = itemHandler.getStackInSlot(slot); .getSlots(); slot++) {
if (stackInSlot.isEmpty()) ItemStack stackInSlot = itemHandler.getStackInSlot(slot);
continue; if (stackInSlot.isEmpty())
continue;
ItemParticleData data = new ItemParticleData(ParticleTypes.ITEM, stackInSlot); ItemParticleData data = new ItemParticleData(ParticleTypes.ITEM, stackInSlot);
float angle = world.rand.nextFloat() * 360; float angle = world.rand.nextFloat() * 360;
Vec3d offset = new Vec3d(0, 0, 0.25f); Vec3d offset = new Vec3d(0, 0, 0.25f);
offset = VecHelper.rotate(offset, angle, Axis.Y); offset = VecHelper.rotate(offset, angle, Axis.Y);
Vec3d target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y).add(0, .25f, 0); Vec3d target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y)
.add(0, .25f, 0);
Vec3d center = offset.add(VecHelper.getCenterOf(pos)); Vec3d center = offset.add(VecHelper.getCenterOf(pos));
target = VecHelper.offsetRandomly(target.subtract(offset), world.rand, 1 / 128f); target = VecHelper.offsetRandomly(target.subtract(offset), world.rand, 1 / 128f);
world.addParticle(data, center.x, center.y - 2, center.z, target.x, target.y, target.z); world.addParticle(data, center.x, center.y - 2, center.z, target.x, target.y, target.z);
}
} }
} }
@Override @Override
protected <C extends IInventory> boolean matchStaticFilters(IRecipe<C> r) { protected <C extends IInventory> boolean matchStaticFilters(IRecipe<C> r) {
return (r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS || r.getType() == AllRecipeTypes.MIXING.type) return (r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS || r.getType() == AllRecipeTypes.MIXING.type)
&& !MechanicalPressTileEntity.canCompress(r.getIngredients()); && !MechanicalPressTileEntity.canCompress(r.getIngredients());
} }
@Override @Override
protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) { protected <C extends IInventory> boolean matchBasinRecipe(IRecipe<C> recipe) {
if (recipe == null) if (recipe == null)
return false; return false;
if (recipe.getIngredients().size() < minIngredients.getValue()) if (recipe.getIngredients()
.size() < minIngredients.getValue())
return false; return false;
NonNullList<Ingredient> ingredients = recipe.getIngredients(); NonNullList<Ingredient> ingredients = recipe.getIngredients();
if (!ingredients.stream() if (!ingredients.stream()
.allMatch(ingredient -> (ingredient.isSimple() || ingredient.getMatchingStacks().length == 1))) .allMatch(ingredient -> (ingredient.isSimple() || ingredient.getMatchingStacks().length == 1)))
return false; return false;
List<ItemStack> remaining = new ArrayList<>(); List<ItemStack> remaining = new ArrayList<>();
inputs.forEach(stack -> remaining.add(stack.copy())); inputs.forEachItemStack(stack -> remaining.add(stack.copy()));
// sort by leniency // sort by leniency
List<Ingredient> sortedIngredients = new LinkedList<>(ingredients); List<Ingredient> sortedIngredients = new LinkedList<>(ingredients);
sortedIngredients.sort((i1, i2) -> i1.getMatchingStacks().length - i2.getMatchingStacks().length); sortedIngredients.sort(Comparator.comparingInt(i -> i.getMatchingStacks().length));
Ingredients: for (Ingredient ingredient : sortedIngredients) { Ingredients: for (Ingredient ingredient : sortedIngredients) {
for (ItemStack stack : remaining) { for (ItemStack stack : remaining) {
if (stack.isEmpty()) if (stack.isEmpty())

View file

@ -39,7 +39,7 @@ import net.minecraftforge.items.wrapper.RecipeWrapper;
public class MechanicalPressTileEntity extends BasinOperatingTileEntity { public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
private static Object compressingRecipesKey = new Object(); private static final Object compressingRecipesKey = new Object();
public List<ItemStack> pressedItems = new ArrayList<>(); public List<ItemStack> pressedItems = new ArrayList<>();
public static class PressingInv extends RecipeWrapper { public static class PressingInv extends RecipeWrapper {
@ -55,12 +55,12 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
float headOffset; float headOffset;
private Mode(float headOffset) { Mode(float headOffset) {
this.headOffset = headOffset; this.headOffset = headOffset;
} }
} }
private static PressingInv pressingInv = new PressingInv(); private static final PressingInv pressingInv = new PressingInv();
public BeltProcessingBehaviour processingBehaviour; public BeltProcessingBehaviour processingBehaviour;
public int runningTicks; public int runningTicks;
@ -128,10 +128,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
float num = (runningTicks - 1 + partialTicks) / 30f; float num = (runningTicks - 1 + partialTicks) / 30f;
return MathHelper.clamp(num * num * num, 0, mode.headOffset); return MathHelper.clamp(num * num * num, 0, mode.headOffset);
} }
if (runningTicks >= 40) { return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0,
return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0, mode.headOffset);
mode.headOffset);
}
} }
return 0; return 0;
} }
@ -148,10 +146,6 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
return mode == Mode.WORLD; return mode == Mode.WORLD;
} }
public boolean onBelt() {
return mode == Mode.BELT;
}
public boolean onBasin() { public boolean onBasin() {
return mode == Mode.BASIN; return mode == Mode.BASIN;
} }
@ -160,7 +154,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
public void tick() { public void tick() {
super.tick(); super.tick();
if (!running) if (!running || world == null)
return; return;
if (runningTicks == 30) { if (runningTicks == 30) {
@ -190,8 +184,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
if (!world.isRemote) { if (!world.isRemote) {
pressedItems.clear(); pressedItems.clear();
applyBasinRecipe(); applyBasinRecipe();
IItemHandler orElse = basinInv.orElse(null); IItemHandler orElse = basinItemInv.orElse(null);
if (basinInv.isPresent() && orElse instanceof BasinInventory) { if (basinItemInv.isPresent() && orElse instanceof BasinInventory) {
BasinInventory inv = (BasinInventory) orElse; BasinInventory inv = (BasinInventory) orElse;
for (int slot = 0; slot < inv.getInputHandler() for (int slot = 0; slot < inv.getInputHandler()
@ -256,7 +250,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
} }
public void makePressingParticleEffect(Vec3d pos, ItemStack stack) { public void makePressingParticleEffect(Vec3d pos, ItemStack stack) {
if (world.isRemote) { if (world != null && world.isRemote) {
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f)
.mul(1, 0, 1); .mul(1, 0, 1);
@ -267,7 +261,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
} }
public void makeCompactingParticleEffect(Vec3d pos, ItemStack stack) { public void makeCompactingParticleEffect(Vec3d pos, ItemStack stack) {
if (world.isRemote) { if (world != null && world.isRemote) {
for (int i = 0; i < 20; i++) { for (int i = 0; i < 20; i++) {
Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f) Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f)
.mul(1, 0, 1); .mul(1, 0, 1);
@ -279,9 +273,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
public Optional<PressingRecipe> getRecipe(ItemStack item) { public Optional<PressingRecipe> getRecipe(ItemStack item) {
pressingInv.setInventorySlotContents(0, item); pressingInv.setInventorySlotContents(0, item);
Optional<PressingRecipe> recipe = world.getRecipeManager() return world.getRecipeManager()
.getRecipe(AllRecipeTypes.PRESSING.getType(), pressingInv, world); .getRecipe(AllRecipeTypes.PRESSING.getType(), pressingInv, world);
return recipe;
} }
public static boolean canCompress(NonNullList<Ingredient> ingredients) { public static boolean canCompress(NonNullList<Ingredient> ingredients) {
@ -305,7 +298,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity {
return false; return false;
List<ItemStack> remaining = new ArrayList<>(); List<ItemStack> remaining = new ArrayList<>();
inputs.forEach(stack -> remaining.add(stack.copy())); inputs.forEachItemStack(stack -> remaining.add(stack.copy()));
Ingredients: for (Ingredient ingredient : ingredients) { Ingredients: for (Ingredient ingredient : ingredients) {
for (ItemStack stack : remaining) { for (ItemStack stack : remaining) {

View file

@ -0,0 +1,135 @@
package com.simibubi.create.content.contraptions.fluids;
import net.minecraft.fluid.Fluid;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.common.util.NonNullConsumer;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class CombinedFluidHandler implements IFluidHandler {
private final int capacity;
private final FluidStack[] tanks;
public CombinedFluidHandler(int tankNumber, int capacity) {
this.capacity = capacity;
this.tanks = new FluidStack[tankNumber];
Arrays.fill(tanks, FluidStack.EMPTY);
}
@Override
public int getTanks() {
return tanks.length;
}
@Nonnull
@Override
public FluidStack getFluidInTank(int tank) {
if (tank < 0 || tank >= tanks.length)
return FluidStack.EMPTY;
return tanks[tank];
}
@Override
public int getTankCapacity(int tank) {
return capacity;
}
@Override
public boolean isFluidValid(int tank, @Nonnull FluidStack stack) {
return (!stack.isEmpty()) && (tanks[tank].isEmpty() || tanks[tank].isFluidEqual(stack))
&& tanks[tank].getAmount() < capacity;
}
@Override
public int fill(FluidStack resource, FluidAction action) {
int tankIndex;
int amount = resource.getAmount();
while ((tankIndex = getFittingFluidSlot(resource)) != -1) {
int newAmount = MathHelper.clamp(amount - capacity - tanks[tankIndex].getAmount(), 0, Integer.MAX_VALUE);
if (action == FluidAction.EXECUTE)
if (tanks[tankIndex].isEmpty())
tanks[tankIndex] = new FluidStack(resource.getFluid(), amount - newAmount);
else
tanks[tankIndex].grow(amount - newAmount);
amount = newAmount;
if (amount == 0)
return 0;
}
return amount;
}
@Nonnull
@Override
public FluidStack drain(FluidStack resource, FluidAction action) {
if (resource.isEmpty())
return FluidStack.EMPTY;
FluidStack stack = new FluidStack(resource, 0);
for (int i = 0; i < tanks.length; i++) {
if (tanks[i].isFluidEqual(resource)) {
stack.grow(tanks[i].getAmount());
if (action == FluidAction.EXECUTE)
tanks[i] = FluidStack.EMPTY;
}
}
return stack.isEmpty() ? FluidStack.EMPTY : stack;
}
@Nonnull
@Override
public FluidStack drain(int maxDrain, FluidAction action) {
FluidStack stack = new FluidStack(tanks[0].getFluid(), 0);
for (int i = 0; i < tanks.length; i++) {
if (tanks[i].isFluidEqual(stack)) {
int newDrainAmount = MathHelper.clamp(stack.getAmount() + tanks[i].getAmount(), 0, maxDrain);
if (action == FluidAction.EXECUTE) {
tanks[i].shrink(newDrainAmount - stack.getAmount());
if (tanks[i].isEmpty())
tanks[i] = FluidStack.EMPTY;
}
stack.setAmount(newDrainAmount);
}
}
return stack.isEmpty() ? FluidStack.EMPTY : stack;
}
private int getFittingFluidSlot(FluidStack fluidStack) {
return IntStream.range(0, tanks.length)
.filter(i -> isFluidValid(i, fluidStack))
.findFirst()
.orElse(-1);
}
private void setFluid(FluidStack fluid, int tank) {
tanks[tank] = fluid;
}
public CombinedFluidHandler readFromNBT(ListNBT fluidNBTs) {
for (int i = 0; i < Math.min(tanks.length, fluidNBTs.size()); i++)
setFluid(FluidStack.loadFluidStackFromNBT(fluidNBTs.getCompound(i)), i);
return this;
}
public ListNBT getListNBT() {
return Arrays.stream(tanks)
.map(fluid -> fluid.writeToNBT(new CompoundNBT()))
.collect(Collectors.toCollection(ListNBT::new));
}
public void forEachTank(NonNullConsumer<FluidStack> fluidStackConsumer) {
Arrays.stream(tanks)
.forEach(fluidStackConsumer::accept);
}
}

View file

@ -51,8 +51,9 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
@Override @Override
public ActionResultType onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, public ActionResultType onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn,
BlockRayTraceResult hit) { BlockRayTraceResult hit) {
if (!player.getHeldItem(handIn).isEmpty()) if (!player.getHeldItem(handIn)
.isEmpty())
return ActionResultType.PASS; return ActionResultType.PASS;
try { try {
@ -63,7 +64,8 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
inv.setStackInSlot(slot, ItemStack.EMPTY); inv.setStackInSlot(slot, ItemStack.EMPTY);
} }
te.onEmptied(); te.onEmptied();
} catch (TileEntityException e) {} } catch (TileEntityException e) {
}
return ActionResultType.SUCCESS; return ActionResultType.SUCCESS;
} }
@ -79,15 +81,15 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
return; return;
ItemEntity itemEntity = (ItemEntity) entityIn; ItemEntity itemEntity = (ItemEntity) entityIn;
withTileEntityDo(worldIn, entityIn.getPosition(), te -> { withTileEntityDo(worldIn, entityIn.getPosition(), te -> {
ItemStack insertItem = ItemHandlerHelper.insertItem(te.inputInventory, itemEntity.getItem().copy(), false); ItemStack insertItem = ItemHandlerHelper.insertItem(te.inputItemInventory, itemEntity.getItem()
.copy(), false);
if (insertItem.isEmpty()) { if (insertItem.isEmpty()) {
itemEntity.remove(); itemEntity.remove();
if (!itemEntity.world.isRemote) if (!itemEntity.world.isRemote)
AllTriggers AllTriggers.triggerForNearbyPlayers(AllTriggers.BASIN_THROW, itemEntity.world,
.triggerForNearbyPlayers(AllTriggers.BASIN_THROW, itemEntity.world, itemEntity.getPosition(), 3);
itemEntity.getPosition(), 3);
return; return;
} }
@ -107,8 +109,8 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
} }
withTileEntityDo(worldIn, pos, te -> { withTileEntityDo(worldIn, pos, te -> {
ItemHelper.dropContents(worldIn, pos, te.inputInventory); ItemHelper.dropContents(worldIn, pos, te.inputItemInventory);
ItemHelper.dropContents(worldIn, pos, te.outputInventory); ItemHelper.dropContents(worldIn, pos, te.outputItemInventory);
}); });
worldIn.removeTileEntity(pos); worldIn.removeTileEntity(pos);
} }
@ -121,8 +123,9 @@ public class BasinBlock extends Block implements ITE<BasinTileEntity>, IWrenchab
@Override @Override
public int getComparatorInputOverride(BlockState blockState, World worldIn, BlockPos pos) { public int getComparatorInputOverride(BlockState blockState, World worldIn, BlockPos pos) {
try { try {
return ItemHelper.calcRedstoneFromInventory(getTileEntity(worldIn, pos).inputInventory); return ItemHelper.calcRedstoneFromInventory(getTileEntity(worldIn, pos).inputItemInventory);
} catch (TileEntityException e) {} } catch (TileEntityException e) {
}
return 0; return 0;
} }

View file

@ -7,6 +7,7 @@ import java.util.stream.Collectors;
import com.simibubi.create.AllTileEntities; import com.simibubi.create.AllTileEntities;
import com.simibubi.create.content.contraptions.base.KineticTileEntity; import com.simibubi.create.content.contraptions.base.KineticTileEntity;
import com.simibubi.create.content.contraptions.fluids.CombinedFluidHandler;
import com.simibubi.create.content.contraptions.processing.BasinTileEntity.BasinInventory; import com.simibubi.create.content.contraptions.processing.BasinTileEntity.BasinInventory;
import com.simibubi.create.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.advancement.SimpleTrigger; import com.simibubi.create.foundation.advancement.SimpleTrigger;
@ -22,6 +23,8 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType; import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.NonNullList; import net.minecraft.util.NonNullList;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandler; import net.minecraftforge.items.IItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
@ -32,8 +35,9 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
public DeferralBehaviour basinChecker; public DeferralBehaviour basinChecker;
public boolean basinRemoved; public boolean basinRemoved;
protected IRecipe<?> lastRecipe; protected IRecipe<?> lastRecipe;
protected LazyOptional<IItemHandler> basinInv = LazyOptional.empty(); protected LazyOptional<IItemHandler> basinItemInv = LazyOptional.empty();
protected List<ItemStack> inputs; protected LazyOptional<IFluidHandler> basinFluidInv = LazyOptional.empty();
protected MultiIngredientTypeList inputs;
public BasinOperatingTileEntity(TileEntityType<?> typeIn) { public BasinOperatingTileEntity(TileEntityType<?> typeIn) {
super(typeIn); super(typeIn);
@ -55,17 +59,19 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
} }
public void gatherInputs() { public void gatherInputs() {
if (!basinInv.isPresent()) inputs = new MultiIngredientTypeList();
return;
BasinInventory inv = (BasinInventory) basinInv.orElse(null); basinItemInv.ifPresent(inv -> {
inputs = new ArrayList<>(); IItemHandlerModifiable inputHandler = ((BasinInventory) inv).getInputHandler();
IItemHandlerModifiable inputHandler = inv.getInputHandler(); for (int slot = 0; slot < inputHandler.getSlots(); ++slot) {
for (int slot = 0; slot < inputHandler.getSlots(); ++slot) { ItemStack itemstack = inputHandler.extractItem(slot, inputHandler.getSlotLimit(slot), true);
ItemStack itemstack = inputHandler.extractItem(slot, inputHandler.getSlotLimit(slot), true); if (!itemstack.isEmpty()) {
if (!itemstack.isEmpty()) { inputs.add(itemstack);
inputs.add(itemstack); }
} }
} });
basinFluidInv.ifPresent(iFluidHandler -> ((CombinedFluidHandler) iFluidHandler).forEachTank(inputs::add));
} }
@Override @Override
@ -91,12 +97,16 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
Optional<BasinTileEntity> basinTe = getBasin(); Optional<BasinTileEntity> basinTe = getBasin();
if (!basinTe.isPresent()) if (!basinTe.isPresent())
return true; return true;
if (!basinInv.isPresent()) if (!basinItemInv.isPresent())
basinInv = basinTe.get().getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); basinItemInv = basinTe.get()
if (!basinInv.isPresent()) .getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY);
if (!basinFluidInv.isPresent())
basinFluidInv = basinTe.get()
.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY);
if (!basinFluidInv.isPresent() || !basinItemInv.isPresent())
return true; return true;
if (world.isRemote) if (world == null || world.isRemote)
return true; return true;
gatherInputs(); gatherInputs();
@ -112,8 +122,7 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
protected abstract boolean isRunning(); protected abstract boolean isRunning();
public void startProcessingBasin() { public void startProcessingBasin() {}
}
public boolean continueWithPreviousRecipe() { public boolean continueWithPreviousRecipe() {
return true; return true;
@ -122,12 +131,10 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
public void applyBasinRecipe() { public void applyBasinRecipe() {
if (lastRecipe == null) if (lastRecipe == null)
return; return;
if (!basinInv.isPresent()) if (!basinItemInv.isPresent() || !basinFluidInv.isPresent())
return; return;
BasinInventory inv = (BasinInventory) basinInv.orElse(null); BasinInventory inv = (BasinInventory) basinItemInv.orElse(null);
if (inv == null)
return;
IItemHandlerModifiable inputs = inv.getInputHandler(); IItemHandlerModifiable inputs = inv.getInputHandler();
IItemHandlerModifiable outputs = inv.getOutputHandler(); IItemHandlerModifiable outputs = inv.getOutputHandler();
@ -142,10 +149,13 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
continue; continue;
ItemStack extracted = inputs.extractItem(slot, 1, false); ItemStack extracted = inputs.extractItem(slot, 1, false);
if ((lastRecipe instanceof ProcessingRecipe) if ((lastRecipe instanceof ProcessingRecipe)
&& ((ProcessingRecipe<?>) lastRecipe).getRollableIngredients().get(i).remains()) { && ((ProcessingRecipe<?>) lastRecipe).getRollableIngredients()
.get(i)
.remains()) {
catalysts.add(extracted.copy()); catalysts.add(extracted.copy());
} else if (extracted.hasContainerItem()) { } else if (extracted.hasContainerItem()) {
containers.add(extracted.getContainerItem().copy()); containers.add(extracted.getContainerItem()
.copy());
} }
continue Ingredients; continue Ingredients;
} }
@ -153,14 +163,15 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
return; return;
} }
if (!world.isRemote) { if (world != null && !world.isRemote) {
SimpleTrigger trigger = AllTriggers.MIXER_MIX; SimpleTrigger trigger = AllTriggers.MIXER_MIX;
if (AllTileEntities.MECHANICAL_PRESS.is(this)) if (AllTileEntities.MECHANICAL_PRESS.is(this))
trigger = AllTriggers.PRESS_COMPACT; trigger = AllTriggers.PRESS_COMPACT;
AllTriggers.triggerForNearbyPlayers(trigger, world, pos, 4); AllTriggers.triggerForNearbyPlayers(trigger, world, pos, 4);
} }
ItemHandlerHelper.insertItemStacked(outputs, lastRecipe.getRecipeOutput().copy(), false); ItemHandlerHelper.insertItemStacked(outputs, lastRecipe.getRecipeOutput()
.copy(), false);
containers.forEach(stack -> ItemHandlerHelper.insertItemStacked(outputs, stack, false)); containers.forEach(stack -> ItemHandlerHelper.insertItemStacked(outputs, stack, false));
catalysts.forEach(c -> ItemHandlerHelper.insertItemStacked(outputs, c, false)); catalysts.forEach(c -> ItemHandlerHelper.insertItemStacked(outputs, c, false));
@ -176,9 +187,12 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
protected List<IRecipe<?>> getMatchingRecipes() { protected List<IRecipe<?>> getMatchingRecipes() {
List<IRecipe<?>> list = RecipeFinder.get(getRecipeCacheKey(), world, this::matchStaticFilters); List<IRecipe<?>> list = RecipeFinder.get(getRecipeCacheKey(), world, this::matchStaticFilters);
return list.stream().filter(this::matchBasinRecipe) return list.stream()
.sorted((r1, r2) -> -r1.getIngredients().size() + r2.getIngredients().size()) .filter(this::matchBasinRecipe)
.collect(Collectors.toList()); .sorted((r1, r2) -> -r1.getIngredients()
.size() + r2.getIngredients()
.size())
.collect(Collectors.toList());
} }
protected void basinRemoved() { protected void basinRemoved() {
@ -186,6 +200,8 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity {
} }
protected Optional<BasinTileEntity> getBasin() { protected Optional<BasinTileEntity> getBasin() {
if (world == null)
return Optional.empty();
TileEntity basinTE = world.getTileEntity(pos.down(2)); TileEntity basinTE = world.getTileEntity(pos.down(2));
if (!(basinTE instanceof BasinTileEntity)) if (!(basinTE instanceof BasinTileEntity))
return Optional.empty(); return Optional.empty();

View file

@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.processing;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import com.simibubi.create.content.contraptions.fluids.CombinedFluidHandler;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity; import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour; import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour; import com.simibubi.create.foundation.tileEntity.behaviour.belt.DirectBeltInputBehaviour;
@ -15,6 +16,7 @@ import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional; import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.CapabilityItemHandler;
import net.minecraftforge.items.IItemHandlerModifiable; import net.minecraftforge.items.IItemHandlerModifiable;
import net.minecraftforge.items.ItemHandlerHelper; import net.minecraftforge.items.ItemHandlerHelper;
@ -22,11 +24,13 @@ import net.minecraftforge.items.ItemStackHandler;
import net.minecraftforge.items.wrapper.CombinedInvWrapper; import net.minecraftforge.items.wrapper.CombinedInvWrapper;
import net.minecraftforge.items.wrapper.RecipeWrapper; import net.minecraftforge.items.wrapper.RecipeWrapper;
import javax.annotation.Nonnull;
public class BasinTileEntity extends SmartTileEntity implements ITickableTileEntity { public class BasinTileEntity extends SmartTileEntity implements ITickableTileEntity {
public boolean contentsChanged; public boolean contentsChanged;
protected ItemStackHandler outputInventory = new ItemStackHandler(9) { protected ItemStackHandler outputItemInventory = new ItemStackHandler(9) {
protected void onContentsChanged(int slot) { protected void onContentsChanged(int slot) {
sendData(); sendData();
markDirty(); markDirty();
@ -35,18 +39,19 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
public class BasinInputInventory extends RecipeWrapper { public class BasinInputInventory extends RecipeWrapper {
public BasinInputInventory() { public BasinInputInventory() {
super(inputInventory); super(inputItemInventory);
} }
} }
protected ItemStackHandler inputInventory = new ItemStackHandler(9) { protected ItemStackHandler inputItemInventory = new ItemStackHandler(9) {
protected void onContentsChanged(int slot) { protected void onContentsChanged(int slot) {
contentsChanged = true; contentsChanged = true;
sendData(); sendData();
markDirty(); markDirty();
}; }
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { @Nonnull
public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
for (int i = 0; i < getSlots(); i++) { for (int i = 0; i < getSlots(); i++) {
ItemStack stackInSlot = getStackInSlot(i); ItemStack stackInSlot = getStackInSlot(i);
if (ItemHandlerHelper.canItemStacksStack(stack, stackInSlot)) if (ItemHandlerHelper.canItemStacksStack(stack, stackInSlot))
@ -54,7 +59,7 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
return stack; return stack;
} }
return super.insertItem(slot, stack, simulate); return super.insertItem(slot, stack, simulate);
}; }
}; };
public static class BasinInventory extends CombinedInvWrapper { public static class BasinInventory extends CombinedInvWrapper {
@ -62,6 +67,7 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
super(input, output); super(input, output);
} }
@Nonnull
@Override @Override
public ItemStack extractItem(int slot, int amount, boolean simulate) { public ItemStack extractItem(int slot, int amount, boolean simulate) {
if (isInput(slot)) if (isInput(slot))
@ -69,8 +75,9 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
return super.extractItem(slot, amount, simulate); return super.extractItem(slot, amount, simulate);
} }
@Nonnull
@Override @Override
public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
if (!isInput(slot)) if (!isInput(slot))
return stack; return stack;
return super.insertItem(slot, stack, simulate); return super.insertItem(slot, stack, simulate);
@ -91,7 +98,11 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
} }
protected LazyOptional<IItemHandlerModifiable> inventory = protected LazyOptional<IItemHandlerModifiable> inventory =
LazyOptional.of(() -> new BasinInventory(inputInventory, outputInventory)); LazyOptional.of(() -> new BasinInventory(inputItemInventory, outputItemInventory));
protected LazyOptional<CombinedFluidHandler> fluidInventory =
LazyOptional.of(() -> new CombinedFluidHandler(9, 1000));
public BasinInputInventory recipeInventory; public BasinInputInventory recipeInventory;
public BasinTileEntity(TileEntityType<? extends BasinTileEntity> type) { public BasinTileEntity(TileEntityType<? extends BasinTileEntity> type) {
@ -108,15 +119,19 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
@Override @Override
public void read(CompoundNBT compound) { public void read(CompoundNBT compound) {
super.read(compound); super.read(compound);
inputInventory.deserializeNBT(compound.getCompound("InputItems")); inputItemInventory.deserializeNBT(compound.getCompound("InputItems"));
outputInventory.deserializeNBT(compound.getCompound("OutputItems")); outputItemInventory.deserializeNBT(compound.getCompound("OutputItems"));
if (compound.hasUniqueId("fluids"))
fluidInventory
.ifPresent(combinedFluidHandler -> combinedFluidHandler.readFromNBT(compound.getList("fluids", 10)));
} }
@Override @Override
public CompoundNBT write(CompoundNBT compound) { public CompoundNBT write(CompoundNBT compound) {
super.write(compound); super.write(compound);
compound.put("InputItems", inputInventory.serializeNBT()); compound.put("InputItems", inputItemInventory.serializeNBT());
compound.put("OutputItems", outputInventory.serializeNBT()); compound.put("OutputItems", outputItemInventory.serializeNBT());
fluidInventory.ifPresent(combinedFuidHandler -> compound.put("fluids", combinedFuidHandler.getListNBT()));
return compound; return compound;
} }
@ -128,13 +143,17 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
public void remove() { public void remove() {
onEmptied(); onEmptied();
inventory.invalidate(); inventory.invalidate();
fluidInventory.invalidate();
super.remove(); super.remove();
} }
@Nonnull
@Override @Override
public <T> LazyOptional<T> getCapability(Capability<T> cap, Direction side) { public <T> LazyOptional<T> getCapability(@Nonnull Capability<T> cap, Direction side) {
if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY)
return inventory.cast(); return inventory.cast();
if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY)
return fluidInventory.cast();
return super.getCapability(cap, side); return super.getCapability(cap, side);
} }
@ -147,6 +166,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt
} }
private Optional<BasinOperatingTileEntity> getOperator() { private Optional<BasinOperatingTileEntity> getOperator() {
if (world == null)
return Optional.empty();
TileEntity te = world.getTileEntity(pos.up(2)); TileEntity te = world.getTileEntity(pos.up(2));
if (te instanceof BasinOperatingTileEntity) if (te instanceof BasinOperatingTileEntity)
return Optional.of((BasinOperatingTileEntity) te); return Optional.of((BasinOperatingTileEntity) te);

View file

@ -0,0 +1,28 @@
package com.simibubi.create.content.contraptions.processing;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import java.util.ArrayList;
import java.util.function.Consumer;
public class MultiIngredientTypeList {
private final ArrayList<ItemStack> itemIngredients = new ArrayList<>();
private final ArrayList<FluidStack> fluidIngredients = new ArrayList<>();
public void add(ItemStack itemstack) {
itemIngredients.add(itemstack);
}
public void add(FluidStack fluidStack) {
fluidIngredients.add(fluidStack);
}
public void forEachItemStack(Consumer<? super ItemStack> itemStackConsumer) {
itemIngredients.forEach(itemStackConsumer);
}
public void forEachFluidStack(Consumer<? super FluidStack> fluidStackConsumer) {
fluidIngredients.forEach(fluidStackConsumer);
}
}