(Sp)out of order

- Added behavioural registry for Spout/Block interaction
- Fixed and Refactored TiCon Casting via Spout
- Fixed fluid pipes getting stuck trying to waterlog non-solid blocks with fluid handling capabilities
- Fixed modlist lookup for non-english locales
This commit is contained in:
simibubi 2021-08-25 13:46:53 +02:00
parent f0736bdc41
commit 925c98792f
14 changed files with 190 additions and 116 deletions

View file

@ -155,8 +155,8 @@ dependencies {
// i'll leave this here commented for easier testing
//runtimeOnly fg.deobf("vazkii.arl:AutoRegLib:1.4-35.69")
//runtimeOnly fg.deobf("vazkii.quark:Quark:r2.0-212.984")
//runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.103")
//runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.0.3.168")
//runtimeOnly fg.deobf("slimeknights.mantle:Mantle:1.16.5-1.6.115")
//runtimeOnly fg.deobf("slimeknights.tconstruct:TConstruct:1.16.5-3.1.1.252")
annotationProcessor 'org.spongepowered:mixin:0.8.2:processor'
}

View file

@ -4,7 +4,7 @@ org.gradle.jvmargs = -Xmx3G
org.gradle.daemon = false
# mod version info
mod_version = 0.3.2d
mod_version = 0.3.2e
minecraft_version = 1.16.5
forge_version = 36.2.0

View file

