diff --git a/src/main/java/com/simibubi/create/Create.java b/src/main/java/com/simibubi/create/Create.java
index 4477ab56af..31119ef0f9 100644
--- a/src/main/java/com/simibubi/create/Create.java
+++ b/src/main/java/com/simibubi/create/Create.java
@@ -7,7 +7,7 @@ import org.slf4j.Logger;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.mojang.logging.LogUtils;
-import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
+import com.simibubi.create.api.behaviour.spouting.BlockSpoutingBehaviour;
import com.simibubi.create.compat.Mods;
import com.simibubi.create.compat.computercraft.ComputerCraftProxy;
import com.simibubi.create.compat.curios.Curios;
@@ -135,7 +135,6 @@ public class Create {
AllArmInteractionPointTypes.register(modEventBus);
AllFanProcessingTypes.register(modEventBus);
AllItemAttributeTypes.register(modEventBus);
- BlockSpoutingBehaviour.registerDefaults();
// FIXME: some of these registrations are not thread-safe
AllMovementBehaviours.registerDefaults();
@@ -173,6 +172,7 @@ public class Create {
BoilerHeaters.registerDefaults();
AllPortalTracks.registerDefaults();
AllDisplayBehaviours.registerDefaults();
+ BlockSpoutingBehaviour.registerDefaults();
// --
AllAdvancements.register();
diff --git a/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java b/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java
deleted file mode 100644
index f3590e4b0b..0000000000
--- a/src/main/java/com/simibubi/create/api/behaviour/BlockSpoutingBehaviour.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.simibubi.create.api.behaviour;
-
-import com.simibubi.create.Create;
-import com.simibubi.create.compat.tconstruct.SpoutCasting;
-import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
-import com.simibubi.create.impl.behaviour.BlockSpoutingBehaviourImpl;
-
-import net.minecraft.core.BlockPos;
-import net.minecraft.resources.ResourceLocation;
-import net.minecraft.world.level.Level;
-import net.minecraftforge.fluids.FluidStack;
-
-public abstract class BlockSpoutingBehaviour {
- /**
- * Register a new custom spout interaction
- *
- * @param resourceLocation The interaction id
- * @param spoutingBehaviour An instance of your behaviour class
- */
- public static void addCustomSpoutInteraction(ResourceLocation resourceLocation, BlockSpoutingBehaviour spoutingBehaviour) {
- BlockSpoutingBehaviourImpl.addCustomSpoutInteraction(resourceLocation, spoutingBehaviour);
- }
-
- public static void registerDefaults() {
- addCustomSpoutInteraction(Create.asResource("ticon_casting"), new SpoutCasting());
- }
-
- /**
- * While idle, Spouts will call this every tick with simulate == true
- * When fillBlock returns > 0, the Spout will start its animation cycle
- *
- * During this animation cycle, fillBlock is called once again with simulate == false but only on the relevant SpoutingBehaviour
- * When fillBlock returns > 0 once again, the Spout will drain its content by the returned amount of units
- * Perform any other side effects in this method
- * This method is called server-side only (except in ponder)
- *
- * @param level The current level
- * @param pos The position of the affected block
- * @param spout The spout block entity that is calling this
- * @param availableFluid A copy of the fluidStack that is available, modifying this will do nothing, return the amount to be subtracted instead
- * @param simulate Whether the spout is testing or actually performing this behaviour
- * @return The amount filled into the block, 0 to idle/cancel
- */
- public abstract int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate);
-
-}
diff --git a/src/main/java/com/simibubi/create/api/behaviour/spouting/BlockSpoutingBehaviour.java b/src/main/java/com/simibubi/create/api/behaviour/spouting/BlockSpoutingBehaviour.java
new file mode 100644
index 0000000000..f1d9ebe32f
--- /dev/null
+++ b/src/main/java/com/simibubi/create/api/behaviour/spouting/BlockSpoutingBehaviour.java
@@ -0,0 +1,103 @@
+package com.simibubi.create.api.behaviour.spouting;
+
+import java.util.List;
+import java.util.function.Predicate;
+
+import org.jetbrains.annotations.Nullable;
+
+import com.simibubi.create.Create;
+import com.simibubi.create.api.registry.SimpleRegistry;
+import com.simibubi.create.compat.Mods;
+import com.simibubi.create.compat.tconstruct.SpoutCasting;
+import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
+
+import net.minecraft.core.BlockPos;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.FarmBlock;
+import net.minecraft.world.level.block.LayeredCauldronBlock;
+import net.minecraft.world.level.block.entity.BlockEntity;
+import net.minecraft.world.level.block.entity.BlockEntityType;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.Fluid;
+import net.minecraft.world.level.material.Fluids;
+
+import net.minecraftforge.fluids.FluidStack;
+import net.minecraftforge.registries.ForgeRegistries;
+
+/**
+ * Interface for custom block-filling behavior for spouts.
+ *
+ * Behaviors are queried by block first, through {@link #BY_BLOCK}. If no behavior was provided,
+ * they are then queried by block entity type, through {@link #BY_BLOCK_ENTITY}.
+ * @see StateChangingBehavior
+ * @see CauldronSpoutingBehavior
+ */
+@FunctionalInterface
+public interface BlockSpoutingBehaviour {
+ SimpleRegistry
+ * When a value greater than 0 is returned, the spout will begin processing. It will call this method again
+ * with simulate == false, which is when any filling behavior should actually occur.
+ *
+ * This method is only called on the server side, except for in Ponder.
+ * @param level The current level
+ * @param pos The position of the affected block
+ * @param spout The spout block entity that is calling this
+ * @param availableFluid A copy of the fluidStack that is available, modifying this will do nothing, return the amount to be subtracted instead
+ * @param simulate Whether the spout is testing or actually performing this behaviour
+ * @return The amount filled into the block, 0 to idle/cancel
+ */
+ int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate);
+}
diff --git a/src/main/java/com/simibubi/create/api/behaviour/spouting/CauldronSpoutingBehavior.java b/src/main/java/com/simibubi/create/api/behaviour/spouting/CauldronSpoutingBehavior.java
new file mode 100644
index 0000000000..773f5dc2f6
--- /dev/null
+++ b/src/main/java/com/simibubi/create/api/behaviour/spouting/CauldronSpoutingBehavior.java
@@ -0,0 +1,56 @@
+package com.simibubi.create.api.behaviour.spouting;
+
+import com.simibubi.create.api.registry.SimpleRegistry;
+import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
+
+import net.minecraft.Util;
+import net.minecraft.core.BlockPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.Blocks;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.level.material.Fluid;
+import net.minecraft.world.level.material.Fluids;
+
+import net.minecraftforge.fluids.FluidStack;
+
+/**
+ * {@link BlockSpoutingBehaviour} for empty cauldrons. Mods can register their fluids
+ * to {@link #CAULDRON_INFO} to allow spouts to fill empty cauldrons with their fluids.
+ */
+public enum CauldronSpoutingBehavior implements BlockSpoutingBehaviour {
+ INSTANCE;
+
+ public static final SimpleRegistry
* This is used to exclude specific tags that would result in exploits, ex. signs that execute commands when clicked.
*
- * This is provided as an alternative to {@link IPartialSafeNBT}.
+ * This is provided as an alternative to {@link PartialSafeNBT}.
*/
public class SafeNbtWriterRegistry {
public static final SimpleRegistry
* This is provided as an alternative to the following interfaces:
*
- *
*/
public class SchematicRequirementRegistries {
diff --git a/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java b/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java
index 18df35cd14..f777cce56b 100644
--- a/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java
+++ b/src/main/java/com/simibubi/create/compat/tconstruct/SpoutCasting.java
@@ -1,31 +1,25 @@
package com.simibubi.create.compat.tconstruct;
-import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
-import com.simibubi.create.compat.Mods;
+import com.simibubi.create.api.behaviour.spouting.BlockSpoutingBehaviour;
import com.simibubi.create.content.fluids.spout.SpoutBlockEntity;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.infrastructure.config.AllConfigs;
-import net.createmod.catnip.platform.CatnipServices;
+
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
-import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
+
import net.minecraftforge.common.capabilities.ForgeCapabilities;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
-public class SpoutCasting extends BlockSpoutingBehaviour {
-
- private static final boolean TICON_PRESENT = Mods.TCONSTRUCT.isLoaded();
-
- ResourceLocation TABLE = new ResourceLocation("tconstruct", "table");
- ResourceLocation BASIN = new ResourceLocation("tconstruct", "basin");
+public enum SpoutCasting implements BlockSpoutingBehaviour {
+ INSTANCE;
@Override
- public int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid,
- boolean simulate) {
+ public int fillBlock(Level level, BlockPos pos, SpoutBlockEntity spout, FluidStack availableFluid, boolean simulate) {
if (!enabled())
return 0;
@@ -40,9 +34,6 @@ public class SpoutCasting extends BlockSpoutingBehaviour {
if (handler.getTanks() != 1)
return 0;
- ResourceLocation registryName = CatnipServices.REGISTRIES.getKeyOrThrow(blockEntity.getType());
- if (!registryName.equals(TABLE) && !registryName.equals(BASIN))
- return 0;
if (!handler.isFluidValid(0, availableFluid))
return 0;
@@ -61,9 +52,6 @@ public class SpoutCasting extends BlockSpoutingBehaviour {
}
private boolean enabled() {
- if (!TICON_PRESENT)
- return false;
return AllConfigs.server().recipes.allowCastingBySpout.get();
}
-
}
diff --git a/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlockEntity.java b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlockEntity.java
index 76774b1836..03e055c648 100644
--- a/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlockEntity.java
+++ b/src/main/java/com/simibubi/create/content/fluids/spout/SpoutBlockEntity.java
@@ -8,7 +8,7 @@ import java.util.List;
import com.simibubi.create.AllItems;
import com.simibubi.create.AllSoundEvents;
-import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
+import com.simibubi.create.api.behaviour.spouting.BlockSpoutingBehaviour;
import com.simibubi.create.api.equipment.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.fluids.FluidFX;
import com.simibubi.create.content.kinetics.belt.behaviour.BeltProcessingBehaviour;
@@ -22,7 +22,6 @@ import com.simibubi.create.foundation.blockEntity.SmartBlockEntity;
import com.simibubi.create.foundation.blockEntity.behaviour.BlockEntityBehaviour;
import com.simibubi.create.foundation.blockEntity.behaviour.fluid.SmartFluidTankBehaviour;
import com.simibubi.create.foundation.fluid.FluidHelper;
-import com.simibubi.create.impl.behaviour.BlockSpoutingBehaviourImpl;
import net.createmod.catnip.math.VecHelper;
import net.createmod.catnip.nbt.NBTHelper;
@@ -199,15 +198,13 @@ public class SpoutBlockEntity extends SmartBlockEntity implements IHaveGoggleInf
FluidStack currentFluidInTank = getCurrentFluidInTank();
if (processingTicks == -1 && (isVirtual() || !level.isClientSide()) && !currentFluidInTank.isEmpty()) {
- BlockSpoutingBehaviourImpl.forEach(behaviour -> {
- if (customProcess != null)
- return;
- if (behaviour.fillBlock(level, worldPosition.below(2), this, currentFluidInTank.copy(), true) > 0) {
- processingTicks = FILLING_TIME;
- customProcess = behaviour;
- notifyUpdate();
- }
- });
+ BlockPos filling = this.worldPosition.below(2);
+ BlockSpoutingBehaviour behavior = BlockSpoutingBehaviour.get(this.level, filling);
+ if (behavior != null && behavior.fillBlock(this.level, filling, this, currentFluidInTank.copy(), true) > 0) {
+ processingTicks = FILLING_TIME;
+ customProcess = behavior;
+ notifyUpdate();
+ }
}
if (processingTicks >= 0) {
diff --git a/src/main/java/com/simibubi/create/impl/behaviour/BlockSpoutingBehaviourImpl.java b/src/main/java/com/simibubi/create/impl/behaviour/BlockSpoutingBehaviourImpl.java
deleted file mode 100644
index 952a4d9b1d..0000000000
--- a/src/main/java/com/simibubi/create/impl/behaviour/BlockSpoutingBehaviourImpl.java
+++ /dev/null
@@ -1,25 +0,0 @@
-package com.simibubi.create.impl.behaviour;
-
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
-
-import org.jetbrains.annotations.ApiStatus;
-
-import com.simibubi.create.api.behaviour.BlockSpoutingBehaviour;
-
-import net.minecraft.resources.ResourceLocation;
-
-// TODO - Make this use AttachedRegistry later
-@ApiStatus.Internal
-public class BlockSpoutingBehaviourImpl {
- private static final Map