FluidState API (#9951)

* Add new FluidState API functionality
---------

Co-authored-by: Bjarne Koll <lynxplay101@gmail.com>
Co-authored-by: Owen1212055 <23108066+Owen1212055@users.noreply.github.com>
This commit is contained in:
viciscat 2024-02-17 21:44:03 +01:00 committed by GitHub
parent 1964b22439
commit d95341e44a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 372 additions and 0 deletions

View File

@ -0,0 +1,164 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: vicisacat <victor.branchu@gmail.com>
Date: Fri, 17 Nov 2023 20:21:47 +0100
Subject: [PATCH] Add FluidState API
diff --git a/src/main/java/io/papermc/paper/block/fluid/FluidData.java b/src/main/java/io/papermc/paper/block/fluid/FluidData.java
new file mode 100644
index 0000000000000000000000000000000000000000..913acd58547d97cafc1466f6e2b3b4d22cf0b02d
--- /dev/null
+++ b/src/main/java/io/papermc/paper/block/fluid/FluidData.java
@@ -0,0 +1,68 @@
+package io.papermc.paper.block.fluid;
+
+import org.bukkit.Fluid;
+import org.bukkit.Location;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Range;
+
+/**
+ * A representation of a fluid in a specific state of data.
+ * This type is not linked to a specific location and hence mostly resembles a {@link org.bukkit.block.data.BlockData}.
+ */
+public interface FluidData extends Cloneable {
+
+ /**
+ * Gets the fluid type of this fluid data.
+ *
+ * @return the fluid type
+ */
+ @NotNull Fluid getFluidType();
+
+ /**
+ * Returns a copy of this FluidData.
+ *
+ * @return a copy of the fluid data
+ */
+ @NotNull FluidData clone();
+
+ /**
+ * Computes the direction of the flow of the liquid at the given location as a vector.
+ * <p>
+ * This method requires the passed location's chunk to be loaded.
+ * If said chunk is not loaded when this method is called, the chunk will first be loaded prior to the computation
+ * which leads to a potentially slow sync chunk load.
+ *
+ * @param location - the location to check the liquid flow
+ * @return the flow direction vector at the given location
+ */
+ @NotNull Vector computeFlowDirection(@NotNull Location location);
+
+ /**
+ * Returns the level of liquid this fluid data holds.
+ *
+ * @return the amount as an integer, between 0 and 8
+ */
+ @Range(from = 0, to = 8)
+ int getLevel();
+
+ /**
+ * Computes the height of the fluid in the world.
+ * <p>
+ * This method requires the passed location's chunk to be loaded.
+ * If said chunk is not loaded when this method is called, the chunk will first be loaded prior to the computation
+ * which leads to a potentially slow sync chunk load.
+ *
+ * @param location the location at which to check the high of this fluid data.
+ * @return the height as a float value
+ */
+ @Range(from = 0, to = 1)
+ float computeHeight(@NotNull Location location);
+
+ /**
+ * Returns whether this fluid is a source block
+ *
+ * @return true if the fluid is a source block, false otherwise
+ */
+ boolean isSource();
+}
diff --git a/src/main/java/io/papermc/paper/block/fluid/type/FallingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/FallingFluidData.java
new file mode 100644
index 0000000000000000000000000000000000000000..7bd9f28ba646f09080b5c29b9d3be5af676c912e
--- /dev/null
+++ b/src/main/java/io/papermc/paper/block/fluid/type/FallingFluidData.java
@@ -0,0 +1,16 @@
+package io.papermc.paper.block.fluid.type;
+
+import io.papermc.paper.block.fluid.FluidData;
+
+/**
+ * A specific subtype of {@link FluidData} that is returned by the API for fluid data of potentially falling fluids.
+ */
+public interface FallingFluidData extends FluidData {
+
+ /**
+ * Get if this liquid is falling.
+ *
+ * @return true if falling
+ */
+ boolean isFalling();
+}
diff --git a/src/main/java/io/papermc/paper/block/fluid/type/FlowingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/FlowingFluidData.java
new file mode 100644
index 0000000000000000000000000000000000000000..fbccdffe8d73e517204081c73bca9154f8c7d69f
--- /dev/null
+++ b/src/main/java/io/papermc/paper/block/fluid/type/FlowingFluidData.java
@@ -0,0 +1,10 @@
+package io.papermc.paper.block.fluid.type;
+
+import io.papermc.paper.block.fluid.FluidData;
+
+/**
+ * A specific subtype of {@link FluidData} that is returned by the API for fluid data of potentially falling fluids.
+ */
+public interface FlowingFluidData extends FallingFluidData {
+
+}
diff --git a/src/main/java/org/bukkit/RegionAccessor.java b/src/main/java/org/bukkit/RegionAccessor.java
index 43dd6c59cceba12f27e6b265acc3ad97eea37abd..eb33e8e671972aa308ad75a7ce9aa9ac526f470f 100644
--- a/src/main/java/org/bukkit/RegionAccessor.java
+++ b/src/main/java/org/bukkit/RegionAccessor.java
@@ -102,6 +102,41 @@ public interface RegionAccessor extends Keyed { // Paper
@NotNull
BlockState getBlockState(int x, int y, int z);
+ // Paper start - FluidState API
+ /**
+ * Gets the {@link io.papermc.paper.block.fluid.FluidData} at the specified position.
+ *
+ * @param x The x-coordinate of the position
+ * @param y The y-coordinate of the position
+ * @param z The z-coordinate of the position
+ * @return The {@link io.papermc.paper.block.fluid.FluidData} at the specified position
+ */
+ @NotNull
+ io.papermc.paper.block.fluid.FluidData getFluidData(int x, int y, int z);
+
+ /**
+ * Gets the {@link io.papermc.paper.block.fluid.FluidData} at the given position
+ *
+ * @param position The position of the fluid
+ * @return The fluid data at the given position
+ */
+ @NotNull
+ default io.papermc.paper.block.fluid.FluidData getFluidData(@NotNull io.papermc.paper.math.Position position) {
+ return getFluidData(position.blockX(), position.blockY(), position.blockZ());
+ }
+
+ /**
+ * Gets the {@link io.papermc.paper.block.fluid.FluidData} at the given position
+ *
+ * @param location The location of the fluid
+ * @return The fluid data at the given position
+ */
+ @NotNull
+ default io.papermc.paper.block.fluid.FluidData getFluidData(@NotNull Location location) {
+ return getFluidData(location.blockX(), location.blockY(), location.blockZ());
+ }
+ // Paper end
+
/**
* Gets the {@link BlockData} at the given {@link Location}.
*

View File

@ -0,0 +1,208 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: vicisacat <victor.branchu@gmail.com>
Date: Fri, 17 Nov 2023 20:22:43 +0100
Subject: [PATCH] Add FluidState API
diff --git a/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java
new file mode 100644
index 0000000000000000000000000000000000000000..479bc32241ebadf8bbc1080b601f61391ad37fa4
--- /dev/null
+++ b/src/main/java/io/papermc/paper/block/fluid/PaperFluidData.java
@@ -0,0 +1,110 @@
+package io.papermc.paper.block.fluid;
+
+import com.google.common.base.Preconditions;
+import io.papermc.paper.block.fluid.type.PaperFallingFluidData;
+import io.papermc.paper.block.fluid.type.PaperFlowingFluidData;
+import io.papermc.paper.util.MCUtil;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+import net.minecraft.world.level.material.FluidState;
+import net.minecraft.world.level.material.LavaFluid;
+import net.minecraft.world.level.material.WaterFluid;
+import org.bukkit.Fluid;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.CraftFluid;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.util.CraftVector;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+
+public class PaperFluidData implements FluidData {
+
+ private final FluidState state;
+
+ protected PaperFluidData(final FluidState state) {
+ this.state = state;
+ }
+
+ /**
+ * Provides the internal server representation of this fluid data.
+ * @return the fluid state.
+ */
+ public FluidState getState() {
+ return this.state;
+ }
+
+ @Override
+ public final @NotNull Fluid getFluidType() {
+ return CraftFluid.minecraftToBukkit(this.state.getType());
+ }
+
+ @Override
+ public @NotNull PaperFluidData clone() {
+ try {
+ return (PaperFluidData) super.clone();
+ } catch (final CloneNotSupportedException ex) {
+ throw new AssertionError("Clone not supported", ex);
+ }
+ }
+
+ @Override
+ public @NotNull Vector computeFlowDirection(final Location location) {
+ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute flow direction on world-less location");
+ return CraftVector.toBukkit(this.state.getFlow(
+ ((CraftWorld) location.getWorld()).getHandle(),
+ MCUtil.toBlockPosition(location)
+ ));
+ }
+
+ @Override
+ public int getLevel() {
+ return this.state.getAmount();
+ }
+
+ @Override
+ public float computeHeight(@NotNull final Location location) {
+ Preconditions.checkArgument(location.getWorld() != null, "Cannot compute height on world-less location");
+ return this.state.getHeight(((CraftWorld) location.getWorld()).getHandle(), MCUtil.toBlockPos(location));
+ }
+
+ @Override
+ public boolean isSource() {
+ return this.state.isSource();
+ }
+
+ @Override
+ public int hashCode() {
+ return this.state.hashCode();
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ return obj instanceof final PaperFluidData paperFluidData && this.state.equals(paperFluidData.state);
+ }
+
+ @Override
+ public String toString() {
+ return "PaperFluidData{" + this.state + "}";
+ }
+
+ /* Registry */
+ private static final Map<Class<? extends net.minecraft.world.level.material.Fluid>, Function<FluidState, PaperFluidData>> MAP = new HashMap<>();
+ static {
+ //<editor-fold desc="PaperFluidData Registration" defaultstate="collapsed">
+ register(LavaFluid.Source.class, PaperFallingFluidData::new);
+ register(WaterFluid.Source.class, PaperFallingFluidData::new);
+ register(LavaFluid.Flowing.class, PaperFlowingFluidData::new);
+ register(WaterFluid.Flowing.class, PaperFlowingFluidData::new);
+ //</editor-fold>
+ }
+
+ static void register(final Class<? extends net.minecraft.world.level.material.Fluid> fluid, final Function<FluidState, PaperFluidData> creator) {
+ Preconditions.checkState(MAP.put(fluid, creator) == null, "Duplicate mapping %s->%s", fluid, creator);
+ MAP.put(fluid, creator);
+ }
+
+ public static PaperFluidData createData(final FluidState state) {
+ return MAP.getOrDefault(state.getType().getClass(), PaperFluidData::new).apply(state);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/block/fluid/package-info.java b/src/main/java/io/papermc/paper/block/fluid/package-info.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfabb814ebd281aab299c6c655266ff357e08806
--- /dev/null
+++ b/src/main/java/io/papermc/paper/block/fluid/package-info.java
@@ -0,0 +1,5 @@
+@DefaultQualifier(NonNull.class)
+package io.papermc.paper.block.fluid;
+
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java
new file mode 100644
index 0000000000000000000000000000000000000000..655dbd83ff4e632f1168b75e9b402b05aa9d8edf
--- /dev/null
+++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFallingFluidData.java
@@ -0,0 +1,18 @@
+
+package io.papermc.paper.block.fluid.type;
+
+import io.papermc.paper.block.fluid.PaperFluidData;
+import net.minecraft.world.level.material.FlowingFluid;
+import net.minecraft.world.level.material.FluidState;
+
+public class PaperFallingFluidData extends PaperFluidData implements FallingFluidData {
+
+ public PaperFallingFluidData(final FluidState state) {
+ super(state);
+ }
+
+ @Override
+ public boolean isFalling() {
+ return this.getState().getValue(FlowingFluid.FALLING);
+ }
+}
diff --git a/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java
new file mode 100644
index 0000000000000000000000000000000000000000..c0c2805cb045cdd835b402776a6923fe2ecc2a99
--- /dev/null
+++ b/src/main/java/io/papermc/paper/block/fluid/type/PaperFlowingFluidData.java
@@ -0,0 +1,11 @@
+package io.papermc.paper.block.fluid.type;
+
+import net.minecraft.world.level.material.FluidState;
+
+public class PaperFlowingFluidData extends PaperFallingFluidData implements FlowingFluidData {
+
+ public PaperFlowingFluidData(final FluidState state) {
+ super(state);
+ }
+
+}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
index 9dd6012556979514f9879f867138bc836c58ef3f..1df2202277ab58d7de844f7bebc07e494a0ecdf3 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
@@ -107,6 +107,13 @@ public abstract class CraftRegionAccessor implements RegionAccessor {
return CraftBlock.at(this.getHandle(), new BlockPos(x, y, z)).getState();
}
+ // Paper start - FluidState API
+ @Override
+ public io.papermc.paper.block.fluid.FluidData getFluidData(final int x, final int y, final int z) {
+ return io.papermc.paper.block.fluid.PaperFluidData.createData(getHandle().getFluidState(new BlockPos(x, y, z)));
+ }
+ // Paper end
+
@Override
public BlockData getBlockData(Location location) {
return this.getBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ());
diff --git a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
index ca9bb98ccfc3863c2ba538953470ab9e2b8a2f29..a2edef9739bad941f8e581da126bbfeac7cab5d8 100644
--- a/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
+++ b/src/main/java/org/bukkit/craftbukkit/generator/CraftLimitedRegion.java
@@ -303,4 +303,11 @@ public class CraftLimitedRegion extends CraftRegionAccessor implements LimitedRe
return centerChunkZ;
}
// Paper end - Add more LimitedRegion API
+ // Paper start - Fluid API
+ @Override
+ public io.papermc.paper.block.fluid.FluidData getFluidData(int x, int y, int z) {
+ Preconditions.checkArgument(this.isInRegion(x, y, z), "Coordinates %s, %s, %s are not in the region", x, y, z);
+ return super.getFluidData(x, y, z);
+ }
+ // Paper end
}