From 3bcdac608077ce1e9a5f689054b10946d3872869 Mon Sep 17 00:00:00 2001 From: LordGrimmauld Date: Wed, 8 Jul 2020 18:20:49 +0200 Subject: [PATCH] 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 --- .../mixer/MechanicalMixerTileEntity.java | 68 ++++----- .../press/MechanicalPressTileEntity.java | 31 ++-- .../fluids/CombinedFluidHandler.java | 135 ++++++++++++++++++ .../contraptions/processing/BasinBlock.java | 27 ++-- .../processing/BasinOperatingTileEntity.java | 76 ++++++---- .../processing/BasinTileEntity.java | 51 +++++-- .../processing/MultiIngredientTypeList.java | 28 ++++ 7 files changed, 306 insertions(+), 110 deletions(-) create mode 100644 src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java create mode 100644 src/main/java/com/simibubi/create/content/contraptions/processing/MultiIngredientTypeList.java diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java index 45ab3b179..76cf705ef 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/mixer/MechanicalMixerTileEntity.java @@ -1,6 +1,7 @@ package com.simibubi.create.content.contraptions.components.mixer; import java.util.ArrayList; +import java.util.Comparator; import java.util.LinkedList; import java.util.List; @@ -32,7 +33,7 @@ import net.minecraftforge.items.IItemHandler; public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { - private static Object shapelessOrMixingRecipesKey = new Object(); + private static final Object shapelessOrMixingRecipesKey = new Object(); public int runningTicks; public int processingTicks; @@ -47,15 +48,15 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { @Override public void addBehaviours(List behaviours) { super.addBehaviours(behaviours); - CenteredSideValueBoxTransform slot = - new CenteredSideValueBoxTransform((state, direction) -> direction.getAxis().isHorizontal()) { + CenteredSideValueBoxTransform slot = new CenteredSideValueBoxTransform((state, direction) -> direction.getAxis() + .isHorizontal()) { - @Override - protected Vec3d getSouthLocation() { - return super.getSouthLocation().add(0, 4 / 16f, 0); - } + @Override + protected Vec3d getSouthLocation() { + return super.getSouthLocation().add(0, 4 / 16f, 0); + } - }; + }; minIngredients = new ScrollValueBehaviour(Lang.translate("mechanical_mixer.min_ingredients"), this, slot); minIngredients.between(1, 9); minIngredients.withCallback(i -> basinChecker.scheduleUpdate()); @@ -74,7 +75,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { offset = num - .5f; } else if (runningTicks <= 20) { offset = 1; - } else if (runningTicks > 20) { + } else { localTick = 40 - runningTicks; float num = (localTick - partialTicks) / 20f; num = ((2 - MathHelper.cos((float) (num * Math.PI))) / 2); @@ -93,9 +94,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { if (runningTicks <= 20) { return speed * 2; } - if (runningTicks > 20) { - return speed; - } + return speed; } return speed / 2; } @@ -130,7 +129,7 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { } float speed = Math.abs(getSpeed()); - if (running) { + if (running && world != null) { if (world.isRemote && runningTicks == 20) renderParticles(); @@ -155,52 +154,53 @@ public class MechanicalMixerTileEntity extends BasinOperatingTileEntity { } public void renderParticles() { - IItemHandler itemHandler = basinInv.orElse(null); - if (itemHandler != null) { - BasinInventory inv = (BasinInventory) itemHandler; + IItemHandler itemHandler = basinItemInv.orElse(null); + BasinInventory inv = (BasinInventory) itemHandler; - for (int slot = 0; slot < inv.getInputHandler().getSlots(); slot++) { - ItemStack stackInSlot = itemHandler.getStackInSlot(slot); - if (stackInSlot.isEmpty()) - continue; + for (int slot = 0; slot < inv.getInputHandler() + .getSlots(); slot++) { + ItemStack stackInSlot = itemHandler.getStackInSlot(slot); + if (stackInSlot.isEmpty()) + continue; - ItemParticleData data = new ItemParticleData(ParticleTypes.ITEM, stackInSlot); - float angle = world.rand.nextFloat() * 360; - Vec3d offset = new Vec3d(0, 0, 0.25f); - offset = VecHelper.rotate(offset, angle, Axis.Y); - Vec3d target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y).add(0, .25f, 0); + ItemParticleData data = new ItemParticleData(ParticleTypes.ITEM, stackInSlot); + float angle = world.rand.nextFloat() * 360; + Vec3d offset = new Vec3d(0, 0, 0.25f); + offset = VecHelper.rotate(offset, angle, Axis.Y); + Vec3d target = VecHelper.rotate(offset, getSpeed() > 0 ? 25 : -25, Axis.Y) + .add(0, .25f, 0); - Vec3d center = offset.add(VecHelper.getCenterOf(pos)); - 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); - } + Vec3d center = offset.add(VecHelper.getCenterOf(pos)); + 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); } } @Override protected boolean matchStaticFilters(IRecipe r) { return (r.getSerializer() == IRecipeSerializer.CRAFTING_SHAPELESS || r.getType() == AllRecipeTypes.MIXING.type) - && !MechanicalPressTileEntity.canCompress(r.getIngredients()); + && !MechanicalPressTileEntity.canCompress(r.getIngredients()); } @Override protected boolean matchBasinRecipe(IRecipe recipe) { if (recipe == null) return false; - if (recipe.getIngredients().size() < minIngredients.getValue()) + if (recipe.getIngredients() + .size() < minIngredients.getValue()) return false; NonNullList ingredients = recipe.getIngredients(); if (!ingredients.stream() - .allMatch(ingredient -> (ingredient.isSimple() || ingredient.getMatchingStacks().length == 1))) + .allMatch(ingredient -> (ingredient.isSimple() || ingredient.getMatchingStacks().length == 1))) return false; List remaining = new ArrayList<>(); - inputs.forEach(stack -> remaining.add(stack.copy())); + inputs.forEachItemStack(stack -> remaining.add(stack.copy())); // sort by leniency List 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) { for (ItemStack stack : remaining) { if (stack.isEmpty()) diff --git a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java index ef4ce6845..e35e23ae7 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/components/press/MechanicalPressTileEntity.java @@ -39,7 +39,7 @@ import net.minecraftforge.items.wrapper.RecipeWrapper; public class MechanicalPressTileEntity extends BasinOperatingTileEntity { - private static Object compressingRecipesKey = new Object(); + private static final Object compressingRecipesKey = new Object(); public List pressedItems = new ArrayList<>(); public static class PressingInv extends RecipeWrapper { @@ -55,12 +55,12 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { float headOffset; - private Mode(float headOffset) { + Mode(float headOffset) { this.headOffset = headOffset; } } - private static PressingInv pressingInv = new PressingInv(); + private static final PressingInv pressingInv = new PressingInv(); public BeltProcessingBehaviour processingBehaviour; public int runningTicks; @@ -128,10 +128,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { float num = (runningTicks - 1 + partialTicks) / 30f; return MathHelper.clamp(num * num * num, 0, mode.headOffset); } - if (runningTicks >= 40) { - return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0, - mode.headOffset); - } + return MathHelper.clamp(((60 - runningTicks) + 1 - partialTicks) / 20f * mode.headOffset, 0, + mode.headOffset); } return 0; } @@ -148,10 +146,6 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { return mode == Mode.WORLD; } - public boolean onBelt() { - return mode == Mode.BELT; - } - public boolean onBasin() { return mode == Mode.BASIN; } @@ -160,7 +154,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { public void tick() { super.tick(); - if (!running) + if (!running || world == null) return; if (runningTicks == 30) { @@ -190,8 +184,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { if (!world.isRemote) { pressedItems.clear(); applyBasinRecipe(); - IItemHandler orElse = basinInv.orElse(null); - if (basinInv.isPresent() && orElse instanceof BasinInventory) { + IItemHandler orElse = basinItemInv.orElse(null); + if (basinItemInv.isPresent() && orElse instanceof BasinInventory) { BasinInventory inv = (BasinInventory) orElse; for (int slot = 0; slot < inv.getInputHandler() @@ -256,7 +250,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { } public void makePressingParticleEffect(Vec3d pos, ItemStack stack) { - if (world.isRemote) { + if (world != null && world.isRemote) { for (int i = 0; i < 20; i++) { Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .125f) .mul(1, 0, 1); @@ -267,7 +261,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { } public void makeCompactingParticleEffect(Vec3d pos, ItemStack stack) { - if (world.isRemote) { + if (world != null && world.isRemote) { for (int i = 0; i < 20; i++) { Vec3d motion = VecHelper.offsetRandomly(Vec3d.ZERO, world.rand, .175f) .mul(1, 0, 1); @@ -279,9 +273,8 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { public Optional getRecipe(ItemStack item) { pressingInv.setInventorySlotContents(0, item); - Optional recipe = world.getRecipeManager() + return world.getRecipeManager() .getRecipe(AllRecipeTypes.PRESSING.getType(), pressingInv, world); - return recipe; } public static boolean canCompress(NonNullList ingredients) { @@ -305,7 +298,7 @@ public class MechanicalPressTileEntity extends BasinOperatingTileEntity { return false; List remaining = new ArrayList<>(); - inputs.forEach(stack -> remaining.add(stack.copy())); + inputs.forEachItemStack(stack -> remaining.add(stack.copy())); Ingredients: for (Ingredient ingredient : ingredients) { for (ItemStack stack : remaining) { diff --git a/src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java b/src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java new file mode 100644 index 000000000..8d62457ea --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/fluids/CombinedFluidHandler.java @@ -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 fluidStackConsumer) { + Arrays.stream(tanks) + .forEach(fluidStackConsumer::accept); + } +} diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java index cd43ee148..bc1c0d703 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinBlock.java @@ -43,7 +43,7 @@ public class BasinBlock extends Block implements ITE, IWrenchab public TileEntity createTileEntity(BlockState state, IBlockReader world) { return AllTileEntities.BASIN.create(); } - + @Override public ActionResultType onWrenched(BlockState state, ItemUseContext context) { return ActionResultType.FAIL; @@ -51,8 +51,9 @@ public class BasinBlock extends Block implements ITE, IWrenchab @Override public ActionResultType onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity player, Hand handIn, - BlockRayTraceResult hit) { - if (!player.getHeldItem(handIn).isEmpty()) + BlockRayTraceResult hit) { + if (!player.getHeldItem(handIn) + .isEmpty()) return ActionResultType.PASS; try { @@ -63,7 +64,8 @@ public class BasinBlock extends Block implements ITE, IWrenchab inv.setStackInSlot(slot, ItemStack.EMPTY); } te.onEmptied(); - } catch (TileEntityException e) {} + } catch (TileEntityException e) { + } return ActionResultType.SUCCESS; } @@ -79,15 +81,15 @@ public class BasinBlock extends Block implements ITE, IWrenchab return; ItemEntity itemEntity = (ItemEntity) entityIn; 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()) { itemEntity.remove(); if (!itemEntity.world.isRemote) - AllTriggers - .triggerForNearbyPlayers(AllTriggers.BASIN_THROW, itemEntity.world, - itemEntity.getPosition(), 3); + AllTriggers.triggerForNearbyPlayers(AllTriggers.BASIN_THROW, itemEntity.world, + itemEntity.getPosition(), 3); return; } @@ -107,8 +109,8 @@ public class BasinBlock extends Block implements ITE, IWrenchab } withTileEntityDo(worldIn, pos, te -> { - ItemHelper.dropContents(worldIn, pos, te.inputInventory); - ItemHelper.dropContents(worldIn, pos, te.outputInventory); + ItemHelper.dropContents(worldIn, pos, te.inputItemInventory); + ItemHelper.dropContents(worldIn, pos, te.outputItemInventory); }); worldIn.removeTileEntity(pos); } @@ -121,8 +123,9 @@ public class BasinBlock extends Block implements ITE, IWrenchab @Override public int getComparatorInputOverride(BlockState blockState, World worldIn, BlockPos pos) { try { - return ItemHelper.calcRedstoneFromInventory(getTileEntity(worldIn, pos).inputInventory); - } catch (TileEntityException e) {} + return ItemHelper.calcRedstoneFromInventory(getTileEntity(worldIn, pos).inputItemInventory); + } catch (TileEntityException e) { + } return 0; } diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java index 121b3e6f4..492c3f106 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinOperatingTileEntity.java @@ -7,6 +7,7 @@ import java.util.stream.Collectors; import com.simibubi.create.AllTileEntities; 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.foundation.advancement.AllTriggers; import com.simibubi.create.foundation.advancement.SimpleTrigger; @@ -22,6 +23,8 @@ import net.minecraft.tileentity.TileEntity; import net.minecraft.tileentity.TileEntityType; import net.minecraft.util.NonNullList; 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.IItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; @@ -32,8 +35,9 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { public DeferralBehaviour basinChecker; public boolean basinRemoved; protected IRecipe lastRecipe; - protected LazyOptional basinInv = LazyOptional.empty(); - protected List inputs; + protected LazyOptional basinItemInv = LazyOptional.empty(); + protected LazyOptional basinFluidInv = LazyOptional.empty(); + protected MultiIngredientTypeList inputs; public BasinOperatingTileEntity(TileEntityType typeIn) { super(typeIn); @@ -55,17 +59,19 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { } public void gatherInputs() { - if (!basinInv.isPresent()) - return; - BasinInventory inv = (BasinInventory) basinInv.orElse(null); - inputs = new ArrayList<>(); - IItemHandlerModifiable inputHandler = inv.getInputHandler(); - for (int slot = 0; slot < inputHandler.getSlots(); ++slot) { - ItemStack itemstack = inputHandler.extractItem(slot, inputHandler.getSlotLimit(slot), true); - if (!itemstack.isEmpty()) { - inputs.add(itemstack); + inputs = new MultiIngredientTypeList(); + + basinItemInv.ifPresent(inv -> { + IItemHandlerModifiable inputHandler = ((BasinInventory) inv).getInputHandler(); + for (int slot = 0; slot < inputHandler.getSlots(); ++slot) { + ItemStack itemstack = inputHandler.extractItem(slot, inputHandler.getSlotLimit(slot), true); + if (!itemstack.isEmpty()) { + inputs.add(itemstack); + } } - } + }); + + basinFluidInv.ifPresent(iFluidHandler -> ((CombinedFluidHandler) iFluidHandler).forEachTank(inputs::add)); } @Override @@ -91,12 +97,16 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { Optional basinTe = getBasin(); if (!basinTe.isPresent()) return true; - if (!basinInv.isPresent()) - basinInv = basinTe.get().getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); - if (!basinInv.isPresent()) + if (!basinItemInv.isPresent()) + basinItemInv = basinTe.get() + .getCapability(CapabilityItemHandler.ITEM_HANDLER_CAPABILITY); + if (!basinFluidInv.isPresent()) + basinFluidInv = basinTe.get() + .getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY); + if (!basinFluidInv.isPresent() || !basinItemInv.isPresent()) return true; - if (world.isRemote) + if (world == null || world.isRemote) return true; gatherInputs(); @@ -112,8 +122,7 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { protected abstract boolean isRunning(); - public void startProcessingBasin() { - } + public void startProcessingBasin() {} public boolean continueWithPreviousRecipe() { return true; @@ -122,12 +131,10 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { public void applyBasinRecipe() { if (lastRecipe == null) return; - if (!basinInv.isPresent()) + if (!basinItemInv.isPresent() || !basinFluidInv.isPresent()) return; - BasinInventory inv = (BasinInventory) basinInv.orElse(null); - if (inv == null) - return; + BasinInventory inv = (BasinInventory) basinItemInv.orElse(null); IItemHandlerModifiable inputs = inv.getInputHandler(); IItemHandlerModifiable outputs = inv.getOutputHandler(); @@ -142,25 +149,29 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { continue; ItemStack extracted = inputs.extractItem(slot, 1, false); if ((lastRecipe instanceof ProcessingRecipe) - && ((ProcessingRecipe) lastRecipe).getRollableIngredients().get(i).remains()) { + && ((ProcessingRecipe) lastRecipe).getRollableIngredients() + .get(i) + .remains()) { catalysts.add(extracted.copy()); } else if (extracted.hasContainerItem()) { - containers.add(extracted.getContainerItem().copy()); + containers.add(extracted.getContainerItem() + .copy()); } continue Ingredients; } // something wasn't found return; } - - if (!world.isRemote) { + + if (world != null && !world.isRemote) { SimpleTrigger trigger = AllTriggers.MIXER_MIX; if (AllTileEntities.MECHANICAL_PRESS.is(this)) trigger = AllTriggers.PRESS_COMPACT; 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)); catalysts.forEach(c -> ItemHandlerHelper.insertItemStacked(outputs, c, false)); @@ -176,9 +187,12 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { protected List> getMatchingRecipes() { List> list = RecipeFinder.get(getRecipeCacheKey(), world, this::matchStaticFilters); - return list.stream().filter(this::matchBasinRecipe) - .sorted((r1, r2) -> -r1.getIngredients().size() + r2.getIngredients().size()) - .collect(Collectors.toList()); + return list.stream() + .filter(this::matchBasinRecipe) + .sorted((r1, r2) -> -r1.getIngredients() + .size() + r2.getIngredients() + .size()) + .collect(Collectors.toList()); } protected void basinRemoved() { @@ -186,6 +200,8 @@ public abstract class BasinOperatingTileEntity extends KineticTileEntity { } protected Optional getBasin() { + if (world == null) + return Optional.empty(); TileEntity basinTE = world.getTileEntity(pos.down(2)); if (!(basinTE instanceof BasinTileEntity)) return Optional.empty(); diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java index 7632d8a11..78f4d7b95 100644 --- a/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/BasinTileEntity.java @@ -3,6 +3,7 @@ package com.simibubi.create.content.contraptions.processing; import java.util.List; 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.TileEntityBehaviour; 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.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.fluids.capability.CapabilityFluidHandler; import net.minecraftforge.items.CapabilityItemHandler; import net.minecraftforge.items.IItemHandlerModifiable; 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.RecipeWrapper; +import javax.annotation.Nonnull; + public class BasinTileEntity extends SmartTileEntity implements ITickableTileEntity { public boolean contentsChanged; - protected ItemStackHandler outputInventory = new ItemStackHandler(9) { + protected ItemStackHandler outputItemInventory = new ItemStackHandler(9) { protected void onContentsChanged(int slot) { sendData(); markDirty(); @@ -35,18 +39,19 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt public class BasinInputInventory extends RecipeWrapper { public BasinInputInventory() { - super(inputInventory); + super(inputItemInventory); } } - protected ItemStackHandler inputInventory = new ItemStackHandler(9) { + protected ItemStackHandler inputItemInventory = new ItemStackHandler(9) { protected void onContentsChanged(int slot) { contentsChanged = true; sendData(); 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++) { ItemStack stackInSlot = getStackInSlot(i); if (ItemHandlerHelper.canItemStacksStack(stack, stackInSlot)) @@ -54,7 +59,7 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt return stack; } return super.insertItem(slot, stack, simulate); - }; + } }; public static class BasinInventory extends CombinedInvWrapper { @@ -62,6 +67,7 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt super(input, output); } + @Nonnull @Override public ItemStack extractItem(int slot, int amount, boolean simulate) { if (isInput(slot)) @@ -69,8 +75,9 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt return super.extractItem(slot, amount, simulate); } + @Nonnull @Override - public ItemStack insertItem(int slot, ItemStack stack, boolean simulate) { + public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) { if (!isInput(slot)) return stack; return super.insertItem(slot, stack, simulate); @@ -91,7 +98,11 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt } protected LazyOptional inventory = - LazyOptional.of(() -> new BasinInventory(inputInventory, outputInventory)); + LazyOptional.of(() -> new BasinInventory(inputItemInventory, outputItemInventory)); + + protected LazyOptional fluidInventory = + LazyOptional.of(() -> new CombinedFluidHandler(9, 1000)); + public BasinInputInventory recipeInventory; public BasinTileEntity(TileEntityType type) { @@ -99,24 +110,28 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt contentsChanged = true; recipeInventory = new BasinInputInventory(); } - + @Override public void addBehaviours(List behaviours) { behaviours.add(new DirectBeltInputBehaviour(this)); } - + @Override public void read(CompoundNBT compound) { super.read(compound); - inputInventory.deserializeNBT(compound.getCompound("InputItems")); - outputInventory.deserializeNBT(compound.getCompound("OutputItems")); + inputItemInventory.deserializeNBT(compound.getCompound("InputItems")); + outputItemInventory.deserializeNBT(compound.getCompound("OutputItems")); + if (compound.hasUniqueId("fluids")) + fluidInventory + .ifPresent(combinedFluidHandler -> combinedFluidHandler.readFromNBT(compound.getList("fluids", 10))); } @Override public CompoundNBT write(CompoundNBT compound) { super.write(compound); - compound.put("InputItems", inputInventory.serializeNBT()); - compound.put("OutputItems", outputInventory.serializeNBT()); + compound.put("InputItems", inputItemInventory.serializeNBT()); + compound.put("OutputItems", outputItemInventory.serializeNBT()); + fluidInventory.ifPresent(combinedFuidHandler -> compound.put("fluids", combinedFuidHandler.getListNBT())); return compound; } @@ -128,13 +143,17 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt public void remove() { onEmptied(); inventory.invalidate(); + fluidInventory.invalidate(); super.remove(); } + @Nonnull @Override - public LazyOptional getCapability(Capability cap, Direction side) { + public LazyOptional getCapability(@Nonnull Capability cap, Direction side) { if (cap == CapabilityItemHandler.ITEM_HANDLER_CAPABILITY) return inventory.cast(); + if (cap == CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY) + return fluidInventory.cast(); return super.getCapability(cap, side); } @@ -147,6 +166,8 @@ public class BasinTileEntity extends SmartTileEntity implements ITickableTileEnt } private Optional getOperator() { + if (world == null) + return Optional.empty(); TileEntity te = world.getTileEntity(pos.up(2)); if (te instanceof BasinOperatingTileEntity) return Optional.of((BasinOperatingTileEntity) te); diff --git a/src/main/java/com/simibubi/create/content/contraptions/processing/MultiIngredientTypeList.java b/src/main/java/com/simibubi/create/content/contraptions/processing/MultiIngredientTypeList.java new file mode 100644 index 000000000..1206bc283 --- /dev/null +++ b/src/main/java/com/simibubi/create/content/contraptions/processing/MultiIngredientTypeList.java @@ -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 itemIngredients = new ArrayList<>(); + private final ArrayList fluidIngredients = new ArrayList<>(); + + public void add(ItemStack itemstack) { + itemIngredients.add(itemstack); + } + + public void add(FluidStack fluidStack) { + fluidIngredients.add(fluidStack); + } + + public void forEachItemStack(Consumer itemStackConsumer) { + itemIngredients.forEach(itemStackConsumer); + } + + public void forEachFluidStack(Consumer fluidStackConsumer) { + fluidIngredients.forEach(fluidStackConsumer); + } +}