@ -10,6 +10,7 @@ import com.google.gson.GsonBuilder;
import com.simibubi.create.content.CreateItemGroup;
import com.simibubi.create.content.contraptions.TorquePropagator;
import com.simibubi.create.content.contraptions.components.structureMovement.train.capability.CapabilityMinecartController;
import com.simibubi.create.content.contraptions.fluids.actors.BlockSpoutingBehaviour;
import com.simibubi.create.content.curiosities.weapons.PotatoCannonProjectileTypes;
import com.simibubi.create.content.logistics.RedstoneLinkNetworkHandler;
import com.simibubi.create.content.palettes.AllPaletteBlocks;
@ -58,7 +59,7 @@ public class Create {
public static final String ID = "create";
public static final String NAME = "Create";
public static final String VERSION = "0.3.2d";
public static final String VERSION = "0.3.2e";
public static final Logger LOGGER = LogManager.getLogger();
@ -92,6 +93,7 @@ public class Create {
AllWorldFeatures.register();
AllEnchantments.register();
AllConfigs.register(ModLoadingContext.get());
BlockSpoutingBehaviour.register();
ForgeMod.enableMilkFluid();

View file

@ -3,13 +3,16 @@ package com.simibubi.create.compat;
import java.util.Optional;
import java.util.function.Supplier;
import com.simibubi.create.foundation.utility.Lang;
import net.minecraftforge.fml.ModList;
/**
* For compatibility with and without another mod present, we have to define load conditions of the specific code
*/
public enum Mods {
DYNAMICTREES;
DYNAMICTREES,
TCONSTRUCT;
/**
* @return a boolean of whether the mod is loaded or not based on mod id
@ -22,7 +25,7 @@ public enum Mods {
* @return the mod id
*/
public String asId() {
return name().toLowerCase();
return Lang.asId(name());
}
/**

View file

@ -0,0 +1,72 @@
package com.simibubi.create.compat.tconstruct;
import com.simibubi.create.compat.Mods;
import com.simibubi.create.content.contraptions.fluids.actors.BlockSpoutingBehaviour;
import com.simibubi.create.content.contraptions.fluids.actors.SpoutTileEntity;
import com.simibubi.create.foundation.config.AllConfigs;
import com.simibubi.create.foundation.fluid.FluidHelper;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.Direction;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler.FluidAction;
public class SpoutCasting extends BlockSpoutingBehaviour {
static Boolean TICON_PRESENT = null;
ResourceLocation TABLE = new ResourceLocation("tconstruct", "table");
ResourceLocation BASIN = new ResourceLocation("tconstruct", "basin");
@Override
public int fillBlock(World level, BlockPos pos, SpoutTileEntity spout, FluidStack availableFluid,
boolean simulate) {
if (!enabled())
return 0;
TileEntity te = level.getBlockEntity(pos);
if (te == null)
return 0;
IFluidHandler handler = te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, Direction.UP)
.orElse(null);
if (handler == null)
return 0;
if (handler.getTanks() != 1)
return 0;
ResourceLocation registryName = te.getType()
.getRegistryName();
if (!registryName.equals(TABLE) && !registryName.equals(BASIN))
return 0;
if (!handler.isFluidValid(0, availableFluid))
return 0;
FluidStack containedFluid = handler.getFluidInTank(0);
if (!(containedFluid.isEmpty() || containedFluid.isFluidEqual(availableFluid)))
return 0;
// Do not fill if it would only partially fill the table (unless > 1000mb)
int amount = availableFluid.getAmount();
if (amount < 1000
&& handler.fill(FluidHelper.copyStackWithAmount(availableFluid, amount + 1), FluidAction.SIMULATE) > amount)
return 0;
// Return amount filled into the table/basin
return handler.fill(availableFluid, simulate ? FluidAction.SIMULATE : FluidAction.EXECUTE);
}
private boolean enabled() {
if (TICON_PRESENT == null)
TICON_PRESENT = Mods.TCONSTRUCT.isLoaded();
if (!TICON_PRESENT)
return false;
return AllConfigs.SERVER.recipes.allowCastingBySpout.get();
}
}

View file

@ -161,6 +161,8 @@ public class FluidPropagator {
return true;
if (BlockHelper.hasBlockSolidSide(connectedState, reader, connectedPos, side.getOpposite()))
return false;
if (hasFluidCapability(reader, connectedPos, side.getOpposite()))
return false;
if (!(connectedState.getMaterial()
.isReplaceable() && connectedState.getDestroySpeed(reader, connectedPos) != -1)
&& !connectedState.hasProperty(BlockStateProperties.WATERLOGGED))

View file

@ -0,0 +1,51 @@
package com.simibubi.create.content.contraptions.fluids.actors;
import java.util.HashMap;
import java.util.function.Consumer;
import com.simibubi.create.Create;
import com.simibubi.create.compat.tconstruct.SpoutCasting;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.fluids.FluidStack;
public abstract class BlockSpoutingBehaviour {
private static final HashMap<ResourceLocation, BlockSpoutingBehaviour> BLOCK_SPOUTING_BEHAVIOURS = new HashMap<>();
public static void addCustomSpoutInteraction(ResourceLocation resourceLocation,
BlockSpoutingBehaviour movementBehaviour) {
BLOCK_SPOUTING_BEHAVIOURS.put(resourceLocation, movementBehaviour);
}
public static void forEach(Consumer<? super BlockSpoutingBehaviour> accept) {
BLOCK_SPOUTING_BEHAVIOURS.values()
.forEach(accept);
}
/**
* While idle, Spouts will call this every tick with simulate == true <br>
* When fillBlock returns &gt; 0, the Spout will start its animation cycle <br>
* <br>
* During this animation cycle, fillBlock is called once again with simulate == false but only on the relevant SpoutingBehaviour <br>
* When fillBlock returns &gt; 0 once again, the Spout will drain its content by the returned amount of units <br>
* Perform any other side-effects in this method <br>
* This method is called server-side only (except in ponder) <br>
*
* @param world
* @param pos of the affected block
* @param spout
* @param availableFluid do not modify, return the amount to be subtracted instead
* @param simulate whether the spout is testing or actually performing this behaviour
* @return amount filled into the block, 0 to idle/cancel
*/
public abstract int fillBlock(World world, BlockPos pos, SpoutTileEntity spout, FluidStack availableFluid,
boolean simulate);
public static void register() {
addCustomSpoutInteraction(Create.asResource("ticon_casting"), new SpoutCasting());
}
}

View file

@ -13,7 +13,6 @@ import net.minecraft.item.MilkBucketItem;
import net.minecraft.potion.PotionUtils;
import net.minecraft.potion.Potions;
import net.minecraft.world.World;
import net.minecraftforge.common.ForgeMod;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;

View file

@ -39,6 +39,7 @@ public class SpoutRenderer extends SafeTileEntityRenderer<SpoutTileEntity> {
.getValue(partialTicks);
if (!fluidStack.isEmpty() && level != 0) {
level = Math.max(level, 0.175f);
float min = 2.5f / 16f;
float max = min + (11 / 16f);
float yOffset = (11 / 16f) * level;
@ -49,8 +50,8 @@ public class SpoutRenderer extends SafeTileEntityRenderer<SpoutTileEntity> {
ms.popPose();
}
int processingTicks = te.getCorrectedProcessingTicks();
float processingPT = te.getCorrectedProcessingTicks() - partialTicks;
int processingTicks = te.processingTicks;
float processingPT = processingTicks - partialTicks;
float processingProgress = 1 - (processingPT - 5) / 10;
processingProgress = MathHelper.clamp(processingProgress, 0, 1);
float radius = 0;

View file

@ -6,12 +6,11 @@ import static com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProce
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Nullable;
import com.simibubi.create.content.contraptions.fluids.FluidFX;
import com.simibubi.create.content.contraptions.goggles.IHaveGoggleInformation;
import com.simibubi.create.content.contraptions.relays.belt.transport.TransportedItemStack;
import com.simibubi.create.foundation.advancement.AllTriggers;
import com.simibubi.create.foundation.fluid.FluidHelper;
import com.simibubi.create.foundation.tileEntity.SmartTileEntity;
import com.simibubi.create.foundation.tileEntity.TileEntityBehaviour;
import com.simibubi.create.foundation.tileEntity.behaviour.belt.BeltProcessingBehaviour;
@ -27,11 +26,9 @@ import net.minecraft.item.PotionItem;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.particles.IParticleData;
import net.minecraft.potion.PotionUtils;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityType;
import net.minecraft.util.Direction;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.util.text.ITextComponent;
import net.minecraftforge.api.distmarker.Dist;
@ -40,28 +37,15 @@ import net.minecraftforge.common.capabilities.Capability;
import net.minecraftforge.common.util.LazyOptional;
import net.minecraftforge.fluids.FluidStack;
import net.minecraftforge.fluids.capability.CapabilityFluidHandler;
import net.minecraftforge.fluids.capability.IFluidHandler;
import net.minecraftforge.fml.ModList;
public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInformation {
private static final boolean IS_TIC_LOADED = ModList.get().isLoaded("tconstruct");
private static final Class<?> CASTING_FLUID_HANDLER_CLASS;
static {
Class<?> testClass;
try {
testClass = Class.forName("slimeknights.tconstruct.library.smeltery.CastingFluidHandler");
} catch (ClassNotFoundException e) {
testClass = null;
}
CASTING_FLUID_HANDLER_CLASS = testClass;
}
public static final int FILLING_TIME = 20;
protected BeltProcessingBehaviour beltProcessing;
protected int processingTicks;
protected boolean sendSplash;
private boolean shouldAnimate = true;
public int processingTicks;
public boolean sendSplash;
public BlockSpoutingBehaviour customProcess;
SmartFluidTankBehaviour tank;
@ -104,7 +88,6 @@ public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInfor
protected ProcessingResult whenItemHeld(TransportedItemStack transported,
TransportedItemStackHandlerBehaviour handler) {
shouldAnimate = true;
if (processingTicks != -1 && processingTicks != 5)
return HOLD;
if (!FillingBySpout.canItemBeFilled(level, transported.stack))
@ -149,59 +132,6 @@ public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInfor
return HOLD;
}
private void processTicCastBlock() {
if (!IS_TIC_LOADED || CASTING_FLUID_HANDLER_CLASS == null)
return;
if (level == null)
return;
IFluidHandler localTank = this.tank.getCapability()
.orElse(null);
if (localTank == null)
return;
FluidStack fluid = getCurrentFluidInTank();
if (fluid.getAmount() == 0)
return;
TileEntity te = level.getBlockEntity(worldPosition.below(2));
if (te == null)
return;
IFluidHandler handler = getFluidHandler(worldPosition.below(2), Direction.UP);
if (!CASTING_FLUID_HANDLER_CLASS.isInstance(handler))
return;
if (handler.getTanks() != 1)
return;
if (!handler.isFluidValid(0, this.getCurrentFluidInTank()))
return;
FluidStack containedFluid = handler.getFluidInTank(0);
if (!(containedFluid.isEmpty() || containedFluid.isFluidEqual(fluid)))
return;
if (processingTicks == -1) {
processingTicks = FILLING_TIME;
notifyUpdate();
return;
}
FluidStack drained = localTank.drain(144, IFluidHandler.FluidAction.SIMULATE);
if (!drained.isEmpty()) {
int filled = handler.fill(drained, IFluidHandler.FluidAction.SIMULATE);
shouldAnimate = filled > 0;
sendSplash = shouldAnimate;
if (processingTicks == 5) {
if (filled > 0) {
drained = localTank.drain(filled, IFluidHandler.FluidAction.EXECUTE);
if (!drained.isEmpty()) {
FluidStack fillStack = drained.copy();
fillStack.setAmount(Math.min(drained.getAmount(), 6));
drained.shrink(filled);
fillStack.setAmount(filled);
handler.fill(fillStack, IFluidHandler.FluidAction.EXECUTE);
}
}
tank.getPrimaryHandler()
.setFluid(fluid);
this.notifyUpdate();
}
}
}
private FluidStack getCurrentFluidInTank() {
return tank.getPrimaryHandler()
.getFluid();
@ -239,10 +169,36 @@ public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInfor
public void tick() {
super.tick();
processTicCastBlock();
if (processingTicks >= 0)
FluidStack currentFluidInTank = getCurrentFluidInTank();
if (processingTicks == -1 && (isVirtual() || !level.isClientSide()) && !currentFluidInTank.isEmpty()) {
BlockSpoutingBehaviour.forEach(behaviour -> {
if (customProcess != null)
return;
if (behaviour.fillBlock(level, worldPosition.below(2), this, currentFluidInTank, true) > 0) {
processingTicks = FILLING_TIME;
customProcess = behaviour;
notifyUpdate();
}
});
}
if (processingTicks >= 0) {
processingTicks--;
if (processingTicks >= 8 && level.isClientSide && shouldAnimate)
if (processingTicks == 5 && customProcess != null) {
int fillBlock = customProcess.fillBlock(level, worldPosition.below(2), this, currentFluidInTank, false);
customProcess = null;
if (fillBlock > 0) {
tank.getPrimaryHandler()
.setFluid(FluidHelper.copyStackWithAmount(currentFluidInTank,
currentFluidInTank.getAmount() - fillBlock));
sendSplash = true;
notifyUpdate();
}
}
}
if (processingTicks >= 8 && level.isClientSide)
spawnProcessingParticles(tank.getPrimaryTank()
.getRenderedFluid());
}
@ -271,25 +227,9 @@ public class SpoutTileEntity extends SmartTileEntity implements IHaveGoggleInfor
}
}
@Nullable
private IFluidHandler getFluidHandler(BlockPos pos, Direction direction) {
if (this.level == null) {
return null;
} else {
TileEntity te = this.level.getBlockEntity(pos);
return te != null ? te.getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY, direction)
.orElse(null) : null;
}
}
public int getCorrectedProcessingTicks() {
if (shouldAnimate)
return processingTicks;
return -1;
}
@Override
public boolean addToGoggleTooltip(List<ITextComponent> tooltip, boolean isPlayerSneaking) {
return containedFluidTooltip(tooltip, isPlayerSneaking, getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY));
return containedFluidTooltip(tooltip, isPlayerSneaking,
getCapability(CapabilityFluidHandler.FLUID_HANDLER_CAPABILITY));
}
}

View file

@ -12,6 +12,7 @@ public class CRecipes extends ConfigBase {
b(false, "allowBiggerFireworksInCrafter", Comments.allowBiggerFireworksInCrafter);
public ConfigBool allowStonecuttingOnSaw = b(true, "allowStonecuttingOnSaw", Comments.allowStonecuttingOnSaw);
public ConfigBool allowWoodcuttingOnSaw = b(true, "allowWoodcuttingOnSaw", Comments.allowWoodcuttingOnSaw);
public ConfigBool allowCastingBySpout = b(true, "allowCastingBySpout", Comments.allowCastingBySpout);
public ConfigInt lightSourceCountForRefinedRadiance =
i(10, 1, "lightSourceCountForRefinedRadiance", Comments.refinedRadiance);
public ConfigBool enableRefinedRadianceRecipe =
@ -24,20 +25,22 @@ public class CRecipes extends ConfigBase {
}
private static class Comments {
static String bulkPressing = "When true, allows the Mechanical Press to process entire stacks at a time.";
static String bulkCutting = "When true, allows the Mechanical Saw to process entire stacks at a time.";
static String bulkPressing = "Allow the Mechanical Press to process entire stacks at a time.";
static String bulkCutting = "Allow the Mechanical Saw to process entire stacks at a time.";
static String allowShapelessInMixer =
"When true, allows any shapeless crafting recipes to be processed by a Mechanical Mixer + Basin.";
"Allow allows any shapeless crafting recipes to be processed by a Mechanical Mixer + Basin.";
static String allowShapedSquareInPress =
"When true, allows any single-ingredient 2x2 or 3x3 crafting recipes to be processed by a Mechanical Press + Basin.";
"Allow any single-ingredient 2x2 or 3x3 crafting recipes to be processed by a Mechanical Press + Basin.";
static String allowRegularCraftingInCrafter =
"When true, allows any standard crafting recipes to be processed by Mechanical Crafters.";
"Allow any standard crafting recipes to be processed by Mechanical Crafters.";
static String allowBiggerFireworksInCrafter =
"When true, allows Firework Rockets with more than 9 ingredients to be crafted using Mechanical Crafters.";
"Allow Firework Rockets with more than 9 ingredients to be crafted using Mechanical Crafters.";
static String allowStonecuttingOnSaw =
"When true, allows any stonecutting recipes to be processed by a Mechanical Saw.";
"Allow any stonecutting recipes to be processed by a Mechanical Saw.";
static String allowWoodcuttingOnSaw =
"When true, allows any Druidcraft woodcutter recipes to be processed by a Mechanical Saw.";
"Allow any Druidcraft woodcutter recipes to be processed by a Mechanical Saw.";
static String allowCastingBySpout =
"Allow Spouts to interact with Casting Tables and Basins from Tinkers' Construct.";
static String refinedRadiance =
"The amount of Light sources destroyed before Chromatic Compound turns into Refined Radiance.";
static String refinedRadianceRecipe = "Allow the standard in-world Refined Radiance recipes.";

View file

@ -54,6 +54,8 @@ public class FluidHelper {
}
public static FluidStack copyStackWithAmount(FluidStack fs, int amount) {
if (amount <= 0)
return FluidStack.EMPTY;
if (fs.isEmpty())
return FluidStack.EMPTY;
FluidStack copy = fs.copy();

View file

@ -45,9 +45,8 @@ public class TreeCutter {
@Nonnull
public static Optional<AbstractBlockBreakQueue> findDynamicTree(Block startBlock, BlockPos pos) {
if (canDynamicTreeCutFrom(startBlock)) {
if (canDynamicTreeCutFrom(startBlock))
return Mods.DYNAMICTREES.runIfInstalled(() -> () -> new DynamicTree(pos));
}
return Optional.empty();
}

View file

@ -5,7 +5,7 @@ license="MIT"
[[mods]]
modId="create"
version="v0.3.2d"
version="v0.3.2e"
displayName="Create"
#updateJSONURL=""
displayURL="https://www.curseforge.com/minecraft/mc-mods/create"