From f81fcae5e1c2cacdbf94e6320fca23ffc60dd3ce Mon Sep 17 00:00:00 2001 From: Maddy Miller Date: Fri, 10 Mar 2023 21:39:24 +1000 Subject: [PATCH 01/15] Add a feature generator and allow undoing of feature placement (https://github.com/EngineHub/WorldEdit/pull/2239) * Add a feature generator and allow undoing of feature placement [WIP] Apply changes to Forge as well Use proper translatable components * Add a brush version of the feature command Use Java proxy classes * Add for Bukkit (only 1.19.3 for now) Clean up the proxies to use a switch Checkstyle is grumpy Add the obfuscated versions Remove debug text Fix missed "destroyBlock" deobfuscated proxy function * checkstyle --- .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 19 +++ .../sk89q/worldedit/bukkit/BukkitWorld.java | 11 ++ .../bukkit/adapter/BukkitImplAdapter.java | 16 +++ .../worldedit/command/BrushCommands.java | 20 +++ .../worldedit/command/GenerationCommands.java | 18 +++ .../command/argument/RegistryConverter.java | 4 +- .../factory/FeatureGeneratorFactory.java | 44 +++++++ .../function/generator/FeatureGenerator.java | 52 ++++++++ .../java/com/sk89q/worldedit/world/World.java | 13 ++ .../generation/ConfiguredFeatureType.java | 43 +++++++ .../src/main/resources/lang/strings.json | 2 + .../FabricServerLevelDelegateProxy.java | 117 ++++++++++++++++++ .../ForgeServerLevelDelegateProxy.java | 117 ++++++++++++++++++ 13 files changed, 475 insertions(+), 1 deletion(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/FeatureGeneratorFactory.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java create mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java create mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index ebf1ada46c..ff7d26f50c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -29,6 +29,7 @@ import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; import com.sk89q.jnbt.NBTConstants; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -65,6 +66,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.Util; import net.minecraft.core.BlockPos; @@ -95,6 +97,7 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -107,6 +110,7 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -890,6 +894,12 @@ public void initializeRegistries() { BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); } } + // Features + for (ResourceLocation name: server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } // BiomeCategories Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); @@ -920,6 +930,15 @@ public void sendBiomeUpdates(World world, Iterable chunks) { originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); } + @Override + public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index 9e4da54019..ea2dac1c9e 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -54,6 +54,7 @@ import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; import io.papermc.lib.PaperLib; @@ -519,6 +520,16 @@ public boolean canPlaceAt(BlockVector3 position, com.sk89q.worldedit.world.block return true; } + @Override + public boolean generateFeature(ConfiguredFeatureType type, EditSession editSession, BlockVector3 position) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + return adapter.generateFeature(type, getWorld(), editSession, position); + } + // No adapter, we can't generate this. + return false; + } + private static volatile boolean hasWarnedImplError = false; @Override 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 986b348d33..eb34bb6973 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 @@ -30,6 +30,7 @@ import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.sk89q.jnbt.LinBusConverter; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -50,6 +51,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.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import org.bukkit.Keyed; @@ -321,6 +323,20 @@ default void initializeRegistries() { * @param chunks a list of chunk coordinates to send biome updates for */ default void sendBiomeUpdates(World world, Iterable chunks) { + + } + + /** + * Generates a Minecraft feature at the given location. + * + * @param feature The feature + * @param world The world + * @param session The EditSession + * @param pt The location + * @return If it succeeded + */ + default boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession session, BlockVector3 pt) { + throw new UnsupportedOperationException("This adapter does not support generating features."); } //FAWE start diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index e6a211a4bb..51a8d3df35 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -66,6 +66,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.command.argument.Arguments; +import com.sk89q.worldedit.command.factory.FeatureGeneratorFactory; import com.sk89q.worldedit.command.factory.ReplaceFactory; import com.sk89q.worldedit.command.factory.TreeGeneratorFactory; import com.sk89q.worldedit.command.tool.BrushTool; @@ -116,6 +117,7 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import org.anarres.parallelgzip.ParallelGZIPOutputStream; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -1556,6 +1558,24 @@ public void butcherBrush( set(context, new ButcherBrush(flags), "worldedit.brush.butcher").setSize(radius); } + @Command( + name = "feature", + desc = "Feature brush, paints Minecraft generation features" + ) + @CommandPermissions("worldedit.brush.feature") + public void feature(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The density of the brush", def = "5") + double density, + @Arg(desc = "The type of feature to use") + ConfiguredFeatureType type) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Paint(new FeatureGeneratorFactory(type), density / 100), shape, "worldedit.brush.feature"); + } + //FAWE start public BrushSettings process(Player player, Arguments arguments, BrushSettings settings) throws WorldEditException { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index f2a3c80ed4..c08314218f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -57,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TextComponent; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -359,6 +360,23 @@ public int pumpkins( return affected; } + @Command( + name = "/feature", + desc = "Generate Minecraft features" + ) + @CommandPermissions("worldedit.generation.feature") + @Logging(POSITION) + public int feature(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The feature") + ConfiguredFeatureType feature) throws WorldEditException { + if (editSession.getWorld().generateFeature(feature, editSession, session.getPlacementPosition(actor))) { + actor.printInfo(Caption.of("worldedit.feature.created")); + } else { + actor.printError(Caption.of("worldedit.feature.failed")); + } + return 0; + } + @Command( name = "/hpyramid", desc = "Generate a hollow pyramid" diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java index 271c0aa072..9ed38c6426 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -32,6 +32,7 @@ import com.sk89q.worldedit.world.fluid.FluidCategory; import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.gamemode.GameMode; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.weather.WeatherType; @@ -62,7 +63,8 @@ public static void register(CommandManager commandManager) { FluidType.class, FluidCategory.class, GameMode.class, - WeatherType.class + WeatherType.class, + ConfiguredFeatureType.class ) .stream() .map(c -> (Class) c) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/FeatureGeneratorFactory.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/FeatureGeneratorFactory.java new file mode 100644 index 0000000000..6434f016bb --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/factory/FeatureGeneratorFactory.java @@ -0,0 +1,44 @@ +/* + * 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.command.factory; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.function.generator.FeatureGenerator; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; + +public final class FeatureGeneratorFactory implements Contextual { + private final ConfiguredFeatureType type; + + public FeatureGeneratorFactory(ConfiguredFeatureType type) { + this.type = type; + } + + @Override + public FeatureGenerator createFromContext(EditContext input) { + return new FeatureGenerator((EditSession) input.getDestination(), type); + } + + @Override + public String toString() { + return "feature of type " + type; + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java new file mode 100644 index 0000000000..6c49138db9 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java @@ -0,0 +1,52 @@ +/* + * 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.function.generator; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; + +/** + * Generates forests by searching for the ground starting from the given upper Y + * coordinate for every column given. + */ +public class FeatureGenerator implements RegionFunction { + + private final ConfiguredFeatureType featureType; + private final EditSession editSession; + + /** + * Create a new instance. + * + * @param editSession the edit session + * @param featureType the feature type + */ + public FeatureGenerator(EditSession editSession, ConfiguredFeatureType featureType) { + this.editSession = editSession; + this.featureType = featureType; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return editSession.getWorld().generateFeature(featureType, editSession, position); + } +} diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 553792599a..6a19abc543 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -46,6 +46,7 @@ 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.generation.ConfiguredFeatureType; import com.sk89q.worldedit.world.weather.WeatherType; import javax.annotation.Nullable; @@ -311,6 +312,18 @@ default boolean regenerate(Region region, Extent extent, RegenOptions options) { boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException; + /** + * Generate a feature at the given position. + * + * @param type The feature type + * @param editSession The {@link EditSession} + * @param position The position + * @return True if the generation was successful + */ + default boolean generateFeature(ConfiguredFeatureType type, EditSession editSession, BlockVector3 position) { + return false; + } + /** * Load the chunk at the given position if it isn't loaded. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java new file mode 100644 index 0000000000..56888acd98 --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java @@ -0,0 +1,43 @@ +/* + * 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.generation; + +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +public class ConfiguredFeatureType implements Keyed { + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("configured feature type"); + + private final String id; + + public ConfiguredFeatureType(String id) { + this.id = id; + } + + @Override + public String getId() { + return this.id; + } + + @Override + public String toString() { + return this.id; + } +} diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 6b7ab19909..5020c8fd12 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -515,6 +515,8 @@ "worldedit.sphere.created": "{0} blocks have been created.", "worldedit.forestgen.created": "{0} trees created.", "worldedit.pumpkins.created": "{0} pumpkin patches created.", + "worldedit.feature.created": "Feature created.", + "worldedit.feature.failed": "Failed to generate feature. Is it a valid spot for it?", "worldedit.pyramid.created": "{0} blocks have been created.", "worldedit.generate.created": "{0} blocks have been created.", "worldedit.generatebiome.changed": "{0} biomes affected.", diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java new file mode 100644 index 0000000000..07ee8d81c5 --- /dev/null +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java @@ -0,0 +1,117 @@ +/* + * 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.fabric.internal; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.fabric.FabricAdapter; +import com.sk89q.worldedit.world.block.BlockTypes; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; + +public class FabricServerLevelDelegateProxy implements InvocationHandler { + + private final EditSession editSession; + private final ServerLevel serverLevel; + + private FabricServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel) { + this.editSession = editSession; + this.serverLevel = serverLevel; + } + + public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel) { + return (WorldGenLevel) Proxy.newProxyInstance( + serverLevel.getClass().getClassLoader(), + serverLevel.getClass().getInterfaces(), + new FabricServerLevelDelegateProxy(editSession, serverLevel) + ); + } + + @Nullable + private BlockEntity getBlockEntity(BlockPos blockPos) { + BlockEntity tileEntity = this.serverLevel.getChunkAt(blockPos).getBlockEntity(blockPos); + if (tileEntity == null) { + return null; + } + BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); + newEntity.load(NBTConverter.toNative(this.editSession.getFullBlock(FabricAdapter.adapt(blockPos)).getNbtReference().getValue())); + + return newEntity; + } + + private BlockState getBlockState(BlockPos blockPos) { + return FabricAdapter.adapt(this.editSession.getBlock(FabricAdapter.adapt(blockPos))); + } + + private boolean setBlock(BlockPos blockPos, BlockState blockState) { + try { + return editSession.setBlock(FabricAdapter.adapt(blockPos), FabricAdapter.adapt(blockState)); + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } + } + + private boolean removeBlock(BlockPos blockPos, boolean bl) { + try { + return editSession.setBlock(FabricAdapter.adapt(blockPos), BlockTypes.AIR.getDefaultState()); + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "getBlockState", "method_8320" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + return getBlockState(blockPos); + } + } + case "getBlockEntity", "method_8321" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + return getBlockEntity(blockPos); + } + } + case "setBlock", "method_8652" -> { + if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { + return setBlock(blockPos, blockState); + } + } + case "removeBlock", "destroyBlock", "method_8650", "method_8651" -> { + if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { + return removeBlock(blockPos, bl); + } + } + default -> { } + } + + return method.invoke(this.serverLevel, args); + } + +} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java new file mode 100644 index 0000000000..ff9e64d4e8 --- /dev/null +++ b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java @@ -0,0 +1,117 @@ +/* + * 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.forge.internal; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.forge.ForgeAdapter; +import com.sk89q.worldedit.world.block.BlockTypes; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Arrays; + +public class ForgeServerLevelDelegateProxy implements InvocationHandler { + + private final EditSession editSession; + private final ServerLevel serverLevel; + + private ForgeServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel) { + this.editSession = editSession; + this.serverLevel = serverLevel; + } + + public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel) { + return (WorldGenLevel) Proxy.newProxyInstance( + serverLevel.getClass().getClassLoader(), + serverLevel.getClass().getInterfaces(), + new ForgeServerLevelDelegateProxy(editSession, serverLevel) + ); + } + + @Nullable + private BlockEntity getBlockEntity(BlockPos blockPos) { + BlockEntity tileEntity = this.serverLevel.getChunkAt(blockPos).getBlockEntity(blockPos); + if (tileEntity == null) { + return null; + } + BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); + newEntity.load(NBTConverter.toNative(this.editSession.getFullBlock(ForgeAdapter.adapt(blockPos)).getNbtReference().getValue())); + + return newEntity; + } + + private BlockState getBlockState(BlockPos blockPos) { + return ForgeAdapter.adapt(this.editSession.getBlock(ForgeAdapter.adapt(blockPos))); + } + + private boolean setBlock(BlockPos blockPos, BlockState blockState) { + try { + return editSession.setBlock(ForgeAdapter.adapt(blockPos), ForgeAdapter.adapt(blockState)); + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } + } + + private boolean removeBlock(BlockPos blockPos, boolean bl) { + try { + return editSession.setBlock(ForgeAdapter.adapt(blockPos), BlockTypes.AIR.getDefaultState()); + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + switch (method.getName()) { + case "getBlockState", "m_8055_" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + return getBlockState(blockPos); + } + } + case "getBlockEntity", "m_7702_" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + return getBlockEntity(blockPos); + } + } + case "setBlock", "m_7731_" -> { + if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { + return setBlock(blockPos, blockState); + } + } + case "removeBlock", "destroyBlock", "m_7471_", "m_7740_" -> { + if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { + return removeBlock(blockPos, bl); + } + } + default -> { } + } + + return method.invoke(this.serverLevel, args); + } + +} From 25d7ca7e300b88ab9a67f6a2d3207af8789bf6e2 Mon Sep 17 00:00:00 2001 From: Madeline Miller Date: Sun, 9 Apr 2023 18:18:23 +1000 Subject: [PATCH 02/15] Add structure generator command (cherry picked from commit 5ca80395a35100c2d7686ad8839baaa57f8db07c) --- .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 35 +++++++++++++++ .../sk89q/worldedit/bukkit/BukkitWorld.java | 11 +++++ .../bukkit/adapter/BukkitImplAdapter.java | 14 ++++++ .../worldedit/command/GenerationCommands.java | 18 ++++++++ .../command/argument/RegistryConverter.java | 4 +- .../java/com/sk89q/worldedit/world/World.java | 5 +++ .../world/generation/StructureType.java | 43 +++++++++++++++++++ .../src/main/resources/lang/strings.json | 2 + 8 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index ff7d26f50c..4c8ba3042d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -67,12 +67,14 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; @@ -111,6 +113,9 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -894,12 +899,19 @@ public void initializeRegistries() { BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); } } + // Features for (ResourceLocation name: server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); } } + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } // BiomeCategories Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); @@ -939,6 +951,29 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); } + public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), chunkManager.chunkMap.structureTemplateManager, originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); + + if (!structureStart.isValid()) { + return false; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos max = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk(proxyLevel, originalWorld.structureManager(), chunkManager.getGenerator(), originalWorld.getRandom(), new BoundingBox(chunkPosx.getMinBlockX(), originalWorld.getMinBuildHeight(), chunkPosx.getMinBlockZ(), chunkPosx.getMaxBlockX(), originalWorld.getMaxBuildHeight(), chunkPosx.getMaxBlockZ()), chunkPosx)); + return true; + } + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java index ea2dac1c9e..ce02dd3682 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitWorld.java @@ -55,6 +55,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.weather.WeatherType; import com.sk89q.worldedit.world.weather.WeatherTypes; import io.papermc.lib.PaperLib; @@ -530,6 +531,16 @@ public boolean generateFeature(ConfiguredFeatureType type, EditSession editSessi return false; } + @Override + public boolean generateStructure(StructureType type, EditSession editSession, BlockVector3 position) { + BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter(); + if (adapter != null) { + return adapter.generateStructure(type, getWorld(), editSession, position); + } + // No adapter, we can't generate this. + return false; + } + private static volatile boolean hasWarnedImplError = false; @Override 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 eb34bb6973..98c95fa848 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 @@ -52,6 +52,7 @@ import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import org.bukkit.Keyed; @@ -339,6 +340,19 @@ default boolean generateFeature(ConfiguredFeatureType feature, World world, Edit throw new UnsupportedOperationException("This adapter does not support generating features."); } + /** + * Generates a Minecraft structure at the given location. + * + * @param feature The feature + * @param world The world + * @param session The EditSession + * @param pt The location + * @return If it succeeded + */ + default boolean generateStructure(StructureType feature, World world, EditSession session, BlockVector3 pt) { + throw new UnsupportedOperationException("This adapter does not support generating features."); + } + //FAWE start default BlockMaterial getMaterial(BlockType blockType) { return getMaterial(blockType.getDefaultState()); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index c08314218f..599e9da837 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -58,6 +58,7 @@ import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -377,6 +378,23 @@ public int feature(Actor actor, LocalSession session, EditSession editSession, return 0; } + @Command( + name = "/structure", + desc = "Generate Minecraft structures" + ) + @CommandPermissions("worldedit.generation.structure") + @Logging(POSITION) + public int structure(Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "The structure") + StructureType feature) throws WorldEditException { + if (editSession.getWorld().generateStructure(feature, editSession, session.getPlacementPosition(actor))) { + actor.printInfo(Caption.of("worldedit.structure.created")); + } else { + actor.printError(Caption.of("worldedit.structure.failed")); + } + return 0; + } + @Command( name = "/hpyramid", desc = "Generate a hollow pyramid" diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java index 9ed38c6426..c9b69cc30c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/argument/RegistryConverter.java @@ -33,6 +33,7 @@ import com.sk89q.worldedit.world.fluid.FluidType; import com.sk89q.worldedit.world.gamemode.GameMode; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemCategory; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.weather.WeatherType; @@ -64,7 +65,8 @@ public static void register(CommandManager commandManager) { FluidCategory.class, GameMode.class, WeatherType.class, - ConfiguredFeatureType.class + ConfiguredFeatureType.class, + StructureType.class ) .stream() .map(c -> (Class) c) diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 6a19abc543..9476ecaae3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -47,6 +47,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.weather.WeatherType; import javax.annotation.Nullable; @@ -312,6 +313,10 @@ default boolean regenerate(Region region, Extent extent, RegenOptions options) { boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException; + default boolean generateStructure(StructureType type, EditSession editSession, BlockVector3 position) { + return false; + } + /** * Generate a feature at the given position. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java new file mode 100644 index 0000000000..e4e8aaebbc --- /dev/null +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java @@ -0,0 +1,43 @@ +/* + * 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.generation; + +import com.sk89q.worldedit.registry.Keyed; +import com.sk89q.worldedit.registry.NamespacedRegistry; + +public class StructureType implements Keyed { + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("structure type"); + + private final String id; + + public StructureType(String id) { + this.id = id; + } + + @Override + public String getId() { + return this.id; + } + + @Override + public String toString() { + return this.id; + } +} diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 5020c8fd12..775c63878e 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -520,6 +520,8 @@ "worldedit.pyramid.created": "{0} blocks have been created.", "worldedit.generate.created": "{0} blocks have been created.", "worldedit.generatebiome.changed": "{0} biomes affected.", + "worldedit.structure.created": "Structure created.", + "worldedit.structure.failed": "Failed to generate structure. Is it a valid spot for it?", "worldedit.reload.config": "Configuration reloaded!", "worldedit.report.written": "FAWE report written to {0}", "worldedit.report.error": "Failed to write report: {0}", From a70cfdf6a06ce15f46a2c87ca48b3749b3f353c7 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 24 Oct 2023 17:32:55 +0100 Subject: [PATCH 03/15] FAWE-inate --- .../v1_20_R2/FaweBlockStateListPopulator.java | 132 +++++++++++++ .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 176 ++++++++++++++++++ .../v1_20_R3/FaweBlockStateListPopulator.java | 106 +++++++++++ .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 172 +++++++++++++++++ .../v1_20_R4/FaweBlockStateListPopulator.java | 100 ++++++++++ .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 176 +++++++++++++++++- .../v1_21_R1/FaweBlockStateListPopulator.java | 100 ++++++++++ .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 176 +++++++++++++++++- .../bukkit/adapter/IBukkitAdapter.java | 8 + .../worldedit/bukkit/WorldEditPlugin.java | 3 +- .../factory/StructureGeneratorFactory.java | 46 +++++ .../core/command/tool/FeaturePlacer.java | 77 ++++++++ .../core/command/tool/StructurePlacer.java | 77 ++++++++ .../generator/StructureGenerator.java | 30 +++ .../core/wrappers/WorldWrapper.java | 23 ++- .../java/com/sk89q/worldedit/EditSession.java | 26 +++ .../worldedit/command/BrushCommands.java | 22 ++- .../worldedit/command/GenerationCommands.java | 39 ++-- .../sk89q/worldedit/command/ToolCommands.java | 34 ++++ .../java/com/sk89q/worldedit/world/World.java | 12 +- .../generation/ConfiguredFeatureType.java | 15 ++ .../world/generation/StructureType.java | 15 ++ .../src/main/resources/lang/strings.json | 8 +- 23 files changed, 1544 insertions(+), 29 deletions(-) create mode 100644 worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java create mode 100644 worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java create mode 100644 worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/command/factory/StructureGeneratorFactory.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/FeaturePlacer.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java new file mode 100644 index 0000000000..a802a2e7af --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java @@ -0,0 +1,132 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import org.bukkit.craftbukkit.v1_20_R2.util.BlockStateListPopulator; +import org.jetbrains.annotations.Nullable; + +public class FaweBlockStateListPopulator extends BlockStateListPopulator { + + private final ServerLevel world; + + public FaweBlockStateListPopulator(ServerLevel world) { + super(world); + this.world = world; + } + + @Override + public long getSeed() { + return world.getSeed(); + } + + @Override + public ServerLevel getLevel() { + return world.getLevel(); + } + + @Override + public MinecraftServer getServer() { + return world.getServer(); + } + + @Override + public ChunkSource getChunkSource() { + return world.getChunkSource(); + } + + @Override + public ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus leastStatus, final boolean create) { + return world.getChunk(chunkX, chunkZ, leastStatus, create); + } + + @Override + public BiomeManager getBiomeManager() { + return world.getBiomeManager(); + } + + @Override + public Holder getUncachedNoiseBiome(final int biomeX, final int biomeY, final int biomeZ) { + return world.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public int getSeaLevel() { + return world.getSeaLevel(); + } + + @Override + public FeatureFlagSet enabledFeatures() { + return world.enabledFeatures(); + } + + @Override + public float getShade(final Direction direction, final boolean shaded) { + return world.getShade(direction, shaded); + } + + @Override + public LevelLightEngine getLightEngine() { + return world.getLightEngine(); + } + + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { + return world.getChunkIfLoadedImmediately(x, z); + } + + @Override + public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { + return world.getBlockStateIfLoaded(blockposition); + } + + @Override + public FluidState getFluidIfLoaded(final BlockPos blockposition) { + return world.getFluidIfLoaded(blockposition); + } + + @Override + public WorldBorder getWorldBorder() { + return world.getWorldBorder(); + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags, final int maxUpdateDepth) { + return world.setBlock(pos, state, flags, maxUpdateDepth); + } + + @Override + public boolean removeBlock(final BlockPos pos, final boolean move) { + return world.removeBlock(pos, move); + } + + @Override + public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity breakingEntity, final int maxUpdateDepth) { + return world.destroyBlock(pos, drop, breakingEntity, maxUpdateDepth); + } + + @Override + public BlockState getBlockState(final BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags) { + return world.setBlock(pos, state, flags); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index e176743c4a..93573f48de 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -11,11 +11,14 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; @@ -45,11 +48,14 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import io.papermc.lib.PaperLib; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.WritableRegistry; import net.minecraft.core.registries.Registries; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; @@ -57,17 +63,24 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -76,6 +89,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R2.entity.CraftPlayer; @@ -526,6 +540,168 @@ protected ServerLevel getServerLevel(final World world) { return ((CraftWorld) world).getHandle(); } + @Override + public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { + //FAWE start + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); + + ConfiguredFeature configuredFeature = serverLevel + .registryAccess() + .registryOrThrow(Registries.CONFIGURED_FEATURE) + .get(ResourceLocation.tryParse(feature.getId())); + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + if (!configuredFeature.place( + populator, + generator, + serverLevel.random, + new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + )) { + return null; + } + return populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + Structure k = serverLevel + .registryAccess() + .registryOrThrow(Registries.STRUCTURE) + .get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = serverLevel.getChunkSource(); + + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + + //FAWE start + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + StructureStart structureStart = k.generate( + serverLevel.registryAccess(), + chunkManager.getGenerator(), + chunkManager.getGenerator().getBiomeSource(), + chunkManager.randomState(), + serverLevel.getStructureManager(), + serverLevel.getSeed(), + chunkPos, + 0, + populator, + biome -> true + ); + if (!structureStart.isValid()) { + return null; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.minX()), + SectionPos.blockToSectionCoord(boundingBox.minZ()) + ); + ChunkPos max = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.maxX()), + SectionPos.blockToSectionCoord(boundingBox.maxZ()) + ); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( + populator, + serverLevel.structureManager(), + chunkManager.getGenerator(), + serverLevel.getRandom(), + new BoundingBox( + chunkPosx.getMinBlockX(), + serverLevel.getMinBuildHeight(), + chunkPosx.getMinBlockZ(), + chunkPosx.getMaxBlockX(), + serverLevel.getMaxBuildHeight(), + chunkPosx.getMaxBlockZ() + ), + chunkPosx + )); + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; + } + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + private boolean placeFeatureIntoSession( + final EditSession editSession, + final FaweBlockStateListPopulator populator, + final Map placed + ) { + if (placed == null || placed.isEmpty()) { + return false; + } + + for (Map.Entry entry : placed.entrySet()) { + CraftBlockState craftBlockState = entry.getValue(); + if (entry.getValue() == null) { + continue; + } + BlockPos pos = entry.getKey(); + editSession.setBlock(pos.getX(), pos.getY(), pos.getZ(), BukkitAdapter.adapt(craftBlockState.getBlockData())); + BlockEntity blockEntity = populator.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + editSession.setTile(pos.getX(), pos.getY(), pos.getZ(), (CompoundTag) toNative(tag)); + } + } + return true; + } + + @Override + public void setupFeatures() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Features + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + } + + @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java new file mode 100644 index 0000000000..0fe2490920 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java @@ -0,0 +1,106 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.ChunkStatus; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import org.bukkit.craftbukkit.v1_20_R3.util.BlockStateListPopulator; +import org.jetbrains.annotations.Nullable; + +public class FaweBlockStateListPopulator extends BlockStateListPopulator { + + private final ServerLevel world; + + public FaweBlockStateListPopulator(ServerLevel world) { + super(world); + this.world = world; + } + + @Override + public long getSeed() { + return world.getSeed(); + } + + @Override + public ServerLevel getLevel() { + return world.getLevel(); + } + + @Override + public MinecraftServer getServer() { + return world.getServer(); + } + + @Override + public ChunkSource getChunkSource() { + return world.getChunkSource(); + } + + @Override + public ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus leastStatus, final boolean create) { + return world.getChunk(chunkX, chunkZ, leastStatus, create); + } + + @Override + public BiomeManager getBiomeManager() { + return world.getBiomeManager(); + } + + @Override + public Holder getUncachedNoiseBiome(final int biomeX, final int biomeY, final int biomeZ) { + return world.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public int getSeaLevel() { + return world.getSeaLevel(); + } + + @Override + public FeatureFlagSet enabledFeatures() { + return world.enabledFeatures(); + } + + @Override + public float getShade(final Direction direction, final boolean shaded) { + return world.getShade(direction, shaded); + } + + @Override + public LevelLightEngine getLightEngine() { + return world.getLightEngine(); + } + + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { + return world.getChunkIfLoadedImmediately(x, z); + } + + @Override + public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { + return world.getBlockStateIfLoaded(blockposition); + } + + @Override + public FluidState getFluidIfLoaded(final BlockPos blockposition) { + return world.getFluidIfLoaded(blockposition); + } + + @Override + public WorldBorder getWorldBorder() { + return world.getWorldBorder(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index c5f4772a03..585d089b12 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -11,11 +11,14 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; @@ -44,11 +47,14 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import io.papermc.lib.PaperLib; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.WritableRegistry; import net.minecraft.core.registries.Registries; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; @@ -56,17 +62,24 @@ import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -75,6 +88,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_20_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; @@ -524,6 +538,164 @@ protected ServerLevel getServerLevel(final World world) { return ((CraftWorld) world).getHandle(); } + @Override + public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); + + ConfiguredFeature configuredFeature = serverLevel + .registryAccess() + .registryOrThrow(Registries.CONFIGURED_FEATURE) + .get(ResourceLocation.tryParse(feature.getId())); + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + if (!configuredFeature.place( + populator, + generator, + serverLevel.random, + new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + )) { + return null; + } + return populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + Structure k = serverLevel + .registryAccess() + .registryOrThrow(Registries.STRUCTURE) + .get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = serverLevel.getChunkSource(); + + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + + //FAWE start + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + StructureStart structureStart = k.generate( + serverLevel.registryAccess(), + chunkManager.getGenerator(), + chunkManager.getGenerator().getBiomeSource(), + chunkManager.randomState(), + serverLevel.getStructureManager(), + serverLevel.getSeed(), + chunkPos, + 0, + serverLevel, + biome -> true + ); + if (!structureStart.isValid()) { + return null; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.minX()), + SectionPos.blockToSectionCoord(boundingBox.minZ()) + ); + ChunkPos max = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.maxX()), + SectionPos.blockToSectionCoord(boundingBox.maxZ()) + ); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( + serverLevel, + serverLevel.structureManager(), + chunkManager.getGenerator(), + serverLevel.getRandom(), + new BoundingBox( + chunkPosx.getMinBlockX(), + serverLevel.getMinBuildHeight(), + chunkPosx.getMinBlockZ(), + chunkPosx.getMaxBlockX(), + serverLevel.getMaxBuildHeight(), + chunkPosx.getMaxBlockZ() + ), + chunkPosx + )); + return populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + } + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + private boolean placeFeatureIntoSession( + final EditSession editSession, + final FaweBlockStateListPopulator populator, + final Map placed + ) { + if (placed == null || placed.isEmpty()) { + return false; + } + + for (Map.Entry entry : placed.entrySet()) { + CraftBlockState craftBlockState = entry.getValue(); + if (entry.getValue() == null) { + continue; + } + BlockPos pos = entry.getKey(); + editSession.setBlock(pos.getX(), pos.getY(), pos.getZ(), BukkitAdapter.adapt(craftBlockState.getBlockData())); + BlockEntity blockEntity = populator.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(); + editSession.setTile(pos.getX(), pos.getY(), pos.getZ(), (CompoundTag) toNative(tag)); + } + } + return true; + } + + @Override + public void setupFeatures() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Features + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + } + @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java new file mode 100644 index 0000000000..51b5514737 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java @@ -0,0 +1,100 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import org.bukkit.craftbukkit.util.BlockStateListPopulator; +import org.jetbrains.annotations.Nullable; + +public class FaweBlockStateListPopulator extends BlockStateListPopulator { + + private final ServerLevel world; + + public FaweBlockStateListPopulator(ServerLevel world) { + super(world); + this.world = world; + } + + @Override + public long getSeed() { + return world.getSeed(); + } + + @Override + public ServerLevel getLevel() { + return world.getLevel(); + } + + @Override + public MinecraftServer getServer() { + return world.getServer(); + } + + @Override + public ChunkSource getChunkSource() { + return world.getChunkSource(); + } + + @Override + public ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus leastStatus, final boolean create) { + return world.getChunk(chunkX, chunkZ, leastStatus, create); + } + + @Override + public BiomeManager getBiomeManager() { + return world.getBiomeManager(); + } + + @Override + public Holder getUncachedNoiseBiome(final int biomeX, final int biomeY, final int biomeZ) { + return world.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public int getSeaLevel() { + return world.getSeaLevel(); + } + + @Override + public float getShade(final Direction direction, final boolean shaded) { + return world.getShade(direction, shaded); + } + + @Override + public LevelLightEngine getLightEngine() { + return world.getLightEngine(); + } + + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { + return world.getChunkIfLoadedImmediately(x, z); + } + + @Override + public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { + return world.getBlockStateIfLoaded(blockposition); + } + + @Override + public FluidState getFluidIfLoaded(final BlockPos blockposition) { + return world.getFluidIfLoaded(blockposition); + } + + @Override + public WorldBorder getWorldBorder() { + return world.getWorldBorder(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index 6c5a5330ec..ca3558b0b3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -11,12 +11,15 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.mojang.serialization.Codec; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; @@ -47,33 +50,42 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import io.papermc.lib.PaperLib; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; +import net.minecraft.core.SectionPos; import net.minecraft.core.WritableRegistry; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -82,6 +94,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; @@ -508,7 +521,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), baseItemStack.getAmount() ); - final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); + final net.minecraft.nbt.CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); if (nbt != null) { final DataComponentPatch patch = COMPONENTS_CODEC .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) @@ -541,6 +554,165 @@ protected ServerLevel getServerLevel(final World world) { return ((CraftWorld) world).getHandle(); } + @Override + public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { + //FAWE start + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); + + ConfiguredFeature configuredFeature = serverLevel + .registryAccess() + .registryOrThrow(Registries.CONFIGURED_FEATURE) + .get(ResourceLocation.tryParse(feature.getId())); + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + if (!configuredFeature.place( + populator, + generator, + serverLevel.random, + new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + )) { + return null; + } + return populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + Structure k = serverLevel + .registryAccess() + .registryOrThrow(Registries.STRUCTURE) + .get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = serverLevel.getChunkSource(); + + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + + //FAWE start + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + StructureStart structureStart = k.generate( + serverLevel.registryAccess(), + chunkManager.getGenerator(), + chunkManager.getGenerator().getBiomeSource(), + chunkManager.randomState(), + serverLevel.getStructureManager(), + serverLevel.getSeed(), + chunkPos, + 0, + serverLevel, + biome -> true + ); + if (!structureStart.isValid()) { + return null; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.minX()), + SectionPos.blockToSectionCoord(boundingBox.minZ()) + ); + ChunkPos max = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.maxX()), + SectionPos.blockToSectionCoord(boundingBox.maxZ()) + ); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( + serverLevel, + serverLevel.structureManager(), + chunkManager.getGenerator(), + serverLevel.getRandom(), + new BoundingBox( + chunkPosx.getMinBlockX(), + serverLevel.getMinBuildHeight(), + chunkPosx.getMinBlockZ(), + chunkPosx.getMaxBlockX(), + serverLevel.getMaxBuildHeight(), + chunkPosx.getMaxBlockZ() + ), + chunkPosx + )); + return populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + } + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + private boolean placeFeatureIntoSession( + final EditSession editSession, + final FaweBlockStateListPopulator populator, + final Map placed + ) { + if (placed == null || placed.isEmpty()) { + return false; + } + + for (Map.Entry entry : placed.entrySet()) { + CraftBlockState craftBlockState = entry.getValue(); + if (entry.getValue() == null) { + continue; + } + BlockPos pos = entry.getKey(); + editSession.setBlock(pos.getX(), pos.getY(), pos.getZ(), BukkitAdapter.adapt(craftBlockState.getBlockData())); + BlockEntity blockEntity = populator.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + editSession.setTile(pos.getX(), pos.getY(), pos.getZ(), (CompoundTag) toNative(tag)); + } + } + return true; + } + + @Override + public void setupFeatures() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Features + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + } + @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java new file mode 100644 index 0000000000..28b85a15d3 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java @@ -0,0 +1,100 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import org.bukkit.craftbukkit.util.BlockStateListPopulator; +import org.jetbrains.annotations.Nullable; + +public class FaweBlockStateListPopulator extends BlockStateListPopulator { + + private final ServerLevel world; + + public FaweBlockStateListPopulator(ServerLevel world) { + super(world); + this.world = world; + } + + @Override + public long getSeed() { + return world.getSeed(); + } + + @Override + public ServerLevel getLevel() { + return world.getLevel(); + } + + @Override + public MinecraftServer getServer() { + return world.getServer(); + } + + @Override + public ChunkSource getChunkSource() { + return world.getChunkSource(); + } + + @Override + public ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus leastStatus, final boolean create) { + return world.getChunk(chunkX, chunkZ, leastStatus, create); + } + + @Override + public BiomeManager getBiomeManager() { + return world.getBiomeManager(); + } + + @Override + public Holder getUncachedNoiseBiome(final int biomeX, final int biomeY, final int biomeZ) { + return world.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public int getSeaLevel() { + return world.getSeaLevel(); + } + + @Override + public float getShade(final Direction direction, final boolean shaded) { + return world.getShade(direction, shaded); + } + + @Override + public LevelLightEngine getLightEngine() { + return world.getLightEngine(); + } + + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { + return world.getChunkIfLoadedImmediately(x, z); + } + + @Override + public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { + return world.getBlockStateIfLoaded(blockposition); + } + + @Override + public FluidState getFluidIfLoaded(final BlockPos blockposition) { + return world.getFluidIfLoaded(blockposition); + } + + @Override + public WorldBorder getWorldBorder() { + return world.getWorldBorder(); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 415a462c93..1d48f4bded 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -11,12 +11,15 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.mojang.serialization.Codec; +import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; @@ -47,33 +50,42 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import io.papermc.lib.PaperLib; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; +import net.minecraft.core.SectionPos; import net.minecraft.core.WritableRegistry; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.Registries; -import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.properties.BlockStateProperties; import net.minecraft.world.level.block.state.properties.DirectionProperty; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -82,6 +94,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; @@ -508,7 +521,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), baseItemStack.getAmount() ); - final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); + final net.minecraft.nbt.CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); if (nbt != null) { final DataComponentPatch patch = COMPONENTS_CODEC .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) @@ -541,6 +554,165 @@ protected ServerLevel getServerLevel(final World world) { return ((CraftWorld) world).getHandle(); } + @Override + public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { + //FAWE start + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); + + ConfiguredFeature configuredFeature = serverLevel + .registryAccess() + .registryOrThrow(Registries.CONFIGURED_FEATURE) + .get(ResourceLocation.tryParse(feature.getId())); + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + if (!configuredFeature.place( + populator, + generator, + serverLevel.random, + new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + )) { + return null; + } + return populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + Structure k = serverLevel + .registryAccess() + .registryOrThrow(Registries.STRUCTURE) + .get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = serverLevel.getChunkSource(); + + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + + //FAWE start + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + StructureStart structureStart = k.generate( + serverLevel.registryAccess(), + chunkManager.getGenerator(), + chunkManager.getGenerator().getBiomeSource(), + chunkManager.randomState(), + serverLevel.getStructureManager(), + serverLevel.getSeed(), + chunkPos, + 0, + serverLevel, + biome -> true + ); + if (!structureStart.isValid()) { + return null; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.minX()), + SectionPos.blockToSectionCoord(boundingBox.minZ()) + ); + ChunkPos max = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.maxX()), + SectionPos.blockToSectionCoord(boundingBox.maxZ()) + ); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( + serverLevel, + serverLevel.structureManager(), + chunkManager.getGenerator(), + serverLevel.getRandom(), + new BoundingBox( + chunkPosx.getMinBlockX(), + serverLevel.getMinBuildHeight(), + chunkPosx.getMinBlockZ(), + chunkPosx.getMaxBlockX(), + serverLevel.getMaxBuildHeight(), + chunkPosx.getMaxBlockZ() + ), + chunkPosx + )); + return populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + } + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + //FAWE end + } + + private boolean placeFeatureIntoSession( + final EditSession editSession, + final FaweBlockStateListPopulator populator, + final Map placed + ) { + if (placed == null || placed.isEmpty()) { + return false; + } + + for (Map.Entry entry : placed.entrySet()) { + CraftBlockState craftBlockState = entry.getValue(); + if (entry.getValue() == null) { + continue; + } + BlockPos pos = entry.getKey(); + editSession.setBlock(pos.getX(), pos.getY(), pos.getZ(), BukkitAdapter.adapt(craftBlockState.getBlockData())); + BlockEntity blockEntity = populator.getBlockEntity(pos); + if (blockEntity != null) { + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + editSession.setTile(pos.getX(), pos.getY(), pos.getZ(), (CompoundTag) toNative(tag)); + } + } + return true; + } + + @Override + public void setupFeatures() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Features + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + } + @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); diff --git a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java index 16e959d273..b8abff0ec3 100644 --- a/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java +++ b/worldedit-bukkit/src/main/java/com/fastasyncworldedit/bukkit/adapter/IBukkitAdapter.java @@ -396,4 +396,12 @@ default List getEntities(org.bukkit.World world) { return TaskManager.taskManager().sync(world::getEntities); } + /** + * Import Minecraft internal features into FAWE. Should be executed after worlds loading (in order to capture datapacks) + * + * @since TODO + */ + default void setupFeatures() { + } + } 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 c11f8bd73b..4d774d3973 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 @@ -21,8 +21,8 @@ import com.fastasyncworldedit.bukkit.BukkitPermissionAttachmentManager; import com.fastasyncworldedit.bukkit.FaweBukkit; -import com.fastasyncworldedit.core.util.UpdateNotification; import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.util.UpdateNotification; import com.fastasyncworldedit.core.util.WEManager; import com.google.common.base.Joiner; import com.google.common.collect.ImmutableList; @@ -300,6 +300,7 @@ private void setupWorldData() { setupTags(); setupBiomes(false); // FAWE - load biomes later. Initialize biomes twice to allow for the registry to be present for // plugins requiring WE biomes during startup, as well as allowing custom biomes loaded later on to be present in WE. + ((BukkitImplAdapter) adapter.value().get()).setupFeatures(); WorldEdit.getInstance().getEventBus().post(new PlatformReadyEvent(platform)); } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/factory/StructureGeneratorFactory.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/factory/StructureGeneratorFactory.java new file mode 100644 index 0000000000..3a74f14a0c --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/factory/StructureGeneratorFactory.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.fastasyncworldedit.core.command.factory; + +import com.fastasyncworldedit.core.function.generator.StructureGenerator; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.function.Contextual; +import com.sk89q.worldedit.function.EditContext; +import com.sk89q.worldedit.world.generation.StructureType; + +public final class StructureGeneratorFactory implements Contextual { + + private final StructureType type; + + public StructureGeneratorFactory(StructureType type) { + this.type = type; + } + + @Override + public StructureGenerator createFromContext(EditContext input) { + return new StructureGenerator((EditSession) input.getDestination(), type); + } + + @Override + public String toString() { + return "structure of type " + type; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/FeaturePlacer.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/FeaturePlacer.java new file mode 100644 index 0000000000..ae47acadaf --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/FeaturePlacer.java @@ -0,0 +1,77 @@ +package com.fastasyncworldedit.core.command.tool; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.command.tool.BlockTool; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; + +import javax.annotation.Nullable; + +/** + * Places a feature + * + * @since TODO + */ +public class FeaturePlacer implements BlockTool { + + private final ConfiguredFeatureType feature; + + /** + * New instance + * + * @since TODO + */ + public FeaturePlacer(ConfiguredFeatureType feature) { + this.feature = feature; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.feature"); + } + + @Override + public boolean actPrimary( + Platform server, + LocalConfiguration config, + Player player, + LocalSession session, + Location clicked, + @Nullable Direction face + ) { + + try (EditSession editSession = session.createEditSession(player)) { + try { + boolean successful = false; + + final BlockVector3 pos = clicked.toVector().add().toBlockPoint(); + for (int i = 0; i < 10; i++) { + if (feature.place(editSession, pos)) { + successful = true; + break; + } + } + + if (!successful) { + player.print(Caption.of("worldedit.tool.feature.failed")); + } + } catch (MaxChangedBlocksException e) { + player.print(Caption.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + + return true; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java new file mode 100644 index 0000000000..99720f65d2 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java @@ -0,0 +1,77 @@ +package com.fastasyncworldedit.core.command.tool; + +import com.fastasyncworldedit.core.configuration.Caption; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.command.tool.BlockTool; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extension.platform.Platform; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.world.generation.StructureType; + +import javax.annotation.Nullable; + +/** + * Places a feature + * + * @since TODO + */ +public class StructurePlacer implements BlockTool { + + private final StructureType structure; + + /** + * New instance + * + * @since TODO + */ + public StructurePlacer(StructureType structure) { + this.structure = structure; + } + + @Override + public boolean canUse(Actor player) { + return player.hasPermission("worldedit.tool.feature"); + } + + @Override + public boolean actPrimary( + Platform server, + LocalConfiguration config, + Player player, + LocalSession session, + Location clicked, + @Nullable Direction face + ) { + + try (EditSession editSession = session.createEditSession(player)) { + try { + boolean successful = false; + + final BlockVector3 pos = clicked.toVector().add().toBlockPoint(); + for (int i = 0; i < 10; i++) { + if (structure.place(editSession, pos)) { + successful = true; + break; + } + } + + if (!successful) { + player.print(Caption.of("worldedit.tool.feature.failed")); + } + } catch (MaxChangedBlocksException e) { + player.print(Caption.of("worldedit.tool.max-block-changes")); + } finally { + session.remember(editSession); + } + } + + return true; + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java new file mode 100644 index 0000000000..537a6c83b3 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java @@ -0,0 +1,30 @@ +package com.fastasyncworldedit.core.function.generator; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.function.RegionFunction; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.generation.StructureType; + +public class StructureGenerator implements RegionFunction { + + private final StructureType structureType; + private final EditSession editSession; + + /** + * Create a new instance. + * + * @param editSession the edit session + * @param structureType the structure type + */ + public StructureGenerator(EditSession editSession, StructureType structureType) { + this.editSession = editSession; + this.structureType = structureType; + } + + @Override + public boolean apply(BlockVector3 position) throws WorldEditException { + return editSession.getWorld().generateStructure(structureType, editSession, position); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java index 616e90b375..8421df551c 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/wrappers/WorldWrapper.java @@ -37,6 +37,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.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.weather.WeatherType; import javax.annotation.Nullable; @@ -133,12 +135,10 @@ public boolean playEffect(Vector3 position, int type, int data) { return parent.playEffect(position, type, data); } - //FAWE start - allow block break effect of non-legacy blocks @Override public boolean playBlockBreakEffect(Vector3 position, BlockType type) { return parent.playBlockBreakEffect(position, type); } - //FAWE end @Override public boolean queueBlockBreakEffect(Platform server, BlockVector3 position, BlockType blockType, double priority) { @@ -207,12 +207,10 @@ public String getName() { return parent.getName(); } - //FAWE start - allow history to read an unloaded world's name @Override public String getNameUnsafe() { return parent.getNameUnsafe(); } - //FAWE end @Override public > boolean setBlock(BlockVector3 position, B block, boolean notifyAndLight) throws @@ -262,12 +260,15 @@ public void run(Object value) { }); } - //FAWE start @Override public Collection getBlockDrops(final BlockVector3 position) { return TaskManager.taskManager().sync(() -> parent.getBlockDrops(position)); } - //FAWE end + + @Override + public boolean canPlaceAt(final BlockVector3 position, final BlockState blockState) { + return parent.canPlaceAt(position, blockState); + } @Override public boolean regenerate(Region region, EditSession session) { @@ -289,6 +290,16 @@ public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession } } + @Override + public boolean generateStructure(final StructureType type, final EditSession editSession, final BlockVector3 position) { + return parent.generateStructure(type, editSession, position); + } + + @Override + public boolean generateFeature(final ConfiguredFeatureType type, final EditSession editSession, final BlockVector3 position) { + return parent.generateFeature(type, editSession, position); + } + @Override public BlockVector3 getSpawnPosition() { return parent.getSpawnPosition(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 4daa116edc..bed4e632fe 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -148,6 +148,8 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.registry.LegacyMapper; import org.apache.logging.log4j.Logger; @@ -4052,5 +4054,29 @@ public int makeBlob( } return changes; } + + /** + * Generate a feature into this EditSession + * + * @param feature feature to generate + * @param position position to generate at + * @return blocks affected + */ + public int generateFeature(ConfiguredFeatureType feature, BlockVector3 position) { + feature.place(this, position); + return changes; + } + + /** + * Generate a structure into this EditSession + * + * @param structure structure to generate + * @param position position to generate at + * @return blocks affected + */ + public int generateStructure(StructureType structure, BlockVector3 position) { + structure.place(this, position); + return changes; + } //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java index 51a8d3df35..589155767e 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/BrushCommands.java @@ -20,6 +20,7 @@ package com.sk89q.worldedit.command; import com.fastasyncworldedit.core.Fawe; +import com.fastasyncworldedit.core.command.factory.StructureGeneratorFactory; import com.fastasyncworldedit.core.command.tool.brush.BlendBall; import com.fastasyncworldedit.core.command.tool.brush.BlobBrush; import com.fastasyncworldedit.core.command.tool.brush.BrushSettings; @@ -116,8 +117,9 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; -import org.anarres.parallelgzip.ParallelGZIPOutputStream; import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; +import org.anarres.parallelgzip.ParallelGZIPOutputStream; import org.enginehub.piston.annotation.Command; import org.enginehub.piston.annotation.CommandContainer; import org.enginehub.piston.annotation.param.Arg; @@ -1577,6 +1579,24 @@ public void feature(Player player, LocalSession localSession, } //FAWE start + @Command( + name = "structure", + desc = "Structure brush, paints Minecraft generation structures" + ) + @CommandPermissions("worldedit.brush.feature") + public void structure(Player player, LocalSession localSession, + @Arg(desc = "The shape of the region") + RegionFactory shape, + @Arg(desc = "The size of the brush", def = "5") + double radius, + @Arg(desc = "The density of the brush", def = "5") + double density, + @Arg(desc = "The type of feature to use") + StructureType type) throws WorldEditException { + setOperationBasedBrush(player, localSession, radius, + new Paint(new StructureGeneratorFactory(type), density / 100), shape, "worldedit.brush.structure"); + } + public BrushSettings process(Player player, Arguments arguments, BrushSettings settings) throws WorldEditException { LocalSession session = worldEdit.getSessionManager().get(player); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java index 599e9da837..93fb6bb4f9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/GenerationCommands.java @@ -65,7 +65,7 @@ import org.enginehub.piston.annotation.param.Switch; import org.jetbrains.annotations.Range; -import java.awt.RenderingHints; +import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URISyntaxException; @@ -363,19 +363,28 @@ public int pumpkins( @Command( name = "/feature", + //FAWE start + aliases = {"/placefeature"}, + //FAWE end desc = "Generate Minecraft features" ) + @Logging(PLACEMENT) @CommandPermissions("worldedit.generation.feature") - @Logging(POSITION) - public int feature(Actor actor, LocalSession session, EditSession editSession, - @Arg(desc = "The feature") - ConfiguredFeatureType feature) throws WorldEditException { - if (editSession.getWorld().generateFeature(feature, editSession, session.getPlacementPosition(actor))) { - actor.printInfo(Caption.of("worldedit.feature.created")); + public int feature( + Actor actor, LocalSession session, EditSession editSession, + @Arg(desc = "Type of feature to place", def = "forest_rock") + ConfiguredFeatureType feature + ) throws WorldEditException { + //FAWE start + int affected = editSession.generateFeature(feature, session.getPlacementPosition(actor)); + + if (affected == 0) { + actor.print(Caption.of("worldedit.generate.feature.failed")); } else { - actor.printError(Caption.of("worldedit.feature.failed")); + actor.print(Caption.of("worldedit.feature.created", TextComponent.of(affected))); } - return 0; + return affected; + //FAWE end } @Command( @@ -387,12 +396,16 @@ public int feature(Actor actor, LocalSession session, EditSession editSession, public int structure(Actor actor, LocalSession session, EditSession editSession, @Arg(desc = "The structure") StructureType feature) throws WorldEditException { - if (editSession.getWorld().generateStructure(feature, editSession, session.getPlacementPosition(actor))) { - actor.printInfo(Caption.of("worldedit.structure.created")); + //FAWE start + int affected = editSession.generateStructure(feature, session.getPlacementPosition(actor)); + + if (affected > 0) { + actor.printInfo(Caption.of("worldedit.structure.created", TextComponent.of(affected))); } else { actor.printError(Caption.of("worldedit.structure.failed")); } - return 0; + return affected; + //FAWE end } @Command( @@ -803,7 +816,7 @@ public int blob( if (actor instanceof Player && Settings.settings().GENERAL.UNSTUCK_ON_GENERATE) { ((Player) actor).findFreePosition(); } - actor.print(Caption.of("worldedit.sphere.created", TextComponent.of(affected))); + actor.print(Caption.of("worldedit.blob.created", TextComponent.of(affected))); return affected; } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java index f3be414693..531593b5ce 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/ToolCommands.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.command; +import com.fastasyncworldedit.core.command.tool.FeaturePlacer; +import com.fastasyncworldedit.core.command.tool.StructurePlacer; import com.fastasyncworldedit.core.command.tool.brush.InspectBrush; import com.fastasyncworldedit.core.configuration.Caption; import com.google.common.collect.Collections2; @@ -56,6 +58,8 @@ import com.sk89q.worldedit.util.formatting.text.event.ClickEvent; import com.sk89q.worldedit.util.formatting.text.format.TextColor; import com.sk89q.worldedit.world.block.BlockStateHolder; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import org.enginehub.piston.CommandManager; import org.enginehub.piston.CommandManagerService; import org.enginehub.piston.CommandMetadata; @@ -244,6 +248,36 @@ public void tree( setTool(player, session, new TreePlanter(type), "worldedit.tool.tree.equip"); } + //FAWE start + @Command( + name = "featureplacer", + aliases = {"/featureplacer", "featuretool", "/featuretool"}, + desc = "Feature placer tool" + ) + @CommandPermissions("worldedit.tool.feature") + public void feature( + Player player, LocalSession session, + @Arg(desc = "Type of feature to place", def = "forest_rock") + ConfiguredFeatureType feature + ) throws WorldEditException { + setTool(player, session, new FeaturePlacer(feature), "worldedit.tool.feature.equip"); + } + + @Command( + name = "structureplacer", + aliases = {"/structureplacer", "structuretool", "/structuretool"}, + desc = "Structure placer tool" + ) + @CommandPermissions("worldedit.tool.structure") + public void structure( + Player player, LocalSession session, + @Arg(desc = "Type of structure to place", def = "") + StructureType feature + ) throws WorldEditException { + setTool(player, session, new StructurePlacer(feature), "worldedit.tool.structure.equip"); + } + //FAWE end + @Command( name = "stacker", desc = "Block stacker tool" diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 9476ecaae3..478a0b778c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -313,6 +313,14 @@ default boolean regenerate(Region region, Extent extent, RegenOptions options) { boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) throws MaxChangedBlocksException; + /** + * Generate a structure at the given position + * + * @param type The structure type + * @param editSession The {@link EditSession} + * @param position The position + * @return True if the generation was successful + */ default boolean generateStructure(StructureType type, EditSession editSession, BlockVector3 position) { return false; } @@ -320,9 +328,9 @@ default boolean generateStructure(StructureType type, EditSession editSession, B /** * Generate a feature at the given position. * - * @param type The feature type + * @param type The feature type * @param editSession The {@link EditSession} - * @param position The position + * @param position The position * @return True if the generation was successful */ default boolean generateFeature(ConfiguredFeatureType type, EditSession editSession, BlockVector3 position) { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java index 56888acd98..bc5126d319 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.world.generation; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; @@ -40,4 +42,17 @@ public String getId() { public String toString() { return this.id; } + + //FAWE start + /** + * Place this feature into an {@link EditSession} + * + * @param extent EditSession to place into + * @param position position to use for placement + * @return true if successful + */ + public boolean place(EditSession extent, BlockVector3 position) { + return extent.getWorld().generateFeature(this, extent, position); + } + //FAWE end } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java index e4e8aaebbc..0713735d70 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java @@ -19,6 +19,8 @@ package com.sk89q.worldedit.world.generation; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; @@ -40,4 +42,17 @@ public String getId() { public String toString() { return this.id; } + + //FAWE start + /** + * Place this structure into an {@link EditSession} + * + * @param extent EditSession to place into + * @param position position to use for placement + * @return true if successful + */ + public boolean place(EditSession extent, BlockVector3 position) { + return extent.getWorld().generateStructure(this, extent, position); + } + //FAWE end } diff --git a/worldedit-core/src/main/resources/lang/strings.json b/worldedit-core/src/main/resources/lang/strings.json index 775c63878e..d8908f88fe 100644 --- a/worldedit-core/src/main/resources/lang/strings.json +++ b/worldedit-core/src/main/resources/lang/strings.json @@ -513,14 +513,16 @@ "worldedit.hcyl.thickness-too-large": "Thickness cannot be larger than x or z radii.", "worldedit.sphere.invalid-radius": "You must either specify 1 or 3 radius values.", "worldedit.sphere.created": "{0} blocks have been created.", + "worldedit.blob.created": "{0} blocks have been created.", + "worldedit.feature.created": "Feature created, {0} blocks placed.", + "worldedit.generate.feature.failed": "This feature cannot go here. Ensure the area meets the requirements.", "worldedit.forestgen.created": "{0} trees created.", "worldedit.pumpkins.created": "{0} pumpkin patches created.", - "worldedit.feature.created": "Feature created.", "worldedit.feature.failed": "Failed to generate feature. Is it a valid spot for it?", "worldedit.pyramid.created": "{0} blocks have been created.", "worldedit.generate.created": "{0} blocks have been created.", "worldedit.generatebiome.changed": "{0} biomes affected.", - "worldedit.structure.created": "Structure created.", + "worldedit.structure.created": "Structure created, {0} blocks placed.", "worldedit.structure.failed": "Failed to generate structure. Is it a valid spot for it?", "worldedit.reload.config": "Configuration reloaded!", "worldedit.report.written": "FAWE report written to {0}", @@ -559,6 +561,8 @@ "worldedit.tool.deltree.not-floating": "That's not a floating tree.", "worldedit.tool.tree.equip": "Tree tool bound to {0}.", "worldedit.tool.tree.obstructed": "A tree can't go there.", + "worldedit.tool.feature.equip": "Feature placer tool bound to {0}.", + "worldedit.tool.feature.obstructed": "This feature cannot go there. Ensure the area meets the requirements.", "worldedit.tool.info.equip": "Info tool bound to {0}.", "worldedit.tool.inspect.equip": "Inspect tool bound to {0}.", "worldedit.tool.info.blockstate.hover": "Block state", From 0034f3806a4ef7e7eb4e382d6eaab4baadcaa73c Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 24 Oct 2023 17:46:40 +0100 Subject: [PATCH 04/15] cleanup --- .../bukkit/adapter/BukkitImplAdapter.java | 4 + .../core/command/tool/StructurePlacer.java | 2 +- .../generator/StructureGenerator.java | 7 ++ .../java/com/sk89q/worldedit/EditSession.java | 4 + .../function/generator/FeatureGenerator.java | 7 +- .../java/com/sk89q/worldedit/world/World.java | 4 + .../FabricServerLevelDelegateProxy.java | 117 ------------------ .../ForgeServerLevelDelegateProxy.java | 117 ------------------ 8 files changed, 25 insertions(+), 237 deletions(-) delete mode 100644 worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java delete mode 100644 worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java 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 98c95fa848..12e96abc95 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 @@ -335,6 +335,8 @@ default void sendBiomeUpdates(World world, Iterable chunks) { * @param session The EditSession * @param pt The location * @return If it succeeded + * + * @since TODO */ default boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession session, BlockVector3 pt) { throw new UnsupportedOperationException("This adapter does not support generating features."); @@ -348,6 +350,8 @@ default boolean generateFeature(ConfiguredFeatureType feature, World world, Edit * @param session The EditSession * @param pt The location * @return If it succeeded + * + * @since TODO */ default boolean generateStructure(StructureType feature, World world, EditSession session, BlockVector3 pt) { throw new UnsupportedOperationException("This adapter does not support generating features."); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java index 99720f65d2..798e74aea9 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/StructurePlacer.java @@ -17,7 +17,7 @@ import javax.annotation.Nullable; /** - * Places a feature + * Places a structure * * @since TODO */ diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java index 537a6c83b3..c99677126b 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/generator/StructureGenerator.java @@ -6,6 +6,11 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.generation.StructureType; +/** + * Generate a structure at the given location + * + * @since TODO + */ public class StructureGenerator implements RegionFunction { private final StructureType structureType; @@ -16,6 +21,8 @@ public class StructureGenerator implements RegionFunction { * * @param editSession the edit session * @param structureType the structure type + * + * @since TODO */ public StructureGenerator(EditSession editSession, StructureType structureType) { this.editSession = editSession; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index bed4e632fe..9f6f9de55d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -4061,6 +4061,8 @@ public int makeBlob( * @param feature feature to generate * @param position position to generate at * @return blocks affected + * + * @since TODO */ public int generateFeature(ConfiguredFeatureType feature, BlockVector3 position) { feature.place(this, position); @@ -4073,6 +4075,8 @@ public int generateFeature(ConfiguredFeatureType feature, BlockVector3 position) * @param structure structure to generate * @param position position to generate at * @return blocks affected + * + * @since TODO */ public int generateStructure(StructureType structure, BlockVector3 position) { structure.place(this, position); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java index 6c49138db9..f01a588db9 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/generator/FeatureGenerator.java @@ -26,8 +26,9 @@ import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; /** - * Generates forests by searching for the ground starting from the given upper Y - * coordinate for every column given. + * Generate a feature at the given location + * + * @since TODO */ public class FeatureGenerator implements RegionFunction { @@ -39,6 +40,8 @@ public class FeatureGenerator implements RegionFunction { * * @param editSession the edit session * @param featureType the feature type + * + * @since TODO */ public FeatureGenerator(EditSession editSession, ConfiguredFeatureType featureType) { this.editSession = editSession; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java index 478a0b778c..7c4f9c12e3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/World.java @@ -320,6 +320,8 @@ boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, Block * @param editSession The {@link EditSession} * @param position The position * @return True if the generation was successful + * + * @since TODO */ default boolean generateStructure(StructureType type, EditSession editSession, BlockVector3 position) { return false; @@ -332,6 +334,8 @@ default boolean generateStructure(StructureType type, EditSession editSession, B * @param editSession The {@link EditSession} * @param position The position * @return True if the generation was successful + * + * @since TODO */ default boolean generateFeature(ConfiguredFeatureType type, EditSession editSession, BlockVector3 position) { return false; diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java deleted file mode 100644 index 07ee8d81c5..0000000000 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.fabric.internal; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.fabric.FabricAdapter; -import com.sk89q.worldedit.world.block.BlockTypes; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.WorldGenLevel; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; - -public class FabricServerLevelDelegateProxy implements InvocationHandler { - - private final EditSession editSession; - private final ServerLevel serverLevel; - - private FabricServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel) { - this.editSession = editSession; - this.serverLevel = serverLevel; - } - - public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel) { - return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new FabricServerLevelDelegateProxy(editSession, serverLevel) - ); - } - - @Nullable - private BlockEntity getBlockEntity(BlockPos blockPos) { - BlockEntity tileEntity = this.serverLevel.getChunkAt(blockPos).getBlockEntity(blockPos); - if (tileEntity == null) { - return null; - } - BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); - newEntity.load(NBTConverter.toNative(this.editSession.getFullBlock(FabricAdapter.adapt(blockPos)).getNbtReference().getValue())); - - return newEntity; - } - - private BlockState getBlockState(BlockPos blockPos) { - return FabricAdapter.adapt(this.editSession.getBlock(FabricAdapter.adapt(blockPos))); - } - - private boolean setBlock(BlockPos blockPos, BlockState blockState) { - try { - return editSession.setBlock(FabricAdapter.adapt(blockPos), FabricAdapter.adapt(blockState)); - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); - } - } - - private boolean removeBlock(BlockPos blockPos, boolean bl) { - try { - return editSession.setBlock(FabricAdapter.adapt(blockPos), BlockTypes.AIR.getDefaultState()); - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); - } - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - switch (method.getName()) { - case "getBlockState", "method_8320" -> { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getBlockState(blockPos); - } - } - case "getBlockEntity", "method_8321" -> { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getBlockEntity(blockPos); - } - } - case "setBlock", "method_8652" -> { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { - return setBlock(blockPos, blockState); - } - } - case "removeBlock", "destroyBlock", "method_8650", "method_8651" -> { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { - return removeBlock(blockPos, bl); - } - } - default -> { } - } - - return method.invoke(this.serverLevel, args); - } - -} diff --git a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java b/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java deleted file mode 100644 index ff9e64d4e8..0000000000 --- a/worldedit-forge/src/main/java/com/sk89q/worldedit/forge/internal/ForgeServerLevelDelegateProxy.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * 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.forge.internal; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.forge.ForgeAdapter; -import com.sk89q.worldedit.world.block.BlockTypes; -import net.minecraft.core.BlockPos; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.WorldGenLevel; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import org.jetbrains.annotations.Nullable; - -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.Method; -import java.lang.reflect.Proxy; -import java.util.Arrays; - -public class ForgeServerLevelDelegateProxy implements InvocationHandler { - - private final EditSession editSession; - private final ServerLevel serverLevel; - - private ForgeServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel) { - this.editSession = editSession; - this.serverLevel = serverLevel; - } - - public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel) { - return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new ForgeServerLevelDelegateProxy(editSession, serverLevel) - ); - } - - @Nullable - private BlockEntity getBlockEntity(BlockPos blockPos) { - BlockEntity tileEntity = this.serverLevel.getChunkAt(blockPos).getBlockEntity(blockPos); - if (tileEntity == null) { - return null; - } - BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); - newEntity.load(NBTConverter.toNative(this.editSession.getFullBlock(ForgeAdapter.adapt(blockPos)).getNbtReference().getValue())); - - return newEntity; - } - - private BlockState getBlockState(BlockPos blockPos) { - return ForgeAdapter.adapt(this.editSession.getBlock(ForgeAdapter.adapt(blockPos))); - } - - private boolean setBlock(BlockPos blockPos, BlockState blockState) { - try { - return editSession.setBlock(ForgeAdapter.adapt(blockPos), ForgeAdapter.adapt(blockState)); - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); - } - } - - private boolean removeBlock(BlockPos blockPos, boolean bl) { - try { - return editSession.setBlock(ForgeAdapter.adapt(blockPos), BlockTypes.AIR.getDefaultState()); - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); - } - } - - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - switch (method.getName()) { - case "getBlockState", "m_8055_" -> { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getBlockState(blockPos); - } - } - case "getBlockEntity", "m_7702_" -> { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getBlockEntity(blockPos); - } - } - case "setBlock", "m_7731_" -> { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { - return setBlock(blockPos, blockState); - } - } - case "removeBlock", "destroyBlock", "m_7471_", "m_7740_" -> { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { - return removeBlock(blockPos, bl); - } - } - default -> { } - } - - return method.invoke(this.serverLevel, args); - } - -} From 07188a1b6993baff330e76702eb2cb5eed9980fa Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Thu, 23 Nov 2023 18:20:09 +0000 Subject: [PATCH 05/15] bring more in line with upstream --- .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 56 ++++++ .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 1 + .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 56 ++++++ .../PaperweightServerLevelDelegateProxy.java | 186 ++++-------------- .../ext/fawe/v1_21_R1/PaperweightAdapter.java | 61 +++++- .../PaperweightServerLevelDelegateProxy.java | 184 ++++------------- 6 files changed, 239 insertions(+), 305 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index e429fede3b..f1e44b66db 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -29,6 +29,7 @@ import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; import com.sk89q.jnbt.NBTConstants; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -65,12 +66,15 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.Util; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; @@ -95,6 +99,7 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -107,6 +112,10 @@ import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -892,6 +901,20 @@ public void initializeRegistries() { } } + // Features + for (ResourceLocation name: server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + // BiomeCategories Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); biomeRegistry.getTagNames().forEach(tagKey -> { @@ -921,6 +944,39 @@ public void sendBiomeUpdates(World world, Iterable chunks) { originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); } + @Override + public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); + + if (!structureStart.isValid()) { + return false; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos max = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk(proxyLevel, originalWorld.structureManager(), chunkManager.getGenerator(), originalWorld.getRandom(), new BoundingBox(chunkPosx.getMinBlockX(), originalWorld.getMinBuildHeight(), chunkPosx.getMinBlockZ(), chunkPosx.getMaxBlockX(), originalWorld.getMaxBuildHeight(), chunkPosx.getMaxBlockZ()), chunkPosx)); + return true; + } + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index 4c8ba3042d..9131dde789 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -951,6 +951,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); } + @Override public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index f45104c142..5fd3928a48 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -29,6 +29,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; import com.sk89q.jnbt.NBTConstants; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -65,6 +66,8 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.Util; import net.minecraft.core.BlockPos; @@ -73,6 +76,7 @@ import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; @@ -99,6 +103,7 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -111,6 +116,10 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -915,6 +924,20 @@ public void initializeRegistries() { } } + // Features + for (ResourceLocation name: server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + // BiomeCategories Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); biomeRegistry.getTagNames().forEach(tagKey -> { @@ -944,6 +967,39 @@ public void sendBiomeUpdates(World world, Iterable chunks) { originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); } + @Override + public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); + + if (!structureStart.isValid()) { + return false; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos max = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk(proxyLevel, originalWorld.structureManager(), chunkManager.getGenerator(), originalWorld.getRandom(), new BoundingBox(chunkPosx.getMinBlockX(), originalWorld.getMinBuildHeight(), chunkPosx.getMinBlockZ(), chunkPosx.getMaxBlockX(), originalWorld.getMaxBuildHeight(), chunkPosx.getMaxBlockZ()), chunkPosx)); + return true; + } + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java index f2f32edcbd..fa52a8a427 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java @@ -19,84 +19,43 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4; -import com.fastasyncworldedit.core.internal.exception.FaweException; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.PaperweightFaweAdapter; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.world.block.BlockTypes; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.entity.Entity; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.AABB; -import org.apache.logging.log4j.Logger; +import com.sk89q.worldedit.math.BlockVector3; +import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.Nullable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; public class PaperweightServerLevelDelegateProxy implements InvocationHandler { - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - // FAWE start - extent not EditSession - private final Extent editSession; - //FAWE end + private final EditSession editSession; private final ServerLevel serverLevel; - //FAWE start - use FAWE adapter - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - //FAWE end - //FAWE start - force error if method not caught by this instance - private final boolean errorOnPassthrough; - //FAWE end + private final PaperweightAdapter adapter; private PaperweightServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { this.editSession = editSession; this.serverLevel = serverLevel; - //FAWE start - this.errorOnPassthrough = false; - //FAWE end + this.adapter = adapter; } public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter) + serverLevel.getClass().getClassLoader(), + serverLevel.getClass().getInterfaces(), + new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter) ); } - //FAWE start - force error if method not caught by this instance - private PaperweightServerLevelDelegateProxy(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - this.editSession = extent; - this.serverLevel = serverLevel; - this.errorOnPassthrough = errorOnPassthrough; - } - - public static WorldGenLevel newInstance(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(extent, serverLevel, errorOnPassthrough) - ); - } - //FAWE end - @Nullable private BlockEntity getBlockEntity(BlockPos blockPos) { BlockEntity tileEntity = this.serverLevel.getChunkAt(blockPos).getBlockEntity(blockPos); @@ -104,25 +63,18 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { return null; } BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); - newEntity.loadWithComponents( - (CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock( - blockPos.getX(), - blockPos.getY(), - blockPos.getZ() - ).getNbtReference().getValue()), - this.serverLevel.registryAccess() - ); - + newEntity.loadWithComponents((CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at(blockPos.getX(), + blockPos.getY(), blockPos.getZ())).getNbtReference().getValue()), MinecraftServer.getServer().registryAccess()); return newEntity; } private BlockState getBlockState(BlockPos blockPos) { - return adapter.adapt(this.editSession.getBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ())); + return adapter.adapt(this.editSession.getBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()))); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), adapter.adapt(blockState)); + return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), adapter.adapt(blockState)); } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); } @@ -130,110 +82,38 @@ private boolean setBlock(BlockPos blockPos, BlockState blockState) { private boolean removeBlock(BlockPos blockPos, boolean bl) { try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), BlockTypes.AIR.getDefaultState()); + return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), BlockTypes.AIR.getDefaultState()); } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); } } - private FluidState getFluidState(BlockPos pos) { - return getBlockState(pos).getFluidState(); - } - - private boolean isWaterAt(BlockPos pos) { - return getBlockState(pos).getFluidState().is(FluidTags.WATER); - } - @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - //FAWE start - cannot use switch where method names are equal - String methodName = method.getName(); - if (Refraction.pickName("getBlockState", "a_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockState - return getBlockState(blockPos); + switch (method.getName()) { + case "a_", "getBlockState" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + // getBlockState + return getBlockState(blockPos); + } } - } - if (Refraction.pickName("getBlockEntity", "c_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockEntity - return getBlockEntity(blockPos); - } - } - if ("a".equals(methodName) || "setBlock".equals(methodName) || "removeBlock".equals(methodName) || "destroyBlock".equals( - methodName)) { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { - // setBlock - return setBlock(blockPos, blockState); - } else if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { - // removeBlock (and also matches destroyBlock) - return removeBlock(blockPos, bl); + case "c_", "getBlockEntity" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + // getBlockEntity + return getBlockEntity(blockPos); + } } - } - //FAWE start - if (Refraction.pickName("getFluidState", "b_").equals(methodName)) { //net.minecraft.world.level.BlockGetter - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getFluidState(blockPos); + case "a", "setBlock", "removeBlock", "destroyBlock" -> { + if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { + // setBlock + return setBlock(blockPos, blockState); + } else if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { + // removeBlock (and also matches destroyBlock) + return removeBlock(blockPos, bl); + } } + default -> { } } - if (Refraction.pickName("isWaterAt", "z").equals(methodName)) { //net.minecraft.world.level.LevelReader - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return isWaterAt(blockPos); - } - } - if (Refraction.pickName("getEntities", "a_").equals(methodName)) { //net.minecraft.world.level.EntityGetter - if (args.length == 2 && args[0] instanceof Entity && args[1] instanceof AABB) { - return new ArrayList<>(); - } - } - // Specific passthroughs that we want to allow - // net.minecraft.world.level.BlockAndTintGetter - if (Refraction.pickName("getRawBrightness", "b").equals(methodName)) { - return method.invoke(this.serverLevel, args); - } - // net.minecraft.world.level.LevelHeightAccessor - if (Refraction.pickName("getMaxBuildHeight", "al").equals(methodName)) { - if (args.length == 0) { - return method.invoke(this.serverLevel, args); - } - } - // net.minecraft.world.level.SignalGetter - if (Refraction.pickName("hasNeighborSignal", "C").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getSignal", "c").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getControlInputSignal", "a").equals(methodName)) { - if (args.length == 3 && args[0] instanceof BlockPos && args[1] instanceof Direction && args[2] instanceof Boolean) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getDirectSignal", "a").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); - } - } - //FAWE start - force error if method not caught by this instance - if (errorOnPassthrough) { - LOGGER.error( - """ - Attempted passthough of method {}. - Method argument types: {} - Method argument values: {} - """, - method.getName(), - Arrays.stream(args).map(a -> a.getClass().getName()).toList(), - Arrays.stream(args).map(Object::toString).toList() - ); - throw new FaweException("Method required passthrough."); - } - //FAWE end - return method.invoke(this.serverLevel, args); } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index 995b221359..ce6fa750de 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -28,11 +28,13 @@ import com.google.common.util.concurrent.Futures; import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -64,6 +66,8 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.SharedConstants; import net.minecraft.Util; @@ -72,6 +76,7 @@ import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; import net.minecraft.core.component.DataComponentPatch; +import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; @@ -98,6 +103,7 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -110,6 +116,10 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -921,6 +931,20 @@ public void initializeRegistries() { } } + // Features + for (ResourceLocation name: server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + // BiomeCategories Registry biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME); biomeRegistry.getTagNames().forEach(tagKey -> { @@ -950,6 +974,39 @@ public void sendBiomeUpdates(World world, Iterable chunks) { originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); } + @Override + public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); + + if (!structureStart.isValid()) { + return false; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos max = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk(proxyLevel, originalWorld.structureManager(), chunkManager.getGenerator(), originalWorld.getRandom(), new BoundingBox(chunkPosx.getMinBlockX(), originalWorld.getMinBuildHeight(), chunkPosx.getMinBlockZ(), chunkPosx.getMaxBlockX(), originalWorld.getMaxBuildHeight(), chunkPosx.getMaxBlockZ()), chunkPosx)); + return true; + } + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ @@ -1120,7 +1177,9 @@ private static class MojangWatchdog implements Watchdog { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField(StaticRefraction.NEXT_TICK_TIME); + Field tickField = MinecraftServer.class.getDeclaredField( + Refraction.pickName("nextTickTime", "ag") + ); if (tickField.getType() != long.class) { throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java index a992e936c8..57786d93b5 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java @@ -19,84 +19,43 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1; -import com.fastasyncworldedit.core.internal.exception.FaweException; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.PaperweightFaweAdapter; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.world.block.BlockTypes; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.entity.Entity; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.AABB; -import org.apache.logging.log4j.Logger; +import com.sk89q.worldedit.math.BlockVector3; +import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.Nullable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; public class PaperweightServerLevelDelegateProxy implements InvocationHandler { - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - // FAWE start - extent not EditSession - private final Extent editSession; - //FAWE end + private final EditSession editSession; private final ServerLevel serverLevel; - //FAWE start - use FAWE adapter - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - //FAWE end - //FAWE start - force error if method not caught by this instance - private final boolean errorOnPassthrough; - //FAWE end + private final PaperweightAdapter adapter; private PaperweightServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { this.editSession = editSession; this.serverLevel = serverLevel; - //FAWE start - this.errorOnPassthrough = false; - //FAWE end + this.adapter = adapter; } public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter) + serverLevel.getClass().getClassLoader(), + serverLevel.getClass().getInterfaces(), + new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter) ); } - //FAWE start - force error if method not caught by this instance - private PaperweightServerLevelDelegateProxy(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - this.editSession = extent; - this.serverLevel = serverLevel; - this.errorOnPassthrough = errorOnPassthrough; - } - - public static WorldGenLevel newInstance(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(extent, serverLevel, errorOnPassthrough) - ); - } - //FAWE end - @Nullable private BlockEntity getBlockEntity(BlockPos blockPos) { BlockEntity tileEntity = this.serverLevel.getChunkAt(blockPos).getBlockEntity(blockPos); @@ -104,25 +63,19 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { return null; } BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); - newEntity.loadWithComponents( - (CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock( - blockPos.getX(), - blockPos.getY(), - blockPos.getZ() - ).getNbtReference().getValue()), - this.serverLevel.registryAccess() - ); + newEntity.loadWithComponents((CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at(blockPos.getX(), + blockPos.getY(), blockPos.getZ())).getNbtReference().getValue()), MinecraftServer.getServer().registryAccess()); return newEntity; } private BlockState getBlockState(BlockPos blockPos) { - return adapter.adapt(this.editSession.getBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ())); + return adapter.adapt(this.editSession.getBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()))); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), adapter.adapt(blockState)); + return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), adapter.adapt(blockState)); } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); } @@ -130,109 +83,38 @@ private boolean setBlock(BlockPos blockPos, BlockState blockState) { private boolean removeBlock(BlockPos blockPos, boolean bl) { try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), BlockTypes.AIR.getDefaultState()); + return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), BlockTypes.AIR.getDefaultState()); } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); } } - private FluidState getFluidState(BlockPos pos) { - return getBlockState(pos).getFluidState(); - } - - private boolean isWaterAt(BlockPos pos) { - return getBlockState(pos).getFluidState().is(FluidTags.WATER); - } - @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - //FAWE start - cannot use switch where method names are equal - String methodName = method.getName(); - if (Refraction.pickName("getBlockState", "a_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockState - return getBlockState(blockPos); + switch (method.getName()) { + case "a_", "getBlockState" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + // getBlockState + return getBlockState(blockPos); + } } - } - if (Refraction.pickName("getBlockEntity", "c_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockEntity - return getBlockEntity(blockPos); - } - } - if ("a".equals(methodName) || "setBlock".equals(methodName) || "removeBlock".equals(methodName) || "destroyBlock".equals( - methodName)) { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { - // setBlock - return setBlock(blockPos, blockState); - } else if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { - // removeBlock (and also matches destroyBlock) - return removeBlock(blockPos, bl); + case "c_", "getBlockEntity" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + // getBlockEntity + return getBlockEntity(blockPos); + } } - } - //FAWE start - if (Refraction.pickName("getFluidState", "b_").equals(methodName)) { //net.minecraft.world.level.BlockGetter - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getFluidState(blockPos); + case "a", "setBlock", "removeBlock", "destroyBlock" -> { + if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { + // setBlock + return setBlock(blockPos, blockState); + } else if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { + // removeBlock (and also matches destroyBlock) + return removeBlock(blockPos, bl); + } } + default -> { } } - if (Refraction.pickName("isWaterAt", "z").equals(methodName)) { //net.minecraft.world.level.LevelReader - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return isWaterAt(blockPos); - } - } - if (Refraction.pickName("getEntities", "a_").equals(methodName)) { //net.minecraft.world.level.EntityGetter - if (args.length == 2 && args[0] instanceof Entity && args[1] instanceof AABB) { - return new ArrayList<>(); - } - } - // Specific passthroughs that we want to allow - // net.minecraft.world.level.BlockAndTintGetter - if (Refraction.pickName("getRawBrightness", "b").equals(methodName)) { - return method.invoke(this.serverLevel, args); - } - // net.minecraft.world.level.LevelHeightAccessor - if (Refraction.pickName("getMaxBuildHeight", "al").equals(methodName)) { - if (args.length == 0) { - return method.invoke(this.serverLevel, args); - } - } - // net.minecraft.world.level.SignalGetter - if (Refraction.pickName("hasNeighborSignal", "C").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getSignal", "c").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getControlInputSignal", "a").equals(methodName)) { - if (args.length == 3 && args[0] instanceof BlockPos && args[1] instanceof Direction && args[2] instanceof Boolean) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getDirectSignal", "a").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); - } - } - //FAWE start - force error if method not caught by this instance - if (errorOnPassthrough) { - LOGGER.error( - """ - Attempted passthough of method {}. - Method argument types: {} - Method argument values: {} - """, - method.getName(), - Arrays.stream(args).map(a -> a.getClass().getName()).toList(), - Arrays.stream(args).map(Object::toString).toList() - ); - throw new FaweException("Method required passthrough."); - } - //FAWE end return method.invoke(this.serverLevel, args); } From aad13f5c376c30a0f69826babd3d0d24982cbad2 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Tue, 12 Dec 2023 17:28:36 +0000 Subject: [PATCH 06/15] Update 1.20.3/4 adapters --- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 1 - .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 3 ++- .../v1_20_R3/FaweBlockStateListPopulator.java | 26 +++++++++++++++++++ .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 9 ++++--- .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 8 +++--- .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 9 ++++--- 6 files changed, 45 insertions(+), 11 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index 93573f48de..6629e8aad8 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -701,7 +701,6 @@ public void setupFeatures() { } } - @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index 9131dde789..53ba325599 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -906,6 +906,7 @@ public void initializeRegistries() { ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); } } + // Structures for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) { if (StructureType.REGISTRY.get(name.toString()) == null) { @@ -962,7 +963,7 @@ public boolean generateStructure(StructureType type, World world, EditSession se ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); - StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), chunkManager.chunkMap.structureTemplateManager, originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); + StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); if (!structureStart.isValid()) { return false; diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java index 0fe2490920..6b9050fed6 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java @@ -5,6 +5,7 @@ import net.minecraft.core.Holder; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; @@ -103,4 +104,29 @@ public WorldBorder getWorldBorder() { return world.getWorldBorder(); } + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags, final int maxUpdateDepth) { + return world.setBlock(pos, state, flags, maxUpdateDepth); + } + + @Override + public boolean removeBlock(final BlockPos pos, final boolean move) { + return world.removeBlock(pos, move); + } + + @Override + public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity breakingEntity, final int maxUpdateDepth) { + return world.destroyBlock(pos, drop, breakingEntity, maxUpdateDepth); + } + + @Override + public BlockState getBlockState(final BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags) { + return world.setBlock(pos, state, flags); + } + } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index 585d089b12..3124565d81 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -540,6 +540,7 @@ protected ServerLevel getServerLevel(final World world) { @Override public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { + //FAWE start ServerLevel serverLevel = ((CraftWorld) world).getHandle(); ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); @@ -606,7 +607,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed serverLevel.getSeed(), chunkPos, 0, - serverLevel, + populator, biome -> true ); if (!structureStart.isValid()) { @@ -622,7 +623,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed SectionPos.blockToSectionCoord(boundingBox.maxZ()) ); ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( - serverLevel, + populator, serverLevel.structureManager(), chunkManager.getGenerator(), serverLevel.getRandom(), @@ -636,10 +637,12 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ), chunkPosx )); - return populator.getList().stream().collect(Collectors.toMap( + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( CraftBlockState::getPosition, craftBlockState -> craftBlockState )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; } } finally { serverLevel.captureBlockStates = false; diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index ca3558b0b3..bd29dc2bbf 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -623,7 +623,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed serverLevel.getSeed(), chunkPos, 0, - serverLevel, + populator, biome -> true ); if (!structureStart.isValid()) { @@ -639,7 +639,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed SectionPos.blockToSectionCoord(boundingBox.maxZ()) ); ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( - serverLevel, + populator, serverLevel.structureManager(), chunkManager.getGenerator(), serverLevel.getRandom(), @@ -653,10 +653,12 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ), chunkPosx )); - return populator.getList().stream().collect(Collectors.toMap( + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( CraftBlockState::getPosition, craftBlockState -> craftBlockState )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; } } finally { serverLevel.captureBlockStates = false; diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 1d48f4bded..cfe48d73e9 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -595,6 +595,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS @Override public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { + //FAWE start ServerLevel serverLevel = ((CraftWorld) world).getHandle(); Structure k = serverLevel .registryAccess() @@ -623,7 +624,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed serverLevel.getSeed(), chunkPos, 0, - serverLevel, + populator, biome -> true ); if (!structureStart.isValid()) { @@ -639,7 +640,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed SectionPos.blockToSectionCoord(boundingBox.maxZ()) ); ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( - serverLevel, + populator, serverLevel.structureManager(), chunkManager.getGenerator(), serverLevel.getRandom(), @@ -653,10 +654,12 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ), chunkPosx )); - return populator.getList().stream().collect(Collectors.toMap( + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( CraftBlockState::getPosition, craftBlockState -> craftBlockState )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; } } finally { serverLevel.captureBlockStates = false; From f7387ad8e7f1d5b3be5e1cf1e9079ed9cf02a559 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Thu, 28 Mar 2024 12:44:28 +0000 Subject: [PATCH 07/15] fix ext.fawe -> ext/fawe --- .../{ext.fawe => ext/fawe}/v1_20_R3/PaperweightAdapter.java | 0 .../fawe}/v1_20_R3/PaperweightDataConverters.java | 0 .../{ext.fawe => ext/fawe}/v1_20_R3/PaperweightFakePlayer.java | 0 .../fawe}/v1_20_R3/PaperweightServerLevelDelegateProxy.java | 0 .../fawe}/v1_20_R3/PaperweightWorldNativeAccess.java | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/{ext.fawe => ext/fawe}/v1_20_R3/PaperweightAdapter.java (100%) rename worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/{ext.fawe => ext/fawe}/v1_20_R3/PaperweightDataConverters.java (100%) rename worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/{ext.fawe => ext/fawe}/v1_20_R3/PaperweightFakePlayer.java (100%) rename worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/{ext.fawe => ext/fawe}/v1_20_R3/PaperweightServerLevelDelegateProxy.java (100%) rename worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/{ext.fawe => ext/fawe}/v1_20_R3/PaperweightWorldNativeAccess.java (100%) diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java similarity index 100% rename from worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightDataConverters.java similarity index 100% rename from worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightDataConverters.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightDataConverters.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightFakePlayer.java similarity index 100% rename from worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightFakePlayer.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightFakePlayer.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightServerLevelDelegateProxy.java similarity index 100% rename from worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightServerLevelDelegateProxy.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightServerLevelDelegateProxy.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightWorldNativeAccess.java similarity index 100% rename from worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightWorldNativeAccess.java rename to worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightWorldNativeAccess.java From c4ccee48d0a46dfcedc917e103a59ca060d12605 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Fri, 31 May 2024 18:15:56 +0100 Subject: [PATCH 08/15] Address vector deprecations --- .../bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java | 4 ++-- .../adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java | 4 ++-- .../bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java | 4 ++-- .../adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java | 4 ++-- .../bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java | 4 ++-- .../adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java | 4 ++-- .../bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java | 4 ++-- .../adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java | 4 ++-- 8 files changed, 16 insertions(+), 16 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index f1e44b66db..1aa2068751 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -950,7 +950,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); } @Override @@ -963,7 +963,7 @@ public boolean generateStructure(StructureType type, World world, EditSession se ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); if (!structureStart.isValid()) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index 6629e8aad8..d2a0db0f60 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -560,7 +560,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS populator, generator, serverLevel.random, - new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + new BlockPos(pt.x(), pt.y(), pt.z()) )) { return null; } @@ -592,7 +592,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ServerChunkCache chunkManager = serverLevel.getChunkSource(); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); //FAWE start FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java index 53ba325599..357e33f365 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java @@ -949,7 +949,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); } @Override @@ -962,7 +962,7 @@ public boolean generateStructure(StructureType type, World world, EditSession se ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); if (!structureStart.isValid()) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index 3124565d81..291d187733 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -558,7 +558,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS populator, generator, serverLevel.random, - new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + new BlockPos(pt.x(), pt.y(), pt.z()) )) { return null; } @@ -590,7 +590,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ServerChunkCache chunkManager = serverLevel.getChunkSource(); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); //FAWE start FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index 5fd3928a48..d889a91db5 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -973,7 +973,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); } @Override @@ -986,7 +986,7 @@ public boolean generateStructure(StructureType type, World world, EditSession se ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); if (!structureStart.isValid()) { diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index bd29dc2bbf..162a8fd26c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -574,7 +574,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS populator, generator, serverLevel.random, - new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + new BlockPos(pt.x(), pt.y(), pt.z()) )) { return null; } @@ -606,7 +606,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ServerChunkCache chunkManager = serverLevel.getChunkSource(); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); //FAWE start FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index ce6fa750de..05c9383ba0 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -980,7 +980,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); } @Override @@ -993,7 +993,7 @@ public boolean generateStructure(StructureType type, World world, EditSession se ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); if (!structureStart.isValid()) { diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index cfe48d73e9..275745e931 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -574,7 +574,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS populator, generator, serverLevel.random, - new BlockPos(pt.getX(), pt.getY(), pt.getZ()) + new BlockPos(pt.x(), pt.y(), pt.z()) )) { return null; } @@ -607,7 +607,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ServerChunkCache chunkManager = serverLevel.getChunkSource(); - ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ())); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); //FAWE start FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); From 93f3573caa8e0e4a593705d6c55ea707c80e2108 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Fri, 7 Jun 2024 19:14:23 +0100 Subject: [PATCH 09/15] Upstream changes, use correct list of cached block changes --- .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 4 +- .../v1_20_R2/FaweBlockStateListPopulator.java | 18 ++++++- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 9 ++-- .../v1_20_R2/PaperweightPlatformAdapter.java | 13 +++++ .../ext/fawe/v1_20_R3/PaperweightAdapter.java | 4 +- .../v1_20_R3/FaweBlockStateListPopulator.java | 18 ++++++- .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 11 ++-- .../v1_20_R3/PaperweightPlatformAdapter.java | 13 +++++ .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 8 ++- .../v1_20_R4/FaweBlockStateListPopulator.java | 50 +++++++++++++++++++ .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 9 ++-- .../v1_20_R4/PaperweightPlatformAdapter.java | 13 +++++ .../ext/fawe/v1_21_R1/PaperweightAdapter.java | 22 ++------ .../v1_21_R1/FaweBlockStateListPopulator.java | 44 ++++++++++++++++ .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 12 ++--- .../v1_21_R1/PaperweightPlatformAdapter.java | 13 +++++ .../Pre13HangingCompatibilityHandler.java | 2 +- .../worldedit/world/chunk/AnvilChunk13.java | 4 +- .../worldedit/world/chunk/AnvilChunk18.java | 10 ++-- .../generation/ConfiguredFeatureType.java | 15 ++---- .../world/generation/StructureType.java | 15 ++---- 21 files changed, 224 insertions(+), 83 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index 1aa2068751..d9cfd3fc89 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -947,7 +947,7 @@ public void sendBiomeUpdates(World world, Iterable chunks) { @Override public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.id())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); @@ -956,7 +956,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess @Override public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java index a802a2e7af..c0233adee9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java @@ -9,6 +9,7 @@ import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; @@ -121,7 +122,22 @@ public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity @Override public BlockState getBlockState(final BlockPos pos) { - return world.getBlockState(pos); + BlockState state = world.getBlockState(pos); + try { + state = new BlockState( + state.getBlock(), + state.getValues(), + PaperweightPlatformAdapter.getStatePropertiesCodec(state) + ) { + @Override + public boolean is(Block block) { + return true; + } + }; + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return state; } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index d2a0db0f60..1e19d2185a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -549,7 +549,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS ConfiguredFeature configuredFeature = serverLevel .registryAccess() .registryOrThrow(Registries.CONFIGURED_FEATURE) - .get(ResourceLocation.tryParse(feature.getId())); + .get(ResourceLocation.tryParse(feature.id())); FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); Map placed = TaskManager.taskManager().sync(() -> { @@ -564,10 +564,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS )) { return null; } - return populator.getList().stream().collect(Collectors.toMap( - CraftBlockState::getPosition, - craftBlockState -> craftBlockState - )); + return new HashMap<>(populator.getLevel().capturedBlockStates); } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; @@ -585,7 +582,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed Structure k = serverLevel .registryAccess() .registryOrThrow(Registries.STRUCTURE) - .get(ResourceLocation.tryParse(type.getId())); + .get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 99f52e4feb..2696e169b8 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -11,6 +11,7 @@ import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; import com.mojang.datafixers.util.Either; +import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -45,6 +46,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.GlobalPalette; @@ -99,6 +101,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; + private static final Field fieldPropertiesCodec; + private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -154,6 +158,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); + fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); + fieldPropertiesCodec.setAccessible(true); + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" @@ -705,6 +712,12 @@ static List getEntities(LevelChunk chunk) { return List.of(); } + public static MapCodec getStatePropertiesCodec( + net.minecraft.world.level.block.state.BlockState state + ) throws IllegalAccessException { + return (MapCodec) fieldPropertiesCodec.get(state); + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java index 357e33f365..ca4580f27a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java @@ -946,7 +946,7 @@ public void sendBiomeUpdates(World world, Iterable chunks) { @Override public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.id())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); @@ -955,7 +955,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess @Override public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java index 6b9050fed6..c05144d92d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java @@ -9,6 +9,7 @@ import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; @@ -121,7 +122,22 @@ public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity @Override public BlockState getBlockState(final BlockPos pos) { - return world.getBlockState(pos); + BlockState state = world.getBlockState(pos); + try { + state = new BlockState( + state.getBlock(), + state.getValues(), + PaperweightPlatformAdapter.getStatePropertiesCodec(state) + ) { + @Override + public boolean is(Block block) { + return true; + } + }; + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return state; } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index 291d187733..a16a7a142c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -547,7 +547,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS ConfiguredFeature configuredFeature = serverLevel .registryAccess() .registryOrThrow(Registries.CONFIGURED_FEATURE) - .get(ResourceLocation.tryParse(feature.getId())); + .get(ResourceLocation.tryParse(feature.id())); FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); Map placed = TaskManager.taskManager().sync(() -> { @@ -560,19 +560,16 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS serverLevel.random, new BlockPos(pt.x(), pt.y(), pt.z()) )) { + return null; } - return populator.getList().stream().collect(Collectors.toMap( - CraftBlockState::getPosition, - craftBlockState -> craftBlockState - )); + return new HashMap<>(populator.getLevel().capturedBlockStates); } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; serverLevel.capturedBlockStates.clear(); } }); - return placeFeatureIntoSession(editSession, populator, placed); //FAWE end } @@ -583,7 +580,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed Structure k = serverLevel .registryAccess() .registryOrThrow(Registries.STRUCTURE) - .get(ResourceLocation.tryParse(type.getId())); + .get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 1ff6819638..87de963ef9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -11,6 +11,7 @@ import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; import com.mojang.datafixers.util.Either; +import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -45,6 +46,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.GlobalPalette; @@ -100,6 +102,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingBlockCount; private static final Field fieldBiomes; + private static final Field fieldPropertiesCodec; + private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -154,6 +158,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); + fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); + fieldPropertiesCodec.setAccessible(true); + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" @@ -705,6 +712,12 @@ static List getEntities(LevelChunk chunk) { return List.of(); } + public static MapCodec getStatePropertiesCodec( + net.minecraft.world.level.block.state.BlockState state + ) throws IllegalAccessException { + return (MapCodec) fieldPropertiesCodec.get(state); + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index d889a91db5..4c756ea215 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -970,7 +970,8 @@ public void sendBiomeUpdates(World world, Iterable chunks) { @Override public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get( + ResourceLocation.tryParse(type.id())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); @@ -979,7 +980,10 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess @Override public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + Structure k = originalWorld + .registryAccess() + .registryOrThrow(Registries.STRUCTURE) + .get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java index 51b5514737..d9cf01e9fb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java @@ -1,13 +1,18 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; @@ -66,6 +71,11 @@ public int getSeaLevel() { return world.getSeaLevel(); } + @Override + public FeatureFlagSet enabledFeatures() { + return world.enabledFeatures(); + } + @Override public float getShade(final Direction direction, final boolean shaded) { return world.getShade(direction, shaded); @@ -97,4 +107,44 @@ public WorldBorder getWorldBorder() { return world.getWorldBorder(); } + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags, final int maxUpdateDepth) { + return world.setBlock(pos, state, flags, maxUpdateDepth); + } + + @Override + public boolean removeBlock(final BlockPos pos, final boolean move) { + return world.removeBlock(pos, move); + } + + @Override + public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity breakingEntity, final int maxUpdateDepth) { + return world.destroyBlock(pos, drop, breakingEntity, maxUpdateDepth); + } + + @Override + public BlockState getBlockState(final BlockPos pos) { + BlockState state = world.getBlockState(pos); + try { + state = new BlockState( + state.getBlock(), + (Reference2ObjectArrayMap, Comparable>) state.getValues(), + PaperweightPlatformAdapter.getStatePropertiesCodec(state) + ) { + @Override + public boolean is(Block block) { + return true; + } + }; + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return state; + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags) { + return world.setBlock(pos, state, flags); + } + } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index 162a8fd26c..c2e6ed0028 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -563,7 +563,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS ConfiguredFeature configuredFeature = serverLevel .registryAccess() .registryOrThrow(Registries.CONFIGURED_FEATURE) - .get(ResourceLocation.tryParse(feature.getId())); + .get(ResourceLocation.tryParse(feature.id())); FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); Map placed = TaskManager.taskManager().sync(() -> { @@ -578,10 +578,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS )) { return null; } - return populator.getList().stream().collect(Collectors.toMap( - CraftBlockState::getPosition, - craftBlockState -> craftBlockState - )); + return new HashMap<>(populator.getLevel().capturedBlockStates); } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; @@ -599,7 +596,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed Structure k = serverLevel .registryAccess() .registryOrThrow(Registries.STRUCTURE) - .get(ResourceLocation.tryParse(type.getId())); + .get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 3ddfbc6fbf..cbadc43df9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -10,6 +10,7 @@ import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; +import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -44,6 +45,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.GlobalPalette; import net.minecraft.world.level.chunk.HashMapPalette; @@ -98,6 +100,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingBlockCount; private static final Field fieldBiomes; + private static final Field fieldPropertiesCodec; + private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -152,6 +156,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); + fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); + fieldPropertiesCodec.setAccessible(true); + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" @@ -698,6 +705,12 @@ static List getEntities(LevelChunk chunk) { return List.of(); } + public static MapCodec getStatePropertiesCodec( + net.minecraft.world.level.block.state.BlockState state + ) throws IllegalAccessException { + return (MapCodec) fieldPropertiesCodec.get(state); + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index 05c9383ba0..d3d37d36c7 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -510,23 +510,7 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state CraftWorld craftWorld = ((CraftWorld) location.getWorld()); ServerLevel worldServer = craftWorld.getHandle(); - String entityId = state.getType().id(); - - LinCompoundTag nativeTag = state.getNbt(); - net.minecraft.nbt.CompoundTag tag; - if (nativeTag != null) { - tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); - removeUnwantedEntityTagsRecursively(tag); - } else { - tag = new net.minecraft.nbt.CompoundTag(); - } - - tag.putString("id", entityId); - - Entity createdEntity = EntityType.loadEntityRecursive(tag, craftWorld.getHandle(), (loadedEntity) -> { - loadedEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - return loadedEntity; - }); + Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); if (createdEntity != null) { worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); @@ -977,7 +961,7 @@ public void sendBiomeUpdates(World world, Iterable chunks) { @Override public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId())); + ConfiguredFeature k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.id())); ServerChunkCache chunkManager = originalWorld.getChunkSource(); WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); @@ -986,7 +970,7 @@ public boolean generateFeature(ConfiguredFeatureType type, World world, EditSess @Override public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { ServerLevel originalWorld = ((CraftWorld) world).getHandle(); - Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId())); + Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java index 28b85a15d3..aa8f6e5e8a 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java @@ -1,13 +1,17 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; +import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; @@ -97,4 +101,44 @@ public WorldBorder getWorldBorder() { return world.getWorldBorder(); } + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags, final int maxUpdateDepth) { + return world.setBlock(pos, state, flags, maxUpdateDepth); + } + + @Override + public boolean removeBlock(final BlockPos pos, final boolean move) { + return world.removeBlock(pos, move); + } + + @Override + public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity breakingEntity, final int maxUpdateDepth) { + return world.destroyBlock(pos, drop, breakingEntity, maxUpdateDepth); + } + + @Override + public BlockState getBlockState(final BlockPos pos) { + BlockState state = world.getBlockState(pos); + try { + state = new BlockState( + state.getBlock(), + (Reference2ObjectArrayMap, Comparable>) state.getValues(), + PaperweightPlatformAdapter.getStatePropertiesCodec(state) + ) { + @Override + public boolean is(Block block) { + return true; + } + }; + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + return state; + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags) { + return world.setBlock(pos, state, flags); + } + } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 275745e931..36a712f513 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -518,7 +518,8 @@ public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, Blo public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); ItemStack stack = new ItemStack( - registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), + DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) + .get(ResourceLocation.tryParse(baseItemStack.getType().id())), baseItemStack.getAmount() ); final net.minecraft.nbt.CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); @@ -563,7 +564,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS ConfiguredFeature configuredFeature = serverLevel .registryAccess() .registryOrThrow(Registries.CONFIGURED_FEATURE) - .get(ResourceLocation.tryParse(feature.getId())); + .get(ResourceLocation.tryParse(feature.id())); FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); Map placed = TaskManager.taskManager().sync(() -> { @@ -578,10 +579,7 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS )) { return null; } - return populator.getList().stream().collect(Collectors.toMap( - CraftBlockState::getPosition, - craftBlockState -> craftBlockState - )); + return new HashMap<>(populator.getLevel().capturedBlockStates); } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; @@ -600,7 +598,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed Structure k = serverLevel .registryAccess() .registryOrThrow(Registries.STRUCTURE) - .get(ResourceLocation.tryParse(type.getId())); + .get(ResourceLocation.tryParse(type.id())); if (k == null) { return false; } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index 6881ea4e24..67a62e6636 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -11,6 +11,7 @@ import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; +import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -43,6 +44,7 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.GlobalPalette; import net.minecraft.world.level.chunk.HashMapPalette; @@ -97,6 +99,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingBlockCount; private static final Field fieldBiomes; + private static final Field fieldPropertiesCodec; + private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -149,6 +153,9 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); + fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); + fieldPropertiesCodec.setAccessible(true); + Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" @@ -672,6 +679,12 @@ static List getEntities(LevelChunk chunk) { } } + public static MapCodec getStatePropertiesCodec( + net.minecraft.world.level.block.state.BlockState state + ) throws IllegalAccessException { + return (MapCodec) fieldPropertiesCodec.get(state); + } + record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java index f0bea016f2..8a72489f1c 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/clipboard/io/legacycompat/Pre13HangingCompatibilityHandler.java @@ -29,7 +29,7 @@ public class Pre13HangingCompatibilityHandler implements EntityNBTCompatibilityH @Override public LinCompoundTag updateNbt(EntityType type, LinCompoundTag tag) { - if (!type.getId().startsWith("minecraft:")) { + if (!type.id().startsWith("minecraft:")) { return tag; } Direction newDirection; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java index 9b3d54027b..34e843f8fc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk13.java @@ -131,7 +131,9 @@ public AnvilChunk13(LinCompoundTag tag) throws DataException { try { blockState = getBlockStateWith(blockState, property, value); } catch (IllegalArgumentException e) { - throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().id() + ", " + property.getName() + ": " + value); + throw new InvalidFormatException("Invalid block state for " + blockState + .getBlockType() + .id() + ", " + property.getName() + ": " + value); } } } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java index c5736bfd5f..79ffa8b7a8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/chunk/AnvilChunk18.java @@ -105,7 +105,9 @@ public AnvilChunk18(CompoundTag tag) throws DataException { try { blockState = getBlockStateWith(blockState, property, value); } catch (IllegalArgumentException e) { - throw new InvalidFormatException("Invalid block state for " + blockState.getBlockType().getId() + ", " + property.getName() + ": " + value); + throw new InvalidFormatException("Invalid block state for " + blockState + .getBlockType() + .id() + ", " + property.getName() + ": " + value); } } } @@ -197,9 +199,9 @@ private CompoundTag getBlockTileEntity(BlockVector3 position) throws DataExcepti @Override public BaseBlock getBlock(BlockVector3 position) throws DataException { - int x = position.getX() - rootX * 16; - int y = position.getY(); - int z = position.getZ() - rootZ * 16; + int x = position.x() - rootX * 16; + int y = position.y(); + int z = position.z() - rootZ * 16; int section = y >> 4; int yIndex = y & 0x0F; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java index bc5126d319..48c61a01cc 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/ConfiguredFeatureType.java @@ -24,19 +24,9 @@ import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; -public class ConfiguredFeatureType implements Keyed { - public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("configured feature type"); - - private final String id; +public record ConfiguredFeatureType(String id) implements Keyed { - public ConfiguredFeatureType(String id) { - this.id = id; - } - - @Override - public String getId() { - return this.id; - } + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("configured feature type"); @Override public String toString() { @@ -44,6 +34,7 @@ public String toString() { } //FAWE start + /** * Place this feature into an {@link EditSession} * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java index 0713735d70..06fef05f8d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/world/generation/StructureType.java @@ -24,19 +24,9 @@ import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.registry.NamespacedRegistry; -public class StructureType implements Keyed { - public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("structure type"); - - private final String id; +public record StructureType(String id) implements Keyed { - public StructureType(String id) { - this.id = id; - } - - @Override - public String getId() { - return this.id; - } + public static final NamespacedRegistry REGISTRY = new NamespacedRegistry<>("structure type"); @Override public String toString() { @@ -44,6 +34,7 @@ public String toString() { } //FAWE start + /** * Place this structure into an {@link EditSession} * From 865456a4b9ffbb90f3e57932bb23bfeb0e172ca0 Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Fri, 7 Jun 2024 20:51:45 +0100 Subject: [PATCH 10/15] Undo Minecraft has a lot of different methods between private and public to determine if structures can be placed. We cannot possibly cover all of them whilst also ensuring issues do not arise with generic "true"s --- .../v1_20_R2/FaweBlockStateListPopulator.java | 18 +---------------- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 7 ++++++- .../v1_20_R2/PaperweightPlatformAdapter.java | 7 ------- .../v1_20_R3/FaweBlockStateListPopulator.java | 18 +---------------- .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 8 +++++++- .../v1_20_R3/PaperweightPlatformAdapter.java | 7 ------- .../v1_20_R4/FaweBlockStateListPopulator.java | 20 +------------------ .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 7 ++++++- .../v1_20_R4/PaperweightPlatformAdapter.java | 7 ------- .../v1_21_R1/FaweBlockStateListPopulator.java | 18 +---------------- .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 7 ++++++- .../v1_21_R1/PaperweightPlatformAdapter.java | 7 ------- 12 files changed, 29 insertions(+), 102 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java index c0233adee9..a802a2e7af 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweBlockStateListPopulator.java @@ -9,7 +9,6 @@ import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; @@ -122,22 +121,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity @Override public BlockState getBlockState(final BlockPos pos) { - BlockState state = world.getBlockState(pos); - try { - state = new BlockState( - state.getBlock(), - state.getValues(), - PaperweightPlatformAdapter.getStatePropertiesCodec(state) - ) { - @Override - public boolean is(Block block) { - return true; - } - }; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return state; + return world.getBlockState(pos); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index 1e19d2185a..298aefceb4 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -564,7 +564,12 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS )) { return null; } - return new HashMap<>(populator.getLevel().capturedBlockStates); + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index 2696e169b8..c6b37295fa 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -11,7 +11,6 @@ import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; import com.mojang.datafixers.util.Either; -import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -712,12 +711,6 @@ static List getEntities(LevelChunk chunk) { return List.of(); } - public static MapCodec getStatePropertiesCodec( - net.minecraft.world.level.block.state.BlockState state - ) throws IllegalAccessException { - return (MapCodec) fieldPropertiesCodec.get(state); - } - record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java index c05144d92d..6b9050fed6 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweBlockStateListPopulator.java @@ -9,7 +9,6 @@ import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; @@ -122,22 +121,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity @Override public BlockState getBlockState(final BlockPos pos) { - BlockState state = world.getBlockState(pos); - try { - state = new BlockState( - state.getBlock(), - state.getValues(), - PaperweightPlatformAdapter.getStatePropertiesCodec(state) - ) { - @Override - public boolean is(Block block) { - return true; - } - }; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return state; + return world.getBlockState(pos); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index a16a7a142c..b2416c03ae 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -563,7 +563,12 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS return null; } - return new HashMap<>(populator.getLevel().capturedBlockStates); + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; @@ -607,6 +612,7 @@ public boolean generateStructure(StructureType type, World world, EditSession ed populator, biome -> true ); + if (!structureStart.isValid()) { return null; } else { diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index 87de963ef9..e4fd42b13a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -11,7 +11,6 @@ import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; import com.mojang.datafixers.util.Either; -import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -712,12 +711,6 @@ static List getEntities(LevelChunk chunk) { return List.of(); } - public static MapCodec getStatePropertiesCodec( - net.minecraft.world.level.block.state.BlockState state - ) throws IllegalAccessException { - return (MapCodec) fieldPropertiesCodec.get(state); - } - record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java index d9cf01e9fb..9a1e20c712 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweBlockStateListPopulator.java @@ -1,6 +1,5 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4; -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; @@ -10,9 +9,7 @@ import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; @@ -124,22 +121,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity @Override public BlockState getBlockState(final BlockPos pos) { - BlockState state = world.getBlockState(pos); - try { - state = new BlockState( - state.getBlock(), - (Reference2ObjectArrayMap, Comparable>) state.getValues(), - PaperweightPlatformAdapter.getStatePropertiesCodec(state) - ) { - @Override - public boolean is(Block block) { - return true; - } - }; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return state; + return world.getBlockState(pos); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index c2e6ed0028..b99ad854f9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -578,7 +578,12 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS )) { return null; } - return new HashMap<>(populator.getLevel().capturedBlockStates); + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index cbadc43df9..5384a15246 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -10,7 +10,6 @@ import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -705,12 +704,6 @@ static List getEntities(LevelChunk chunk) { return List.of(); } - public static MapCodec getStatePropertiesCodec( - net.minecraft.world.level.block.state.BlockState state - ) throws IllegalAccessException { - return (MapCodec) fieldPropertiesCodec.get(state); - } - record FakeIdMapBlock(int size) implements IdMap { @Override diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java index aa8f6e5e8a..dd17271bb4 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java @@ -9,7 +9,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.Property; import net.minecraft.world.level.border.WorldBorder; @@ -118,22 +117,7 @@ public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity @Override public BlockState getBlockState(final BlockPos pos) { - BlockState state = world.getBlockState(pos); - try { - state = new BlockState( - state.getBlock(), - (Reference2ObjectArrayMap, Comparable>) state.getValues(), - PaperweightPlatformAdapter.getStatePropertiesCodec(state) - ) { - @Override - public boolean is(Block block) { - return true; - } - }; - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - return state; + return world.getBlockState(pos); } @Override diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 36a712f513..0933297d22 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -579,7 +579,12 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS )) { return null; } - return new HashMap<>(populator.getLevel().capturedBlockStates); + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; } finally { serverLevel.captureBlockStates = false; serverLevel.captureTreeGeneration = false; diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index 67a62e6636..e9a24a4463 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -11,7 +11,6 @@ import com.fastasyncworldedit.core.math.IntPair; import com.fastasyncworldedit.core.util.MathMan; import com.fastasyncworldedit.core.util.TaskManager; -import com.mojang.serialization.MapCodec; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.bukkit.adapter.Refraction; @@ -679,12 +678,6 @@ static List getEntities(LevelChunk chunk) { } } - public static MapCodec getStatePropertiesCodec( - net.minecraft.world.level.block.state.BlockState state - ) throws IllegalAccessException { - return (MapCodec) fieldPropertiesCodec.get(state); - } - record FakeIdMapBlock(int size) implements IdMap { @Override From 44dd4865ab9029c4be9ff32590ba5ebd843776ad Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Wed, 12 Jun 2024 16:02:41 +0100 Subject: [PATCH 11/15] Cleanup --- .../main/java/com/sk89q/worldedit/world/fluid/FluidType.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 1b191f07f3..1aca4c25f7 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 @@ -40,17 +40,18 @@ public FluidType(String id) { } /** - * Gets the ID of this block. + * Gets the ID of this fluid. * * @return The id * @since 2.11.0 */ + @Override public String id() { return this.id; } /** - * Gets the ID of this block. + * Gets the ID of this fluid. * * @return The id * @deprecated use {@link #id()} From 90240180bc04bbcf1d4c460f8141809cb28da82d Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Thu, 27 Jun 2024 11:51:53 +0100 Subject: [PATCH 12/15] Cleanup after merge --- .../v1_20_R4/PaperweightServerLevelDelegateProxy.java | 11 +++++++++-- .../v1_21_R1/PaperweightServerLevelDelegateProxy.java | 10 ++++++++-- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java index fa52a8a427..a8b5f11cb1 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightServerLevelDelegateProxy.java @@ -63,8 +63,15 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { return null; } BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); - newEntity.loadWithComponents((CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at(blockPos.getX(), - blockPos.getY(), blockPos.getZ())).getNbtReference().getValue()), MinecraftServer.getServer().registryAccess()); + newEntity.loadWithComponents( + (CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at( + blockPos.getX(), + blockPos.getY(), + blockPos.getZ() + )).getNbtReference().getValue()), + MinecraftServer.getServer().registryAccess() + ); + return newEntity; } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java index 57786d93b5..43506eb044 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightServerLevelDelegateProxy.java @@ -63,8 +63,14 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { return null; } BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); - newEntity.loadWithComponents((CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at(blockPos.getX(), - blockPos.getY(), blockPos.getZ())).getNbtReference().getValue()), MinecraftServer.getServer().registryAccess()); + newEntity.loadWithComponents( + (CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at( + blockPos.getX(), + blockPos.getY(), + blockPos.getZ() + )).getNbtReference().getValue()), + MinecraftServer.getServer().registryAccess() + ); return newEntity; } From c5636af501e89246996aa12eb445283ebb1bd53b Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sun, 30 Jun 2024 10:47:18 +0100 Subject: [PATCH 13/15] Cleanup and add for 1.21 --- .../adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java | 2 +- .../impl/fawe/v1_20_R2/PaperweightFaweAdapter.java | 10 +++++----- .../fawe/v1_20_R2/PaperweightPlatformAdapter.java | 6 ------ .../impl/fawe/v1_20_R3/PaperweightFaweAdapter.java | 10 +++++----- .../fawe/v1_20_R3/PaperweightPlatformAdapter.java | 6 ------ .../impl/fawe/v1_20_R4/PaperweightFaweAdapter.java | 10 +++++----- .../fawe/v1_20_R4/PaperweightPlatformAdapter.java | 6 ------ .../fawe/v1_21_R1/FaweBlockStateListPopulator.java | 11 ++++++++--- .../impl/fawe/v1_21_R1/PaperweightFaweAdapter.java | 11 +++++------ 9 files changed, 29 insertions(+), 43 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index d9cfd3fc89..50a2d783b0 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -651,7 +651,7 @@ public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { = CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new)); @Override - public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { + public boolean simulateItemUse(World world, BlockVector3 position, BaseItem item, Direction face) { CraftWorld craftWorld = (CraftWorld) world; ServerLevel worldServer = craftWorld.getHandle(); ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index 298aefceb4..7f625f4c95 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -313,7 +313,7 @@ public Set getSupportedSideEffects() { } @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @@ -462,7 +462,7 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt } @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + public void sendFakeChunk(World world, Player player, ChunkPacket chunkPacket) { ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { @@ -497,7 +497,7 @@ public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chu } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + public boolean canPlaceAt(World world, BlockVector3 blockVector3, BlockState blockState) { int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( @@ -725,12 +725,12 @@ public net.minecraft.nbt.Tag fromNative(Tag foreign) { } @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + public boolean regenerate(World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); } @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + public IChunkGet get(World world, int chunkX, int chunkZ) { return new PaperweightGetBlocks(world, chunkX, chunkZ); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java index c6b37295fa..99f52e4feb 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightPlatformAdapter.java @@ -45,7 +45,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.GlobalPalette; @@ -100,8 +99,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingFluidCount; private static final Field fieldTickingBlockCount; - private static final Field fieldPropertiesCodec; - private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -157,9 +154,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); - fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); - fieldPropertiesCodec.setAccessible(true); - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index b2416c03ae..8cac149990 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -312,7 +312,7 @@ public Set getSupportedSideEffects() { } @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @@ -461,7 +461,7 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt } @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + public void sendFakeChunk(World world, Player player, ChunkPacket chunkPacket) { ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { @@ -496,7 +496,7 @@ public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chu } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + public boolean canPlaceAt(World world, BlockVector3 blockVector3, BlockState blockState) { net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(getOrdinalToIbdID()[blockState.getOrdinal()]); return blockState1.hasPostProcess( getServerLevel(world), @@ -724,12 +724,12 @@ public net.minecraft.nbt.Tag fromNative(Tag foreign) { } @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + public boolean regenerate(World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); } @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + public IChunkGet get(World world, int chunkX, int chunkZ) { return new PaperweightGetBlocks(world, chunkX, chunkZ); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java index e4fd42b13a..1ff6819638 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightPlatformAdapter.java @@ -45,7 +45,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkStatus; import net.minecraft.world.level.chunk.GlobalPalette; @@ -101,8 +100,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingBlockCount; private static final Field fieldBiomes; - private static final Field fieldPropertiesCodec; - private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -157,9 +154,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); - fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); - fieldPropertiesCodec.setAccessible(true); - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index b99ad854f9..b03725f1d3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -321,7 +321,7 @@ public Set getSupportedSideEffects() { } @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @@ -470,7 +470,7 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt } @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + public void sendFakeChunk(World world, Player player, ChunkPacket chunkPacket) { ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { @@ -505,7 +505,7 @@ public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chu } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + public boolean canPlaceAt(World world, BlockVector3 blockVector3, BlockState blockState) { int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( @@ -746,12 +746,12 @@ public net.minecraft.nbt.Tag fromNative(Tag foreign) { } @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + public boolean regenerate(World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); } @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + public IChunkGet get(World world, int chunkX, int chunkZ) { return new PaperweightGetBlocks(world, chunkX, chunkZ); } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java index 5384a15246..3ddfbc6fbf 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightPlatformAdapter.java @@ -44,7 +44,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.GlobalPalette; import net.minecraft.world.level.chunk.HashMapPalette; @@ -99,8 +98,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingBlockCount; private static final Field fieldBiomes; - private static final Field fieldPropertiesCodec; - private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -155,9 +152,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); - fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); - fieldPropertiesCodec.setAccessible(true); - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java index dd17271bb4..6add96e108 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweBlockStateListPopulator.java @@ -1,6 +1,5 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1; -import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.Holder; @@ -10,7 +9,7 @@ import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeManager; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.block.state.properties.Property; +import net.minecraft.world.flag.FeatureFlagSet; import net.minecraft.world.level.border.WorldBorder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.ChunkSource; @@ -18,7 +17,8 @@ import net.minecraft.world.level.lighting.LevelLightEngine; import net.minecraft.world.level.material.FluidState; import org.bukkit.craftbukkit.util.BlockStateListPopulator; -import org.jetbrains.annotations.Nullable; + +import javax.annotation.Nullable; public class FaweBlockStateListPopulator extends BlockStateListPopulator { @@ -69,6 +69,11 @@ public int getSeaLevel() { return world.getSeaLevel(); } + @Override + public FeatureFlagSet enabledFeatures() { + return world.enabledFeatures(); + } + @Override public float getShade(final Direction direction, final boolean shaded) { return world.getShade(direction, shaded); diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 0933297d22..2944408b6c 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -321,7 +321,7 @@ public Set getSupportedSideEffects() { } @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @@ -470,7 +470,7 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt } @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + public void sendFakeChunk(World world, Player player, ChunkPacket chunkPacket) { ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { @@ -505,7 +505,7 @@ public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chu } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + public boolean canPlaceAt(World world, BlockVector3 blockVector3, BlockState blockState) { int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( @@ -598,7 +598,6 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS @Override public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { - //FAWE start ServerLevel serverLevel = ((CraftWorld) world).getHandle(); Structure k = serverLevel .registryAccess() @@ -748,12 +747,12 @@ public net.minecraft.nbt.Tag fromNative(Tag foreign) { } @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + public boolean regenerate(World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); } @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + public IChunkGet get(World world, int chunkX, int chunkZ) { return new PaperweightGetBlocks(world, chunkX, chunkZ); } From 5face1786cd58d2fef3c146e6049363d673e01fc Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Sat, 16 Nov 2024 11:59:29 +0000 Subject: [PATCH 14/15] Add for 1.21.3 --- .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 17 -- .../ext/fawe/v1_20_R3/PaperweightAdapter.java | 17 -- .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 17 -- .../ext/fawe/v1_21_R1/PaperweightAdapter.java | 34 ++- .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 10 +- .../v1_21_R1/PaperweightPlatformAdapter.java | 6 - .../ext/fawe/v1_21_3/PaperweightAdapter.java | 104 ++++++--- .../PaperweightServerLevelDelegateProxy.java | 180 +++------------- .../v1_21_3/FaweBlockStateListPopulator.java | 133 ++++++++++++ .../fawe/v1_21_3/PaperweightFaweAdapter.java | 202 ++++++++++++++++-- 10 files changed, 441 insertions(+), 279 deletions(-) create mode 100644 worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/FaweBlockStateListPopulator.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index 50a2d783b0..fc06c2a94f 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -28,7 +28,6 @@ import com.google.common.util.concurrent.Futures; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; @@ -528,22 +527,6 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state } } - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - @Override public Component getRichBlockName(BlockType blockType) { return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java index ca4580f27a..23701aea22 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java @@ -28,7 +28,6 @@ import com.google.common.util.concurrent.Futures; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; @@ -527,22 +526,6 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state } } - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - @Override public Component getRichBlockName(BlockType blockType) { return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index 4c756ea215..a9a208de33 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -28,7 +28,6 @@ import com.google.common.util.concurrent.Futures; import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; -import com.sk89q.jnbt.NBTConstants; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; @@ -535,22 +534,6 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state } } - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", NBTConstants.TYPE_LIST)) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", NBTConstants.TYPE_COMPOUND); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - @Override public Component getRichBlockName(BlockType blockType) { return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index d3d37d36c7..ea7b5917e9 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -34,7 +34,6 @@ import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; -import com.sk89q.worldedit.bukkit.adapter.Refraction; import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; @@ -513,29 +512,24 @@ public org.bukkit.entity.Entity createEntity(Location location, BaseEntity state Entity createdEntity = createEntityFromId(state.getType().id(), craftWorld.getHandle()); if (createdEntity != null) { - worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); + LinCompoundTag nativeTag = state.getNbt(); + if (nativeTag != null) { + net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) fromNativeLin(nativeTag); + for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { + tag.remove(name); + } + readTagIntoEntity(tag, createdEntity); + } + + createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); + + worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); return createdEntity.getBukkitEntity(); } else { return null; } } - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", LinTagId.LIST.id())) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", LinTagId.COMPOUND.id()); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - @Override public Component getRichBlockName(BlockType blockType) { return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); @@ -1161,9 +1155,7 @@ private static class MojangWatchdog implements Watchdog { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { this.server = server; - Field tickField = MinecraftServer.class.getDeclaredField( - Refraction.pickName("nextTickTime", "ag") - ); + Field tickField = MinecraftServer.class.getDeclaredField(StaticRefraction.NEXT_TICK_TIME); if (tickField.getType() != long.class) { throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 2944408b6c..7c17aa5d89 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -64,6 +64,7 @@ import net.minecraft.core.registries.Registries; import net.minecraft.nbt.NbtOps; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; @@ -518,11 +519,10 @@ public boolean canPlaceAt(World world, BlockVector3 blockVector3, BlockState blo public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); ItemStack stack = new ItemStack( - DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM) - .get(ResourceLocation.tryParse(baseItemStack.getType().id())), + registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())), baseItemStack.getAmount() ); - final net.minecraft.nbt.CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData()); + final net.minecraft.nbt.CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNativeLin(baseItemStack.getNbt()); if (nbt != null) { final DataComponentPatch patch = COMPONENTS_CODEC .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) @@ -557,7 +557,6 @@ protected ServerLevel getServerLevel(final World world) { @Override public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { - //FAWE start ServerLevel serverLevel = ((CraftWorld) world).getHandle(); ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); @@ -593,7 +592,6 @@ public boolean generateFeature(ConfiguredFeatureType feature, World world, EditS }); return placeFeatureIntoSession(editSession, populator, placed); - //FAWE end } @Override @@ -611,7 +609,6 @@ public boolean generateStructure(StructureType type, World world, EditSession ed ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); - //FAWE start FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); Map placed = TaskManager.taskManager().sync(() -> { serverLevel.captureTreeGeneration = true; @@ -671,7 +668,6 @@ public boolean generateStructure(StructureType type, World world, EditSession ed }); return placeFeatureIntoSession(editSession, populator, placed); - //FAWE end } private boolean placeFeatureIntoSession( diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java index e9a24a4463..6881ea4e24 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightPlatformAdapter.java @@ -43,7 +43,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.StateHolder; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.GlobalPalette; import net.minecraft.world.level.chunk.HashMapPalette; @@ -98,8 +97,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final Field fieldTickingBlockCount; private static final Field fieldBiomes; - private static final Field fieldPropertiesCodec; - private static final MethodHandle methodGetVisibleChunk; private static final Field fieldThreadingDetector; @@ -152,9 +149,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldBiomes = tmpFieldBiomes; fieldBiomes.setAccessible(true); - fieldPropertiesCodec = StateHolder.class.getDeclaredField(Refraction.pickName("propertiesCodec", "f")); - fieldPropertiesCodec.setAccessible(true); - Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName( "getVisibleChunkIfPresent", "b" diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java index d3497145c9..c44677ae5f 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightAdapter.java @@ -28,6 +28,7 @@ import com.google.common.util.concurrent.Futures; import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -61,6 +62,8 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.SharedConstants; import net.minecraft.Util; @@ -68,6 +71,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; @@ -82,6 +86,7 @@ import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.RandomSource; import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.world.Clearable; import net.minecraft.world.InteractionHand; @@ -94,6 +99,7 @@ import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelSettings; +import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; @@ -105,6 +111,10 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -178,6 +188,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter { - loadedEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - return loadedEntity; - }); + createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - if (createdEntity != null) { - worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); + worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); return createdEntity.getBukkitEntity(); } else { return null; } } - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", LinTagId.LIST.id())) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", LinTagId.COMPOUND.id()); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - @Override public Component getRichBlockName(BlockType blockType) { return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); @@ -884,6 +875,20 @@ public void initializeRegistries() { } } + // Features + for (ResourceLocation name: server.registryAccess().lookupOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().lookupOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + // BiomeCategories Registry biomeRegistry = server.registryAccess().lookupOrThrow(Registries.BIOME); biomeRegistry.getTags().forEach(tag -> { @@ -913,6 +918,39 @@ public void sendBiomeUpdates(World world, Iterable chunks) { originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); } + @Override + public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + ConfiguredFeature k = originalWorld.registryAccess().lookupOrThrow(Registries.CONFIGURED_FEATURE).getValue(ResourceLocation.tryParse(type.id())); + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + Structure k = originalWorld.registryAccess().lookupOrThrow(Registries.STRUCTURE).getValue(ResourceLocation.tryParse(type.id())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this); + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); + StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true); + + if (!structureStart.isValid()) { + return false; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos max = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk(proxyLevel, originalWorld.structureManager(), chunkManager.getGenerator(), originalWorld.getRandom(), new BoundingBox(chunkPosx.getMinBlockX(), originalWorld.getMinY(), chunkPosx.getMinBlockZ(), chunkPosx.getMaxBlockX(), originalWorld.getMaxY(), chunkPosx.getMaxBlockZ()), chunkPosx)); + return true; + } + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightServerLevelDelegateProxy.java index 4b660ccf34..6fd6085705 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_3/PaperweightServerLevelDelegateProxy.java @@ -19,83 +19,42 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_3; -import com.fastasyncworldedit.core.internal.exception.FaweException; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3.PaperweightFaweAdapter; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.world.block.BlockTypes; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; -import net.minecraft.world.entity.Entity; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.AABB; -import org.apache.logging.log4j.Logger; +import com.sk89q.worldedit.math.BlockVector3; +import net.minecraft.server.MinecraftServer; import org.jetbrains.annotations.Nullable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; public class PaperweightServerLevelDelegateProxy implements InvocationHandler { - private static final Logger LOGGER = LogManagerCompat.getLogger(); - - // FAWE start - extent not EditSession - private final Extent editSession; - //FAWE end + private final EditSession editSession; private final ServerLevel serverLevel; - //FAWE start - use FAWE adapter - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - //FAWE end - //FAWE start - force error if method not caught by this instance - private final boolean errorOnPassthrough; - //FAWE end + private final PaperweightAdapter adapter; private PaperweightServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { this.editSession = editSession; this.serverLevel = serverLevel; - //FAWE start - this.errorOnPassthrough = false; - //FAWE end + this.adapter = adapter; } public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter) - ); - } - - //FAWE start - force error if method not caught by this instance - private PaperweightServerLevelDelegateProxy(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - this.editSession = extent; - this.serverLevel = serverLevel; - this.errorOnPassthrough = errorOnPassthrough; - } - - public static WorldGenLevel newInstance(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(extent, serverLevel, errorOnPassthrough) + serverLevel.getClass().getClassLoader(), + serverLevel.getClass().getInterfaces(), + new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter) ); } - //FAWE end @Nullable private BlockEntity getBlockEntity(BlockPos blockPos) { @@ -105,24 +64,24 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { } BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); newEntity.loadWithComponents( - (CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock( + (CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at( blockPos.getX(), blockPos.getY(), blockPos.getZ() - ).getNbtReference().getValue()), - this.serverLevel.registryAccess() + )).getNbtReference().getValue()), + MinecraftServer.getServer().registryAccess() ); return newEntity; } private BlockState getBlockState(BlockPos blockPos) { - return adapter.adapt(this.editSession.getBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ())); + return adapter.adapt(this.editSession.getBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()))); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), adapter.adapt(blockState)); + return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), adapter.adapt(blockState)); } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); } @@ -130,109 +89,38 @@ private boolean setBlock(BlockPos blockPos, BlockState blockState) { private boolean removeBlock(BlockPos blockPos, boolean bl) { try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), BlockTypes.AIR.getDefaultState()); + return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), BlockTypes.AIR.getDefaultState()); } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); } } - private FluidState getFluidState(BlockPos pos) { - return getBlockState(pos).getFluidState(); - } - - private boolean isWaterAt(BlockPos pos) { - return getBlockState(pos).getFluidState().is(FluidTags.WATER); - } - @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - //FAWE start - cannot use switch where method names are equal - String methodName = method.getName(); - if (Refraction.pickName("getBlockState", "a_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockState - return getBlockState(blockPos); - } - } - if (Refraction.pickName("getBlockEntity", "c_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockEntity - return getBlockEntity(blockPos); - } - } - if ("a".equals(methodName) || "setBlock".equals(methodName) || "removeBlock".equals(methodName) || "destroyBlock".equals( - methodName)) { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { - // setBlock - return setBlock(blockPos, blockState); - } else if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { - // removeBlock (and also matches destroyBlock) - return removeBlock(blockPos, bl); + switch (method.getName()) { + case "a_", "getBlockState" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + // getBlockState + return getBlockState(blockPos); + } } - } - //FAWE start - if (Refraction.pickName("getFluidState", "b_").equals(methodName)) { //net.minecraft.world.level.BlockGetter - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getFluidState(blockPos); - } - } - if (Refraction.pickName("isWaterAt", "z").equals(methodName)) { //net.minecraft.world.level.LevelReader - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return isWaterAt(blockPos); - } - } - if (Refraction.pickName("getEntities", "a_").equals(methodName)) { //net.minecraft.world.level.EntityGetter - if (args.length == 2 && args[0] instanceof Entity && args[1] instanceof AABB) { - return new ArrayList<>(); - } - } - // Specific passthroughs that we want to allow - // net.minecraft.world.level.BlockAndTintGetter - if (Refraction.pickName("getRawBrightness", "b").equals(methodName)) { - return method.invoke(this.serverLevel, args); - } - // net.minecraft.world.level.LevelHeightAccessor - if (Refraction.pickName("getMaxBuildHeight", "al").equals(methodName)) { - if (args.length == 0) { - return method.invoke(this.serverLevel, args); + case "c_", "getBlockEntity" -> { + if (args.length == 1 && args[0] instanceof BlockPos blockPos) { + // getBlockEntity + return getBlockEntity(blockPos); + } } - } - // net.minecraft.world.level.SignalGetter - if (Refraction.pickName("hasNeighborSignal", "C").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getSignal", "c").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getControlInputSignal", "a").equals(methodName)) { - if (args.length == 3 && args[0] instanceof BlockPos && args[1] instanceof Direction && args[2] instanceof Boolean) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getDirectSignal", "a").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); + case "a", "setBlock", "removeBlock", "destroyBlock" -> { + if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { + // setBlock + return setBlock(blockPos, blockState); + } else if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { + // removeBlock (and also matches destroyBlock) + return removeBlock(blockPos, bl); + } } + default -> { } } - //FAWE start - force error if method not caught by this instance - if (errorOnPassthrough) { - LOGGER.error( - """ - Attempted passthough of method {}. - Method argument types: {} - Method argument values: {} - """, - method.getName(), - Arrays.stream(args).map(a -> a.getClass().getName()).toList(), - Arrays.stream(args).map(Object::toString).toList() - ); - throw new FaweException("Method required passthrough."); - } - //FAWE end return method.invoke(this.serverLevel, args); } diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/FaweBlockStateListPopulator.java new file mode 100644 index 0000000000..e8c212e03e --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/FaweBlockStateListPopulator.java @@ -0,0 +1,133 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_3; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import org.bukkit.craftbukkit.util.BlockStateListPopulator; + +import javax.annotation.Nullable; + +public class FaweBlockStateListPopulator extends BlockStateListPopulator { + + private final ServerLevel world; + + public FaweBlockStateListPopulator(ServerLevel world) { + super(world); + this.world = world; + } + + @Override + public long getSeed() { + return world.getSeed(); + } + + @Override + public ServerLevel getLevel() { + return world.getLevel(); + } + + @Override + public MinecraftServer getServer() { + return world.getServer(); + } + + @Override + public ChunkSource getChunkSource() { + return world.getChunkSource(); + } + + @Override + public ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus leastStatus, final boolean create) { + return world.getChunk(chunkX, chunkZ, leastStatus, create); + } + + @Override + public BiomeManager getBiomeManager() { + return world.getBiomeManager(); + } + + @Override + public Holder getUncachedNoiseBiome(final int biomeX, final int biomeY, final int biomeZ) { + return world.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public int getSeaLevel() { + return world.getSeaLevel(); + } + + @Override + public FeatureFlagSet enabledFeatures() { + return world.enabledFeatures(); + } + + @Override + public float getShade(final Direction direction, final boolean shaded) { + return world.getShade(direction, shaded); + } + + @Override + public LevelLightEngine getLightEngine() { + return world.getLightEngine(); + } + + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { + return world.getChunkIfLoadedImmediately(x, z); + } + + @Override + public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { + return world.getBlockStateIfLoaded(blockposition); + } + + @Override + public FluidState getFluidIfLoaded(final BlockPos blockposition) { + return world.getFluidIfLoaded(blockposition); + } + + @Override + public WorldBorder getWorldBorder() { + return world.getWorldBorder(); + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags, final int maxUpdateDepth) { + return world.setBlock(pos, state, flags, maxUpdateDepth); + } + + @Override + public boolean removeBlock(final BlockPos pos, final boolean move) { + return world.removeBlock(pos, move); + } + + @Override + public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity breakingEntity, final int maxUpdateDepth) { + return world.destroyBlock(pos, drop, breakingEntity, maxUpdateDepth); + } + + @Override + public BlockState getBlockState(final BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags) { + return world.setBlock(pos, state, flags); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java index 47aba48713..452bbfcfe4 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21_3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_3/PaperweightFaweAdapter.java @@ -11,12 +11,13 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.mojang.serialization.Codec; -import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; @@ -47,33 +48,44 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import io.papermc.lib.PaperLib; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; +import net.minecraft.core.SectionPos; import net.minecraft.core.WritableRegistry; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -82,6 +94,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; @@ -112,7 +125,7 @@ import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends FaweAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -165,12 +178,12 @@ private static String getEntityId(Entity entity) { return net.minecraft.world.entity.EntityType.getKey(entity.getType()).toString(); } - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + private static void readEntityIntoTag(Entity entity, CompoundTag compoundTag) { entity.save(compoundTag); } @Override - public BukkitImplAdapter getParent() { + public BukkitImplAdapter getParent() { return parent; } @@ -273,7 +286,7 @@ public BaseBlock getFullBlock(final Location location) { // Read the NBT data BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } } @@ -294,7 +307,7 @@ public Set getSupportedSideEffects() { } @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @@ -308,7 +321,7 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { String id = getEntityId(mcEntity); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); + final CompoundTag minecraftTag = new CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); @@ -439,7 +452,7 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt } @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + public void sendFakeChunk(World world, Player player, ChunkPacket chunkPacket) { ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { @@ -474,7 +487,7 @@ public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chu } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + public boolean canPlaceAt(World world, BlockVector3 blockVector3, BlockState blockState) { int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( @@ -492,7 +505,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { )), baseItemStack.getAmount() ); - final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNativeLin(baseItemStack.getNbt()); + final CompoundTag nbt = (CompoundTag) fromNativeLin(baseItemStack.getNbt()); if (nbt != null) { final DataComponentPatch patch = COMPONENTS_CODEC .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) @@ -525,11 +538,170 @@ protected ServerLevel getServerLevel(final World world) { return ((CraftWorld) world).getHandle(); } + @Override + public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); + + ConfiguredFeature configuredFeature = serverLevel + .registryAccess() + .lookupOrThrow(Registries.CONFIGURED_FEATURE) + .getValue(ResourceLocation.tryParse(feature.id())); + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + if (!configuredFeature.place( + populator, + generator, + serverLevel.random, + new BlockPos(pt.x(), pt.y(), pt.z()) + )) { + return null; + } + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + Structure k = serverLevel + .registryAccess() + .lookupOrThrow(Registries.STRUCTURE) + .getValue(ResourceLocation.tryParse(type.id())); + if (k == null) { + return false; + } + + ServerChunkCache chunkManager = serverLevel.getChunkSource(); + + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); + + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + StructureStart structureStart = k.generate( + serverLevel.registryAccess(), + chunkManager.getGenerator(), + chunkManager.getGenerator().getBiomeSource(), + chunkManager.randomState(), + serverLevel.getStructureManager(), + serverLevel.getSeed(), + chunkPos, + 0, + populator, + biome -> true + ); + if (!structureStart.isValid()) { + return null; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.minX()), + SectionPos.blockToSectionCoord(boundingBox.minZ()) + ); + ChunkPos max = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.maxX()), + SectionPos.blockToSectionCoord(boundingBox.maxZ()) + ); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( + populator, + serverLevel.structureManager(), + chunkManager.getGenerator(), + serverLevel.getRandom(), + new BoundingBox( + chunkPosx.getMinBlockX(), + serverLevel.getMinY(), + chunkPosx.getMinBlockZ(), + chunkPosx.getMaxBlockX(), + serverLevel.getMaxY(), + chunkPosx.getMaxBlockZ() + ), + chunkPosx + )); + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; + } + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + } + + private boolean placeFeatureIntoSession( + final EditSession editSession, + final FaweBlockStateListPopulator populator, + final Map placed + ) { + if (placed == null || placed.isEmpty()) { + return false; + } + + for (Map.Entry entry : placed.entrySet()) { + CraftBlockState craftBlockState = entry.getValue(); + if (entry.getValue() == null) { + continue; + } + BlockPos pos = entry.getKey(); + editSession.setBlock(pos.getX(), pos.getY(), pos.getZ(), BukkitAdapter.adapt(craftBlockState.getBlockData())); + BlockEntity blockEntity = populator.getBlockEntity(pos); + if (blockEntity != null) { + CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + editSession.setTile(pos.getX(), pos.getY(), pos.getZ(), (com.sk89q.jnbt.CompoundTag) toNative(tag)); + } + } + return true; + } + + @Override + public void setupFeatures() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Features + for (ResourceLocation name : server.registryAccess().lookupOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().lookupOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + } + @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart( + final Tag tag = COMPONENTS_CODEC.encodeStart( registryAccess.createSerializationContext(NbtOps.INSTANCE), nmsStack.getComponentsPatch() ).getOrThrow(); @@ -541,22 +713,22 @@ public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { } @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { + public com.sk89q.jnbt.Tag toNative(Tag foreign) { return parent.toNative(foreign); } @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { + public Tag fromNative(com.sk89q.jnbt.Tag foreign) { return parent.fromNative(foreign); } @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + public boolean regenerate(World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); } @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + public IChunkGet get(World world, int chunkX, int chunkZ) { return new PaperweightGetBlocks(world, chunkX, chunkZ); } From 03bb783d64e0e4fc5516badadb5418b6f282410a Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Thu, 26 Dec 2024 22:30:50 +0000 Subject: [PATCH 15/15] Add for 1.21.4 --- .../ext/fawe/v1_21_4/PaperweightAdapter.java | 126 ++++-- .../PaperweightServerLevelDelegateProxy.java | 358 ++++++++++-------- .../ext/fawe/v1_21_4/StaticRefraction.java | 6 + .../v1_21_4/FaweBlockStateListPopulator.java | 133 +++++++ .../fawe/v1_21_4/PaperweightFaweAdapter.java | 202 +++++++++- 5 files changed, 618 insertions(+), 207 deletions(-) create mode 100644 worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/FaweBlockStateListPopulator.java diff --git a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightAdapter.java index dcee6e1462..c8fc548511 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightAdapter.java @@ -28,6 +28,8 @@ import com.google.common.util.concurrent.Futures; import com.mojang.serialization.Codec; import com.mojang.serialization.Lifecycle; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItem; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -61,6 +63,8 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import net.minecraft.SharedConstants; import net.minecraft.Util; @@ -68,6 +72,7 @@ import net.minecraft.core.Holder; import net.minecraft.core.HolderSet; import net.minecraft.core.Registry; +import net.minecraft.core.SectionPos; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; @@ -82,6 +87,7 @@ import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.progress.ChunkProgressListener; +import net.minecraft.util.RandomSource; import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.world.Clearable; import net.minecraft.world.InteractionHand; @@ -105,6 +111,10 @@ import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.levelgen.WorldOptions; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.PrimaryLevelData; import net.minecraft.world.phys.BlockHitResult; @@ -178,6 +188,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter { - loadedEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - return loadedEntity; - }); + createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); - if (createdEntity != null) { - worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM); + worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM); return createdEntity.getBukkitEntity(); } else { return null; } } - // This removes all unwanted tags from the main entity and all its passengers - private void removeUnwantedEntityTagsRecursively(net.minecraft.nbt.CompoundTag tag) { - for (String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) { - tag.remove(name); - } - - // Adapted from net.minecraft.world.entity.EntityType#loadEntityRecursive - if (tag.contains("Passengers", LinTagId.LIST.id())) { - net.minecraft.nbt.ListTag nbttaglist = tag.getList("Passengers", LinTagId.COMPOUND.id()); - - for (int i = 0; i < nbttaglist.size(); ++i) { - removeUnwantedEntityTagsRecursively(nbttaglist.getCompound(i)); - } - } - } - @Override public Component getRichBlockName(BlockType blockType) { return TranslatableComponent.of(getBlockFromType(blockType).getDescriptionId()); @@ -877,6 +867,20 @@ public void initializeRegistries() { } } + // Features + for (ResourceLocation name: server.registryAccess().lookupOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().lookupOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + // BiomeCategories Registry biomeRegistry = server.registryAccess().lookupOrThrow(Registries.BIOME); biomeRegistry.getTags().forEach(tag -> { @@ -906,6 +910,60 @@ public void sendBiomeUpdates(World world, Iterable chunks) { originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks); } + public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + ConfiguredFeature feature = originalWorld.registryAccess().lookupOrThrow(Registries.CONFIGURED_FEATURE).getValue(ResourceLocation.tryParse(type.id())); + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + try (PaperweightServerLevelDelegateProxy.LevelAndProxy proxyLevel = + PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this)) { + return feature != null && feature.place(proxyLevel.level(), chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } + } + + public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { + ServerLevel originalWorld = ((CraftWorld) world).getHandle(); + Registry structureRegistry = originalWorld.registryAccess().lookupOrThrow(Registries.STRUCTURE); + Structure structure = structureRegistry.getValue(ResourceLocation.tryParse(type.id())); + if (structure == null) { + return false; + } + + ServerChunkCache chunkManager = originalWorld.getChunkSource(); + try (PaperweightServerLevelDelegateProxy.LevelAndProxy proxyLevel = + PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this)) { + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); + StructureStart structureStart = structure.generate( + structureRegistry.wrapAsHolder(structure), originalWorld.dimension(), originalWorld.registryAccess(), + chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), + originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, + proxyLevel.level(), biome -> true + ); + + if (!structureStart.isValid()) { + return false; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ())); + ChunkPos max = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ())); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> + structureStart.placeInChunk( + proxyLevel.level(), originalWorld.structureManager(), chunkManager.getGenerator(), + originalWorld.getRandom(), + new BoundingBox( + chunkPosx.getMinBlockX(), originalWorld.getMinY(), chunkPosx.getMinBlockZ(), + chunkPosx.getMaxBlockX(), originalWorld.getMaxY(), chunkPosx.getMaxBlockZ() + ), chunkPosx + ) + ); + return true; + } + } catch (MaxChangedBlocksException e) { + throw new RuntimeException(e); + } + } + // ------------------------------------------------------------------------ // Code that is less likely to break // ------------------------------------------------------------------------ diff --git a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightServerLevelDelegateProxy.java index 52dac65a09..0219b3dc8e 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/PaperweightServerLevelDelegateProxy.java @@ -19,221 +19,263 @@ package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_4; -import com.fastasyncworldedit.core.internal.exception.FaweException; +import com.google.common.collect.ImmutableTable; +import com.google.common.collect.Table; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.bukkit.WorldEditPlugin; -import com.sk89q.worldedit.bukkit.adapter.Refraction; -import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_4.PaperweightFaweAdapter; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.internal.util.LogManagerCompat; -import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.entity.BaseEntity; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.concurrency.LazyReference; +import com.sk89q.worldedit.world.entity.EntityTypes; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; +import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; -import net.minecraft.tags.FluidTags; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.EntityBlock; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.level.material.FluidState; -import net.minecraft.world.phys.AABB; -import org.apache.logging.log4j.Logger; +import net.minecraft.world.phys.Vec3; +import org.bukkit.event.entity.CreatureSpawnEvent; +import org.enginehub.linbus.tree.LinCompoundTag; import org.jetbrains.annotations.Nullable; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; -import java.util.ArrayList; -import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; -public class PaperweightServerLevelDelegateProxy implements InvocationHandler { +public class PaperweightServerLevelDelegateProxy implements InvocationHandler, AutoCloseable { - private static final Logger LOGGER = LogManagerCompat.getLogger(); + private static BlockVector3 adapt(BlockPos blockPos) { + return BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()); + } - // FAWE start - extent not EditSession - private final Extent editSession; - //FAWE end + private final EditSession editSession; private final ServerLevel serverLevel; - //FAWE start - use FAWE adapter - private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin - .getInstance() - .getBukkitImplAdapter()); - //FAWE end - //FAWE start - force error if method not caught by this instance - private final boolean errorOnPassthrough; - //FAWE end + private final PaperweightAdapter adapter; + private final Map createdBlockEntities = new HashMap<>(); private PaperweightServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { this.editSession = editSession; this.serverLevel = serverLevel; - //FAWE start - this.errorOnPassthrough = false; - //FAWE end + this.adapter = adapter; } - public static WorldGenLevel newInstance(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { - return (WorldGenLevel) Proxy.newProxyInstance( - serverLevel.getClass().getClassLoader(), - serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter) - ); - } - - //FAWE start - force error if method not caught by this instance - private PaperweightServerLevelDelegateProxy(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - this.editSession = extent; - this.serverLevel = serverLevel; - this.errorOnPassthrough = errorOnPassthrough; + public record LevelAndProxy(WorldGenLevel level, PaperweightServerLevelDelegateProxy proxy) implements AutoCloseable { + @Override + public void close() throws MaxChangedBlocksException { + proxy.close(); + } } - public static WorldGenLevel newInstance(Extent extent, ServerLevel serverLevel, boolean errorOnPassthrough) { - return (WorldGenLevel) Proxy.newProxyInstance( + public static LevelAndProxy newInstance(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) { + PaperweightServerLevelDelegateProxy proxy = new PaperweightServerLevelDelegateProxy(editSession, serverLevel, adapter); + return new LevelAndProxy( + (WorldGenLevel) Proxy.newProxyInstance( serverLevel.getClass().getClassLoader(), serverLevel.getClass().getInterfaces(), - new PaperweightServerLevelDelegateProxy(extent, serverLevel, errorOnPassthrough) + proxy + ), + proxy ); } - //FAWE end @Nullable private BlockEntity getBlockEntity(BlockPos blockPos) { - BlockEntity tileEntity = this.serverLevel.getChunkAt(blockPos).getBlockEntity(blockPos); - if (tileEntity == null) { - return null; - } - BlockEntity newEntity = tileEntity.getType().create(blockPos, getBlockState(blockPos)); - newEntity.loadWithComponents( - (CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock( - blockPos.getX(), - blockPos.getY(), - blockPos.getZ() - ).getNbtReference().getValue()), - this.serverLevel.registryAccess() - ); - - return newEntity; + // This doesn't synthesize or load from world. I think editing existing block entities without setting the block + // (in the context of features) should not be supported in the first place. + BlockVector3 pos = adapt(blockPos); + return createdBlockEntities.get(pos); } private BlockState getBlockState(BlockPos blockPos) { - return adapter.adapt(this.editSession.getBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ())); + return adapter.adapt(this.editSession.getBlock(adapt(blockPos))); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), adapter.adapt(blockState)); + handleBlockEntity(blockPos, blockState); + return editSession.setBlock(adapt(blockPos), adapter.adapt(blockState)); } catch (MaxChangedBlocksException e) { throw new RuntimeException(e); } } - private boolean removeBlock(BlockPos blockPos, boolean bl) { - try { - return editSession.setBlock(blockPos.getX(), blockPos.getY(), blockPos.getZ(), BlockTypes.AIR.getDefaultState()); - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); + // For BlockEntity#setBlockState, not sure why it's deprecated + @SuppressWarnings("deprecation") + private void handleBlockEntity(BlockPos blockPos, BlockState blockState) { + BlockVector3 pos = adapt(blockPos); + if (blockState.hasBlockEntity()) { + if (!(blockState.getBlock() instanceof EntityBlock entityBlock)) { + // This will probably never happen, as Mojang's own code assumes that + // hasBlockEntity implies instanceof EntityBlock, but just to be safe... + throw new AssertionError("BlockState has block entity but block is not an EntityBlock: " + blockState); + } + BlockEntity newEntity = entityBlock.newBlockEntity(blockPos, blockState); + if (newEntity != null) { + newEntity.setBlockState(blockState); + createdBlockEntities.put(pos, newEntity); + // Should we load existing NBT here? This is for feature / structure gen so it seems unnecessary. + // But it would align with the behavior of the real setBlock method. + return; + } } + // Discard any block entity that was previously created if new block is set without block entity + createdBlockEntities.remove(pos); } - private FluidState getFluidState(BlockPos pos) { - return getBlockState(pos).getFluidState(); + private boolean removeBlock(BlockPos blockPos, boolean bl) { + return setBlock(blockPos, Blocks.AIR.defaultBlockState()); } - private boolean isWaterAt(BlockPos pos) { - return getBlockState(pos).getFluidState().is(FluidTags.WATER); + private boolean addEntity(Entity entity) { + Vec3 pos = entity.getPosition(0.0f); + Location location = new Location(BukkitAdapter.adapt(serverLevel.getWorld()), pos.x(), pos.y(), pos.z()); + + ResourceLocation id = serverLevel.registryAccess().lookupOrThrow(Registries.ENTITY_TYPE).getKey(entity.getType()); + CompoundTag tag = new CompoundTag(); + entity.saveWithoutId(tag); + BaseEntity baseEntity = new BaseEntity(EntityTypes.get(id.toString()), + LazyReference.from(() -> (LinCompoundTag) adapter.toNativeLin(tag))); + + return editSession.createEntity(location, baseEntity) != null; } @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { - //FAWE start - cannot use switch where method names are equal - String methodName = method.getName(); - if (Refraction.pickName("getBlockState", "a_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockState - return getBlockState(blockPos); - } - } - if (Refraction.pickName("getBlockEntity", "c_").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - // getBlockEntity - return getBlockEntity(blockPos); - } - } - if ("a".equals(methodName) || "setBlock".equals(methodName) || "removeBlock".equals(methodName) || "destroyBlock".equals( - methodName)) { - if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof BlockState blockState) { - // setBlock - return setBlock(blockPos, blockState); - } else if (args.length >= 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Boolean bl) { - // removeBlock (and also matches destroyBlock) - return removeBlock(blockPos, bl); - } - } - //FAWE start - if (Refraction.pickName("getFluidState", "b_").equals(methodName)) { //net.minecraft.world.level.BlockGetter - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return getFluidState(blockPos); - } - } - if (Refraction.pickName("isWaterAt", "z").equals(methodName)) { //net.minecraft.world.level.LevelReader - if (args.length == 1 && args[0] instanceof BlockPos blockPos) { - return isWaterAt(blockPos); - } - } - if (Refraction.pickName("getEntities", "a_").equals(methodName)) { //net.minecraft.world.level.EntityGetter - if (args.length == 2 && args[0] instanceof Entity && args[1] instanceof AABB) { - return new ArrayList<>(); - } - } - // Specific passthroughs that we want to allow - // net.minecraft.world.level.BlockAndTintGetter - if (Refraction.pickName("getRawBrightness", "b").equals(methodName)) { - return method.invoke(this.serverLevel, args); - } - // net.minecraft.world.level.LevelHeightAccessor - if (Refraction.pickName("getMaxBuildHeight", "al").equals(methodName)) { - if (args.length == 0) { - return method.invoke(this.serverLevel, args); - } - } - // net.minecraft.world.level.SignalGetter - if (Refraction.pickName("hasNeighborSignal", "C").equals(methodName)) { - if (args.length == 1 && args[0] instanceof BlockPos) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getSignal", "c").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getControlInputSignal", "a").equals(methodName)) { - if (args.length == 3 && args[0] instanceof BlockPos && args[1] instanceof Direction && args[2] instanceof Boolean) { - return method.invoke(this.serverLevel, args); - } - } - if (Refraction.pickName("getDirectSignal", "a").equals(methodName)) { - if (args.length == 2 && args[0] instanceof BlockPos && args[1] instanceof Direction) { - return method.invoke(this.serverLevel, args); - } + public void close() throws MaxChangedBlocksException { + for (Map.Entry entry : createdBlockEntities.entrySet()) { + BlockVector3 blockPos = entry.getKey(); + BlockEntity blockEntity = entry.getValue(); + net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(serverLevel.registryAccess()); + editSession.setBlock( + blockPos, + adapter.adapt(blockEntity.getBlockState()) + .toBaseBlock(LazyReference.from(() -> (LinCompoundTag) adapter.toNativeLin(tag))) + ); } - //FAWE start - force error if method not caught by this instance - if (errorOnPassthrough) { - LOGGER.error( - """ - Attempted passthough of method {}. - Method argument types: {} - Method argument values: {} - """, - method.getName(), - Arrays.stream(args).map(a -> a.getClass().getName()).toList(), - Arrays.stream(args).map(Object::toString).toList() + } + + private static void addMethodHandleToTable( + ImmutableTable.Builder table, + String methodName, + MethodHandle methodHandle + ) { + // We want to call these with Object[] args, not plain args + // We skip the first argument, which is our receiver + MethodHandle spreader = methodHandle.asSpreader( + 1, Object[].class, methodHandle.type().parameterCount() - 1 + ); + // We drop the first argument, which is our receiver + // We also drop the return type, which is not important + table.put(methodName, methodHandle.type().dropParameterTypes(0, 1).changeReturnType(void.class), spreader); + } + + private static final Table METHOD_MAP; + + static { + var lookup = MethodHandles.lookup(); + var builder = ImmutableTable.builder(); + try { + addMethodHandleToTable( + builder, + StaticRefraction.GET_BLOCK_STATE, + lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("getBlockState", BlockPos.class)) + ); + + MethodHandle addEntity = lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("addEntity", Entity.class)); + addMethodHandleToTable( + builder, + StaticRefraction.ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY, + addEntity + ); + addMethodHandleToTable( + builder, + StaticRefraction.ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY_SPAWN_REASON, + // 0 - this, 1 - entity, 2 - reason + MethodHandles.dropArguments(addEntity, 2, CreatureSpawnEvent.SpawnReason.class) ); - throw new FaweException("Method required passthrough."); + addMethodHandleToTable( + builder, + StaticRefraction.ADD_FRESH_ENTITY, + addEntity + ); + addMethodHandleToTable( + builder, + StaticRefraction.ADD_FRESH_ENTITY_SPAWN_REASON, + // 0 - this, 1 - entity, 2 - reason + MethodHandles.dropArguments(addEntity, 2, CreatureSpawnEvent.SpawnReason.class) + ); + + addMethodHandleToTable( + builder, + StaticRefraction.GET_BLOCK_ENTITY, + lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("getBlockEntity", BlockPos.class)) + ); + + MethodHandle setBlock = lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("setBlock", BlockPos.class, BlockState.class)); + addMethodHandleToTable( + builder, + StaticRefraction.SET_BLOCK, + // 0 - this, 1 - blockPos, 2 - blockState, 3 - flags + MethodHandles.dropArguments(setBlock, 3, int.class) + ); + addMethodHandleToTable( + builder, + StaticRefraction.SET_BLOCK_MAX_UPDATE, + // 0 - this, 1 - blockPos, 2 - blockState, 3 - flags, 4 - maxUpdateDepth + MethodHandles.dropArguments(setBlock, 3, int.class, int.class) + ); + + MethodHandle removeBlock = lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("removeBlock", BlockPos.class)); + addMethodHandleToTable( + builder, + StaticRefraction.REMOVE_BLOCK, + // 0 - this, 1 - blockPos, 2 - move + MethodHandles.dropArguments(removeBlock, 2, boolean.class) + ); + addMethodHandleToTable( + builder, + StaticRefraction.DESTROY_BLOCK, + // 0 - this, 1 - blockPos, 2 - drop + MethodHandles.dropArguments(removeBlock, 2, boolean.class) + ); + addMethodHandleToTable( + builder, + StaticRefraction.DESTROY_BLOCK_BREAKING_ENTITY, + // 0 - this, 1 - blockPos, 2 - drop, 3 - breakingEntity + MethodHandles.dropArguments(removeBlock, 2, boolean.class, Entity.class) + ); + addMethodHandleToTable( + builder, + StaticRefraction.DESTROY_BLOCK_BREAKING_ENTITY_MAX_UPDATE, + // 0 - this, 1 - blockPos, 2 - drop, 3 - breakingEntity, 4 - maxUpdateDepth + MethodHandles.dropArguments(removeBlock, 2, boolean.class, Entity.class, int.class) + ); + } catch (IllegalAccessException | NoSuchMethodException e) { + throw new RuntimeException("Failed to bind to own methods", e); } - //FAWE end + METHOD_MAP = builder.build(); + } + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + MethodHandle delegate = METHOD_MAP.get( + // ignore return type, we only need the parameter types + method.getName(), MethodType.methodType(void.class, method.getParameterTypes()) + ); + if (delegate != null) { + return delegate.invoke(this, args); + } return method.invoke(this.serverLevel, args); } diff --git a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/StaticRefraction.java b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/StaticRefraction.java index a44766f44e..e3e01cbe06 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/StaticRefraction.java +++ b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_4/StaticRefraction.java @@ -52,6 +52,12 @@ public final class StaticRefraction { * {@code addFreshEntity(Entity entity)}. */ public static final String ADD_FRESH_ENTITY = Refraction.pickName("addFreshEntity", "b"); + /** + * {@code addFreshEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason)}. + */ + public static final String ADD_FRESH_ENTITY_SPAWN_REASON = Refraction.pickName( + "addFreshEntity", "b" + ); /** * {@code getBlockEntity(BlockPos blockPos)}. */ diff --git a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/FaweBlockStateListPopulator.java b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/FaweBlockStateListPopulator.java new file mode 100644 index 0000000000..f4a896a0c4 --- /dev/null +++ b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/FaweBlockStateListPopulator.java @@ -0,0 +1,133 @@ +package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_4; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.flag.FeatureFlagSet; +import net.minecraft.world.level.biome.Biome; +import net.minecraft.world.level.biome.BiomeManager; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.border.WorldBorder; +import net.minecraft.world.level.chunk.ChunkAccess; +import net.minecraft.world.level.chunk.ChunkSource; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.level.lighting.LevelLightEngine; +import net.minecraft.world.level.material.FluidState; +import org.bukkit.craftbukkit.util.BlockStateListPopulator; + +import javax.annotation.Nullable; + +public class FaweBlockStateListPopulator extends BlockStateListPopulator { + + private final ServerLevel world; + + public FaweBlockStateListPopulator(ServerLevel world) { + super(world); + this.world = world; + } + + @Override + public long getSeed() { + return world.getSeed(); + } + + @Override + public ServerLevel getLevel() { + return world.getLevel(); + } + + @Override + public MinecraftServer getServer() { + return world.getServer(); + } + + @Override + public ChunkSource getChunkSource() { + return world.getChunkSource(); + } + + @Override + public ChunkAccess getChunk(final int chunkX, final int chunkZ, final ChunkStatus leastStatus, final boolean create) { + return world.getChunk(chunkX, chunkZ, leastStatus, create); + } + + @Override + public BiomeManager getBiomeManager() { + return world.getBiomeManager(); + } + + @Override + public Holder getUncachedNoiseBiome(final int biomeX, final int biomeY, final int biomeZ) { + return world.getUncachedNoiseBiome(biomeX, biomeY, biomeZ); + } + + @Override + public int getSeaLevel() { + return world.getSeaLevel(); + } + + @Override + public FeatureFlagSet enabledFeatures() { + return world.enabledFeatures(); + } + + @Override + public float getShade(final Direction direction, final boolean shaded) { + return world.getShade(direction, shaded); + } + + @Override + public LevelLightEngine getLightEngine() { + return world.getLightEngine(); + } + + @Nullable + @Override + public ChunkAccess getChunkIfLoadedImmediately(final int x, final int z) { + return world.getChunkIfLoadedImmediately(x, z); + } + + @Override + public BlockState getBlockStateIfLoaded(final BlockPos blockposition) { + return world.getBlockStateIfLoaded(blockposition); + } + + @Override + public FluidState getFluidIfLoaded(final BlockPos blockposition) { + return world.getFluidIfLoaded(blockposition); + } + + @Override + public WorldBorder getWorldBorder() { + return world.getWorldBorder(); + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags, final int maxUpdateDepth) { + return world.setBlock(pos, state, flags, maxUpdateDepth); + } + + @Override + public boolean removeBlock(final BlockPos pos, final boolean move) { + return world.removeBlock(pos, move); + } + + @Override + public boolean destroyBlock(final BlockPos pos, final boolean drop, final Entity breakingEntity, final int maxUpdateDepth) { + return world.destroyBlock(pos, drop, breakingEntity, maxUpdateDepth); + } + + @Override + public BlockState getBlockState(final BlockPos pos) { + return world.getBlockState(pos); + } + + @Override + public boolean setBlock(final BlockPos pos, final BlockState state, final int flags) { + return world.setBlock(pos, state, flags); + } + +} diff --git a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/PaperweightFaweAdapter.java index b0ec904cd3..94df9432a5 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_4/PaperweightFaweAdapter.java @@ -11,12 +11,13 @@ import com.fastasyncworldedit.core.queue.IChunkGet; import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket; import com.fastasyncworldedit.core.util.NbtUtils; +import com.fastasyncworldedit.core.util.TaskManager; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Sets; import com.mojang.serialization.Codec; -import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; @@ -47,33 +48,44 @@ import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypesCache; import com.sk89q.worldedit.world.entity.EntityType; +import com.sk89q.worldedit.world.generation.ConfiguredFeatureType; +import com.sk89q.worldedit.world.generation.StructureType; import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.registry.BlockMaterial; import io.papermc.lib.PaperLib; import net.minecraft.core.BlockPos; import net.minecraft.core.Registry; import net.minecraft.core.RegistryAccess; +import net.minecraft.core.SectionPos; import net.minecraft.core.WritableRegistry; import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.level.ChunkHolder; +import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.StringRepresentable; import net.minecraft.world.entity.Entity; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.levelgen.feature.ConfiguredFeature; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.level.levelgen.structure.Structure; +import net.minecraft.world.level.levelgen.structure.StructureStart; import org.apache.logging.log4j.Logger; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -82,6 +94,7 @@ import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftPlayer; @@ -112,7 +125,7 @@ import static net.minecraft.core.registries.Registries.BIOME; -public final class PaperweightFaweAdapter extends FaweAdapter { +public final class PaperweightFaweAdapter extends FaweAdapter { private static final Logger LOGGER = LogManagerCompat.getLogger(); private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE; @@ -165,12 +178,12 @@ private static String getEntityId(Entity entity) { return net.minecraft.world.entity.EntityType.getKey(entity.getType()).toString(); } - private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) { + private static void readEntityIntoTag(Entity entity, CompoundTag compoundTag) { entity.save(compoundTag); } @Override - public BukkitImplAdapter getParent() { + public BukkitImplAdapter getParent() { return parent; } @@ -273,7 +286,7 @@ public BaseBlock getFullBlock(final Location location) { // Read the NBT data BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK); if (blockEntity != null) { - net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); return state.toBaseBlock((LinCompoundTag) toNativeLin(tag)); } } @@ -294,7 +307,7 @@ public Set getSupportedSideEffects() { } @Override - public WorldNativeAccess createWorldNativeAccess(org.bukkit.World world) { + public WorldNativeAccess createWorldNativeAccess(World world) { return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world))); } @@ -308,7 +321,7 @@ public BaseEntity getEntity(org.bukkit.entity.Entity entity) { String id = getEntityId(mcEntity); EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id); Supplier saveTag = () -> { - final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag(); + final CompoundTag minecraftTag = new CompoundTag(); readEntityIntoTag(mcEntity, minecraftTag); //add Id for AbstractChangeSet to work final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag); @@ -439,7 +452,7 @@ public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockSt } @Override - public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) { + public void sendFakeChunk(World world, Player player, ChunkPacket chunkPacket) { ServerLevel nmsWorld = getServerLevel(world); ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ()); if (map != null && wasAccessibleSinceLastSave(map)) { @@ -474,7 +487,7 @@ public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chu } @Override - public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) { + public boolean canPlaceAt(World world, BlockVector3 blockVector3, BlockState blockState) { int internalId = BlockStateIdAccess.getBlockStateId(blockState); net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId); return blockState1.hasPostProcess( @@ -492,7 +505,7 @@ public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) { )), baseItemStack.getAmount() ); - final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNativeLin(baseItemStack.getNbt()); + final CompoundTag nbt = (CompoundTag) fromNativeLin(baseItemStack.getNbt()); if (nbt != null) { final DataComponentPatch patch = COMPONENTS_CODEC .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) @@ -525,11 +538,170 @@ protected ServerLevel getServerLevel(final World world) { return ((CraftWorld) world).getHandle(); } + @Override + public boolean generateFeature(ConfiguredFeatureType feature, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator(); + + ConfiguredFeature configuredFeature = serverLevel + .registryAccess() + .lookupOrThrow(Registries.CONFIGURED_FEATURE) + .getValue(ResourceLocation.tryParse(feature.id())); + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + if (!configuredFeature.place( + populator, + generator, + serverLevel.random, + new BlockPos(pt.x(), pt.y(), pt.z()) + )) { + return null; + } + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + } + + @Override + public boolean generateStructure(StructureType type, World world, EditSession editSession, BlockVector3 pt) { + ServerLevel serverLevel = ((CraftWorld) world).getHandle(); + Registry structureRegistry = serverLevel.registryAccess().lookupOrThrow(Registries.STRUCTURE); + Structure structure = structureRegistry.getValue(ResourceLocation.tryParse(type.id())); + if (structure == null) { + return false; + } + + ServerChunkCache chunkManager = serverLevel.getChunkSource(); + + ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.x(), pt.y(), pt.z())); + + FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel); + Map placed = TaskManager.taskManager().sync(() -> { + serverLevel.captureTreeGeneration = true; + serverLevel.captureBlockStates = true; + try { + StructureStart structureStart = structure.generate( + structureRegistry.wrapAsHolder(structure), + serverLevel.dimension(), + serverLevel.registryAccess(), + chunkManager.getGenerator(), + chunkManager.getGenerator().getBiomeSource(), + chunkManager.randomState(), + serverLevel.getStructureManager(), + serverLevel.getSeed(), + chunkPos, + 0, + populator, + biome -> true + ); + if (!structureStart.isValid()) { + return null; + } else { + BoundingBox boundingBox = structureStart.getBoundingBox(); + ChunkPos min = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.minX()), + SectionPos.blockToSectionCoord(boundingBox.minZ()) + ); + ChunkPos max = new ChunkPos( + SectionPos.blockToSectionCoord(boundingBox.maxX()), + SectionPos.blockToSectionCoord(boundingBox.maxZ()) + ); + ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk( + populator, + serverLevel.structureManager(), + chunkManager.getGenerator(), + serverLevel.getRandom(), + new BoundingBox( + chunkPosx.getMinBlockX(), + serverLevel.getMinY(), + chunkPosx.getMinBlockZ(), + chunkPosx.getMaxBlockX(), + serverLevel.getMaxY(), + chunkPosx.getMaxBlockZ() + ), + chunkPosx + )); + Map placedBlocks = populator.getList().stream().collect(Collectors.toMap( + CraftBlockState::getPosition, + craftBlockState -> craftBlockState + )); + placedBlocks.putAll(serverLevel.capturedBlockStates); + return placedBlocks; + } + } finally { + serverLevel.captureBlockStates = false; + serverLevel.captureTreeGeneration = false; + serverLevel.capturedBlockStates.clear(); + } + }); + + return placeFeatureIntoSession(editSession, populator, placed); + } + + private boolean placeFeatureIntoSession( + final EditSession editSession, + final FaweBlockStateListPopulator populator, + final Map placed + ) { + if (placed == null || placed.isEmpty()) { + return false; + } + + for (Map.Entry entry : placed.entrySet()) { + CraftBlockState craftBlockState = entry.getValue(); + if (entry.getValue() == null) { + continue; + } + BlockPos pos = entry.getKey(); + editSession.setBlock(pos.getX(), pos.getY(), pos.getZ(), BukkitAdapter.adapt(craftBlockState.getBlockData())); + BlockEntity blockEntity = populator.getBlockEntity(pos); + if (blockEntity != null) { + CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()); + editSession.setTile(pos.getX(), pos.getY(), pos.getZ(), (com.sk89q.jnbt.CompoundTag) toNative(tag)); + } + } + return true; + } + + @Override + public void setupFeatures() { + DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); + + // Features + for (ResourceLocation name : server.registryAccess().lookupOrThrow(Registries.CONFIGURED_FEATURE).keySet()) { + if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) { + ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString())); + } + } + + // Structures + for (ResourceLocation name : server.registryAccess().lookupOrThrow(Registries.STRUCTURE).keySet()) { + if (StructureType.REGISTRY.get(name.toString()) == null) { + StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); + } + } + } + @Override public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack); - final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart( + final Tag tag = COMPONENTS_CODEC.encodeStart( registryAccess.createSerializationContext(NbtOps.INSTANCE), nmsStack.getComponentsPatch() ).getOrThrow(); @@ -541,22 +713,22 @@ public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { } @Override - public Tag toNative(net.minecraft.nbt.Tag foreign) { + public com.sk89q.jnbt.Tag toNative(Tag foreign) { return parent.toNative(foreign); } @Override - public net.minecraft.nbt.Tag fromNative(Tag foreign) { + public Tag fromNative(com.sk89q.jnbt.Tag foreign) { return parent.fromNative(foreign); } @Override - public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { + public boolean regenerate(World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception { return new PaperweightRegen(bukkitWorld, region, target, options).regenerate(); } @Override - public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) { + public IChunkGet get(World world, int chunkX, int chunkZ) { return new PaperweightGetBlocks(world, chunkX, chunkZ); }