Created
August 1, 2021 21:04
-
-
Save Lanse505/b6aeae94957c9e38497b7449d7a60c3e 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
| package net.minecraftforge.common.extensions; | |
| import java.util.Set; | |
| import javax.annotation.Nullable; | |
| import com.mojang.math.Vector3d; | |
| import net.minecraft.util.Mth; | |
| import net.minecraft.world.effect.MobEffects; | |
| 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.item.enchantment.EnchantmentHelper; | |
| import net.minecraft.world.item.enchantment.Enchantments; | |
| import net.minecraft.world.level.Level; | |
| import net.minecraft.world.level.block.state.BlockState; | |
| import net.minecraft.world.level.material.Material; | |
| import net.minecraft.world.entity.Entity; | |
| import net.minecraft.world.level.material.Fluid; | |
| import net.minecraft.world.level.material.FluidState; | |
| import net.minecraft.tags.SetTag; | |
| import net.minecraft.resources.ResourceLocation; | |
| import net.minecraft.world.level.pathfinder.BlockPathTypes; | |
| import net.minecraft.world.phys.AABB; | |
| import net.minecraft.core.BlockPos; | |
| import net.minecraft.world.level.Explosion; | |
| import net.minecraft.world.level.BlockGetter; | |
| import net.minecraft.world.level.LevelReader; | |
| import net.minecraft.world.phys.Vec3; | |
| import net.minecraftforge.common.ForgeMod; | |
| import net.minecraftforge.fluids.FluidAttributes; | |
| public interface IForgeFluid | |
| { | |
| /** | |
| * Called when the entity is inside this block, may be used to determined if the entity can breathing, | |
| * display material overlays, or if the entity can swim inside a block. | |
| * | |
| * @param world that is being tested. | |
| * @param pos position thats being tested. | |
| * @param entity that is being tested. | |
| * @param yToTest, primarily for testingHead, which sends the the eye level of the entity, other wise it sends a y that can be tested vs liquid height. | |
| * @param tag Fluid category | |
| * @param testingHead when true, its testing the entities head for vision, breathing ect... otherwise its testing the body, for swimming and movement adjustment. | |
| */ | |
| default boolean isEntityInside(FluidState state, LevelReader world, BlockPos pos, Entity entity, double yToTest, SetTag<Fluid> tag, boolean testingHead) | |
| { | |
| return state.is(tag) && yToTest < (double)(pos.getY() + state.getHeight(world, pos) + 0.11111111F); | |
| } | |
| /** | |
| * Called when boats or fishing hooks are inside the block to check if they are inside | |
| * the material requested. | |
| * | |
| * @param world world that is being tested. | |
| * @param pos block thats being tested. | |
| * @param boundingBox box to test, generally the bounds of an entity that are besting tested. | |
| * @param materialIn to check for. | |
| * @return null for default behavior, true if the box is within the material, false if it was not. | |
| */ | |
| @Nullable | |
| default Boolean isAABBInsideMaterial(FluidState state, LevelReader world, BlockPos pos, AABB boundingBox, Material materialIn) | |
| { | |
| return null; | |
| } | |
| /** | |
| * Called when entities are moving to check if they are inside a liquid | |
| * | |
| * @param world world that is being tested. | |
| * @param pos block thats being tested. | |
| * @param boundingBox box to test, generally the bounds of an entity that are besting tested. | |
| * @return null for default behavior, true if the box is within the material, false if it was not. | |
| */ | |
| @Nullable | |
| default Boolean isAABBInsideLiquid(FluidState state, LevelReader world, BlockPos pos, AABB boundingBox) | |
| { | |
| return null; | |
| } | |
| /** | |
| * 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. | |
| */ | |
| @SuppressWarnings("deprecation") | |
| default float getExplosionResistance(FluidState state, BlockGetter world, 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, including localized name. | |
| */ | |
| 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 world The current world'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 world, 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 world The current world'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 world, 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); //0_FLUIDS: Check potential hardcoding instance | |
| 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 Vector3d} | |
| * @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)); | |
| } | |
| /** | |
| * 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 this fluid can act as an "hydration source" for a specific {@link BlockState}. | |
| * For example, this can hydrate {@link net.minecraft.world.level.block.ConcretePowderBlock}s, hydrate {@link net.minecraft.world.level.block.FarmBlock}s, or be absorbed by {@link net.minecraft.world.level.block.SpongeBlock}s. | |
| * | |
| * @param fluidState The current {@link FluidState} | |
| * @param blockState The provided {@link BlockState} to be hydrated | |
| * @return Returns whether the {@link FluidState} can hydrate the provided {@link BlockState} | |
| */ | |
| default boolean canHydrate(FluidState fluidState, BlockState blockState) | |
| { | |
| return fluidState.getType().getAttributes().canHydrate(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 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; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment