3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-11-05 19:10:07 +01:00

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
Dieser Commit ist enthalten in:
Maddy Miller 2023-03-10 21:39:24 +10:00 committet von dordsor21
Ursprung b4635e85c9
Commit 17d7850cf3
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 1E53E88969FFCF0B
14 geänderte Dateien mit 596 neuen und 1 gelöschten Zeilen

Datei anzeigen

@ -29,6 +29,7 @@ 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;
import com.sk89q.worldedit.blocks.BaseItemStack;
@ -65,6 +66,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.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.ItemStack;
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.ChunkStatus;
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 final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
@ -920,6 +930,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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
// ------------------------------------------------------------------------

Datei anzeigen

@ -0,0 +1,121 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.MaxChangedBlocksException;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.block.BlockTypes;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
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;
public class PaperweightServerLevelDelegateProxy implements InvocationHandler {
private final EditSession editSession;
private final ServerLevel serverLevel;
private final PaperweightAdapter adapter;
private PaperweightServerLevelDelegateProxy(EditSession editSession, ServerLevel serverLevel, PaperweightAdapter adapter) {
this.editSession = editSession;
this.serverLevel = serverLevel;
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)
);
}
@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((CompoundTag) adapter.fromNativeLin(this.editSession.getFullBlock(BlockVector3.at(blockPos.getX(),
blockPos.getY(), blockPos.getZ())).getNbtReference().getValue()));
return newEntity;
}
private BlockState getBlockState(BlockPos blockPos) {
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(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), adapter.adapt(blockState));
} catch (MaxChangedBlocksException e) {
throw new RuntimeException(e);
}
}
private boolean removeBlock(BlockPos blockPos, boolean bl) {
try {
return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), 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 "a_", "getBlockState" -> {
if (args.length == 1 && args[0] instanceof BlockPos blockPos) {
// getBlockState
return getBlockState(blockPos);
}
}
case "c_", "getBlockEntity" -> {
if (args.length == 1 && args[0] instanceof BlockPos blockPos) {
// getBlockEntity
return getBlockEntity(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 -> { }
}
return method.invoke(this.serverLevel, args);
}
}

Datei anzeigen

@ -54,6 +54,7 @@ import com.sk89q.worldedit.world.biome.BiomeType;
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 class BukkitWorld extends AbstractWorld {
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

Datei anzeigen

@ -29,6 +29,7 @@ import com.fastasyncworldedit.core.queue.IChunkGet;
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;
@ -48,6 +49,7 @@ import com.sk89q.worldedit.world.biome.BiomeType;
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;
@ -319,6 +321,20 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
* @param chunks a list of chunk coordinates to send biome updates for
*/
default void sendBiomeUpdates(World world, Iterable<BlockVector2> 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

Datei anzeigen

@ -66,6 +66,7 @@ import com.sk89q.worldedit.LocalSession;
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.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 org.enginehub.piston.annotation.Command;
import org.enginehub.piston.annotation.CommandContainer;
import org.enginehub.piston.annotation.param.Arg;
@ -1556,6 +1558,24 @@ public class BrushCommands {
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 {

Datei anzeigen

@ -57,6 +57,7 @@ import com.sk89q.worldedit.util.TreeGenerator.TreeType;
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 class GenerationCommands {
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"

Datei anzeigen

@ -32,6 +32,7 @@ import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.fluid.FluidCategory;
import com.sk89q.worldedit.world.fluid.FluidType;
import com.sk89q.worldedit.world.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 final class RegistryConverter<V extends Keyed> implements ArgumentConvert
FluidType.class,
FluidCategory.class,
GameMode.class,
WeatherType.class
WeatherType.class,
ConfiguredFeatureType.class
)
.stream()
.map(c -> (Class<Keyed>) c)

Datei anzeigen

@ -0,0 +1,44 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <https://www.gnu.org/licenses/>.
*/
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<FeatureGenerator> {
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;
}
}

Datei anzeigen

@ -0,0 +1,52 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <https://www.gnu.org/licenses/>.
*/
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);
}
}

Datei anzeigen

@ -46,6 +46,7 @@ import com.sk89q.worldedit.world.biome.BiomeType;
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 @@ public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
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.
*

Datei anzeigen

@ -0,0 +1,43 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <https://www.gnu.org/licenses/>.
*/
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<ConfiguredFeatureType> 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;
}
}

Datei anzeigen

@ -514,6 +514,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.",

Datei anzeigen

@ -0,0 +1,117 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <https://www.gnu.org/licenses/>.
*/
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);
}
}

Datei anzeigen

@ -0,0 +1,117 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* 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 <https://www.gnu.org/licenses/>.
*/
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);
}
}