User:ChampionAsh5357/Sandbox/Fluids API
In Forge 41.0.28, the Fluid API had been completely overhauled. These changes expanded the system to allow for custom physics logic and additional behavior not tied directly to the water and lava tags. This guide will go through all the changes and additions that Fluids now provide for you to use.
An example of the new fluid system can be found in the test mod.
Quick Guide
This is a quick guide representing the one to one conversions that the Fluid API changed
FluidAttributes
->FluidType
(This is a Forge Registry forge:fluid_type)FluidAttributes#BUCKET_VOLUME
->FluidType#BUCKET_VOLUME
FluidAttributes#getBucket
->FluidType#getBucket
FluidAttributes#getBlock
->FluidType#getBlockForFluidState
FluidAttributes#getStateForPlacement
->FluidType#getStateForPlacement
FluidAttributes#canBePlacedInWorld
->FluidType#canBePlacedInLevel
FluidAttributes#isLighterThanAir
->FluidType#isLighterThanAir
FluidAttributes#doesVaporize
->FluidType#isVaporizedOnPlacement
FluidAttributes#vaporize
->FluidType#onVaporize
FluidAttributes#getDisplayName(FluidStack)
->FluidType#getDescription(FluidStack)
FluidAttributes#getTranslationKey(FluidStack)
->FluidType#getDescriptionId(FluidStack)
FluidAttributes#getTranslationKey
->FluidType#getDescriptionId
FluidAttributes#getLuminosity
->FluidType#getLightLevel
FluidAttributes#getDensity
->FluidType#getDensity
FluidAttributes#getTemperature
->FluidType#getTemperature
FluidAttributes#getViscosity
->FluidType#getViscosity
FluidAttributes#isGaseous
->Tags$Fluids#GASEOUS
FluidAttributes#getRarity
->FluidType#getRarity
FluidAttributes#getColor
->IFluidTypeRenderProperties#getColorTint
FluidAttributes#getStillTexture
->IFluidTypeRenderProperties#getStillTexture
FluidAttributes#getFlowingTexture
->IFluidTypeRenderProperties#getFlowingTexture
FluidAttributes#getOverlayTexture
->IFluidTypeRenderProperties#getOverlayTexture
FluidAttributes#getFillSound
->FluidType#getSound(SoundActions.BUCKET_FILL)
FluidAttributes#getEmptySound
->FluidType#getSound(SoundActions.BUCKET_EMPTY)
FluidAttributes#getLuminosity(FluidStack)
->FluidType#getLightLevel(FluidStack)
FluidAttributes#getDensity(FluidStack)
->FluidType#getDensity(FluidStack)
FluidAttributes#getTemperature(FluidStack)
->FluidType#getTemperature(FluidStack)
FluidAttributes#getViscosity(FluidStack)
->FluidType#getViscosity(FluidStack)
FluidAttributes#isGaseous(FluidStack)
-> REMOVEDFluidAttributes#getColor(FluidStack)
->IFluidTypeRenderProperties#getColorTint(FluidStack)
FluidAttributes#getStillTexture(FluidStack)
->IFluidTypeRenderProperties#getStillTexture(FluidStack)
FluidAttributes#getFlowingTexture(FluidStack)
->IFluidTypeRenderProperties#getFlowingTexture(FluidStack)
FluidAttributes#getFillSound(FluidStack)
->FluidType#getSound(FluidStack, SoundActions.BUCKET_FILL
FluidAttributes#getEmptySound(FluidStack)
->FluidType#getSound(FluidStack, SoundActions.BUCKET_EMPTY)
FluidAttributes#getLuminosity(BlockAndTintGetter, BlockPos)
->FluidType#getLightLevel(FluidState, BlockAndTintGetter, BlockPos)
FluidAttributes#getDensity(BlockAndTintGetter, BlockPos)
->FluidType#getDensity(FluidState, BlockAndTintGetter, BlockPos)
FluidAttributes#getTemperature(BlockAndTintGetter, BlockPos)
->FluidType#getTemperature(FluidState, BlockAndTintGetter, BlockPos)
FluidAttributes#getViscosity(BlockAndTintGetter, BlockPos)
->FluidType#getViscosity(FluidState, BlockAndTintGetter, BlockPos)
FluidAttributes#isGaseous(BlockAndTintGetter, BlockPos)
-> REMOVEDFluidAttributes#getRarity(BlockAndTintGetter, BlockPos)
-> REMOVEDFluidAttributes#getColor(BlockAndTintGetter, BlockPos)
->FluidType#getColorTint(FluidState, BlockAndTintGetter, BlockPos)
FluidAttributes#getStillTexture(BlockAndTintGetter, BlockPos)
->FluidType#getStillTexture(FluidState, BlockAndTintGetter, BlockPos)
FluidAttributes#getFlowingTexture(BlockAndTintGetter, BlockPos)
->FluidType#getFlowingTexture(FluidState, BlockAndTintGetter, BlockPos)
FluidAttributes#getFillSound(BlockAndTintGetter, BlockPos)
->FluidType#getSound(Player, BlockGetter, BlockPos, SoundActions.BUCKET_FILL)
FluidAttributes#getEmptySound(BlockAndTintGetter, BlockPos)
->FluidType#getSound(Player, BlockGetter, BlockPos, SoundActions.BUCKET_EMPTY)
FluidAttributes#getTextures
->IFluidTypeRenderProperties#getTextures
FluidAttributes$Builder
->FluidType$Properties
IForgeBlock#getAiPathNodeType
->IForgeBlock#getBlockPathType
IForgeEntity#canBeRiddenInWater
->IForgeEntity#canBeRiddenUnderFluidType
IForgeFluid#isEntityInside
-> REMOVEDIForgeFluid#isAABBInsideMaterial
-> REMOVEDIForgeFluid#getAttributes
->IForgeFluid#getFluidType
IForgeFluidState#isEntityInside
-> REMOVEDForgeFlowingFluid$Properties(Fluid, Fluid, FluidAttributes)
->ForgeFlowingFluid$Properties(FluidType, Fluid, Fluid)
ForgeFlowingFluid#canMultiply
->FluidType#canConvertToSource(FluidState, LevelReader, BlockPos)
Vanilla Breaking Change: No Physics in Tags
One of the largest changes within the Fluid API is that Fluid Tags no longer control the physics of fluids. To account for this, a different unifying object which can represent any group of fluids must be chosen. After much consideration, this became FluidType
, which replaced FluidAttributes
.
Removal of FluidAttributes
FluidAttributes
has been completely removed with most of its logic being delegated to either FluidType
or IFluidTypeRenderProperties
for rendering. The object itself wasn't unique and tended to be reconstructed whenever referenced. As such, it was removed in favor of a more singleton approach.
FluidType
FluidType
replaces FluidAttributes
. All fluids must override IForgeFluid#getFluidType
similar to the previous #getAttributes
. Additionally, the FluidType
can be accessed from the fluid or fluid state for convenience.
private static final DeferredRegister<Fluid> FLUIDS = DeferredRegister.create(ForgeRegistries.FLUIDS, ID); // TestFluid extends FlowingFluid private static final RegistryObject<FlowingFluid> TEST_FLUID = FLUIDS.register("test_fluid", () -> new TestFluid() { @Override public FluidType getFluidType() { return TEST_FLUID_TYPE.get(); } });
FluidType
is a forge registry, and as such needs to be registered. If using DeferredRegister
, you must use the one that takes in the registry name and modid since the registry does not exist during mod construction.
private static final DeferredRegister<FluidType> FLUID_TYPES = DeferredRegister.create(ForgeRegistries.Keys.FLUID_TYPES, ID); private static final RegistryObject<FluidType> TEST_FLUID_TYPE = FLUID_TYPES.register("test_fluid", () -> new FluidType(FluidType.Properties.create()));
isVaporizedOnPlacement
FluidType#isVaporizedOnPlacement
has now been expanded to allow for vaporization to occur outside of only ultra warm dimensions. To do so, simply override the method.
IFluidTypeRenderProperties
IFluidTypeRenderProperties
contains all rendering related logic to fluids. This includes the color tint, still texture, flowing texture, and overlay texture. Note that the still texture and flowing texture must be specified by overriding #getStillTexture
and #getFlowingTexture
respectively.
Modified Accessors
All properties in FluidType
and IFluidTypeRenderProperties
have either an entity, level, or stack based accessor attached to it. These provide context in question if the behavior of the fluid should change in relation to the entity its acting upon, the location of the fluid in the level, or the containing fluid stack respectively.
There are some accessors with no parameters. These are typically because the use case may not be fully defined in every context that are available to the modder. They should not be used whenever possible as they may be removed in future releases once the context has been fully specified.
Chained Methods
A good portion of the accessors in FluidType
are chained in some capacity. This means that modders who are using fluids from other mods can specify unique behavior without having to modify the fluid itself. Let's take two examples: #canHydrate(Level Accessor)
and #supportsBoating
.
#canHydrate
can be modified by the FluidType
, Fluid
, or Block
. This means that the FluidType
can define general behavior to use while the Block
may define specific behavior for if it can be hydrated.
#supportsBoating
works similarly with FluidType
and Boat
. The FluidType
can define in general if boats should work on it while a specific Boat
can determine whether it actually can float on the fluid.
Entity Pathing
Entity pathing can now be specified for a given block or the underlying fluid using IForgeBlock#getBlockPathType
, IForgeBlock#getAdjacentBlockPathType
, FluidType#getBlockPathType
, and FluidType#getAdjacentBlockPathType
. For clarity, the regular block path type gets the raw type to be used if the adjacents are not specified. The adjacent path type specifically determines which one the entity will move to and will either default to OPEN
, WALKABLE
or BLOCKED
internally. Typically, the entity will pathfind to the smallest positive malus of the type, where negative numbers are considered intraversable. Additional types can be created using BlockPathTypes#create
.
IForgeEntity
IForgeEntity
now contains many additional commands to handle fluid physics logic. These include the height, which fluid the entity's eyes are in, and if an entity is in a fluid type. All of these methods are properly documented in the extension. Note that these replace their vanilla counterparts and should be used instead.
IForgeLivingEntity
IForgeLivingEntity
contains two unique fluid logic handlers: how an entity "jumps" in a fluid, and how they "sink". These methods can currently only be overridden on an entity and not by the FluidType
.
SoundAction
SoundAction
is the abstracted sound manager for defining which sound to play in a given context. It works exactly like ToolAction
where it simply defines a unique name that performs a given action. A new action can be created using SoundAction#get
. Vanilla actions are defined within SoundActions
(filling/empty bucket, vaporizing).
Fluid Interactions
Fluid interactions are handled by the FluidInteractionRegistry
. Interactions define the behavior a block should handle in all directions besides down. The down direction must be defined by the fluid in FlowingFluid#spreadTo
, and will not be considered in this registry. An interaction can be registered using #addInteraction
in FMLCommonSetupEvent
by specifying the source of the interaction (which is typically the fluid being replaced), and the interaction information which defines the conditions of when the interaction should occur and what the interaction should do.
private void commonSetup(FMLCommonSetupEvent event) {
// Test Fluid + Lava (source/flowing) -> Gold Block (Test fluid source/flowing gets replaced) FluidInteractionRegistry.addInteraction(TEST_FLUID_TYPE.get(), new FluidInteractionRegistry.InteractionInformation(ForgeMod.LAVA_TYPE.get(), Blocks.GOLD_BLOCK.defaultBlockState()));
}
Gaseous Fluids
A Fluid
is considered gaseous at room temperature if it is in the forge:gaseous
tag. This is typically correlated with a negative density.