Skip to content

Commit

Permalink
feat: allow placement of minecraft ConfiguredFeatures
Browse files Browse the repository at this point in the history
 - closes #2343
 - scope to add further features
  • Loading branch information
dordsor21 committed Jul 17, 2023
1 parent e0507e6 commit 2383c55
Show file tree
Hide file tree
Showing 21 changed files with 1,145 additions and 5 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
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.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_17_R1.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 Biome 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 FluidState getFluidIfLoaded(final BlockPos blockposition) {
return world.getFluidIfLoaded(blockposition);
}

@Override
public WorldBorder getWorldBorder() {
return world.getWorldBorder();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.blocks.BaseItemStack;
Expand Down Expand Up @@ -58,6 +59,8 @@
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.data.BuiltinRegistries;
import net.minecraft.data.worldgen.Features;
import net.minecraft.nbt.IntTag;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacket;
import net.minecraft.resources.ResourceLocation;
Expand All @@ -74,14 +77,17 @@
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.chunk.LevelChunkSection;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.TreeType;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_17_R1.CraftChunk;
import org.bukkit.craftbukkit.v1_17_R1.CraftServer;
Expand All @@ -105,7 +111,9 @@
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
Expand Down Expand Up @@ -593,6 +601,90 @@ public boolean generateTree(
return true;
}

@Override
public boolean placeFeature(
com.fastasyncworldedit.core.world.feature.ConfiguredFeature feature,
EditSession editSession,
World world,
int x,
int y,
int z
) {
ServerLevel serverLevel = ((CraftWorld) world).getHandle();
ChunkGenerator generator = serverLevel.getMinecraftWorld().getChunkSource().getGenerator();
Random random = ThreadLocalRandom.current();
FaweBlockStateListPopulator populator = new FaweBlockStateListPopulator(serverLevel);

Map<BlockPos, CraftBlockState> placed = TaskManager.taskManager().sync(() -> {
serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true;
try {
if (!((ConfiguredFeature<?, ?>) feature.getKey()).place(populator, generator, random, new BlockPos(x, y, z))) {
return null;
}
return populator.getList().stream().collect(Collectors.toMap(
CraftBlockState::getPosition,
craftBlockState -> craftBlockState
));
} finally {
serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false;
serverLevel.capturedBlockStates.clear();
}
});

if (placed == null || placed.isEmpty()) {
return false;
}

for (Map.Entry<BlockPos, CraftBlockState> 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 = new net.minecraft.nbt.CompoundTag();
blockEntity.save(tag);
editSession.setTile(pos.getX(), pos.getY(), pos.getZ(), (CompoundTag) toNative(tag));
}
}
return true;
}

@Override
public void setupFeatures() {
try {
for (Field f : Features.class.getDeclaredFields()) {
if (!f.canAccess(null)) {
continue;
}
if (f.getType() != ConfiguredFeature.class) {
continue;
}
Object obj = f.get(null);
if (obj instanceof ConfiguredFeature<?, ?> key) {
ResourceLocation location = BuiltinRegistries.CONFIGURED_FEATURE.getKey(key);
if (location == null) {
continue;
}
String id = location.getNamespace() + ":" + location.getPath();
com.fastasyncworldedit.core.world.feature.ConfiguredFeature<ConfiguredFeature<?, ?>> feature = new com.fastasyncworldedit.core.world.feature.ConfiguredFeature<>(
id,
key
);
com.fastasyncworldedit.core.world.feature.ConfiguredFeature.REGISTRY.register(id, feature);
}
}
} catch (IllegalAccessException e) {
LOGGER.error("Cannot load features.");
}
}

@Override
public List<org.bukkit.entity.Entity> getEntities(org.bukkit.World world) {
// Quickly add each entity to a list copy.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_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.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_18_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<Biome> 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();
}

}
Loading

0 comments on commit 2383c55

Please sign in to comment.