Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,13 @@
"changes": [
"METHOD_NEW_DEFAULT"
]
},
{
"type": "com.sk89q.worldedit.world.World",
"member": "Method com.sk89q.worldedit.world.World.generateFeature(com.sk89q.worldedit.world.generation.ConfiguredFeatureType,com.sk89q.worldedit.EditSession,com.sk89q.worldedit.math.BlockVector3)",
"changes": [
"METHOD_NEW_DEFAULT"
]
}
],
"LazyReference was never publicly extensible": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either;
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;
Expand Down Expand Up @@ -63,6 +64,7 @@
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.item.ItemType;
import net.minecraft.Util;
import net.minecraft.core.BlockPos;
Expand Down Expand Up @@ -92,6 +94,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.StringRepresentable;
import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.Clearable;
Expand All @@ -104,6 +107,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;
Expand All @@ -116,6 +120,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;
Expand Down Expand Up @@ -188,6 +193,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter {
private final Field chunkProviderExecutorField;
private final Watchdog watchdog;

private static final RandomSource random = RandomSource.create();

// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
Expand Down Expand Up @@ -320,6 +327,21 @@ public OptionalInt getInternalBlockStateId(BlockState state) {
return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId);
}

public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) {
int internalId = Block.getId(blockState);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
state = BukkitAdapter.adapt(CraftBlockData.createData(blockState));
}

return state;
}

public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
return Block.stateById(internalId);
}

@Override
public BlockState getBlock(Location location) {
checkNotNull(location);
Expand All @@ -333,14 +355,7 @@ public BlockState getBlock(Location location) {
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
int internalId = Block.getId(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}

return state;
return adapt(blockData);
}

@Override
Expand Down Expand Up @@ -873,6 +888,21 @@ 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()));
}
}
}

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()));
}

// ------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* 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.impl.v1_19_R2;

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.fromNative(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()) {
Comment thread
octylFractal marked this conversation as resolved.
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)
Comment thread
me4502 marked this conversation as resolved.
return removeBlock(blockPos, bl);
}
}
default -> { }
}

return method.invoke(this.serverLevel, args);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,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.generation.ConfiguredFeatureType;
import com.sk89q.worldedit.world.weather.WeatherType;
import com.sk89q.worldedit.world.weather.WeatherTypes;
import io.papermc.lib.PaperLib;
Expand Down Expand Up @@ -435,6 +436,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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

package com.sk89q.worldedit.bukkit.adapter;

import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItem;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.entity.BaseEntity;
Expand All @@ -36,6 +37,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 org.bukkit.Location;
import org.bukkit.World;
Expand Down Expand Up @@ -254,6 +256,7 @@ default boolean clearContainerBlockContents(World world, BlockVector3 pt) {
}

/**
<<<<<<< HEAD
* Checks if this adapter supports custom biomes.
* @return if custom biomes are supported
*/
Expand All @@ -279,6 +282,19 @@ default BiomeType getBiome(Location location) {
throw new UnsupportedOperationException("This adapter does not support custom biomes.");
}

/**
* 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.");
}

/**
* Initialize registries that require NMS access.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.command.argument.HeightConverter;
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;
Expand Down Expand Up @@ -78,6 +79,7 @@
import com.sk89q.worldedit.util.formatting.text.format.TextColor;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BlockTypes;
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;
Expand Down Expand Up @@ -546,6 +548,24 @@ public void forest(Player player, LocalSession localSession,
new Paint(new TreeGeneratorFactory(type), density / 100), shape, "worldedit.brush.forest");
}

@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");
}

@Command(
name = "raise",
desc = "Raise brush, raise all blocks by one"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.world.biome.BiomeType;
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;
Expand Down Expand Up @@ -235,6 +236,23 @@ public int pumpkins(Actor actor, LocalSession session, EditSession editSession,
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(TranslatableComponent.of("worldedit.feature.created"));
} else {
actor.printError(TranslatableComponent.of("worldedit.feature.failed"));
}
return 0;
}

@Command(
name = "/hpyramid",
desc = "Generate a hollow pyramid"
Expand Down
Loading