Last active
August 7, 2021 15:08
-
-
Save Lanse505/e95c9da5d97c89d30253597d8c404d40 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Determines whether the entity is able to be pushed by a fluid. | |
* | |
* @param state The fluid pushing the entity | |
* @return If the entity can be pushed, defaults to vanilla behavior for water | |
*/ | |
default boolean isPushedByFluid(FluidState state) | |
{ | |
return !(self() instanceof Player) || !((Player) self()).getAbilities().flying; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.minecraftforge.common.extensions; | |
import net.minecraft.world.entity.LivingEntity; | |
import net.minecraft.world.level.material.FluidState; | |
public interface IForgeLivingEntity { | |
default LivingEntity getLivingEntity() | |
{ | |
return (LivingEntity) this; | |
} | |
/** | |
* Returns whether the {@link LivingEntity} can breathe in the fluid. | |
* | |
* @param state The current {@link FluidState} the entity is within | |
* @return Whether the {@link LivingEntity} can breathe in the fluid | |
*/ | |
default boolean canBreatheInFluid(FluidState state) | |
{ | |
return false; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.minecraftforge.common.extensions; | |
import net.minecraft.world.level.material.FlowingFluid; | |
import net.minecraft.world.level.material.Fluid; | |
import net.minecraft.world.level.material.FluidState; | |
public interface IForgeFlowingFluid extends IForgeFluid | |
{ | |
default FlowingFluid self() | |
{ | |
return (FlowingFluid) this; | |
} | |
/** | |
* Impl Spec of {@link IForgeFluid#is(FluidState, FluidState)} | |
* Used to check if two FluidStates matches each other by comparing the fluid of the state itself. | |
* | |
* @param state The primary state to check | |
* @param otherState The secondary state to check | |
* @return Whether the fluid type of the other fluid matches either the flowing or source type of the first fluidstate. | |
*/ | |
@Override | |
default boolean is(FluidState state, FluidState otherState) | |
{ | |
Fluid otherFluid = otherState.getType(); | |
return otherFluid == self().getFlowing() || otherFluid == self().getSource(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.minecraftforge.common.extensions; | |
import net.minecraft.core.BlockPos; | |
import net.minecraft.tags.SetTag; | |
import net.minecraft.tags.Tag; | |
import net.minecraft.world.entity.Entity; | |
import net.minecraft.world.entity.LivingEntity; | |
import net.minecraft.world.entity.Mob; | |
import net.minecraft.world.entity.vehicle.Boat; | |
import net.minecraft.world.level.BlockGetter; | |
import net.minecraft.world.level.Explosion; | |
import net.minecraft.world.level.Level; | |
import net.minecraft.world.level.LevelReader; | |
import net.minecraft.world.level.block.ConcretePowderBlock; | |
import net.minecraft.world.level.block.FarmBlock; | |
import net.minecraft.world.level.block.SpongeBlock; | |
import net.minecraft.world.level.block.state.BlockState; | |
import net.minecraft.world.level.material.Fluid; | |
import net.minecraft.world.level.material.FluidState; | |
import net.minecraft.world.level.pathfinder.BlockPathTypes; | |
import net.minecraft.world.phys.Vec3; | |
import javax.annotation.Nullable; | |
public interface IForgeFluidState | |
{ | |
private FluidState self() | |
{ | |
return (FluidState)this; | |
} | |
/** | |
* Location sensitive version of getExplosionResistance | |
* | |
* @param world The current world | |
* @param pos Block position in world | |
* @param explosion The explosion | |
* @return The amount of the explosion absorbed. | |
*/ | |
default float getExplosionResistance(BlockGetter world, BlockPos pos, Explosion explosion) | |
{ | |
return self().getType().getExplosionResistance(self(), world, pos, explosion); | |
} | |
/** | |
* Queried for the Fluids Base PathNodeType. | |
* Used to determine what the path node priority value is for the fluid. | |
* <ul> | |
* <li>Negative Values = Untraversable</li> | |
* <li>0 = Best</li> | |
* <li>Highest = Worst</li> | |
* </ul> | |
* @param level The current world's block reader | |
* @param pos The position of the fluid | |
* @return {@code null} for default behavior; otherwise, returns the fluid's PathNodeType for pathfinding purposes | |
*/ | |
@Nullable | |
default BlockPathTypes getPathNodeType(BlockGetter level, BlockPos pos) | |
{ | |
return getPathNodeType(level, pos, null); | |
} | |
/** | |
* Queried for the Fluids Base PathNodeType. | |
* Used to determine what the path node priority value is for the fluid. | |
* <ul> | |
* <li>Negative Values = Untraversable</li> | |
* <li>0 = Best</li> | |
* <li>Highest = Worst</li> | |
* </ul> | |
* @param level The current level's block getter | |
* @param pos The position of the fluid | |
* @param entity The pathing entity, can be null | |
* @return {@code null} for default behavior; otherwise, returns the fluid's PathNodeType for pathfinding purposes | |
*/ | |
@Nullable | |
default BlockPathTypes getPathNodeType(BlockGetter level, BlockPos pos, @Nullable Mob entity) | |
{ | |
return self().getType().getPathNodeType(self(), level, pos, entity); | |
} | |
/** | |
* Gets the {@link BlockPathTypes} of the fluid when adjacent to some pathfinding entity. | |
* <ul> | |
* <li>Negative Values = Untraversable</li> | |
* <li>0 = Best</li> | |
* <li>Highest = Worst</li> | |
* </ul> | |
* @param level The current level's block getter | |
* @param pos The position of the fluid | |
* @param originalType The {@link BlockPathTypes} obtained from {@link IForgeBlock#getAiPathNodeType(BlockState, BlockGetter, BlockPos, Mob)} | |
* @return {@code null} for default behavior; otherwise, returns the fluid's adjacent {@link BlockPathTypes} | |
*/ | |
@Nullable | |
default BlockPathTypes getAdjacentNodeType(BlockGetter level, BlockPos pos, BlockPathTypes originalType) | |
{ | |
return getAdjacentNodeType(level, pos, null, originalType); | |
} | |
/** | |
* Gets the {@link BlockPathTypes} of the fluid when adjacent to some pathfinding entity. | |
* <ul> | |
* <li>Negative Values = Untraversable</li> | |
* <li>0 = Best</li> | |
* <li>Highest = Worst</li> | |
* </ul> | |
* @param level The current level's block getter | |
* @param pos The position of the fluid | |
* @param entity The pathing entity, can be null | |
* @param originalType The {@link BlockPathTypes} obtained from {@link IForgeBlock#getAiPathNodeType(BlockState, BlockGetter, BlockPos, Mob)} | |
* @return {@code null} for default behavior; otherwise, returns the fluid's adjacent {@link BlockPathTypes} | |
*/ | |
@Nullable | |
default BlockPathTypes getAdjacentNodeType(BlockGetter level, BlockPos pos, @Nullable Mob entity, BlockPathTypes originalType) | |
{ | |
return self().getType().getAdjacentNodeType(self(), level, pos, entity, originalType); | |
} | |
/** | |
* Handles acceleration or "pushing" while moving through the fluid. | |
* This implementation is slightly modified default behavior for fluid acceleration, based on {@link Entity#updateFluidHeightAndDoFluidPushing(Tag, double)}. | |
* | |
* @param entity The current {@link Entity} that motion is being applied to | |
* @return Whether the motion was successfully applied to the {@link Entity} | |
*/ | |
default boolean updateFluidHeightAndDoFluidPushing(Entity entity) | |
{ | |
return self().getType().updateFluidHeightAndDoFluidPushing(self(), entity); | |
} | |
/** | |
* Handles "motion" modification for fluids. | |
* Things like slower movement, "swimming" slowdown, etc. | |
* | |
* @param entity The {@link LivingEntity} whose motion is being handled | |
* @param travelVector The current travel {@link Vec3} | |
* @param gravity The current gravity being applied to the {@link LivingEntity} | |
*/ | |
default void handleMotion(LivingEntity entity, Vec3 travelVector, double gravity) | |
{ | |
self().getType().handleMotion(self(), entity, travelVector, gravity); | |
} | |
/** | |
* Handles modification of 'jumps' inside of a fluid. | |
* | |
* @param entity The {@link LivingEntity} whose jump is being modified | |
*/ | |
default void jump(LivingEntity entity) | |
{ | |
self().getType().jump(self(), entity); | |
} | |
/** | |
* Handles modifications of 'sinking' inside of a fluid | |
* | |
* @param entity The {@link LivingEntity} whose jump is being modified | |
*/ | |
default void sink(LivingEntity entity) | |
{ | |
self().getType().sink(self(), entity); | |
} | |
/** | |
* Dictates whether a player can swim in this fluid or not. | |
* Swimming in this case refers the the "sneak" behavior swimming and swimming animation in custom fluids. | |
* | |
* @return Whether a player can "swim" in this fluid | |
*/ | |
default boolean canSwim() | |
{ | |
return self().getType().canSwim(self()); | |
} | |
/** | |
* Dictates whether a {@link LivingEntity} can drown in this fluid or not. | |
* | |
* @param entity The entity within the fluid | |
* @return Whether the {@link LivingEntity} can drown or not | |
*/ | |
default boolean canDrown(LivingEntity entity) | |
{ | |
return self().getType().canDrown(self(), entity); | |
} | |
/** | |
* Dictates whether this {@link FluidState} can provide "hydration" to the provided {@link BlockState} | |
* This is used for checks such as: | |
* - {@link net.minecraft.world.level.block.FarmBlock#isNearWater(LevelReader, BlockPos)} | |
* - {@link net.minecraft.world.level.block.ConcretePowderBlock#touchesLiquid(BlockGetter, BlockPos)} | |
* - {@link net.minecraft.world.level.block.CoralBlock#scanForWater(BlockGetter, BlockPos)} | |
* - {@link net.minecraft.world.level.block.SpongeBlock#tryAbsorbWater(Level, BlockPos)} | |
* - {@link net.minecraft.world.level.block.SugarCaneBlock#canSurvive(BlockState, LevelReader, BlockPos)} | |
* | |
* @param blockState the provided {@link BlockState} | |
* @return Whether the provided {@link FluidState} can provide hydration for the {@link BlockState} | |
*/ | |
default boolean canHydrate(BlockState blockState) | |
{ | |
return self().getType().canHydrate(self(), blockState); | |
} | |
/** | |
* This method is used to handle fluid interactions. | |
* The current position of the fluid is the one that should be replaced during the interaction. | |
* | |
* IE. (Fluid + Catalyst = Result) where the Fluid and Result are in the same position. | |
* Lava(Source/Flowing) + Water = Obsidian/Cobblestone. | |
* Lava(Source/Flowing) + Blue Ice = Basalt. | |
* | |
* @param level The {@link Level} containing the interaction | |
* @param pos The {@link BlockPos} the interaction is being applied at | |
* @return Whether a fluid tick needs to be scheduled. Should return true only if no reaction has occurred or the Result is another fluid. | |
*/ | |
default boolean handleFluidInteraction(Level level, BlockPos pos) | |
{ | |
return self().getType().handleFluidInteraction(self(), level, pos); | |
} | |
/** | |
* This is a checker method to check whether two fluidstates match each other using their Fluid as the reference point. | |
* | |
* @param otherState The secondary state to check | |
* @return Whether the two provided {@link FluidState}s {@link Fluid}s match. | |
*/ | |
default boolean is(FluidState otherState) | |
{ | |
return self().getType().is(self(), otherState); | |
} | |
/** | |
* This method dictates whether this fluid supports boats being "usable" with it. | |
* | |
* @param boat The supplied {@link Boat} entity | |
* @return Whether the fluid supports boats being used with it. | |
*/ | |
default boolean canBoat(Boat boat) | |
{ | |
return self().getType().canBoat(self(), boat); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.minecraftforge.common.extensions; | |
import net.minecraft.core.BlockPos; | |
import net.minecraft.resources.ResourceLocation; | |
import net.minecraft.util.Mth; | |
import net.minecraft.world.effect.MobEffects; | |
import net.minecraft.world.entity.Entity; | |
import net.minecraft.world.entity.LivingEntity; | |
import net.minecraft.world.entity.Mob; | |
import net.minecraft.world.entity.MoverType; | |
import net.minecraft.world.entity.player.Player; | |
import net.minecraft.world.entity.vehicle.Boat; | |
import net.minecraft.world.item.enchantment.Enchantments; | |
import net.minecraft.world.level.BlockGetter; | |
import net.minecraft.world.level.Explosion; | |
import net.minecraft.world.level.Level; | |
import net.minecraft.world.level.LevelReader; | |
import net.minecraft.world.level.block.state.BlockState; | |
import net.minecraft.world.level.material.Fluid; | |
import net.minecraft.world.level.material.FluidState; | |
import net.minecraft.world.level.pathfinder.BlockPathTypes; | |
import net.minecraft.world.phys.AABB; | |
import net.minecraft.world.phys.Vec3; | |
import net.minecraftforge.common.ForgeMod; | |
import net.minecraftforge.fluids.FluidAttributes; | |
import javax.annotation.Nullable; | |
import java.util.Set; | |
public interface IForgeFluid | |
{ | |
/** | |
* Location sensitive version of getExplosionResistance | |
* | |
* @param state the provided {@link FluidState} | |
* @param level the current {@link Level} | |
* @param pos the provided {@link BlockPos} location | |
* @param explosion the occurring {@link Explosion} | |
* @return The amount of the explosion absorbed, defaults to the states getExplosionResistance value. | |
*/ | |
@SuppressWarnings("deprecation") | |
default float getExplosionResistance(FluidState state, BlockGetter level, BlockPos pos, Explosion explosion) | |
{ | |
return state.getExplosionResistance(); | |
} | |
/** | |
* Retrieves a list of tags names this is known to be associated with. | |
* This should be used in favor of TagCollection.getOwningTags, as this caches the result and automatically updates when the TagCollection changes. | |
*/ | |
Set<ResourceLocation> getTags(); | |
/** | |
* Retrieves the non-vanilla fluid attributes. | |
*/ | |
FluidAttributes getAttributes(); | |
/** | |
* Queried for the Fluids Base PathNodeType. | |
* Used to determine what the path node priority value is for the fluid. | |
* <ul> | |
* <li>Negative Values = Untraversable</li> | |
* <li>0 = Best</li> | |
* <li>Highest = Worst</li> | |
* </ul> | |
* @param state The current FluidState | |
* @param level The current {@link Level}'s block reader | |
* @param pos The position of the fluid | |
* @param entity The pathing entity, can be null | |
* @return {@code null} for default behavior; otherwise, returns the fluid's {@link BlockPathTypes} for pathfinding purposes | |
*/ | |
@Nullable | |
default BlockPathTypes getPathNodeType(FluidState state, BlockGetter level, BlockPos pos, @Nullable Mob entity) | |
{ | |
return null; | |
} | |
/** | |
* Gets the {@link BlockPathTypes} of the fluid when adjacent to some pathfinding entity. | |
* <ul> | |
* <li>Negative Values = Untraversable</li> | |
* <li>0 = Best</li> | |
* <li>Highest = Worst</li> | |
* </ul> | |
* @param state the current FluidState | |
* @param level the current {@link Level}'s block reader | |
* @param pos the position of the fluid | |
* @param entity the pathing entity, can be null | |
* @param originalType the {@link BlockPathTypes} obtained from {@link IForgeBlock#getAiPathNodeType(BlockState, BlockGetter, BlockPos, Mob)} | |
* @return {@code null} for default behavior; otherwise, returns the fluid's adjacent {@link BlockPathTypes} | |
*/ | |
@Nullable | |
default BlockPathTypes getAdjacentNodeType(FluidState state, BlockGetter level, BlockPos pos, @Nullable Mob entity, BlockPathTypes originalType) | |
{ | |
return null; | |
} | |
/** | |
* Handles acceleration or "pushing" while moving through the fluid. | |
* This implementation is slightly modified default behavior for fluid acceleration, based on {@link Entity#updateFluidHeightAndDoFluidPushing(net.minecraft.tags.Tag, double)}. | |
* | |
* @param state The {@link FluidState} the entity is in | |
* @param entity The current {@link Entity} that motion is being applied to | |
* @return Whether the motion was successfully applied to the {@link Entity} | |
*/ | |
default boolean updateFluidHeightAndDoFluidPushing(FluidState state, Entity entity) | |
{ | |
if (entity.touchingUnloadedChunk()) return false; | |
else | |
{ | |
AABB box = entity.getBoundingBox().deflate(0.001D); | |
int minX = Mth.floor(box.minX); | |
int maxX = Mth.ceil(box.maxX); | |
int minY = Mth.floor(box.minY); | |
int maxY = Mth.ceil(box.maxY); | |
int minZ = Mth.floor(box.minZ); | |
int maxZ = Mth.ceil(box.maxZ); | |
double eyeLevel = 0.0D; | |
boolean isInFluid = false; | |
Vec3 motion = Vec3.ZERO; | |
int withinFluidBlocks = 0; | |
BlockPos.MutableBlockPos fluidPos = new BlockPos.MutableBlockPos(); | |
for (int x = minX; x < maxX; ++x) | |
{ | |
for (int y = minY; y < maxY; ++y) | |
{ | |
for (int z = minZ; z < maxZ; ++z) | |
{ | |
fluidPos.set(x, y, z); | |
FluidState currentState = entity.level.getFluidState(fluidPos); | |
if (currentState == state) | |
{ | |
double fluidHeight = y + currentState.getHeight(entity.level, fluidPos); | |
if (fluidHeight >= box.minY) | |
{ | |
isInFluid = true; | |
eyeLevel = Math.max(fluidHeight - box.minY, eyeLevel); | |
if (entity.isPushedByFluid(currentState)) | |
{ | |
Vec3 fluidFlow = currentState.getFlow(entity.level, fluidPos); | |
if (eyeLevel < 0.4D) fluidFlow = fluidFlow.scale(eyeLevel); | |
motion = motion.add(fluidFlow); | |
++withinFluidBlocks; | |
} | |
} | |
} | |
} | |
} | |
} | |
if (motion.length() > 0.0D) | |
{ | |
if (withinFluidBlocks > 0) motion = motion.scale(1.0D / (double) withinFluidBlocks); | |
if (!(this instanceof Player)) motion = motion.normalize(); | |
Vec3 entityMotion = entity.getDeltaMovement(); | |
motion = motion.scale(getAttributes().getMotionScale(state, entity)); | |
if (Math.abs(entityMotion.x) < 0.003D && Math.abs(entityMotion.z) < 0.003D && motion.length() < 0.0045D) | |
motion = motion.normalize().scale(0.0045D); | |
entity.setDeltaMovement(entityMotion.add(motion)); | |
} | |
entity.setInFluid(state); | |
entity.addFluidHeight(state, eyeLevel); | |
if (isInFluid) | |
{ | |
FluidAttributes attr = state.getType().getAttributes(); | |
entity.fallDistance *= attr.getFallDistanceModifier(state, entity); | |
if (attr.canExtinguish(state, entity)) entity.clearFire(); | |
} | |
return isInFluid; | |
} | |
} | |
/** | |
* Handles "motion" modification for fluids. | |
* Things like slower movement, "swimming" slowdown, etc. | |
* | |
* @param state The current {@link FluidState} | |
* @param entity The {@link LivingEntity} whose motion is being handled | |
* @param travelVector The current travel {@link Vec3} | |
* @param gravity The current gravity being applied to the {@link LivingEntity} | |
*/ | |
default void handleMotion(FluidState state, LivingEntity entity, Vec3 travelVector, double gravity) | |
{ | |
FluidAttributes attributes = state.getType().getAttributes(); | |
boolean hasNegativeYMotion = entity.getDeltaMovement().y <= 0.0D; | |
double originalY = entity.getY(); | |
float horizontalModifier = attributes.getHorizontalMotionModifier(state, entity); | |
float movementAmount = 0.02F; | |
float depthStriderModifier = attributes.getEnchantmentMotionModifier(Enchantments.DEPTH_STRIDER, entity); | |
if (depthStriderModifier > 3.0F) depthStriderModifier = 3.0F; | |
if (!entity.isOnGround()) depthStriderModifier *= 0.5F; | |
if (depthStriderModifier > 0.0F) | |
{ | |
horizontalModifier += (0.546 - horizontalModifier) * depthStriderModifier / 3.0F; | |
movementAmount += (entity.getSpeed() - movementAmount) * depthStriderModifier / 3.0F; | |
} | |
if (entity.hasEffect(MobEffects.DOLPHINS_GRACE)) attributes.modifyMotionByEffect(MobEffects.DOLPHINS_GRACE, entity, horizontalModifier, true); | |
movementAmount *= entity.getAttribute(ForgeMod.SWIM_SPEED.get()).getValue(); | |
entity.moveRelative(movementAmount, travelVector); | |
entity.move(MoverType.SELF, entity.getDeltaMovement()); | |
Vec3 entityMotion = entity.getDeltaMovement(); | |
if (entity.horizontalCollision && entity.onClimbable()) | |
entityMotion = new Vec3(entityMotion.x, 0.2D, entityMotion.z); | |
entity.setDeltaMovement(entityMotion.multiply(horizontalModifier, 0.8F, horizontalModifier)); | |
Vec3 finalMotion = entity.getFluidFallingAdjustedMovement(gravity, hasNegativeYMotion, entity.getDeltaMovement()); | |
entity.setDeltaMovement(finalMotion); | |
if (entity.horizontalCollision && entity.isFree(finalMotion.x, finalMotion.y + 0.6D - entity.getY() + originalY, finalMotion.z)) | |
entity.setDeltaMovement(finalMotion.x, 0.3F, finalMotion.z); | |
} | |
/** | |
* Handles modification of jumps inside of a fluid. | |
* | |
* @param state The current {@link FluidState} the {@link LivingEntity} is in | |
* @param entity The {@link LivingEntity} whose jump is being modified | |
*/ | |
default void jump(FluidState state, LivingEntity entity) | |
{ | |
entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, 0.04D * entity.getAttribute(ForgeMod.SWIM_SPEED.get()).getValue(), 0.0D)); | |
} | |
/** | |
* Handles modifications of 'sinking' inside of a fluid | |
* | |
* @param state The current {@link FluidState} the {@link LivingEntity} is in | |
* @param entity The {@link LivingEntity} whose jump is being modified | |
*/ | |
default void sink(FluidState state, LivingEntity entity) | |
{ | |
entity.setDeltaMovement(entity.getDeltaMovement().add(0.0D, (double)-0.04F * entity.getAttribute(net.minecraftforge.common.ForgeMod.SWIM_SPEED.get()).getValue(), 0.0D)); | |
} | |
/** | |
* This method is used to handle fluid interactions. | |
* The current position of the fluid is the one that should be replaced during the interaction. | |
* | |
* IE. (Fluid + Catalyst = Result) where the Fluid and Result are in the same position. | |
* Lava(Source/Flowing) + Water = Obsidian/Cobblestone. | |
* Lava(Source/Flowing) + Blue Ice = Basalt. | |
* | |
* @param state The current {@link FluidState} | |
* @param level The {@link Level} containing the interaction | |
* @param pos The {@link BlockPos} the interaction is being applied at | |
* @return Whether a fluid tick needs to be scheduled. Should return true only if no reaction has occurred or the Result is another fluid. | |
*/ | |
default boolean handleFluidInteraction(FluidState state, Level level, BlockPos pos) | |
{ | |
return true; | |
} | |
/** | |
* This is a checker method to check whether two fluidstates match each other using their Fluid as the reference point. | |
* | |
* @param state The primary state to check | |
* @param otherState The secondary state to check | |
* @return Whether the two provided {@link FluidState}s {@link Fluid}s match. | |
*/ | |
default boolean is(FluidState state, FluidState otherState) | |
{ | |
return state.getType() == otherState.getType(); | |
} | |
/** | |
* Dictates whether a player can swim in this fluid or not. | |
* Swimming in this case refers the the "sneak" behavior swimming and swimming animation in custom fluids. | |
* | |
* @param state The current {@link FluidState} the player is in | |
* @return Whether a player can "swim" in this fluid | |
*/ | |
default boolean canSwim(FluidState state) | |
{ | |
return state.getType().getAttributes().canSwim(state); | |
} | |
/** | |
* Dictates whether a {@link LivingEntity} can drown in this fluid or not. | |
* | |
* @param state The current {@link FluidState} | |
* @param entity The entity within the fluid | |
* @return Whether the {@link LivingEntity} can drown or not | |
*/ | |
default boolean canDrown(FluidState state, LivingEntity entity) | |
{ | |
return state.getType().getAttributes().canDrown(state, entity); | |
} | |
/** | |
* Dictates whether a {@link Entity} can be extinguished by the fluid if on fire. | |
* | |
* @param state the current {@link FluidState} | |
* @param entity the {@link Entity} to test against | |
* @return Whether the provided {@link Entity} can be extinguished | |
*/ | |
default boolean canExtinguish(FluidState state, Entity entity) { | |
return state.getType().getAttributes().canExtinguish(state, entity); | |
} | |
/** | |
* Dictates whether this {@link FluidState} can provide "hydration" to the provided {@link BlockState} | |
* This is used for checks such as: | |
* - {@link net.minecraft.world.level.block.FarmBlock#isNearWater(LevelReader, BlockPos)} | |
* - {@link net.minecraft.world.level.block.ConcretePowderBlock#touchesLiquid(BlockGetter, BlockPos)} | |
* - {@link net.minecraft.world.level.block.CoralBlock#scanForWater(BlockGetter, BlockPos)} | |
* - {@link net.minecraft.world.level.block.SpongeBlock#tryAbsorbWater(Level, BlockPos)} | |
* - {@link net.minecraft.world.level.block.SugarCaneBlock#canSurvive(BlockState, LevelReader, BlockPos)} | |
* | |
* @param fluidState the provided {@link FluidState} | |
* @param blockState the provided {@link BlockState} | |
* @return Whether the provided {@link FluidState} can provide hydration for the {@link BlockState} | |
*/ | |
default boolean canHydrate(FluidState fluidState, BlockState blockState) | |
{ | |
return fluidState.getType().getAttributes().canHydrate(blockState); | |
} | |
/** | |
* This method dictates whether this fluid supports boats being "usable" with it. | |
* | |
* @param state The supplied {@link FluidState} | |
* @param boat The supplied {@link Boat} entity | |
* @return Whether the fluid supports boats being used with it. | |
*/ | |
default boolean canBoat(FluidState state, Boat boat) | |
{ | |
return state.getType().getAttributes().canBoat(state, boat); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.minecraftforge.client; | |
import com.mojang.blaze3d.systems.RenderSystem; | |
import com.mojang.blaze3d.vertex.*; | |
import com.mojang.math.Matrix4f; | |
import com.mojang.math.Vector3f; | |
import net.minecraft.client.Camera; | |
import net.minecraft.client.Minecraft; | |
import net.minecraft.client.multiplayer.ClientLevel; | |
import net.minecraft.client.player.LocalPlayer; | |
import net.minecraft.client.renderer.FogRenderer; | |
import net.minecraft.client.renderer.GameRenderer; | |
import net.minecraft.resources.ResourceLocation; | |
import net.minecraft.world.entity.player.Player; | |
import net.minecraftforge.fluids.FluidAttributes; | |
import javax.annotation.Nullable; | |
public interface IFluidRenderProperties | |
{ | |
IFluidRenderProperties DUMMY = new IFluidRenderProperties() | |
{ | |
}; | |
/** | |
* Used to render the FluidOverlay while inside of a Fluid | |
* @param mc The current {@link Minecraft} client instance | |
* @param stack The current {@link PoseStack} instance | |
*/ | |
default void renderOverlay(Minecraft mc, PoseStack stack) | |
{ | |
Player player = mc.player; | |
FluidAttributes attr = player.getTouchingFluid().getType().getAttributes(); | |
@Nullable ResourceLocation overlayTexture = attr.getViewOverlayTexture(); | |
if (overlayTexture != null) | |
{ | |
RenderSystem.setShader(GameRenderer::getPositionColorTexShader); | |
RenderSystem.enableTexture(); | |
RenderSystem.setShaderTexture(0, overlayTexture); | |
BufferBuilder builder = Tesselator.getInstance().getBuilder(); | |
RenderSystem.enableBlend(); | |
RenderSystem.defaultBlendFunc(); | |
float brightness = player.getBrightness(); | |
long color = Integer.toUnsignedLong(attr.getColor()); | |
float red = ((color >> 16) & 0xFF) / 255.0F * brightness; | |
float green = ((color >> 8) & 0xFF) / 255.0F * brightness; | |
float blue = (color & 0xFF) / 255.0F * brightness; | |
float alpha = 0.1F; | |
float uOffset = -player.getYRot() / 64.0F; | |
float vOffset = player.getXRot() / 64.0F; | |
Matrix4f matrix = stack.last().pose(); | |
builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); | |
builder.vertex(matrix, -1.0F, -1.0F, -0.5F).color(red, green, blue, alpha).uv(4.0F + uOffset, 4.0F + vOffset).endVertex(); | |
builder.vertex(matrix, 1.0F, -1.0F, -0.5F).color(red, green, blue, alpha).uv(uOffset, 4.0F + vOffset).endVertex(); | |
builder.vertex(matrix, 1.0F, 1.0F, -0.5F).color(red, green, blue, alpha).uv(uOffset, vOffset).endVertex(); | |
builder.vertex(matrix, -1.0F, 1.0F, -0.5F).color(red, green, blue, alpha).uv(4.0F + uOffset, vOffset).endVertex(); | |
builder.end(); | |
BufferUploader.end(builder); | |
RenderSystem.disableBlend(); | |
} | |
} | |
/** | |
* Used to properly set the fog color into an Vector3f for the Shader system to interpret. | |
* | |
* @param camera The current {@link Camera} instance | |
* @param partialTicks The current partial ticks represented as a float | |
* @param level The current {@link ClientLevel} | |
* @return Returns an {@link Vector3f} representation of the stored color value of the fluid the camera is currently inside of. | |
*/ | |
default Vector3f setFogColor(Camera camera, float partialTicks, ClientLevel level) | |
{ | |
long color = Integer.toUnsignedLong(camera.getEntity().getTouchingFluid().getType().getAttributes().getColor()); | |
return new Vector3f(((color >> 16) & 0xFF) / 255.0F, ((color >> 8) & 0xFF) / 255.0F, (color & 0xFF) / 255.0F); | |
} | |
/** | |
* Used to manually modify the current fog color while inside of a fluid. | |
* This new fog color is represented as a {@link Vector3f} for the Shader system to interpret. | |
* | |
* @param camera The current {@link Camera} instance | |
* @param partialTicks The current partial ticks represented as a float | |
* @param level The current {@link ClientLevel} | |
* @param red The red value represented as a float between 0-1 | |
* @param green The green value represented as a float between 0-1 | |
* @param blue The blue value represented as a float between 0-1 | |
* @return Returns an {@link Vector3f} representation of the stored color value of the fluid the camera is currently inside of. | |
*/ | |
default Vector3f modifyFogColor(Camera camera, float partialTicks, ClientLevel level, float red, float green, float blue) | |
{ | |
return new Vector3f(red, green, blue); | |
} | |
/** | |
* Used to properly setup the fluid fog for when you're inside of the fluid. | |
* | |
* @param camera The current {@link Camera} instance | |
* @param fogMode The currently set {@link net.minecraft.client.renderer.FogRenderer.FogMode} | |
* @param renderDistance The currently set renderDistance represented as a float value. | |
*/ | |
default void setupFog(Camera camera, FogRenderer.FogMode fogMode, float renderDistance) | |
{ | |
float constant = 180.0F; | |
if (camera.getEntity() instanceof LocalPlayer player) { | |
constant *= player.areEyesInCustomFluid() ? 1.0 : 0.25; | |
} | |
RenderSystem.setShaderFogStart(-8F); | |
RenderSystem.setShaderFogEnd(constant * 0.5F); | |
net.minecraftforge.client.ForgeHooksClient.onFogRender(fogMode, camera, renderDistance, constant); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package net.minecraftforge.fluids; | |
import net.minecraft.Util; | |
import net.minecraft.client.renderer.BiomeColors; | |
import net.minecraft.core.BlockPos; | |
import net.minecraft.core.particles.ParticleTypes; | |
import net.minecraft.network.chat.Component; | |
import net.minecraft.network.chat.TranslatableComponent; | |
import net.minecraft.resources.ResourceLocation; | |
import net.minecraft.sounds.SoundEvent; | |
import net.minecraft.sounds.SoundEvents; | |
import net.minecraft.sounds.SoundSource; | |
import net.minecraft.world.effect.MobEffect; | |
import net.minecraft.world.effect.MobEffects; | |
import net.minecraft.world.entity.Entity; | |
import net.minecraft.world.entity.LivingEntity; | |
import net.minecraft.world.entity.player.Player; | |
import net.minecraft.world.entity.vehicle.Boat; | |
import net.minecraft.world.item.ItemStack; | |
import net.minecraft.world.item.Rarity; | |
import net.minecraft.world.item.enchantment.Enchantment; | |
import net.minecraft.world.item.enchantment.EnchantmentHelper; | |
import net.minecraft.world.item.enchantment.WaterWalkerEnchantment; | |
import net.minecraft.world.level.BlockAndTintGetter; | |
import net.minecraft.world.level.Level; | |
import net.minecraft.world.level.LevelReader; | |
import net.minecraft.world.level.block.state.BlockState; | |
import net.minecraft.world.level.material.Fluid; | |
import net.minecraft.world.level.material.FluidState; | |
import net.minecraft.world.phys.BlockHitResult; | |
import net.minecraft.world.phys.Vec3; | |
import javax.annotation.Nullable; | |
import java.util.function.BiFunction; | |
import java.util.function.BiPredicate; | |
import java.util.function.Predicate; | |
import java.util.function.ToDoubleBiFunction; | |
import java.util.stream.Stream; | |
/** | |
* Minecraft Forge Fluid Implementation | |
* | |
* This class is a fluid (liquid or gas) equivalent to "Item." It describes the nature of a fluid | |
* and contains its general properties. | |
* | |
* These properties do not have inherent gameplay mechanics - they are provided so that mods may | |
* choose to take advantage of them. | |
* | |
* Fluid implementations are not required to actively use these properties, nor are objects | |
* interfacing with fluids required to make use of them, but it is encouraged. | |
* | |
* The default values can be used as a reference point for mods adding fluids such as oil or heavy | |
* water. | |
* | |
*/ | |
public class FluidAttributes | |
{ | |
public static final int BUCKET_VOLUME = 1000; | |
private String translationKey; | |
private final ResourceLocation stillTexture; | |
private final ResourceLocation flowingTexture; | |
@Nullable | |
private final ResourceLocation overlayTexture; | |
@Nullable | |
private final ResourceLocation viewOverlayTexture; | |
private final SoundEvent fillSound; | |
private final SoundEvent emptySound; | |
/** | |
* The light level emitted by this fluid. | |
* | |
* Default value is 0, as most fluids do not actively emit light. | |
*/ | |
private final int luminosity; | |
/** | |
* Density of the fluid - completely arbitrary; negative density indicates that the fluid is | |
* lighter than air. | |
* | |
* Default value is approximately the real-life density of water in kg/m^3. | |
*/ | |
private final int density; | |
/** | |
* Temperature of the fluid - completely arbitrary; higher temperature indicates that the fluid is | |
* hotter than air. | |
* | |
* Default value is approximately the real-life room temperature of water in degrees Kelvin. | |
*/ | |
private final int temperature; | |
/** | |
* Viscosity ("thickness") of the fluid - completely arbitrary; negative values are not | |
* permissible. | |
* | |
* Default value is approximately the real-life density of water in m/s^2 (x10^-3). | |
* | |
* Higher viscosity means that a fluid flows more slowly, like molasses. | |
* Lower viscosity means that a fluid flows more quickly, like helium. | |
* | |
*/ | |
private final int viscosity; | |
/** | |
* The rarity of the fluid. | |
* | |
* Used primarily in tool tips. | |
*/ | |
private final Rarity rarity; | |
/** | |
* Color used by universal bucket and the ModelFluid baked model. | |
* Note that this int includes the alpha so converting this to RGB with alpha would be | |
* float r = ((color >> 16) & 0xFF) / 255f; // red | |
* float g = ((color >> 8) & 0xFF) / 255f; // green | |
* float b = ((color >> 0) & 0xFF) / 255f; // blue | |
* float a = ((color >> 24) & 0xFF) / 255f; // alpha | |
*/ | |
private final int color; | |
/** | |
* The scaled motion {@link ToDoubleBiFunction} of the fluid when "pushing" entities. | |
*/ | |
private final ToDoubleBiFunction<FluidState, Entity> motionScale; | |
/** | |
* The fall distance multiplier {@link ToDoubleBiFunction} while within a fluid. | |
* For example used if it should increase/dampen fall damage. | |
*/ | |
private final ToDoubleBiFunction<FluidState, Entity> fallDistanceModifier; | |
/** | |
* The {@link Predicate} used to check if a player can swim in the {@link Fluid}. | |
*/ | |
private final Predicate<FluidState> canSwim; | |
/** | |
* The {@link BiPredicate} used to determine if a {@link LivingEntity} can drown in the {@link Fluid}. | |
*/ | |
private final BiPredicate<FluidState, LivingEntity> canDrown; | |
/** | |
* The {@link BiPredicate} used to determine if the {@link Fluid} should extinguish a burning entity. | |
*/ | |
private final BiPredicate<FluidState, Entity> canExtinguish; | |
/** | |
* The {@link Predicate} used to determine if the {@link Fluid} can hydrate a specific {@link BlockState}. | |
* Used for example with {@link net.minecraft.world.level.block.ConcretePowderBlock#canSolidify(BlockState)} (BlockState)}, {@link net.minecraft.world.level.block.SpongeBlock#tryAbsorbWater(Level, BlockPos)} and {@link net.minecraft.world.level.block.FarmBlock#isNearWater(LevelReader, BlockPos)}. | |
*/ | |
private final Predicate<BlockState> canHydrate; | |
/** | |
* The {@link BiFunction} used to determine the {@link Fluid}s horizontal motion modifier. | |
* Used inside of {@link net.minecraftforge.common.extensions.IForgeFluid#handleMotion(FluidState, LivingEntity, Vec3, double)} to modify the horizontal movement speed while inside of the {@link Fluid}. | |
*/ | |
private final BiFunction<FluidState, LivingEntity, Float> horizontalMotionModifier; | |
/** | |
* Used to determine motion modifiers based off an {@link Enchantment} and an {@link LivingEntity}. | |
* Used inside of {@link net.minecraftforge.common.extensions.IForgeFluid#handleMotion(FluidState, LivingEntity, Vec3, double)} to modify the final motion vectors. | |
*/ | |
private final BiFunction<Enchantment, LivingEntity, Float> enchantmentModifier; | |
/** | |
* Used to alters the motion of the entity based off an {@link MobEffect}, an {@link LivingEntity}, an original horizontal motion modifier represented as a {@link Float} and finally a boolean dictating is the motion is horizontal. | |
* Used inside of {@link net.minecraftforge.common.extensions.IForgeFluid#handleMotion(FluidState, LivingEntity, Vec3, double)} to modify the final motion vectors. | |
*/ | |
private final IFluidEffectModifier effectModifier; | |
/** | |
* Used to decide if a {@link Boat} should have intended interaction behaviour with a fluid. | |
*/ | |
private final BiPredicate<FluidState, Boat> canBoat; | |
protected FluidAttributes(Builder builder, Fluid fluid) | |
{ | |
this.translationKey = builder.translationKey != null ? builder.translationKey : Util.makeDescriptionId("fluid", fluid.getRegistryName()); | |
this.stillTexture = builder.stillTexture; | |
this.flowingTexture = builder.flowingTexture; | |
this.overlayTexture = builder.overlayTexture; | |
this.viewOverlayTexture = builder.viewOverlayTexture; | |
this.color = builder.color; | |
this.fillSound = builder.fillSound; | |
this.emptySound = builder.emptySound; | |
this.luminosity = builder.luminosity; | |
this.temperature = builder.temperature; | |
this.viscosity = builder.viscosity; | |
this.density = builder.density; | |
this.rarity = builder.rarity; | |
this.motionScale = builder.motionScale; | |
this.fallDistanceModifier = builder.fallDistanceModifier; | |
this.canSwim = builder.canSwim; | |
this.canDrown = builder.canDrown; | |
this.canExtinguish = builder.canExtinguish; | |
this.canHydrate = builder.canHydrate; | |
this.horizontalMotionModifier = builder.horizontalMotionModifier; | |
this.enchantmentModifier = builder.enchantmentModifier; | |
this.effectModifier = builder.effectModifier; | |
this.canBoat = builder.canBoat; | |
} | |
public ItemStack getBucket(FluidStack stack) | |
{ | |
return new ItemStack(stack.getFluid().getBucket()); | |
} | |
public BlockState getBlock(BlockAndTintGetter reader, BlockPos pos, FluidState state) | |
{ | |
return state.createLegacyBlock(); | |
} | |
public FluidState getStateForPlacement(BlockAndTintGetter reader, BlockPos pos, FluidStack state) | |
{ | |
return state.getFluid().defaultFluidState(); | |
} | |
public final boolean canBePlacedInWorld(BlockAndTintGetter reader, BlockPos pos, FluidState state) | |
{ | |
return !getBlock(reader, pos, state).isAir(); | |
} | |
public final boolean canBePlacedInWorld(BlockAndTintGetter reader, BlockPos pos, FluidStack state) | |
{ | |
return !getBlock(reader, pos, getStateForPlacement(reader, pos, state)).isAir(); | |
} | |
/** | |
* Determines if the fluid is lighter than "air" based of the fluids density value. | |
* If the density value is lower than or equal to 0 where 0 is the "canonical" density of air. | |
* Then the fluid will be using the upside-down bucket texture/model, as well as the upward-flowing fluid block model. | |
* @return Returns whether the fluid is lighter than air, making it use the upside down bucket texture and fluid block model. | |
*/ | |
public final boolean isLighterThanAir() | |
{ | |
return this.getDensity() <= 0; | |
} | |
/** | |
* Determines if this fluid should vaporize in dimensions where water vaporizes when placed. | |
* To preserve the intentions of vanilla, fluids that can turn lava into obsidian should vaporize. | |
* This prevents players from making the nether safe with a single bucket. | |
* Based on {@link net.minecraft.world.item.BucketItem#emptyContents(Player, Level, BlockPos, BlockHitResult)} | |
* | |
* @param fluidStack The fluidStack is trying to be placed. | |
* @return true if this fluid should vaporize in dimensions where water vaporizes when placed. | |
*/ | |
public boolean doesVaporize(BlockAndTintGetter reader, BlockPos pos, FluidStack fluidStack) | |
{ | |
BlockState blockstate = getBlock(reader, pos, getStateForPlacement(reader, pos, fluidStack)); | |
if (blockstate == null) | |
return false; | |
return blockstate.getMaterial() == net.minecraft.world.level.material.Material.WATER; | |
} | |
/** | |
* Called instead of placing the fluid block if {@link net.minecraft.world.level.dimension.DimensionType#ultrawarm()} and {@link #doesVaporize(BlockAndTintGetter, BlockPos, FluidStack)} are true. | |
* Override this to make your explosive liquid blow up instead of the default smoke, etc. | |
* Based on {@link net.minecraft.world.item.BucketItem#emptyContents(Player, Level, BlockPos, BlockHitResult)} | |
* | |
* @param player Player who tried to place the fluid. May be null for blocks like dispensers. | |
* @param worldIn World to vaporize the fluid in. | |
* @param pos The position in the world the fluid block was going to be placed. | |
* @param fluidStack The fluidStack that was going to be placed. | |
*/ | |
public void vaporize(@Nullable Player player, Level worldIn, BlockPos pos, FluidStack fluidStack) | |
{ | |
worldIn.playSound(player, pos, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (worldIn.random.nextFloat() - worldIn.random.nextFloat()) * 0.8F); | |
for (int l = 0; l < 8; ++l) | |
{ | |
worldIn.addAlwaysVisibleParticle(ParticleTypes.LARGE_SMOKE, (double) pos.getX() + Math.random(), (double) pos.getY() + Math.random(), (double) pos.getZ() + Math.random(), 0.0D, 0.0D, 0.0D); | |
} | |
} | |
/** | |
* Returns the localized name of the provided {@code FluidStack}. | |
* @param stack the provided {@code FluidStack} to get the display name of. | |
* @return Returns the display name of the provided {@code FluidStack} as a {@code Component}. | |
*/ | |
public Component getDisplayName(FluidStack stack) | |
{ | |
return new TranslatableComponent(getTranslationKey()); | |
} | |
/** | |
* A FluidStack sensitive version of getTranslationKey | |
* @param stack the provided {@code FluidStack} to get the display name of. | |
* @return Returns the translation key of the provided {@code FluidStack} as a string. | |
*/ | |
public String getTranslationKey(FluidStack stack) | |
{ | |
return this.getTranslationKey(); | |
} | |
/** | |
* @return Returns the translation key of this fluid. | |
*/ | |
public String getTranslationKey() | |
{ | |
return this.translationKey; | |
} | |
/** | |
* Luminosity is currently only used as part of {@link net.minecraftforge.client.model.DynamicBucketModel#bake(IModelConfiguration, ModelBakery, Function<Material, TextureAtlasSprite>, ModelState, ItemOverrides, ResourceLocation)} to determine if the fluid should render fullbright in the bucket texture or not. | |
* The luminosity check for fullbright on the DynamicBucketModel is calculated as 'luminosity > 0' and requires the "applyFluidLuminosity" model attribute to be present and enabled in the fluid model file. | |
* @return Returns the luminosity value for the fluid. | |
*/ | |
/* Default Accessors */ | |
public final int getLuminosity() | |
{ | |
return this.luminosity; | |
} | |
public final int getDensity() | |
{ | |
return this.density; | |
} | |
public final int getTemperature() | |
{ | |
return this.temperature; | |
} | |
public final int getViscosity() | |
{ | |
return this.viscosity; | |
} | |
public Rarity getRarity() | |
{ | |
return rarity; | |
} | |
public int getColor() | |
{ | |
return color; | |
} | |
public double getMotionScale(FluidState state, Entity entity) | |
{ | |
return motionScale.applyAsDouble(state, entity); | |
} | |
public double getFallDistanceModifier(FluidState state, Entity entity) | |
{ | |
return fallDistanceModifier.applyAsDouble(state, entity); | |
} | |
public boolean canSwim(FluidState state) | |
{ | |
return canSwim.test(state); | |
} | |
public boolean canDrown(FluidState state, LivingEntity entity) | |
{ | |
return canDrown.test(state, entity); | |
} | |
public boolean canExtinguish(FluidState state, Entity entity) | |
{ | |
return canExtinguish.test(state, entity); | |
} | |
public boolean canHydrate(BlockState state) | |
{ | |
return canHydrate.test(state); | |
} | |
public float getHorizontalMotionModifier(FluidState state, LivingEntity entity) | |
{ | |
return this.horizontalMotionModifier.apply(state, entity); | |
} | |
public float getEnchantmentMotionModifier(Enchantment enchantment, LivingEntity entity) | |
{ | |
return this.enchantmentModifier.apply(enchantment, entity); | |
} | |
public boolean canBoat(FluidState state, Boat boat) | |
{ | |
return this.canBoat.test(state, boat); | |
} | |
public void modifyMotionByEffect(MobEffect effect, LivingEntity entity, Float originalMovement, Boolean isHorizontal) | |
{ | |
this.effectModifier.modify(effect, entity, originalMovement, isHorizontal); | |
} | |
public ResourceLocation getStillTexture() | |
{ | |
return stillTexture; | |
} | |
public ResourceLocation getFlowingTexture() | |
{ | |
return flowingTexture; | |
} | |
@Nullable | |
public ResourceLocation getOverlayTexture() | |
{ | |
return overlayTexture; | |
} | |
@Nullable | |
public ResourceLocation getViewOverlayTexture() | |
{ | |
return viewOverlayTexture; | |
} | |
public SoundEvent getFillSound() | |
{ | |
return fillSound; | |
} | |
public SoundEvent getEmptySound() | |
{ | |
return emptySound; | |
} | |
/* Stack-based Accessors */ | |
public int getLuminosity(FluidStack stack){ return getLuminosity(); } | |
public int getDensity(FluidStack stack){ return getDensity(); } | |
public int getTemperature(FluidStack stack){ return getTemperature(); } | |
public int getViscosity(FluidStack stack){ return getViscosity(); } | |
public Rarity getRarity(FluidStack stack){ return getRarity(); } | |
public int getColor(FluidStack stack){ return getColor(); } | |
public ResourceLocation getStillTexture(FluidStack stack) { return getStillTexture(); } | |
public ResourceLocation getFlowingTexture(FluidStack stack) { return getFlowingTexture(); } | |
public SoundEvent getFillSound(FluidStack stack) { return getFillSound(); } | |
public SoundEvent getEmptySound(FluidStack stack) { return getEmptySound(); } | |
/* World-based Accessors */ | |
public int getLuminosity(BlockAndTintGetter world, BlockPos pos){ return getLuminosity(); } | |
public int getDensity(BlockAndTintGetter world, BlockPos pos){ return getDensity(); } | |
public int getTemperature(BlockAndTintGetter world, BlockPos pos){ return getTemperature(); } | |
public int getViscosity(BlockAndTintGetter world, BlockPos pos){ return getViscosity(); } | |
public Rarity getRarity(BlockAndTintGetter world, BlockPos pos){ return getRarity(); } | |
public int getColor(BlockAndTintGetter world, BlockPos pos){ return getColor(); } | |
public ResourceLocation getStillTexture(BlockAndTintGetter world, BlockPos pos) { return getStillTexture(); } | |
public ResourceLocation getFlowingTexture(BlockAndTintGetter world, BlockPos pos) { return getFlowingTexture(); } | |
public SoundEvent getFillSound(BlockAndTintGetter world, BlockPos pos) { return getFillSound(); } | |
public SoundEvent getEmptySound(BlockAndTintGetter world, BlockPos pos) { return getEmptySound(); } | |
public boolean canSwim(BlockAndTintGetter world, BlockPos pos) { return canSwim(world.getFluidState(pos)); } | |
public boolean canHydrate(BlockAndTintGetter world, BlockPos pos) { return canHydrate(world.getBlockState(pos)); } | |
public static Builder builder(ResourceLocation stillTexture, ResourceLocation flowingTexture) { | |
return new Builder(stillTexture, flowingTexture, FluidAttributes::new); | |
} | |
public Stream<ResourceLocation> getTextures() | |
{ | |
if (overlayTexture != null) | |
return Stream.of(stillTexture, flowingTexture, overlayTexture); | |
return Stream.of(stillTexture, flowingTexture); | |
} | |
public static class Builder | |
{ | |
private final ResourceLocation stillTexture; | |
private final ResourceLocation flowingTexture; | |
private ResourceLocation overlayTexture; | |
private ResourceLocation viewOverlayTexture; | |
private int color = 0xFFFFFFFF; | |
private String translationKey; | |
private SoundEvent fillSound; | |
private SoundEvent emptySound; | |
private int luminosity = 0; | |
private int density = 1000; | |
private int temperature = 300; | |
private int viscosity = 1000; | |
private Rarity rarity = Rarity.COMMON; | |
private ToDoubleBiFunction<FluidState, Entity> motionScale = (state, entity) -> 0.014D; | |
private ToDoubleBiFunction<FluidState, Entity> fallDistanceModifier = (state, entity) -> 0.0D; | |
private Predicate<FluidState> canSwim = state -> false; | |
private BiPredicate<FluidState, LivingEntity> canDrown = (state, entity) -> true; | |
private BiPredicate<FluidState, Entity> canExtinguish = (state, entity) -> false; | |
private Predicate<BlockState> canHydrate = state -> false; | |
private BiFunction<FluidState, LivingEntity, Float> horizontalMotionModifier = (state, entity) -> entity.isSprinting() ? 0.9F : 0.8F; | |
private BiFunction<Enchantment, LivingEntity, Float> enchantmentModifier = (enchantment, entity) -> enchantment instanceof WaterWalkerEnchantment ? EnchantmentHelper.getDepthStrider(entity) : 0F; | |
private IFluidEffectModifier effectModifier = (effect, entity, originalModifier, isHorizontal) -> { if (isHorizontal && effect.equals(MobEffects.DOLPHINS_GRACE) && entity.hasEffect(effect)) { originalModifier = 0.97f; } }; | |
private BiPredicate<FluidState, Boat> canBoat = (state, boat) -> false; | |
private BiFunction<Builder,Fluid,FluidAttributes> factory; | |
protected Builder(ResourceLocation stillTexture, ResourceLocation flowingTexture, BiFunction<Builder,Fluid,FluidAttributes> factory) { | |
this.factory = factory; | |
this.stillTexture = stillTexture; | |
this.flowingTexture = flowingTexture; | |
} | |
public final Builder translationKey(String translationKey) | |
{ | |
this.translationKey = translationKey; | |
return this; | |
} | |
public final Builder color(int color) | |
{ | |
this.color = color; | |
return this; | |
} | |
public final Builder overlay(ResourceLocation texture) | |
{ | |
overlayTexture = texture; | |
return this; | |
} | |
public final Builder viewOverlay(ResourceLocation texture) | |
{ | |
viewOverlayTexture = new ResourceLocation(texture.getNamespace(), "textures/" + texture.getPath() + ".png"); | |
return this; | |
} | |
public final Builder luminosity(int luminosity) | |
{ | |
this.luminosity = luminosity; | |
return this; | |
} | |
public final Builder density(int density) | |
{ | |
this.density = density; | |
return this; | |
} | |
public final Builder temperature(int temperature) | |
{ | |
this.temperature = temperature; | |
return this; | |
} | |
public final Builder viscosity(int viscosity) | |
{ | |
this.viscosity = viscosity; | |
return this; | |
} | |
public final Builder rarity(Rarity rarity) | |
{ | |
this.rarity = rarity; | |
return this; | |
} | |
public final Builder sound(SoundEvent sound) | |
{ | |
this.fillSound = this.emptySound = sound; | |
return this; | |
} | |
public final Builder sound(SoundEvent fillSound, SoundEvent emptySound) | |
{ | |
this.fillSound = fillSound; | |
this.emptySound = emptySound; | |
return this; | |
} | |
public final Builder motionScale(ToDoubleBiFunction<FluidState, Entity> motionScale) | |
{ | |
this.motionScale = motionScale; | |
return this; | |
} | |
public final Builder fallDistanceModifier(ToDoubleBiFunction<FluidState, Entity> fallDistanceModifier) | |
{ | |
this.fallDistanceModifier = fallDistanceModifier; | |
return this; | |
} | |
public final Builder canSwim(Predicate<FluidState> canSwim) | |
{ | |
this.canSwim = canSwim; | |
return this; | |
} | |
public final Builder canDrown(BiPredicate<FluidState, LivingEntity> canDrown) | |
{ | |
this.canDrown = canDrown; | |
return this; | |
} | |
public final Builder canExtinguish(BiPredicate<FluidState, Entity> canExtinguish) | |
{ | |
this.canExtinguish = canExtinguish; | |
return this; | |
} | |
public final Builder canHydrate(Predicate<BlockState> canHydrate) | |
{ | |
this.canHydrate = canHydrate; | |
return this; | |
} | |
public final Builder horizontalMotionModifier(BiFunction<FluidState, LivingEntity, Float> horizontalMotionModifier) | |
{ | |
this.horizontalMotionModifier = horizontalMotionModifier; | |
return this; | |
} | |
public final Builder enchantmentModifier(BiFunction<Enchantment, LivingEntity, Float> enchantmentModifier) | |
{ | |
this.enchantmentModifier = enchantmentModifier; | |
return this; | |
} | |
public final Builder effectModifier(IFluidEffectModifier effectModifier) | |
{ | |
this.effectModifier = effectModifier; | |
return this; | |
} | |
public final Builder canBoat(BiPredicate<FluidState, Boat> canBoat) | |
{ | |
this.canBoat = canBoat; | |
return this; | |
} | |
public FluidAttributes build(Fluid fluid) | |
{ | |
return factory.apply(this, fluid); | |
} | |
} | |
public static class Water extends FluidAttributes | |
{ | |
protected Water(Builder builder, Fluid fluid) | |
{ | |
super(builder, fluid); | |
} | |
@Override | |
public int getColor(BlockAndTintGetter world, BlockPos pos) | |
{ | |
return BiomeColors.getAverageWaterColor(world, pos) | 0xFF000000; | |
} | |
public static Builder builder(ResourceLocation stillTexture, ResourceLocation flowingTexture) { | |
return new Builder(stillTexture, flowingTexture, Water::new).canExtinguish((state, entity) -> true); | |
} | |
} | |
public interface IFluidEffectModifier { | |
void modify(MobEffect effect, LivingEntity entity, float motion, boolean isHorizontal); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment