Skip to content

Commit

Permalink
feat: implement basic liquid functions
Browse files Browse the repository at this point in the history
  • Loading branch information
smartcmd committed Dec 28, 2024
1 parent 123d712 commit 9266014
Show file tree
Hide file tree
Showing 13 changed files with 667 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,20 @@ default double calculateBreakTime(BlockState blockState, ItemStack usedItem, Ent
return 1d / speed;
}

/**
* Check if a position on the side of the block placed in the world at a specific position is
* closed. When this returns true (for example, when the side is below the position and the block is a
* slab), liquid inside the block won't flow from pos into side.
*
* @param blockState the block to check.
* @param blockFace the side of the block to check.
*
* @return {@code true} if the side is closed, {@code false} otherwise.
*/
default boolean canLiquidFlowIntoSide(BlockState blockState, BlockFace blockFace) {
return true;
}

private double speedBonusByEfficiency(int efficiencyLevel) {
if (efficiencyLevel == 0) return 0;
return efficiencyLevel * efficiencyLevel + 1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.allaymc.api.block.property.type.BlockPropertyTypes;
import org.allaymc.api.block.type.BlockState;
import org.allaymc.api.block.type.BlockType;
import org.allaymc.api.world.DimensionInfo;

/**
Expand All @@ -11,41 +12,32 @@
*/
public interface BlockLiquidBaseComponent extends BlockBaseComponent {
/**
* Check if the liquid is flowing down.
* Check if the liquid is falling.
*
* @param blockState the block state to check.
*
* @return {@code true} if the liquid is flowing down, {@code false} otherwise.
*/
default boolean isFlowingDown(BlockState blockState) {
// The first bit of the liquid depth property is set to 1 if the liquid is flowing down.
static boolean isFalling(BlockState blockState) {
// The first bit of the liquid depth property is set to 1 if the liquid is falling
return (blockState.getPropertyValue(BlockPropertyTypes.LIQUID_DEPTH) & 0b1000) == 0b1000;
}

/**
* Get the block state of the flowing down block.
*
* @return the block state of the flowing down block.
*/
default BlockState getFlowingDownBlockState() {
return getBlockType().ofState(BlockPropertyTypes.LIQUID_DEPTH.createValue(0b1111));
}

/**
* Get the liquid level of the block.
* Get the liquid depth of the block.
* <p>
* Flowing down blocks and source blocks have a liquid level of 8.
* Other blocks have a liquid level between 1 and 7.
* Falling blocks and source blocks have a liquid depth of 8.
* Other blocks have a liquid depth between 1 and 7.
*
* @param blockState the block state to get the liquid level from.
* @param blockState the block state to get the liquid depth from.
*
* @return the liquid level of the block.
* @return the liquid depth of the block.
*/
default int getLevel(BlockState blockState) {
if (isFlowingDown(blockState) || isSource(blockState)) {
static int getDepth(BlockState blockState) {
if (isFalling(blockState) || isSource(blockState)) {
return 8;
}
return blockState.getPropertyValue(BlockPropertyTypes.LIQUID_DEPTH) & 0b0111;
return 8 - blockState.getPropertyValue(BlockPropertyTypes.LIQUID_DEPTH) & 0b0111;
}

/**
Expand All @@ -55,10 +47,31 @@ default int getLevel(BlockState blockState) {
*
* @return {@code true} if the block state represents a liquid source, {@code false} otherwise.
*/
default boolean isSource(BlockState blockState) {
static boolean isSource(BlockState blockState) {
return blockState.getPropertyValue(BlockPropertyTypes.LIQUID_DEPTH) == 0;
}

/**
* Get the block state of the liquid block with given depth and falling state.
*
* @param depth the depth of the liquid.
* @param falling {@code true} if the liquid is falling, {@code false} otherwise.
*
* @return the block state of the liquid block with given depth and falling state.
*/
default BlockState getLiquidBlockState(int depth, boolean falling) {
return getBlockType().ofState(BlockPropertyTypes.LIQUID_DEPTH.createValue(falling ? 0b1000 | 8 - depth : 8 - depth));
}

/**
* Get the block state of the falling block.
*
* @return the block state of the falling block.
*/
default BlockState getFallingBlockState() {
return getBlockType().ofState(BlockPropertyTypes.LIQUID_DEPTH.createValue(0b1000));
}

/**
* Get the block state of the source block.
*
Expand Down Expand Up @@ -94,4 +107,13 @@ default BlockState getSourceBlockState() {
* @return {@code true} if the block can become a source block, {@code false} otherwise.
*/
boolean canFormSource();

/**
* Check if the given block type is the same liquid type as this block type.
*
* @param blockType the block type to check.
*
* @return {@code true} if the given block type is the same liquid type as this block type, {@code false} otherwise.
*/
boolean isSameLiquidType(BlockType<?> blockType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

import java.awt.*;

import static org.allaymc.api.block.component.data.LiquidReactionOnTouch.NOREACTION;

/**
* @author daoge_cmd | CoolLoong
*/
Expand Down Expand Up @@ -69,10 +71,10 @@ public class BlockStateData {
@Builder.Default
protected int burnOdds = 0;
/**
* Whether the block state can contain liquid.
* Whether the block state can contain liquid source.
*/
@Builder.Default
protected boolean canContainLiquid = false;
protected boolean canContainLiquidSource = false;
/**
* The reaction of this block state when liquid flow into.
*/
Expand Down Expand Up @@ -194,4 +196,13 @@ public VoxelShape computeOffsetShape(Vector3ic vector) {
public boolean isTransparent() {
return translucency() != 1.0f;
}

/**
* Check if the block state can contain liquid, no matter it is liquid source or not.
*
* @return {@code true} if the block state can contain liquid, otherwise {@code false}.
*/
public boolean canContainLiquid() {
return canContainLiquidSource || liquidReactionOnTouch == NOREACTION;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,22 @@ public enum LiquidReactionOnTouch {
POPPED,
/**
* The block will prevent the liquid from flowing into.
* Compared to {@link BlockStateData#canContainLiquidSource}, this only
* affects flowing liquid, not source liquid. That's mean the block
* may still can contain source liquid block.
*/
BLOCKING,
/**
* The block won't have any reaction, also won't have any impact on the liquid just like air.
*/
NOREACTION
NOREACTION;

/**
* Check if the block should be removed when touched by liquid.
*
* @return true if the block should be removed when touched by liquid.
*/
public boolean removedOnTouch() {
return this == BROKEN || this == POPPED;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
import java.util.EnumMap;
import java.util.Map;

import static org.allaymc.api.block.data.BlockFace.getBlockFaceByStairDirectionValue;

/**
* VoxelShapes contains some useful voxel shapes.
*
Expand Down Expand Up @@ -41,7 +39,7 @@ public final class VoxelShapes {

public static VoxelShape buildStairShape(BlockState stairBlockState) {
var isDownwards = stairBlockState.getPropertyValue(BlockPropertyTypes.UPSIDE_DOWN_BIT);
var face = getBlockFaceByStairDirectionValue(stairBlockState.getPropertyValue(BlockPropertyTypes.WEIRDO_DIRECTION));
var face = BlockFace.getBlockFaceByStairDirectionValue(stairBlockState.getPropertyValue(BlockPropertyTypes.WEIRDO_DIRECTION));
return isDownwards ? DOWNWARDS_STAIR_SHAPES.get(face) : UPWARDS_STAIR_SHAPES.get(face);
}

Expand All @@ -50,7 +48,7 @@ public static VoxelShape buildLiquidShape(BlockState liquidBlockState) {
throw new IllegalArgumentException("The liquidBlockState must implement BlockLiquidBaseComponent!");
}
return VoxelShape.builder()
.solid(0, 0, 0, 1, 0.125f * liquidBaseComponent.getLevel(liquidBlockState), 1)
.solid(0, 0, 0, 1, 0.125f * BlockLiquidBaseComponent.getDepth(liquidBlockState), 1)
.build();
}
}
2 changes: 1 addition & 1 deletion data/resources/block_states.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion data/resources/unpacked/block_states_raw.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public static void main(String[] args) {

public static class RawBlockStateData {
public int burnOdds = 0;
public boolean canContainLiquid = false;
public boolean canContainLiquidSource;
public String liquidReactionOnTouch;
public float[] collisionShape;
public float[] liquidClipShape;
Expand All @@ -57,7 +57,7 @@ public static class RawBlockStateData {

public static class NewBlockStateData {
public int burnOdds = 0;
public boolean canContainLiquid = false;
public boolean canContainLiquidSource;
public String liquidReactionOnTouch;
public float[] collisionShape;
public float[] shape;
Expand All @@ -79,7 +79,7 @@ public static class NewBlockStateData {
public static NewBlockStateData fromRaw(RawBlockStateData raw) {
var data = new NewBlockStateData();
data.burnOdds = raw.burnOdds;
data.canContainLiquid = raw.canContainLiquid;
data.canContainLiquidSource = raw.canContainLiquidSource;
data.liquidReactionOnTouch = raw.liquidReactionOnTouch;
data.collisionShape = clampShape(raw.collisionShape);
data.hardness = raw.hardness;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ public BlockLavaBaseComponentImpl(BlockType<? extends BlockBehavior> blockType)
super(blockType);
}

@Override
public boolean isSameLiquidType(BlockType<?> blockType) {
return blockType == BlockTypes.LAVA || blockType == BlockTypes.FLOWING_LAVA;
}

@Override
public void onCollideWithEntity(BlockStateWithPos blockStateWithPos, Entity entity) {
if (!(entity instanceof EntityDamageComponent damageComponent)) {
Expand Down
Loading

0 comments on commit 9266014

Please sign in to comment.