From 4931bc4878cf28da34534a8968df4b095e78fa34 Mon Sep 17 00:00:00 2001 From: Maddy Miller Date: Sat, 8 Aug 2026 16:01:01 +1000 Subject: [PATCH 1/3] Properly support fluids --- .../impl/v1_21_11/PaperweightAdapter.java | 13 +++++ .../impl/v1_21_4/PaperweightAdapter.java | 13 +++++ .../impl/v1_21_5/PaperweightAdapter.java | 13 +++++ .../impl/v1_21_6/PaperweightAdapter.java | 13 +++++ .../impl/v1_21_9/PaperweightAdapter.java | 13 +++++ .../impl/v26_1/PaperweightAdapter.java | 13 +++++ .../impl/v26_2/PaperweightAdapter.java | 13 +++++ .../worldedit/bukkit/BukkitBlockRegistry.java | 9 ++++ .../worldedit/bukkit/WorldEditPlugin.java | 11 ++++ .../bukkit/adapter/BukkitImplAdapter.java | 11 ++++ .../coremc/internal/CoreMcBlockRegistry.java | 14 ++++++ .../worldedit/coremc/internal/CoreMcMod.java | 15 ++++++ .../worldedit/world/block/BlockState.java | 15 ++++++ .../world/fluid/FluidCategories.java | 35 +++++++------ .../worldedit/world/fluid/FluidState.java | 50 +++++++++++++++++++ .../worldedit/world/fluid/FluidTypes.java | 29 +++++------ .../world/registry/BlockRegistry.java | 14 ++++++ .../worldedit/sponge/SpongeBlockRegistry.java | 15 ++++++ .../worldedit/sponge/SpongeWorldEdit.java | 17 +++++++ 19 files changed, 294 insertions(+), 32 deletions(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java diff --git a/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java index 816930823e..7419a07109 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java @@ -65,6 +65,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; @@ -354,6 +356,17 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public BlockState getBlock(Location location) { checkNotNull(location); diff --git a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java index fcf1579cea..a58f5e6c6b 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java @@ -65,6 +65,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; @@ -349,6 +351,17 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public BlockState getBlock(Location location) { checkNotNull(location); diff --git a/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java index 4d48915dee..adb94b0a90 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java @@ -65,6 +65,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; @@ -349,6 +351,17 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public BlockState getBlock(Location location) { checkNotNull(location); diff --git a/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java index b7fb495d5f..cc3eb08238 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java @@ -65,6 +65,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; @@ -355,6 +357,17 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public BlockState getBlock(Location location) { checkNotNull(location); diff --git a/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java index 65692f02f5..9363388ac8 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java @@ -65,6 +65,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; @@ -354,6 +356,17 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public BlockState getBlock(Location location) { checkNotNull(location); diff --git a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java index 00290bbaf5..748060b00b 100644 --- a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java @@ -64,6 +64,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; @@ -365,6 +367,17 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public BlockState getBlock(Location location) { checkNotNull(location); diff --git a/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java index 5393abeffe..fd0953de16 100644 --- a/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java @@ -64,6 +64,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; @@ -366,6 +368,17 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public BlockState getBlock(Location location) { checkNotNull(location); diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 70cd562329..082ca72477 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockRegistry; import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial; @@ -70,6 +71,14 @@ public BlockMaterial getMaterial(BlockType blockType) { return null; } + @Override + public FluidState getFluidState(BlockState state) { + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { + return WorldEditPlugin.getInstance().getBukkitImplAdapter().getFluidState(state); + } + return FluidState.EMPTY; + } + @Override public OptionalInt getInternalBlockStateId(BlockState state) { if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java index 900a033b72..6e0aed0a3b 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/WorldEditPlugin.java @@ -58,6 +58,8 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.FuzzyBlockState; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.fluid.FluidCategory; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; import io.papermc.lib.PaperLib; @@ -239,6 +241,11 @@ private void initializeRegistries() { String key = entityType.getKey().toString(); EntityType.REGISTRY.register(key, new EntityType(key)); }); + // Fluid + Registry.FLUID.forEach(fluid -> { + String key = fluid.getKey().toString(); + FluidType.REGISTRY.register(key, new FluidType(key)); + }); // Registries only available via NMS BukkitImplAdapter adapter = getBukkitImplAdapter(); @@ -260,6 +267,10 @@ private void setupTags() { String key = itemTag.getKey().toString(); ItemCategory.REGISTRY.register(key, new ItemCategory(key)); } + for (Tag fluidTag : Bukkit.getTags(Tag.REGISTRY_FLUIDS, Material.class)) { + String key = fluidTag.getKey().toString(); + FluidCategory.REGISTRY.register(key, new FluidCategory(key)); + } } private void loadAdapter() { diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index 041b4872a9..f9509c30f8 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -39,6 +39,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; @@ -232,6 +233,16 @@ default boolean simulateItemUse(World world, BlockVector3 position, BaseItem ite */ Set getSupportedSideEffects(); + /** + * Gets the fluid state supplied by a block state. + * + * @param state the block state + * @return the fluid state, or {@link FluidState#EMPTY} if unavailable + */ + default FluidState getFluidState(BlockState state) { + return FluidState.EMPTY; + } + default OptionalInt getInternalBlockStateId(BlockData data) { return OptionalInt.empty(); } diff --git a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java index 6d6119d0a4..8ffa4980b2 100644 --- a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java +++ b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java @@ -24,8 +24,11 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockRegistry; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.Block; import java.util.Collection; @@ -73,6 +76,17 @@ public BlockMaterial getMaterial(BlockType blockType) { return map; } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.material.FluidState fluidState = platform.getAdapter() + .toNativeBlockState(state).getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = BuiltInRegistries.FLUID.getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public OptionalInt getInternalBlockStateId(BlockState state) { net.minecraft.world.level.block.state.BlockState equivalent = platform.getAdapter().toNativeBlockState(state); diff --git a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcMod.java b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcMod.java index e86bd55427..aba8697c90 100644 --- a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcMod.java +++ b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcMod.java @@ -43,6 +43,8 @@ import com.sk89q.worldedit.world.block.BlockCategory; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.fluid.FluidCategory; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; @@ -159,6 +161,12 @@ protected void setupRegistries(MinecraftServer server) { ItemCategory.REGISTRY.register(key, new ItemCategory(key)); } }); + server.registryAccess().lookupOrThrow(Registries.FLUID).getTags().map(t -> t.key().location()).forEach(name -> { + String key = name.toString(); + if (FluidCategory.REGISTRY.get(key) == null) { + FluidCategory.REGISTRY.register(key, new FluidCategory(key)); + } + }); Registry biomeRegistry = server.registryAccess().lookupOrThrow(Registries.BIOME); biomeRegistry.getTags().forEach(tag -> { String key = tag.key().location().toString(); @@ -200,6 +208,13 @@ protected void setupRegistries(MinecraftServer server) { } } } + // Fluid + for (Identifier name : server.registryAccess().lookupOrThrow(Registries.FLUID).keySet()) { + String key = name.toString(); + if (FluidType.REGISTRY.get(key) == null) { + FluidType.REGISTRY.register(key, new FluidType(key)); + } + } // Common registries CommonRegistries.init(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java index cb94239af9..4a2e9edfe1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/block/BlockState.java @@ -19,9 +19,12 @@ package com.sk89q.worldedit.world.block; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.fluid.FluidState; import org.enginehub.linbus.tree.LinCompoundTag; import java.util.HashSet; @@ -55,6 +58,9 @@ public void setInternalId(BlockState blockState, int internalId) { private final BaseBlock emptyBaseBlock; private final LazyReference lazyStringRepresentation; + private final LazyReference fluidState = LazyReference.from(() -> WorldEdit.getInstance() + .getPlatformManager().queryCapability(Capability.GAME_HOOKS).getRegistries() + .getBlockRegistry().getFluidState(this)); /** * The internal ID of the block state. @@ -103,6 +109,15 @@ public Map, Object> getStates() { return this.values; } + /** + * Gets the fluid state supplied by this block state. + * + * @return the fluid state + */ + public FluidState getFluidState() { + return fluidState.getValue(); + } + @Override public boolean equalsFuzzy(BlockStateHolder o) { if (null == o) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java index 1dd97c2804..4ad296433d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidCategories.java @@ -19,28 +19,31 @@ package com.sk89q.worldedit.world.fluid; -import javax.annotation.Nullable; - /** - * Stores a list of categories of Block Types. + * Stores a list of common {@link FluidCategory FluidCategories}. + * + * @see FluidCategory */ +@SuppressWarnings("unused") public final class FluidCategories { - - public static final FluidCategory LAVA = register("minecraft:lava"); - public static final FluidCategory WATER = register("minecraft:water"); + public static final FluidCategory BUBBLE_COLUMN_CAN_OCCUPY = get("minecraft:bubble_column_can_occupy"); + public static final FluidCategory LAVA = get("minecraft:lava"); + public static final FluidCategory SUPPORTS_FROGSPAWN = get("minecraft:supports_frogspawn"); + public static final FluidCategory SUPPORTS_LILY_PAD = get("minecraft:supports_lily_pad"); + public static final FluidCategory SUPPORTS_SUGAR_CANE_ADJACENTLY = get("minecraft:supports_sugar_cane_adjacently"); + public static final FluidCategory WATER = get("minecraft:water"); private FluidCategories() { } - private static FluidCategory register(final String id) { - return register(new FluidCategory(id)); - } - - public static FluidCategory register(final FluidCategory tag) { - return FluidCategory.REGISTRY.register(tag.id(), tag); - } - - public static @Nullable FluidCategory get(final String id) { - return FluidCategory.REGISTRY.get(id); + /** + * Gets the {@link FluidCategory} associated with the given id. + */ + public static FluidCategory get(String id) { + FluidCategory entry = FluidCategory.REGISTRY.get(id); + if (entry == null) { + return new FluidCategory(id); + } + return entry; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java new file mode 100644 index 0000000000..160cfda2e9 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java @@ -0,0 +1,50 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.fluid; + +import static com.google.common.base.Preconditions.checkNotNull; + +/** + * The fluid supplied by a block state. + * + *

A fluid state is derived from a block state by the active platform. This + * allows blocks such as kelp and waterlogged blocks to supply fluid without + * being fluid blocks themselves.

+ * + * @param type the type of fluid supplied + */ +public record FluidState(FluidType type) { + + public static final FluidState EMPTY = new FluidState(FluidTypes.EMPTY); + + public FluidState { + checkNotNull(type); + } + + /** + * Returns whether this state supplies no fluid. + * + * @return whether this state is empty + */ + public boolean isEmpty() { + return type == FluidTypes.EMPTY; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java index 40cdb8933b..84cb8271b0 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypes.java @@ -22,28 +22,25 @@ import javax.annotation.Nullable; /** - * Stores a list of common Fluid String IDs. + * Stores a list of common {@link FluidType FluidTypes}. + * + * @see FluidType */ +@SuppressWarnings("unused") public final class FluidTypes { - - public static final FluidType EMPTY = register("minecraft:empty"); - public static final FluidType FLOWING_LAVA = register("minecraft:flowing_lava"); - public static final FluidType FLOWING_WATER = register("minecraft:flowing_water"); - public static final FluidType LAVA = register("minecraft:lava"); - public static final FluidType WATER = register("minecraft:water"); + @Nullable public static final FluidType EMPTY = get("minecraft:empty"); + @Nullable public static final FluidType FLOWING_LAVA = get("minecraft:flowing_lava"); + @Nullable public static final FluidType FLOWING_WATER = get("minecraft:flowing_water"); + @Nullable public static final FluidType LAVA = get("minecraft:lava"); + @Nullable public static final FluidType WATER = get("minecraft:water"); private FluidTypes() { } - private static FluidType register(final String id) { - return register(new FluidType(id)); - } - - public static FluidType register(final FluidType fluid) { - return FluidType.REGISTRY.register(fluid.id(), fluid); - } - - public static @Nullable FluidType get(final String id) { + /** + * Gets the {@link FluidType} associated with the given id. + */ + public static @Nullable FluidType get(String id) { return FluidType.REGISTRY.get(id); } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java index 012b13d849..d9c2c529c6 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; import java.util.Map; import java.util.OptionalInt; @@ -58,6 +59,19 @@ public interface BlockRegistry { */ Map> getProperties(BlockType blockType); + /** + * Get the fluid state supplied by a block state. + * + *

Implementations that cannot obtain this information should return + * {@link FluidState#EMPTY}.

+ * + * @param state the block state + * @return the fluid state supplied by the block state + */ + default FluidState getFluidState(BlockState state) { + return FluidState.EMPTY; + } + /** * Retrieve the internal ID for a given state, if possible. * diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java index 5c0434d36a..3a6f4f9dbb 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java @@ -24,8 +24,11 @@ import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockRegistry; +import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.Block; import org.spongepowered.api.ResourceKey; import org.spongepowered.api.Sponge; @@ -80,6 +83,18 @@ public BlockMaterial getMaterial(BlockType blockType) { return map; } + @Override + public FluidState getFluidState(BlockState state) { + net.minecraft.world.level.block.state.BlockState equivalent = (net.minecraft.world.level.block.state.BlockState) + SpongeAdapter.adapt(state); + net.minecraft.world.level.material.FluidState fluidState = equivalent.getFluidState(); + if (fluidState.isEmpty()) { + return FluidState.EMPTY; + } + String id = BuiltInRegistries.FLUID.getKey(fluidState.getType()).toString(); + return new FluidState(FluidTypes.get(id)); + } + @Override public OptionalInt getInternalBlockStateId(BlockState state) { org.spongepowered.api.block.BlockState equivalent = SpongeAdapter.adapt(state); diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java index af9afa2e9a..662b6f15a8 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeWorldEdit.java @@ -40,6 +40,8 @@ import com.sk89q.worldedit.world.biome.BiomeCategory; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.fluid.FluidCategory; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.generation.TreeType; import com.sk89q.worldedit.world.item.ItemCategory; import net.kyori.adventure.audience.Audience; @@ -223,6 +225,7 @@ public void serverStarted(StartedEngineEvent event) { } } }); + // Tags event.game().registry(RegistryTypes.BLOCK_TYPE).tags().forEach(blockTypeTag -> { String id = blockTypeTag.key().asString(); if (!BlockCategory.REGISTRY.keySet().contains(id)) { @@ -235,12 +238,26 @@ public void serverStarted(StartedEngineEvent event) { ItemCategory.REGISTRY.register(id, new ItemCategory(id)); } }); + event.game().registry(RegistryTypes.FLUID_TYPE).tags().forEach(fluidTypeTag -> { + String id = fluidTypeTag.key().asString(); + if (!FluidCategory.REGISTRY.keySet().contains(id)) { + FluidCategory.REGISTRY.register(id, new FluidCategory(id)); + } + }); + // Biome RegistryTypes.BIOME.get().tags().forEach(biomeTag -> { String id = biomeTag.key().asString(); if (!BiomeCategory.REGISTRY.keySet().contains(id)) { BiomeCategory.REGISTRY.register(id, new BiomeCategory(id, () -> event.game().registry(RegistryTypes.BIOME).taggedValues(biomeTag).map(SpongeAdapter::adapt).collect(Collectors.toSet()))); } }); + // Fluid + event.game().registry(RegistryTypes.FLUID_TYPE).tags().forEach(fluidTag -> { + String id = fluidTag.key().asString(); + if (!FluidType.REGISTRY.keySet().contains(id)) { + FluidType.REGISTRY.register(id, new FluidType(id)); + } + }); // Common registries CommonRegistries.init(); From 08ffb0be007a078cc3ff63e9b0cffaad8006be96 Mon Sep 17 00:00:00 2001 From: Maddy Miller Date: Sat, 8 Aug 2026 16:06:38 +1000 Subject: [PATCH 2/3] Fix verification/checkstyle --- .../accepted-core-public-api-changes.json | 16 ++++++++++++++++ .../impl/v1_21_11/PaperweightAdapter.java | 4 ++-- .../adapter/impl/v1_21_4/PaperweightAdapter.java | 4 ++-- .../adapter/impl/v1_21_5/PaperweightAdapter.java | 4 ++-- .../adapter/impl/v1_21_6/PaperweightAdapter.java | 4 ++-- .../adapter/impl/v1_21_9/PaperweightAdapter.java | 4 ++-- .../adapter/impl/v26_1/PaperweightAdapter.java | 4 ++-- .../adapter/impl/v26_2/PaperweightAdapter.java | 4 ++-- 8 files changed, 30 insertions(+), 14 deletions(-) diff --git a/verification/src/changes/accepted-core-public-api-changes.json b/verification/src/changes/accepted-core-public-api-changes.json index d6b6f34429..299d6c18aa 100644 --- a/verification/src/changes/accepted-core-public-api-changes.json +++ b/verification/src/changes/accepted-core-public-api-changes.json @@ -116,5 +116,21 @@ "ANNOTATION_REMOVED" ] } + ], + "Fluid overhaul": [ + { + "type": "com.sk89q.worldedit.world.fluid.FluidCategories", + "member": "Method com.sk89q.worldedit.world.fluid.FluidCategories.register(com.sk89q.worldedit.world.fluid.FluidCategory)", + "changes": [ + "METHOD_REMOVED" + ] + }, + { + "type": "com.sk89q.worldedit.world.fluid.FluidTypes", + "member": "Method com.sk89q.worldedit.world.fluid.FluidTypes.register(com.sk89q.worldedit.world.fluid.FluidType)", + "changes": [ + "METHOD_REMOVED" + ] + } ] } diff --git a/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java index 7419a07109..5e400943e6 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java @@ -65,10 +65,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.fluid.FluidState; -import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; diff --git a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java index a58f5e6c6b..8a1dfd25f7 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java @@ -65,10 +65,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.fluid.FluidState; -import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; diff --git a/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java index adb94b0a90..92700001f8 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java @@ -65,10 +65,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.fluid.FluidState; -import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; diff --git a/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java index cc3eb08238..99e8118af7 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java @@ -65,10 +65,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.fluid.FluidState; -import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; diff --git a/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java index 9363388ac8..83b4989e39 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java @@ -65,10 +65,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.fluid.FluidState; -import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; diff --git a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java index 748060b00b..660e3e84c6 100644 --- a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java @@ -64,10 +64,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.fluid.FluidState; -import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; diff --git a/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java index fd0953de16..a75d6af4b7 100644 --- a/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java @@ -64,10 +64,10 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.fluid.FluidState; -import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; From 4aab7ebd0a0b6e276b0a86ddbff2fda0ae4b60e7 Mon Sep 17 00:00:00 2001 From: Maddy Miller Date: Sat, 8 Aug 2026 19:16:45 +1000 Subject: [PATCH 3/3] Mirror the entire block property system for fluids too --- .../impl/v1_21_11/PaperweightAdapter.java | 25 +++- .../impl/v1_21_4/PaperweightAdapter.java | 24 +++- .../impl/v1_21_5/PaperweightAdapter.java | 24 +++- .../impl/v1_21_6/PaperweightAdapter.java | 24 +++- .../impl/v1_21_9/PaperweightAdapter.java | 24 +++- .../impl/v26_1/PaperweightAdapter.java | 25 +++- .../impl/v26_2/PaperweightAdapter.java | 25 +++- .../worldedit/bukkit/BukkitBlockRegistry.java | 3 +- .../worldedit/bukkit/BukkitFluidRegistry.java | 37 ++++++ .../worldedit/bukkit/BukkitRegistries.java | 7 + .../bukkit/adapter/BukkitImplAdapter.java | 16 ++- .../coremc/internal/CoreMcBlockRegistry.java | 11 +- .../coremc/internal/CoreMcFluidRegistry.java | 49 +++++++ .../coremc/internal/CoreMcRegistries.java | 8 ++ .../fluid/DefaultFluidTypeStateList.java | 124 ++++++++++++++++++ .../worldedit/world/fluid/FluidState.java | 60 ++++++++- .../worldedit/world/fluid/FluidType.java | 100 +++++++++++++- .../world/fluid/FluidTypeStateList.java | 41 ++++++ .../fluid/SingletonFluidTypeStateList.java | 62 +++++++++ .../world/registry/BlockRegistry.java | 6 +- .../world/registry/FluidRegistry.java | 39 ++++++ .../world/registry/NullFluidRegistry.java | 41 ++++++ .../worldedit/world/registry/Registries.java | 9 ++ .../worldedit/sponge/SpongeBlockRegistry.java | 11 +- .../worldedit/sponge/SpongeFluidRegistry.java | 46 +++++++ .../worldedit/sponge/SpongeRegistries.java | 7 + 26 files changed, 813 insertions(+), 35 deletions(-) create mode 100644 worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitFluidRegistry.java create mode 100644 worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcFluidRegistry.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/DefaultFluidTypeStateList.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypeStateList.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/SingletonFluidTypeStateList.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/FluidRegistry.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullFluidRegistry.java create mode 100644 worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeFluidRegistry.java diff --git a/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java index 5e400943e6..fdce051ad0 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.11/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_11/PaperweightAdapter.java @@ -68,6 +68,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; @@ -356,15 +357,21 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) .getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (net.minecraft.world.level.block.state.properties.Property property : fluidState.getProperties()) { + properties.put(PROPERTY_CACHE.getUnchecked(property), fluidState.getValue(property)); + } + return type.getState(properties); } @Override @@ -636,6 +643,20 @@ yield new EnumProperty(state.getName(), return properties; } + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getFluidProperties(FluidType fluidType) { + Map> properties = new TreeMap<>(); + var fluid = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .listElements().filter(reference -> reference.key().identifier().toString().equals(fluidType.id())) + .findFirst().orElseThrow(); + for (net.minecraft.world.level.block.state.properties.Property state : fluid.value().defaultFluidState().getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.name(), property); + } + return properties; + } + @Override public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { var structureBlock = new StructureBlockEntity( diff --git a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java index 8a1dfd25f7..07b10f53b5 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightAdapter.java @@ -68,6 +68,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; @@ -351,15 +352,21 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) .getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (net.minecraft.world.level.block.state.properties.Property property : fluidState.getProperties()) { + properties.put(PROPERTY_CACHE.getUnchecked(property), fluidState.getValue(property)); + } + return type.getState(properties); } @Override @@ -617,6 +624,19 @@ yield new EnumProperty(state.getName(), return properties; } + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getFluidProperties(FluidType fluidType) { + Map> properties = new TreeMap<>(); + var fluid = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .get(ResourceLocation.parse(fluidType.id())).orElseThrow(); + for (net.minecraft.world.level.block.state.properties.Property state : fluid.value().defaultFluidState().getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.name(), property); + } + return properties; + } + @Override public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { var structureBlock = new StructureBlockEntity( diff --git a/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java index 92700001f8..1dd1595d30 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_5/PaperweightAdapter.java @@ -68,6 +68,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; @@ -351,15 +352,21 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) .getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (net.minecraft.world.level.block.state.properties.Property property : fluidState.getProperties()) { + properties.put(PROPERTY_CACHE.getUnchecked(property), fluidState.getValue(property)); + } + return type.getState(properties); } @Override @@ -615,6 +622,19 @@ yield new EnumProperty(state.getName(), return properties; } + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getFluidProperties(FluidType fluidType) { + Map> properties = new TreeMap<>(); + var fluid = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .get(ResourceLocation.parse(fluidType.id())).orElseThrow(); + for (net.minecraft.world.level.block.state.properties.Property state : fluid.value().defaultFluidState().getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.name(), property); + } + return properties; + } + @Override public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { var structureBlock = new StructureBlockEntity( diff --git a/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java index 99e8118af7..dc75fb35e0 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.6/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_6/PaperweightAdapter.java @@ -68,6 +68,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; @@ -357,15 +358,21 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) .getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (net.minecraft.world.level.block.state.properties.Property property : fluidState.getProperties()) { + properties.put(PROPERTY_CACHE.getUnchecked(property), fluidState.getValue(property)); + } + return type.getState(properties); } @Override @@ -637,6 +644,19 @@ yield new EnumProperty(state.getName(), return properties; } + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getFluidProperties(FluidType fluidType) { + Map> properties = new TreeMap<>(); + var fluid = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .get(ResourceLocation.parse(fluidType.id())).orElseThrow(); + for (net.minecraft.world.level.block.state.properties.Property state : fluid.value().defaultFluidState().getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.name(), property); + } + return properties; + } + @Override public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { var structureBlock = new StructureBlockEntity( diff --git a/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java index 83b4989e39..c9959eef6f 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1.21.9/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_9/PaperweightAdapter.java @@ -68,6 +68,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; @@ -356,15 +357,21 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) .getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (net.minecraft.world.level.block.state.properties.Property property : fluidState.getProperties()) { + properties.put(PROPERTY_CACHE.getUnchecked(property), fluidState.getValue(property)); + } + return type.getState(properties); } @Override @@ -636,6 +643,19 @@ yield new EnumProperty(state.getName(), return properties; } + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getFluidProperties(FluidType fluidType) { + Map> properties = new TreeMap<>(); + var fluid = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .get(ResourceLocation.parse(fluidType.id())).orElseThrow(); + for (net.minecraft.world.level.block.state.properties.Property state : fluid.value().defaultFluidState().getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.name(), property); + } + return properties; + } + @Override public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { var structureBlock = new StructureBlockEntity( diff --git a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java index 660e3e84c6..ac79eb3e3a 100644 --- a/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-26.1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_1/PaperweightAdapter.java @@ -67,6 +67,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; @@ -367,15 +368,21 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) .getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (net.minecraft.world.level.block.state.properties.Property property : fluidState.getProperties()) { + properties.put(PROPERTY_CACHE.getUnchecked(property), fluidState.getValue(property)); + } + return type.getState(properties); } @Override @@ -653,6 +660,20 @@ yield new EnumProperty(state.getName(), return properties; } + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getFluidProperties(FluidType fluidType) { + Map> properties = new TreeMap<>(); + var fluid = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .listElements().filter(reference -> reference.key().identifier().toString().equals(fluidType.id())) + .findFirst().orElseThrow(); + for (net.minecraft.world.level.block.state.properties.Property state : fluid.value().defaultFluidState().getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.name(), property); + } + return properties; + } + @Override public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { var structureBlock = new StructureBlockEntity( diff --git a/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java index a75d6af4b7..9d9f0f66d4 100644 --- a/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-26.2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v26_2/PaperweightAdapter.java @@ -67,6 +67,7 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; @@ -368,15 +369,21 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt return Block.stateById(internalId); } + @SuppressWarnings({ "rawtypes", "unchecked" }) @Override public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = adapt(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) .getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (net.minecraft.world.level.block.state.properties.Property property : fluidState.getProperties()) { + properties.put(PROPERTY_CACHE.getUnchecked(property), fluidState.getValue(property)); + } + return type.getState(properties); } @Override @@ -658,6 +665,20 @@ yield new EnumProperty(state.getName(), return properties; } + @SuppressWarnings({ "rawtypes" }) + @Override + public Map> getFluidProperties(FluidType fluidType) { + Map> properties = new TreeMap<>(); + var fluid = DedicatedServer.getServer().registryAccess().lookupOrThrow(Registries.FLUID) + .listElements().filter(reference -> reference.key().identifier().toString().equals(fluidType.id())) + .findFirst().orElseThrow(); + for (net.minecraft.world.level.block.state.properties.Property state : fluid.value().defaultFluidState().getProperties()) { + Property property = PROPERTY_CACHE.getUnchecked(state); + properties.put(property.name(), property); + } + return properties; + } + @Override public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { var structureBlock = new StructureBlockEntity( diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java index 082ca72477..fe81dbd032 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitBlockRegistry.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockRegistry; import com.sk89q.worldedit.world.registry.PassthroughBlockMaterial; @@ -76,7 +77,7 @@ public FluidState getFluidState(BlockState state) { if (WorldEditPlugin.getInstance().getBukkitImplAdapter() != null) { return WorldEditPlugin.getInstance().getBukkitImplAdapter().getFluidState(state); } - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } @Override diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitFluidRegistry.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitFluidRegistry.java new file mode 100644 index 0000000000..552ea0b971 --- /dev/null +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitFluidRegistry.java @@ -0,0 +1,37 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.bukkit; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.fluid.FluidType; +import com.sk89q.worldedit.world.registry.FluidRegistry; + +import java.util.Collections; +import java.util.Map; + +final class BukkitFluidRegistry implements FluidRegistry { + @Override + public Map> getProperties(FluidType fluidType) { + if (WorldEditPlugin.getInstance().getBukkitImplAdapter() == null) { + return Collections.emptyMap(); + } + return WorldEditPlugin.getInstance().getBukkitImplAdapter().getFluidProperties(fluidType); + } +} diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java index 80de555df8..481e236c97 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitRegistries.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import com.sk89q.worldedit.world.registry.BlockRegistry; import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.FluidRegistry; import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import com.sk89q.worldedit.world.registry.ItemRegistry; @@ -33,6 +34,7 @@ class BukkitRegistries extends BundledRegistries { private static final BukkitRegistries INSTANCE = new BukkitRegistries(); private final BlockRegistry blockRegistry = new BukkitBlockRegistry(); + private final FluidRegistry fluidRegistry = new BukkitFluidRegistry(); private final BiomeRegistry biomeRegistry = new BukkitBiomeRegistry(); private final ItemRegistry itemRegistry = new BukkitItemRegistry(); private final BlockCategoryRegistry blockCategoryRegistry = new BukkitBlockCategoryRegistry(); @@ -49,6 +51,11 @@ public BlockRegistry getBlockRegistry() { return blockRegistry; } + @Override + public FluidRegistry getFluidRegistry() { + return fluidRegistry; + } + @Override public BiomeRegistry getBiomeRegistry() { return biomeRegistry; diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index f9509c30f8..caa8ad3a26 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -40,6 +40,8 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; +import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.generation.TreeType; @@ -170,6 +172,16 @@ default void tickWatchdog() { */ Map> getProperties(BlockType blockType); + /** + * Gets the state properties for a fluid type. + * + * @param fluidType the fluid type + * @return the properties map + */ + default Map> getFluidProperties(FluidType fluidType) { + return Map.of(); + } + /** * Send the given NBT data to the player. * @@ -237,10 +249,10 @@ default boolean simulateItemUse(World world, BlockVector3 position, BaseItem ite * Gets the fluid state supplied by a block state. * * @param state the block state - * @return the fluid state, or {@link FluidState#EMPTY} if unavailable + * @return the fluid state */ default FluidState getFluidState(BlockState state) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } default OptionalInt getInternalBlockStateId(BlockData data) { diff --git a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java index 8ffa4980b2..cc1399ea0e 100644 --- a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java +++ b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcBlockRegistry.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockRegistry; @@ -81,10 +82,16 @@ public FluidState getFluidState(BlockState state) { net.minecraft.world.level.material.FluidState fluidState = platform.getAdapter() .toNativeBlockState(state).getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = BuiltInRegistries.FLUID.getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (var property : fluidState.getProperties()) { + properties.put(platform.getTransmogrifier().transmogToWorldEditProperty(property), + fluidState.getValue(property)); + } + return type.getState(properties); } @Override diff --git a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcFluidRegistry.java b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcFluidRegistry.java new file mode 100644 index 0000000000..190fcccea5 --- /dev/null +++ b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcFluidRegistry.java @@ -0,0 +1,49 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.coremc.internal; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.fluid.FluidType; +import com.sk89q.worldedit.world.registry.FluidRegistry; +import net.minecraft.core.registries.BuiltInRegistries; + +import java.util.Map; +import java.util.TreeMap; + +final class CoreMcFluidRegistry implements FluidRegistry { + private final CoreMcPlatform platform; + + CoreMcFluidRegistry(CoreMcPlatform platform) { + this.platform = platform; + } + + @Override + public Map> getProperties(FluidType fluidType) { + var fluid = BuiltInRegistries.FLUID.stream() + .filter(candidate -> BuiltInRegistries.FLUID.getKey(candidate).toString().equals(fluidType.id())) + .findFirst().orElseThrow(); + Map> properties = new TreeMap<>(); + for (var property : fluid.defaultFluidState().getProperties()) { + Property worldEditProperty = platform.getTransmogrifier().transmogToWorldEditProperty(property); + properties.put(worldEditProperty.name(), worldEditProperty); + } + return properties; + } +} diff --git a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcRegistries.java b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcRegistries.java index e18feec9fb..dfd3b6c6b3 100644 --- a/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcRegistries.java +++ b/worldedit-core-mc/src/main/java/com/sk89q/worldedit/coremc/internal/CoreMcRegistries.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import com.sk89q.worldedit.world.registry.BlockRegistry; import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.FluidRegistry; import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import com.sk89q.worldedit.world.registry.ItemRegistry; @@ -32,6 +33,7 @@ public final class CoreMcRegistries extends BundledRegistries { private final BlockRegistry blockRegistry; + private final FluidRegistry fluidRegistry; private final BiomeRegistry biomeRegistry = new CoreMcBiomeRegistry(); private final ItemRegistry itemRegistry; private final BlockCategoryRegistry blockCategoryRegistry; @@ -39,6 +41,7 @@ public final class CoreMcRegistries extends BundledRegistries { public CoreMcRegistries(CoreMcPlatform platform) { this.blockRegistry = new CoreMcBlockRegistry(platform); + this.fluidRegistry = new CoreMcFluidRegistry(platform); this.itemRegistry = new CoreMcItemRegistry(platform); this.blockCategoryRegistry = new CoreMcBlockCategoryRegistry(platform); this.itemCategoryRegistry = new CoreMcItemCategoryRegistry(platform); @@ -49,6 +52,11 @@ public BlockRegistry getBlockRegistry() { return blockRegistry; } + @Override + public FluidRegistry getFluidRegistry() { + return fluidRegistry; + } + @Override public BiomeRegistry getBiomeRegistry() { return biomeRegistry; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/DefaultFluidTypeStateList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/DefaultFluidTypeStateList.java new file mode 100644 index 0000000000..acc6b62677 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/DefaultFluidTypeStateList.java @@ -0,0 +1,124 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.fluid; + +import com.google.common.collect.ImmutableList; +import com.sk89q.worldedit.registry.state.Property; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; + +import java.util.Collection; +import java.util.Map; + +/** + * The canonical fluid states for a fluid type. + */ +final class DefaultFluidTypeStateList extends FluidTypeStateList { + private record PropertyEntry(Property property, ImmutableList values, int stride) { + int offset(Object value) { + int index = values.indexOf(value); + return index == -1 ? -1 : index * stride; + } + } + + private final ImmutableList properties; + private final ImmutableList states; + + DefaultFluidTypeStateList(FluidType fluidType) { + Collection> fluidProperties = fluidType.getProperties(); + ImmutableList.Builder entries = ImmutableList.builder(); + int totalStates = 1; + for (Property property : fluidProperties) { + entries.add(new PropertyEntry(property, ImmutableList.copyOf(property.values()), totalStates)); + totalStates = Math.multiplyExact(totalStates, property.values().size()); + } + this.properties = entries.build(); + this.states = createStates(fluidType, totalStates); + } + + private ImmutableList createStates(FluidType type, int totalStates) { + Property[] keys = new Property[properties.size()]; + Object[] values = new Object[properties.size()]; + int[] counters = new int[properties.size()]; + for (int i = 0; i < properties.size(); i++) { + keys[i] = properties.get(i).property(); + values[i] = properties.get(i).values().getFirst(); + } + ImmutableList.Builder result = ImmutableList.builderWithExpectedSize(totalStates); + for (int i = 0; i < totalStates; i++) { + result.add(new FluidState(type, + Object2ObjectMaps.unmodifiable(new Object2ObjectArrayMap<>(keys, values.clone())), i)); + for (int slot = 0; slot < properties.size(); slot++) { + PropertyEntry property = properties.get(slot); + if (++counters[slot] < property.values().size()) { + values[slot] = property.values().get(counters[slot]); + break; + } + counters[slot] = 0; + values[slot] = property.values().getFirst(); + } + } + return result.build(); + } + + @Override + public FluidState get(int index) { + return states.get(index); + } + + @Override + public int size() { + return states.size(); + } + + @Override + int calculateIndex(Map, ?> state) { + if (state.size() != properties.size()) { + throw new IllegalArgumentException("State has incorrect number of properties."); + } + int index = 0; + for (PropertyEntry property : properties) { + if (!state.containsKey(property.property())) { + throw new IllegalArgumentException("Missing property " + property.property().name()); + } + int offset = property.offset(state.get(property.property())); + if (offset == -1) { + throw new IllegalArgumentException("Invalid value for property " + property.property().name()); + } + index += offset; + } + return index; + } + + @Override + int updateIndexOrInvalid(int currentIndex, Property property, Object oldValue, Object newValue) { + if (currentIndex < 0 || currentIndex >= size()) { + return -1; + } + for (PropertyEntry entry : properties) { + if (entry.property() == property) { + int oldOffset = entry.offset(oldValue); + int newOffset = entry.offset(newValue); + return oldOffset == -1 || newOffset == -1 ? -1 : currentIndex - oldOffset + newOffset; + } + } + return -1; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java index 160cfda2e9..51d0c80286 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidState.java @@ -19,6 +19,11 @@ package com.sk89q.worldedit.world.fluid; +import com.sk89q.worldedit.registry.state.Property; + +import java.util.Map; +import java.util.Objects; + import static com.google.common.base.Preconditions.checkNotNull; /** @@ -27,15 +32,26 @@ *

A fluid state is derived from a block state by the active platform. This * allows blocks such as kelp and waterlogged blocks to supply fluid without * being fluid blocks themselves.

- * - * @param type the type of fluid supplied */ -public record FluidState(FluidType type) { +public class FluidState { - public static final FluidState EMPTY = new FluidState(FluidTypes.EMPTY); + private final FluidType type; + private final Map, Object> values; + private final int stateListIndex; - public FluidState { - checkNotNull(type); + protected FluidState(FluidType type, Map, Object> values, int stateListIndex) { + this.type = checkNotNull(type); + this.values = values; + this.stateListIndex = stateListIndex; + } + + /** + * Gets the type of fluid supplied. + * + * @return the fluid type + */ + public FluidType getType() { + return type; } /** @@ -47,4 +63,36 @@ public boolean isEmpty() { return type == FluidTypes.EMPTY; } + public FluidState with(Property property, V value) { + Object currentValue = values.get(property); + if (Objects.equals(currentValue, value)) { + return this; + } + int newIndex = type.getInternalStateList().updateIndexOrInvalid( + stateListIndex, property, currentValue, value); + return newIndex == -1 ? this : type.getInternalStateList().get(newIndex); + } + + @SuppressWarnings("unchecked") + public V getState(Property property) { + return (V) values.get(property); + } + + public Map, Object> getStates() { + return values; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof FluidState fluidState)) { + return false; + } + return type.equals(fluidState.type) && values.equals(fluidState.values); + } + + @Override + public int hashCode() { + return Objects.hash(type, values); + } + } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java index 9e8ff63731..61299fba5e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidType.java @@ -19,20 +19,112 @@ package com.sk89q.worldedit.world.fluid; + +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMaps; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; /** * Minecraft now has a 'fluid' system. This is a stub class to represent what it may be in the future. - * - * @param id the id of the fluid */ -public record FluidType(String id) implements Keyed { +public final class FluidType implements Keyed { public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("fluid type", "fluid_type", "minecraft"); + private final String id; + @SuppressWarnings("this-escape") + private final LazyReference>> properties = + LazyReference.from(() -> computeProperties(this)); + @SuppressWarnings("this-escape") + private final LazyReference defaultState = + LazyReference.from(() -> getInternalStateList().getFirst()); + @SuppressWarnings("this-escape") + private final LazyReference internalStateList = + LazyReference.from(() -> FluidTypeStateList.createFor(this)); + + public FluidType(String id) { + if (!id.contains(":")) { + id = "minecraft:" + id; + } + this.id = id; + } + + private static Map> computeProperties(FluidType self) { + Map> propertiesMap = WorldEdit.getInstance().getPlatformManager() + .queryCapability(Capability.GAME_HOOKS).getRegistries().getFluidRegistry().getProperties(self); + String[] propertyNames = propertiesMap.keySet().toArray(new String[0]); + Arrays.sort(propertyNames); + Object[] properties = new Object[propertyNames.length]; + for (int i = 0; i < propertyNames.length; i++) { + properties[i] = propertiesMap.get(propertyNames[i]); + } + return Object2ObjectMaps.unmodifiable(new Object2ObjectArrayMap<>(propertyNames, properties)); + } + + @Override + public String id() { + return id; + } + + FluidTypeStateList getInternalStateList() { + return internalStateList.getValue(); + } + + /** + * Gets the default state of this fluid type. + * + * @return the default state + */ + public FluidState getDefaultState() { + return defaultState.getValue(); + } + + public Map> getPropertyMap() { + return properties.getValue(); + } + + public List> getProperties() { + return List.copyOf(getPropertyMap().values()); + } + + public Property getProperty(String name) { + @SuppressWarnings("unchecked") + Property property = (Property) getPropertyMap().get(name); + if (property == null) { + throw new IllegalArgumentException(this + " has no property named " + name); + } + return property; + } + + public List getAllStates() { + return getInternalStateList(); + } + + public FluidState getState(Map, Object> values) { + return getInternalStateList().get(getInternalStateList().calculateIndex(values)); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof FluidType fluidType && id.equals(fluidType.id); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + @Override public String toString() { - return id(); + return id; } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypeStateList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypeStateList.java new file mode 100644 index 0000000000..1e328f2ec1 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/FluidTypeStateList.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.fluid; + +import com.sk89q.worldedit.registry.state.Property; +import it.unimi.dsi.fastutil.objects.AbstractObjectList; + +import java.util.Map; + +/** + * A specialized list for looking up canonical fluid states from a fluid type. + */ +abstract class FluidTypeStateList extends AbstractObjectList { + static FluidTypeStateList createFor(FluidType fluidType) { + if (fluidType.getProperties().isEmpty()) { + return new SingletonFluidTypeStateList(fluidType); + } + return new DefaultFluidTypeStateList(fluidType); + } + + abstract int calculateIndex(Map, ?> state); + + abstract int updateIndexOrInvalid(int currentIndex, Property property, Object oldValue, Object newValue); +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/SingletonFluidTypeStateList.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/SingletonFluidTypeStateList.java new file mode 100644 index 0000000000..96616e7473 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/fluid/SingletonFluidTypeStateList.java @@ -0,0 +1,62 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.fluid; + +import com.google.common.base.Preconditions; +import com.sk89q.worldedit.registry.state.Property; + +import java.util.Map; + +/** + * {@link FluidTypeStateList} with only one possible state. + */ +final class SingletonFluidTypeStateList extends FluidTypeStateList { + + private final FluidState state; + + SingletonFluidTypeStateList(FluidType fluidType) { + this.state = new FluidState(fluidType, Map.of(), 0); + } + + @Override + public FluidState get(int index) { + Preconditions.checkElementIndex(index, 1); + return state; + } + + @Override + public int size() { + return 1; + } + + @Override + int calculateIndex(Map, ?> state) { + if (!state.isEmpty()) { + throw new IllegalArgumentException("No properties expected for singleton state"); + } + return 0; + } + + @Override + int updateIndexOrInvalid(int currentIndex, Property property, Object oldValue, Object newValue) { + return -1; + } + +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java index d9c2c529c6..47debab315 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/BlockRegistry.java @@ -24,6 +24,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidTypes; import java.util.Map; import java.util.OptionalInt; @@ -62,14 +63,11 @@ public interface BlockRegistry { /** * Get the fluid state supplied by a block state. * - *

Implementations that cannot obtain this information should return - * {@link FluidState#EMPTY}.

- * * @param state the block state * @return the fluid state supplied by the block state */ default FluidState getFluidState(BlockState state) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } /** diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/FluidRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/FluidRegistry.java new file mode 100644 index 0000000000..3e71888db4 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/FluidRegistry.java @@ -0,0 +1,39 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.fluid.FluidType; + +import java.util.Map; + +/** + * Provides platform-specific fluid state properties. + */ +public interface FluidRegistry { + + /** + * Gets an unmodifiable map of properties for a fluid type. + * + * @param fluidType the fluid type + * @return a map from property names to properties + */ + Map> getProperties(FluidType fluidType); +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullFluidRegistry.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullFluidRegistry.java new file mode 100644 index 0000000000..89a859df77 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/NullFluidRegistry.java @@ -0,0 +1,41 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.world.registry; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.fluid.FluidType; + +import java.util.Collections; +import java.util.Map; + +/** + * Fluid registry used only when a platform has no fluid support. + */ +final class NullFluidRegistry implements FluidRegistry { + static final NullFluidRegistry INSTANCE = new NullFluidRegistry(); + + private NullFluidRegistry() { + } + + @Override + public Map> getProperties(FluidType fluidType) { + return Collections.emptyMap(); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/Registries.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/Registries.java index 94cdb12f1c..f2ed62975d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/Registries.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/registry/Registries.java @@ -31,6 +31,15 @@ public interface Registries { */ BlockRegistry getBlockRegistry(); + /** + * Get the fluid registry. + * + * @return the fluid registry + */ + default FluidRegistry getFluidRegistry() { + return NullFluidRegistry.INSTANCE; + } + /** * Get the item registry. * diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java index 3a6f4f9dbb..1220daa5ef 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeBlockRegistry.java @@ -25,6 +25,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.fluid.FluidState; +import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.fluid.FluidTypes; import com.sk89q.worldedit.world.registry.BlockMaterial; import com.sk89q.worldedit.world.registry.BlockRegistry; @@ -89,10 +90,16 @@ public FluidState getFluidState(BlockState state) { SpongeAdapter.adapt(state); net.minecraft.world.level.material.FluidState fluidState = equivalent.getFluidState(); if (fluidState.isEmpty()) { - return FluidState.EMPTY; + return FluidTypes.EMPTY.getDefaultState(); } String id = BuiltInRegistries.FLUID.getKey(fluidState.getType()).toString(); - return new FluidState(FluidTypes.get(id)); + FluidType type = FluidTypes.get(id); + Map, Object> properties = new HashMap<>(); + for (var property : fluidState.getProperties()) { + properties.put(SpongeTransmogrifier.transmogToWorldEditProperty((StateProperty) property), + fluidState.getValue(property)); + } + return type.getState(properties); } @Override diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeFluidRegistry.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeFluidRegistry.java new file mode 100644 index 0000000000..84ef88d26e --- /dev/null +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeFluidRegistry.java @@ -0,0 +1,46 @@ +/* + * WorldEdit, a Minecraft world manipulation toolkit + * Copyright (C) sk89q + * Copyright (C) WorldEdit team and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package com.sk89q.worldedit.sponge; + +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.sponge.internal.SpongeTransmogrifier; +import com.sk89q.worldedit.world.fluid.FluidType; +import com.sk89q.worldedit.world.registry.FluidRegistry; +import net.minecraft.core.registries.BuiltInRegistries; +import org.spongepowered.api.state.StateProperty; + +import java.util.Map; +import java.util.TreeMap; + +final class SpongeFluidRegistry implements FluidRegistry { + @Override + public Map> getProperties(FluidType fluidType) { + var fluid = BuiltInRegistries.FLUID.stream() + .filter(candidate -> BuiltInRegistries.FLUID.getKey(candidate).toString().equals(fluidType.id())) + .findFirst().orElseThrow(); + Map> properties = new TreeMap<>(); + for (var property : fluid.defaultFluidState().getProperties()) { + Property worldEditProperty = SpongeTransmogrifier.transmogToWorldEditProperty( + (StateProperty) property); + properties.put(worldEditProperty.name(), worldEditProperty); + } + return properties; + } +} diff --git a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java index 04baa39365..bdb12184b9 100644 --- a/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java +++ b/worldedit-sponge/src/main/java/com/sk89q/worldedit/sponge/SpongeRegistries.java @@ -23,6 +23,7 @@ import com.sk89q.worldedit.world.registry.BlockCategoryRegistry; import com.sk89q.worldedit.world.registry.BlockRegistry; import com.sk89q.worldedit.world.registry.BundledRegistries; +import com.sk89q.worldedit.world.registry.FluidRegistry; import com.sk89q.worldedit.world.registry.ItemCategoryRegistry; import com.sk89q.worldedit.world.registry.ItemRegistry; @@ -39,6 +40,7 @@ public static SpongeRegistries getInstance() { private final BiomeRegistry biomeRegistry = new SpongeBiomeRegistry(); private final BlockRegistry blockRegistry = new SpongeBlockRegistry(); + private final FluidRegistry fluidRegistry = new SpongeFluidRegistry(); private final BlockCategoryRegistry blockCategoryRegistry = new SpongeBlockCategoryRegistry(); private final ItemRegistry itemRegistry = new SpongeItemRegistry(); private final ItemCategoryRegistry itemCategoryRegistry = new SpongeItemCategoryRegistry(); @@ -53,6 +55,11 @@ public BlockRegistry getBlockRegistry() { return blockRegistry; } + @Override + public FluidRegistry getFluidRegistry() { + return fluidRegistry; + } + @Override public BlockCategoryRegistry getBlockCategoryRegistry() { return blockCategoryRegistry;