3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-12-27 03:12:37 +01:00

Add a BiomeCategories API (#2338) (#2777)

* Add a BiomeCategories API (#2338)

* Add a BiomeCategories API

* licenses

* Use a supplier to retain the lazy-load & dynamicness of the existing system, but still retaining the inversion of control that this PR was intended to provide

* Minor fawe adapter cleanup

* Actually add the new files?

* Fixes

---------

Co-authored-by: Maddy Miller <mnmiller1@me.com>
Dieser Commit ist enthalten in:
Jordan 2024-06-27 15:15:14 +02:00 committet von GitHub
Ursprung ad5739e014
Commit fee9029bf0
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: B5690EEEBB952194
25 geänderte Dateien mit 975 neuen und 371 gelöschten Zeilen

Datei anzeigen

@ -57,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -67,6 +68,9 @@ import com.sk89q.worldedit.world.block.BlockTypes;
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.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -292,6 +296,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id()));
}
public BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
if (mcBiome == null) {
return null;
}
return BiomeType.REGISTRY.get(mcBiome.toString());
}
@Override
public OptionalInt getInternalBlockStateId(BlockData data) {
net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState();
@ -806,6 +818,34 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false;
}
@Override
public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes
for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) {
if (BiomeType.REGISTRY.get(name.toString()) == null) {
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
}
}
// BiomeCategories
Registry<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
biomeRegistry.getTagNames().forEach(tagKey -> {
String key = tagKey.location().toString();
if (BiomeCategory.REGISTRY.get(key) == null) {
BiomeCategory.REGISTRY.register(key, new BiomeCategory(
key,
() -> biomeRegistry.getTag(tagKey)
.stream()
.flatMap(HolderSet.Named::stream)
.map(Holder::value)
.map(this::adapt)
.collect(Collectors.toSet()))
);
}
});
}
// ------------------------------------------------------------------------
// Code that is less likely to break
// ------------------------------------------------------------------------

Datei anzeigen

@ -154,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
}
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {

Datei anzeigen

@ -217,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override
public void onBlockStateChange(
BlockPos blockPos,

Datei anzeigen

@ -57,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -68,6 +69,8 @@ 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.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -310,6 +313,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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 BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
if (mcBiome == null) {
return null;
}
return BiomeType.REGISTRY.get(mcBiome.toString());
}
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);
@ -579,17 +605,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
));
}
/*@Override
public void sendFakeNBT(Player player, BlockVector3 pos, CompoundTag nbtData) {
((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create(
new StructureBlockEntity(
new BlockPos(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ()),
Blocks.STRUCTURE_BLOCK.defaultBlockState()
),
__ -> (net.minecraft.nbt.CompoundTag) fromNative(nbtData)
));
}*/
@Override
public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
@ -858,7 +873,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false;
}
/*@Override
@Override
public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes
@ -867,8 +882,24 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
}
}
}*
// BiomeCategories
Registry<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
biomeRegistry.getTagNames().forEach(tagKey -> {
String key = tagKey.location().toString();
if (BiomeCategory.REGISTRY.get(key) == null) {
BiomeCategory.REGISTRY.register(key, new BiomeCategory(
key,
() -> biomeRegistry.getTag(tagKey)
.stream()
.flatMap(HolderSet.Named::stream)
.map(Holder::value)
.map(this::adapt)
.collect(Collectors.toSet()))
);
}
});
}
// ------------------------------------------------------------------------
// Code that is less likely to break
// ------------------------------------------------------------------------

Datei anzeigen

@ -154,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
}
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {

Datei anzeigen

@ -217,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override
public void onBlockStateChange(
BlockPos blockPos,

Datei anzeigen

@ -23,6 +23,7 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either;
@ -56,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -67,6 +69,8 @@ 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.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -78,6 +82,7 @@ import net.minecraft.server.level.ChunkHolder;
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;
@ -108,6 +113,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
@ -147,6 +153,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -174,6 +181,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private final Field chunkProviderExecutorField;
private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
@ -191,13 +200,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
serverWorldsField.setAccessible(true);
getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod(
Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class
Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class
);
getChunkFutureMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "g")
Refraction.pickName("mainThreadProcessor", "g")
);
chunkProviderExecutorField.setAccessible(true);
@ -282,7 +291,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private static Block getBlockFromType(BlockType blockType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id()));
}
@ -307,6 +315,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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 BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
if (mcBiome == null) {
return null;
}
return BiomeType.REGISTRY.get(mcBiome.toString());
}
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);
@ -320,14 +351,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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
@ -357,8 +381,40 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle()));
public BiomeType getBiome(Location location) {
checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString()));
}
@Override
public void setBiome(Location location, BiomeType biome) {
checkNotNull(location);
checkNotNull(biome);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id())))));
chunk.setUnsaved(true);
}
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world) {
return new PaperweightWorldNativeAccess(this,
new WeakReference<>(((CraftWorld) world).getHandle()));
}
private static net.minecraft.core.Direction adapt(Direction face) {
@ -381,13 +437,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@SuppressWarnings({"rawtypes", "unchecked"})
private net.minecraft.world.level.block.state.BlockState applyProperties(
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states
) {
for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
net.minecraft.world.level.block.state.properties.Property<?> property =
stateContainer.getProperty(state.getKey().getName());
stateContainer.getProperty(state.getKey().getName());
Comparable<?> value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop
if (property instanceof DirectionProperty) {
@ -396,16 +452,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
String enumName = (String) value;
value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property)
.getValue(enumName).orElseThrow(() ->
new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName
)
);
.getValue(enumName).orElseThrow(() ->
new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName
)
);
}
newState = newState.setValue(
(net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value
(net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value
);
}
return newState;
@ -502,10 +558,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(),
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList()));
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList());
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList()));
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList());
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
@ -520,7 +576,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
Map<String, Property<?>> properties = new TreeMap<>();
Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList =
block.getStateDefinition();
block.getStateDefinition();
for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state);
properties.put(property.getName(), property);
@ -542,15 +598,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override
public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
((CraftPlayer) player).getHandle(), (byte) 28
((CraftPlayer) player).getHandle(), (byte) 28
));
}
@Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount()
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount()
);
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())));
return CraftItemStack.asCraftMirror(stack);
@ -565,7 +621,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private final LoadingCache<ServerLevel, PaperweightFakePlayer> fakePlayers
= CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new));
= CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new));
@Override
public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) {
@ -583,7 +639,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.x(), position.y(), position.z(),
(float) face.toVector().toYaw(), (float) face.toVector().toPitch());
(float) face.toVector().toYaw(), (float) face.toVector().toPitch());
final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
@ -603,14 +659,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
@Override
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) {
public boolean canPlaceAt(World world, BlockVector3 position, BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId);
return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z()));
}
@Override
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) {
public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) {
try {
doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) {
@ -620,7 +676,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true;
}
private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator();
@ -630,51 +686,52 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData();
.getWorldData().overworldData();
WorldOptions originalOpts = levelProperties.worldGenOptions();
long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
levelProperties.settings.gameType(),
levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration()
"faweregentempworld",
levelProperties.settings.gameType(),
levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration()
);
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
ServerLevel freshWorld = new ServerLevel(
originalWorld.getServer(),
originalWorld.getServer().executor,
session, newWorldData,
originalWorld.dimension(),
new LevelStem(
originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator()
),
new NoOpWorldLoadListener(),
originalWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalWorld.getRandomSequences(),
env,
gen,
bukkitWorld.getBiomeProvider()
originalWorld.getServer(),
originalWorld.getServer().executor,
session, newWorldData,
originalWorld.dimension(),
new LevelStem(
originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator()
),
new NoOpWorldLoadListener(),
originalWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalWorld.getRandomSequences(),
env,
gen,
bukkitWorld.getBiomeProvider()
);
try {
regenForWorld(region, extent, freshWorld, options);
@ -684,7 +741,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally {
try {
@SuppressWarnings("unchecked")
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
Map<String, World> map = (Map<String, World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException ignored) {
}
@ -712,7 +769,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
executor.managedBlock(() -> {
// bail out early if a future fails
if (chunkLoadings.stream().anyMatch(ftr ->
ftr.isDone() && Futures.getUnchecked(ftr) == null
ftr.isDone() && Futures.getUnchecked(ftr) == null
)) {
return false;
}
@ -758,9 +815,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try {
//noinspection unchecked
chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null))
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null))
);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Couldn't load chunk for regen.", e);
@ -782,12 +839,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
);
@Override
@ -796,7 +853,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
@Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) {
public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
@ -807,6 +864,45 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false;
}
@Override
public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes
for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) {
if (BiomeType.REGISTRY.get(name.toString()) == null) {
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
}
}
// BiomeCategories
Registry<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
biomeRegistry.getTagNames().forEach(tagKey -> {
String key = tagKey.location().toString();
if (BiomeCategory.REGISTRY.get(key) == null) {
BiomeCategory.REGISTRY.register(key, new BiomeCategory(
key,
() -> biomeRegistry.getTag(tagKey)
.stream()
.flatMap(HolderSet.Named::stream)
.map(Holder::value)
.map(this::adapt)
.collect(Collectors.toSet()))
);
}
});
}
@Override
public void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
List<ChunkAccess> nativeChunks = chunks instanceof Collection<BlockVector2> chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList();
for (BlockVector2 chunk : chunks) {
nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false));
}
originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks);
}
// ------------------------------------------------------------------------
// Code that is less likely to break
// ------------------------------------------------------------------------
@ -978,7 +1074,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah")
Refraction.pickName("nextTickTime", "ag")
);
if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect");

Datei anzeigen

@ -41,7 +41,7 @@ class PaperweightFakePlayer extends ServerPlayer {
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]");
private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation(
"en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false
"en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false
);
PaperweightFakePlayer(ServerLevel world) {

Datei anzeigen

@ -26,9 +26,11 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
@ -102,7 +104,14 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override
public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) {
return false;
// We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false;
}
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
}
@Override
@ -144,6 +153,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
}
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
@ -153,8 +168,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();

Datei anzeigen

@ -217,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override
public void onBlockStateChange(
BlockPos blockPos,

Datei anzeigen

@ -23,6 +23,7 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either;
@ -56,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -67,6 +69,8 @@ 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.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -78,6 +82,7 @@ import net.minecraft.server.level.ChunkHolder;
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;
@ -108,6 +113,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
@ -147,6 +153,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -174,6 +181,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private final Field chunkProviderExecutorField;
private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
@ -191,13 +200,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
serverWorldsField.setAccessible(true);
getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod(
Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class
Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class
);
getChunkFutureMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "g")
Refraction.pickName("mainThreadProcessor", "g")
);
chunkProviderExecutorField.setAccessible(true);
@ -282,7 +291,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private static Block getBlockFromType(BlockType blockType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id()));
}
@ -307,6 +315,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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 BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
if (mcBiome == null) {
return null;
}
return BiomeType.REGISTRY.get(mcBiome.toString());
}
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);
@ -320,14 +351,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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
@ -357,7 +381,38 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
public BiomeType getBiome(Location location) {
checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString()));
}
@Override
public void setBiome(Location location, BiomeType biome) {
checkNotNull(location);
checkNotNull(biome);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id())))));
chunk.setUnsaved(true);
}
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world) {
return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle()));
}
@ -381,13 +436,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@SuppressWarnings({"rawtypes", "unchecked"})
private net.minecraft.world.level.block.state.BlockState applyProperties(
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states
) {
for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
net.minecraft.world.level.block.state.properties.Property<?> property =
stateContainer.getProperty(state.getKey().getName());
stateContainer.getProperty(state.getKey().getName());
Comparable<?> value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop
if (property instanceof DirectionProperty) {
@ -396,16 +451,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
String enumName = (String) value;
value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property)
.getValue(enumName).orElseThrow(() ->
new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName
)
);
.getValue(enumName).orElseThrow(() ->
new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName
)
);
}
newState = newState.setValue(
(net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value
(net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value
);
}
return newState;
@ -502,10 +557,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(),
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList()));
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList());
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList()));
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList());
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
@ -520,7 +575,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
Map<String, Property<?>> properties = new TreeMap<>();
Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList =
block.getStateDefinition();
block.getStateDefinition();
for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state);
properties.put(property.getName(), property);
@ -542,15 +597,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override
public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
((CraftPlayer) player).getHandle(), (byte) 28
((CraftPlayer) player).getHandle(), (byte) 28
));
}
@Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount()
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount()
);
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())));
return CraftItemStack.asCraftMirror(stack);
@ -583,7 +638,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.x(), position.y(), position.z(),
(float) face.toVector().toYaw(), (float) face.toVector().toPitch());
(float) face.toVector().toYaw(), (float) face.toVector().toPitch());
final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
@ -603,14 +658,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
@Override
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) {
public boolean canPlaceAt(World world, BlockVector3 position, BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId);
return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z()));
}
@Override
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) {
public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) {
try {
doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) {
@ -620,7 +675,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true;
}
private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator();
@ -630,51 +685,52 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData();
.getWorldData().overworldData();
WorldOptions originalOpts = levelProperties.worldGenOptions();
long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
levelProperties.settings.gameType(),
levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration()
"faweregentempworld",
levelProperties.settings.gameType(),
levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration()
);
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
ServerLevel freshWorld = new ServerLevel(
originalWorld.getServer(),
originalWorld.getServer().executor,
session, newWorldData,
originalWorld.dimension(),
new LevelStem(
originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator()
),
new NoOpWorldLoadListener(),
originalWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalWorld.getRandomSequences(),
env,
gen,
bukkitWorld.getBiomeProvider()
originalWorld.getServer(),
originalWorld.getServer().executor,
session, newWorldData,
originalWorld.dimension(),
new LevelStem(
originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator()
),
new NoOpWorldLoadListener(),
originalWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalWorld.getRandomSequences(),
env,
gen,
bukkitWorld.getBiomeProvider()
);
try {
regenForWorld(region, extent, freshWorld, options);
@ -684,7 +740,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally {
try {
@SuppressWarnings("unchecked")
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
Map<String, World> map = (Map<String, World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException ignored) {
}
@ -712,7 +768,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
executor.managedBlock(() -> {
// bail out early if a future fails
if (chunkLoadings.stream().anyMatch(ftr ->
ftr.isDone() && Futures.getUnchecked(ftr) == null
ftr.isDone() && Futures.getUnchecked(ftr) == null
)) {
return false;
}
@ -758,9 +814,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try {
//noinspection unchecked
chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null))
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null))
);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Couldn't load chunk for regen.", e);
@ -782,12 +838,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
);
@Override
@ -796,7 +852,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
@Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) {
public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
@ -807,6 +863,45 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false;
}
@Override
public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes
for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) {
if (BiomeType.REGISTRY.get(name.toString()) == null) {
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
}
}
// BiomeCategories
Registry<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
biomeRegistry.getTagNames().forEach(tagKey -> {
String key = tagKey.location().toString();
if (BiomeCategory.REGISTRY.get(key) == null) {
BiomeCategory.REGISTRY.register(key, new BiomeCategory(
key,
() -> biomeRegistry.getTag(tagKey)
.stream()
.flatMap(HolderSet.Named::stream)
.map(Holder::value)
.map(this::adapt)
.collect(Collectors.toSet()))
);
}
});
}
@Override
public void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
List<ChunkAccess> nativeChunks = chunks instanceof Collection<BlockVector2> chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList();
for (BlockVector2 chunk : chunks) {
nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false));
}
originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks);
}
// ------------------------------------------------------------------------
// Code that is less likely to break
// ------------------------------------------------------------------------
@ -978,7 +1073,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah")
Refraction.pickName("nextTickTime", "ag")
);
if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect");

Datei anzeigen

@ -41,7 +41,7 @@ class PaperweightFakePlayer extends ServerPlayer {
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]");
private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation(
"en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false
"en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false
);
PaperweightFakePlayer(ServerLevel world) {

Datei anzeigen

@ -73,8 +73,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
@ -110,7 +110,7 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
if (tileEntity == null) {
return false;
}
Tag nativeTag = adapter.fromNative(new CompoundTag(tag));
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
}
@ -154,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
}
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
@ -163,8 +169,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
@ -187,5 +191,4 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public void flush() {
}
}

Datei anzeigen

@ -217,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override
public void onBlockStateChange(
BlockPos blockPos,

Datei anzeigen

@ -23,6 +23,7 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures;
import com.mojang.serialization.Codec;
@ -56,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeCategory;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock;
@ -67,12 +69,13 @@ 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.RegistryAccess;
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.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
import net.minecraft.resources.ResourceKey;
@ -83,6 +86,7 @@ import net.minecraft.server.level.ChunkResult;
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;
@ -113,6 +117,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.CraftServer;
@ -152,6 +157,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@ -183,6 +189,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private final Field chunkProviderExecutorField;
private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
@ -200,13 +208,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
serverWorldsField.setAccessible(true);
getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod(
Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class
Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class
);
getChunkFutureMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "g")
Refraction.pickName("mainThreadProcessor", "g")
);
chunkProviderExecutorField.setAccessible(true);
@ -241,7 +249,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* Read the given NBT data into the given tile entity.
*
* @param tileEntity the tile entity
* @param tag the tag
* @param tag the tag
*/
static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) {
tileEntity.loadWithComponents(tag, MinecraftServer.getServer().registryAccess());
@ -261,7 +269,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
/**
* Create an entity using the given entity ID.
*
* @param id the entity ID
* @param id the entity ID
* @param world the world
* @return an entity or null
*/
@ -274,7 +282,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* Write the given NBT data into the given entity.
*
* @param entity the entity
* @param tag the tag
* @param tag the tag
*/
private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) {
entity.load(tag);
@ -284,21 +292,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* Write the entity's NBT data to the given tag.
*
* @param entity the entity
* @param tag the tag
* @param tag the tag
*/
private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) {
entity.save(tag);
}
private static Block getBlockFromType(BlockType blockType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(
blockType.id()));
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK).get(ResourceLocation.tryParse(blockType.id()));
}
private static Item getItemFromType(ItemType itemType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(
itemType.id()));
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id()));
}
@Override
@ -329,14 +334,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
public BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(
biome);
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
if (mcBiome == null) {
return null;
}
return BiomeType.REGISTRY.get(mcBiome.toString());
}
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);
@ -350,14 +359,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
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
@ -387,7 +389,38 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
public BiomeType getBiome(Location location) {
checkNotNull(location);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
return biomeTypeFromNMSCache.computeIfAbsent(chunk.getNoiseBiome(x >> 2, y >> 2, z >> 2), b -> BiomeType.REGISTRY.get(b.unwrapKey().get().location().toString()));
}
@Override
public void setBiome(Location location, BiomeType biome) {
checkNotNull(location);
checkNotNull(biome);
CraftWorld craftWorld = ((CraftWorld) location.getWorld());
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = craftWorld.getHandle();
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
chunk.setBiome(x >> 2, y >> 2, z >> 2, biomeTypeToNMSCache.computeIfAbsent(biome, b -> ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getHolderOrThrow(ResourceKey.create(Registries.BIOME, new ResourceLocation(b.id())))));
chunk.setUnsaved(true);
}
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world) {
return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle()));
}
@ -411,13 +444,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@SuppressWarnings({"rawtypes", "unchecked"})
private net.minecraft.world.level.block.state.BlockState applyProperties(
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states
) {
for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
net.minecraft.world.level.block.state.properties.Property<?> property =
stateContainer.getProperty(state.getKey().getName());
stateContainer.getProperty(state.getKey().getName());
Comparable<?> value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop
if (property instanceof DirectionProperty) {
@ -426,16 +459,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
String enumName = (String) value;
value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property)
.getValue(enumName).orElseThrow(() ->
new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName
)
);
.getValue(enumName).orElseThrow(() ->
new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName
)
);
}
newState = newState.setValue(
(net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value
(net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value
);
}
return newState;
@ -486,7 +519,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
worldServer.addFreshEntity(createdEntity, SpawnReason.CUSTOM);
worldServer.addFreshEntityWithPassengers(createdEntity, SpawnReason.CUSTOM);
return createdEntity.getBukkitEntity();
} else {
return null;
@ -524,51 +557,33 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId());
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder
.newBuilder()
.build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() {
@Override
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
return new DirectionalProperty(
state.getName(),
(List<Direction>) state
.getPossibleValues()
.stream()
.map(e -> Direction.valueOf(((StringRepresentable) e)
.getSerializedName()
.toUpperCase(Locale.ROOT)))
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(
state.getName(),
(List<String>) state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
}
}
});
@SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() {
@Override
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(),
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList());
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList());
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
}
}
});
@SuppressWarnings({"rawtypes"})
@SuppressWarnings({ "rawtypes" })
@Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
Map<String, Property<?>> properties = new TreeMap<>();
Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList =
block.getStateDefinition();
block.getStateDefinition();
for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state);
properties.put(property.getName(), property);
@ -579,8 +594,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override
public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) {
var structureBlock = new StructureBlockEntity(
new BlockPos(pos.x(), pos.y(), pos.z()),
Blocks.STRUCTURE_BLOCK.defaultBlockState()
new BlockPos(pos.x(), pos.y(), pos.z()),
Blocks.STRUCTURE_BLOCK.defaultBlockState()
);
structureBlock.setLevel(((CraftPlayer) player).getHandle().level());
((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create(
@ -592,18 +607,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override
public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
((CraftPlayer) player).getHandle(), (byte) 28
((CraftPlayer) player).getHandle(), (byte) 28
));
}
@Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
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(item.getType().id())),
item.getAmount()
registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())),
baseItemStack.getAmount()
);
final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData());
final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData());
final DataComponentPatch patch = COMPONENTS_CODEC
.parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt)
.getOrThrow();
@ -613,11 +628,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
var registryAccess = DedicatedServer.getServer().registryAccess();
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final Tag tag = COMPONENTS_CODEC.encodeStart(
registryAccess.createSerializationContext(NbtOps.INSTANCE),
nmsStack.getComponentsPatch()
CompoundTag tag = (CompoundTag) COMPONENTS_CODEC.encodeStart(
registryAccess.createSerializationContext(NbtOps.INSTANCE),
nmsStack.getComponentsPatch()
).getOrThrow();
return new BaseItemStack(
BukkitAdapter.asItemType(itemStack.getType()),
@ -627,16 +642,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private final LoadingCache<ServerLevel, PaperweightFakePlayer> fakePlayers
= CacheBuilder.newBuilder().weakKeys().softValues().build(CacheLoader.from(PaperweightFakePlayer::new));
= 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(adapt(
item instanceof BaseItemStack
? ((BaseItemStack) item)
: new BaseItemStack(item.getType(), item.getNbtReference(), 1)
item instanceof BaseItemStack
? ((BaseItemStack) item)
: new BaseItemStack(item.getType(), item.getNbtReference(), 1)
));
PaperweightFakePlayer fakePlayer;
@ -647,8 +662,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.x(), position.y(), position.z(),
(float) face.toVector().toYaw(), (float) face.toVector().toPitch()
);
(float) face.toVector().toYaw(), (float) face.toVector().toPitch());
final BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
@ -657,10 +671,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace);
InteractionResult result = stack.useOn(context);
if (result != InteractionResult.SUCCESS) {
if (worldServer
.getBlockState(blockPos)
.useItemOn(stack, worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace)
.consumesAction()) {
if (worldServer.getBlockState(blockPos).useItemOn(stack, worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) {
result = InteractionResult.SUCCESS;
} else {
result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult();
@ -671,17 +682,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
@Override
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 position, BlockState blockState) {
public boolean canPlaceAt(World world, BlockVector3 position, BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId);
return blockData.canSurvive(
((CraftWorld) world).getHandle(),
new BlockPos(position.x(), position.y(), position.z())
);
return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z()));
}
@Override
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) {
public boolean regenerate(World bukkitWorld, Region region, Extent extent, RegenOptions options) {
try {
doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) {
@ -691,7 +699,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true;
}
private void doRegen(org.bukkit.World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
private void doRegen(World bukkitWorld, Region region, Extent extent, RegenOptions options) throws Exception {
Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator();
@ -701,56 +709,52 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData();
.getWorldData().overworldData();
WorldOptions originalOpts = levelProperties.worldGenOptions();
long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
levelProperties.settings.gameType(),
levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration()
"faweregentempworld",
levelProperties.settings.gameType(),
levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration()
);
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(
newWorldSettings,
newOpts,
specialWorldProperty,
Lifecycle.stable()
);
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
ServerLevel freshWorld = new ServerLevel(
originalWorld.getServer(),
originalWorld.getServer().executor,
session, newWorldData,
originalWorld.dimension(),
new LevelStem(
originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator()
),
new NoOpWorldLoadListener(),
originalWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalWorld.getRandomSequences(),
env,
gen,
bukkitWorld.getBiomeProvider()
originalWorld.getServer(),
originalWorld.getServer().executor,
session, newWorldData,
originalWorld.dimension(),
new LevelStem(
originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator()
),
new NoOpWorldLoadListener(),
originalWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalWorld.getRandomSequences(),
env,
gen,
bukkitWorld.getBiomeProvider()
);
try {
regenForWorld(region, extent, freshWorld, options);
@ -760,7 +764,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally {
try {
@SuppressWarnings("unchecked")
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
Map<String, World> map = (Map<String, World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException ignored) {
}
@ -777,8 +781,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
@SuppressWarnings("unchecked")
private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws
WorldEditException {
private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException {
List<CompletableFuture<ChunkAccess>> chunkLoadings = submitChunkLoadTasks(region, serverWorld);
BlockableEventLoop<Runnable> executor;
try {
@ -789,7 +792,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
executor.managedBlock(() -> {
// bail out early if a future fails
if (chunkLoadings.stream().anyMatch(ftr ->
ftr.isDone() && Futures.getUnchecked(ftr) == null
ftr.isDone() && Futures.getUnchecked(ftr) == null
)) {
return false;
}
@ -835,9 +838,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try {
//noinspection unchecked
chunkLoadings.add(
((CompletableFuture<ChunkResult<ChunkAccess>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.orElse(null))
((CompletableFuture<ChunkResult<ChunkAccess>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.orElse(null))
);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Couldn't load chunk for regen.", e);
@ -859,12 +862,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
SideEffect.NEIGHBORS,
SideEffect.LIGHTING,
SideEffect.VALIDATION,
SideEffect.ENTITY_AI,
SideEffect.EVENTS,
SideEffect.UPDATE
);
@Override
@ -873,7 +876,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
@Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) {
public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
@ -884,6 +887,45 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false;
}
@Override
public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes
for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.BIOME).keySet()) {
if (BiomeType.REGISTRY.get(name.toString()) == null) {
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
}
}
// BiomeCategories
Registry<Biome> biomeRegistry = server.registryAccess().registryOrThrow(Registries.BIOME);
biomeRegistry.getTagNames().forEach(tagKey -> {
String key = tagKey.location().toString();
if (BiomeCategory.REGISTRY.get(key) == null) {
BiomeCategory.REGISTRY.register(key, new BiomeCategory(
key,
() -> biomeRegistry.getTag(tagKey)
.stream()
.flatMap(HolderSet.Named::stream)
.map(Holder::value)
.map(this::adapt)
.collect(Collectors.toSet()))
);
}
});
}
@Override
public void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
List<ChunkAccess> nativeChunks = chunks instanceof Collection<BlockVector2> chunkCollection ? Lists.newArrayListWithCapacity(chunkCollection.size()) : Lists.newArrayList();
for (BlockVector2 chunk : chunks) {
nativeChunks.add(originalWorld.getChunk(chunk.x(), chunk.z(), ChunkStatus.BIOMES, false));
}
originalWorld.getChunkSource().chunkMap.resendBiomesForChunks(nativeChunks);
}
// ------------------------------------------------------------------------
// Code that is less likely to break
// ------------------------------------------------------------------------
@ -1022,7 +1064,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
private class SpigotWatchdog implements Watchdog {
private final Field instanceField;
private final Field lastTickField;
@ -1047,18 +1088,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
logger.log(Level.WARNING, "Failed to tick watchdog", e);
}
}
}
private static class MojangWatchdog implements Watchdog {
private final DedicatedServer server;
private final Field tickField;
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah")
Refraction.pickName("nextTickTime", "ag")
);
if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect");
@ -1074,21 +1113,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} catch (IllegalAccessException ignored) {
}
}
}
private static class NoOpWorldLoadListener implements ChunkProgressListener {
@Override
public void updateSpawnPos(ChunkPos spawnPos) {
}
@Override
public void onStatusChange(
final ChunkPos pos,
@org.jetbrains.annotations.Nullable final net.minecraft.world.level.chunk.status.ChunkStatus status
) {
public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) {
}
@Override
@ -1100,5 +1133,4 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}
}
}

Datei anzeigen

@ -41,7 +41,7 @@ class PaperweightFakePlayer extends ServerPlayer {
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]");
private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation(
"en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false
"en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false
);
PaperweightFakePlayer(ServerLevel world) {

Datei anzeigen

@ -26,9 +26,11 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
@ -102,7 +104,14 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override
public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) {
return false;
// We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false;
}
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
}
@Override
@ -144,7 +153,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
}
}
// Not sure why neighborChanged is deprecated
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false);
}
@ -152,8 +166,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
@ -176,5 +188,4 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public void flush() {
}
}

Datei anzeigen

@ -218,6 +218,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
Level world = getLevel();
newState.onPlace(world, pos, oldState, false);
}
@Override
public void onBlockStateChange(
BlockPos blockPos,

Datei anzeigen

@ -8,6 +8,7 @@ import com.sk89q.worldedit.bukkit.BukkitPlayer;
import com.sk89q.worldedit.bukkit.BukkitWorld;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.math.Vector3;
import com.sk89q.worldedit.registry.state.Property;
@ -114,6 +115,26 @@ public interface IDelegateBukkitImplAdapter<T> extends BukkitImplAdapter<T> {
return getParent().getInternalBlockStateId(state);
}
@Override
default boolean clearContainerBlockContents(World world, BlockVector3 pt) {
return getParent().clearContainerBlockContents(world, pt);
}
@Override
default void setBiome(Location location, BiomeType biome) {
getParent().setBiome(location, biome);
}
@Override
default BiomeType getBiome(Location location) {
return getParent().getBiome(location);
}
@Override
default void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
getParent().sendBiomeUpdates(world, chunks);
}
@Override
default BlockMaterial getMaterial(BlockType blockType) {
return getParent().getMaterial(blockType);

Datei anzeigen

@ -35,6 +35,7 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.Property;
@ -110,7 +111,7 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
BlockState getBlock(Location location);
/**
* Get the block at the given location.
* Get the block with NBT data at the given location.
*
* @param location the location
* @return the block
@ -280,6 +281,46 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
throw new UnsupportedOperationException("This adapter does not support clearing block contents.");
}
/**
* Set the biome at a location.
*
* @param location the location
* @param biome the new biome
*/
default void setBiome(Location location, BiomeType biome) {
throw new UnsupportedOperationException("This adapter does not support custom biomes.");
}
/**
* Gets the current biome at a location.
*
* @param location the location
* @return the biome
*/
default BiomeType getBiome(Location location) {
throw new UnsupportedOperationException("This adapter does not support custom biomes.");
}
/**
* Initialize registries that require NMS access.
*/
default void initializeRegistries() {
}
/**
* Sends biome updates for the given chunks.
*
* <p>This doesn't modify biomes at all, it just sends the current state of the biomes
* in the world to all of the nearby players, updating the visual representation of the
* biomes on their clients.</p>
*
* @param world the world
* @param chunks a list of chunk coordinates to send biome updates for
*/
default void sendBiomeUpdates(World world, Iterable<BlockVector2> chunks) {
}
//FAWE start
default BlockMaterial getMaterial(BlockType blockType) {
return getMaterial(blockType.getDefaultState());

Datei anzeigen

@ -109,26 +109,22 @@ public class FastSchematicReader extends NBTSchematicReader {
if (fixer == null || dataVersion == -1) {
return tag;
}
//FAWE start - LinTag
return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp(
DataFixer.FixTypes.BLOCK_ENTITY,
tag.toLinTag(),
dataVersion
));
//FAWE end
}
private CompoundTag fixEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) {
return tag;
}
//FAWE start - LinTag
return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp(
DataFixer.FixTypes.ENTITY,
tag.toLinTag(),
dataVersion
));
//FAWE end
}
private String fixBiome(String biomePalettePart) {

Datei anzeigen

@ -146,7 +146,9 @@ public interface WorldNativeAccess<NC, NBS, NP> {
void markBlockChanged(NC chunk, NP position);
void notifyNeighbors(NP pos, NBS oldState, NBS newState);
void notifyNeighbors(NP pos, NBS oldState, NBS newState);;
void updateBlock(NP pos, NBS oldState, NBS newState);
void updateNeighbors(NP pos, NBS oldState, NBS newState, int recursionLimit);

Datei anzeigen

@ -23,17 +23,25 @@ import com.fastasyncworldedit.core.registry.RegistryItem;
import java.util.HashSet;
import java.util.Set;
import java.util.function.Supplier;
//FAWE start - implements RegistryItem
public abstract class Category<T extends Keyed> implements RegistryItem, Keyed {
//FAWE end
private final Set<T> set = new HashSet<>();
private final Supplier<Set<T>> supplier;
protected final String id;
private boolean empty = true;
protected Category(final String id) {
public Category(final String id) {
this.id = id;
this.supplier = null;
}
public Category(String id, Supplier<Set<T>> contentSupplier) {
this.id = id;
this.supplier = contentSupplier;
}
@Override
@ -43,7 +51,11 @@ public abstract class Category<T extends Keyed> implements RegistryItem, Keyed {
public final Set<T> getAll() {
if (this.empty) {
this.set.addAll(this.load());
if (supplier != null) {
this.set.addAll(this.supplier.get());
} else {
this.set.addAll(this.load());
}
this.empty = false;
}
return this.set;
@ -62,6 +74,14 @@ public abstract class Category<T extends Keyed> implements RegistryItem, Keyed {
return internalId;
}
/**
* Loads the contents of this category from the platform.
*
* @return The loaded contents of the category
* @deprecated The load system will be removed in a future WorldEdit release. The registries should be populated by
* the platforms via the supplier constructor.
*/
@Deprecated
protected abstract Set<T> load();
//FAWE end

Datei anzeigen

@ -0,0 +1,112 @@
/*
* 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.biome;
/**
* Stores a list of common {@link BiomeCategory BiomeCategories}.
*
* @see BiomeCategory
*/
@SuppressWarnings("unused")
public final class BiomeCategories {
public static final BiomeCategory ALLOWS_SURFACE_SLIME_SPAWNS = get("minecraft:allows_surface_slime_spawns");
public static final BiomeCategory ALLOWS_TROPICAL_FISH_SPAWNS_AT_ANY_HEIGHT = get("minecraft:allows_tropical_fish_spawns_at_any_height");
public static final BiomeCategory HAS_CLOSER_WATER_FOG = get("minecraft:has_closer_water_fog");
public static final BiomeCategory HAS_STRUCTURE_ANCIENT_CITY = get("minecraft:has_structure/ancient_city");
public static final BiomeCategory HAS_STRUCTURE_BASTION_REMNANT = get("minecraft:has_structure/bastion_remnant");
public static final BiomeCategory HAS_STRUCTURE_BURIED_TREASURE = get("minecraft:has_structure/buried_treasure");
public static final BiomeCategory HAS_STRUCTURE_DESERT_PYRAMID = get("minecraft:has_structure/desert_pyramid");
public static final BiomeCategory HAS_STRUCTURE_END_CITY = get("minecraft:has_structure/end_city");
public static final BiomeCategory HAS_STRUCTURE_IGLOO = get("minecraft:has_structure/igloo");
public static final BiomeCategory HAS_STRUCTURE_JUNGLE_TEMPLE = get("minecraft:has_structure/jungle_temple");
public static final BiomeCategory HAS_STRUCTURE_MINESHAFT = get("minecraft:has_structure/mineshaft");
public static final BiomeCategory HAS_STRUCTURE_MINESHAFT_MESA = get("minecraft:has_structure/mineshaft_mesa");
public static final BiomeCategory HAS_STRUCTURE_NETHER_FORTRESS = get("minecraft:has_structure/nether_fortress");
public static final BiomeCategory HAS_STRUCTURE_NETHER_FOSSIL = get("minecraft:has_structure/nether_fossil");
public static final BiomeCategory HAS_STRUCTURE_OCEAN_MONUMENT = get("minecraft:has_structure/ocean_monument");
public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_COLD = get("minecraft:has_structure/ocean_ruin_cold");
public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_WARM = get("minecraft:has_structure/ocean_ruin_warm");
public static final BiomeCategory HAS_STRUCTURE_PILLAGER_OUTPOST = get("minecraft:has_structure/pillager_outpost");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_DESERT = get("minecraft:has_structure/ruined_portal_desert");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_JUNGLE = get("minecraft:has_structure/ruined_portal_jungle");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_MOUNTAIN = get("minecraft:has_structure/ruined_portal_mountain");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_NETHER = get("minecraft:has_structure/ruined_portal_nether");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_OCEAN = get("minecraft:has_structure/ruined_portal_ocean");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_STANDARD = get("minecraft:has_structure/ruined_portal_standard");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_SWAMP = get("minecraft:has_structure/ruined_portal_swamp");
public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK = get("minecraft:has_structure/shipwreck");
public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK_BEACHED = get("minecraft:has_structure/shipwreck_beached");
public static final BiomeCategory HAS_STRUCTURE_STRONGHOLD = get("minecraft:has_structure/stronghold");
public static final BiomeCategory HAS_STRUCTURE_SWAMP_HUT = get("minecraft:has_structure/swamp_hut");
public static final BiomeCategory HAS_STRUCTURE_TRAIL_RUINS = get("minecraft:has_structure/trail_ruins");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_DESERT = get("minecraft:has_structure/village_desert");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_PLAINS = get("minecraft:has_structure/village_plains");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SAVANNA = get("minecraft:has_structure/village_savanna");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SNOWY = get("minecraft:has_structure/village_snowy");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_TAIGA = get("minecraft:has_structure/village_taiga");
public static final BiomeCategory HAS_STRUCTURE_WOODLAND_MANSION = get("minecraft:has_structure/woodland_mansion");
public static final BiomeCategory INCREASED_FIRE_BURNOUT = get("minecraft:increased_fire_burnout");
public static final BiomeCategory IS_BADLANDS = get("minecraft:is_badlands");
public static final BiomeCategory IS_BEACH = get("minecraft:is_beach");
public static final BiomeCategory IS_DEEP_OCEAN = get("minecraft:is_deep_ocean");
public static final BiomeCategory IS_END = get("minecraft:is_end");
public static final BiomeCategory IS_FOREST = get("minecraft:is_forest");
public static final BiomeCategory IS_HILL = get("minecraft:is_hill");
public static final BiomeCategory IS_JUNGLE = get("minecraft:is_jungle");
public static final BiomeCategory IS_MOUNTAIN = get("minecraft:is_mountain");
public static final BiomeCategory IS_NETHER = get("minecraft:is_nether");
public static final BiomeCategory IS_OCEAN = get("minecraft:is_ocean");
public static final BiomeCategory IS_OVERWORLD = get("minecraft:is_overworld");
public static final BiomeCategory IS_RIVER = get("minecraft:is_river");
public static final BiomeCategory IS_SAVANNA = get("minecraft:is_savanna");
public static final BiomeCategory IS_TAIGA = get("minecraft:is_taiga");
public static final BiomeCategory MINESHAFT_BLOCKING = get("minecraft:mineshaft_blocking");
public static final BiomeCategory MORE_FREQUENT_DROWNED_SPAWNS = get("minecraft:more_frequent_drowned_spawns");
public static final BiomeCategory PLAYS_UNDERWATER_MUSIC = get("minecraft:plays_underwater_music");
public static final BiomeCategory POLAR_BEARS_SPAWN_ON_ALTERNATE_BLOCKS = get("minecraft:polar_bears_spawn_on_alternate_blocks");
public static final BiomeCategory PRODUCES_CORALS_FROM_BONEMEAL = get("minecraft:produces_corals_from_bonemeal");
public static final BiomeCategory REDUCE_WATER_AMBIENT_SPAWNS = get("minecraft:reduce_water_ambient_spawns");
public static final BiomeCategory REQUIRED_OCEAN_MONUMENT_SURROUNDING = get("minecraft:required_ocean_monument_surrounding");
public static final BiomeCategory SNOW_GOLEM_MELTS = get("minecraft:snow_golem_melts");
public static final BiomeCategory SPAWNS_COLD_VARIANT_FROGS = get("minecraft:spawns_cold_variant_frogs");
public static final BiomeCategory SPAWNS_GOLD_RABBITS = get("minecraft:spawns_gold_rabbits");
public static final BiomeCategory SPAWNS_SNOW_FOXES = get("minecraft:spawns_snow_foxes");
public static final BiomeCategory SPAWNS_WARM_VARIANT_FROGS = get("minecraft:spawns_warm_variant_frogs");
public static final BiomeCategory SPAWNS_WHITE_RABBITS = get("minecraft:spawns_white_rabbits");
public static final BiomeCategory STRONGHOLD_BIASED_TO = get("minecraft:stronghold_biased_to");
public static final BiomeCategory WATER_ON_MAP_OUTLINES = get("minecraft:water_on_map_outlines");
public static final BiomeCategory WITHOUT_PATROL_SPAWNS = get("minecraft:without_patrol_spawns");
public static final BiomeCategory WITHOUT_WANDERING_TRADER_SPAWNS = get("minecraft:without_wandering_trader_spawns");
public static final BiomeCategory WITHOUT_ZOMBIE_SIEGES = get("minecraft:without_zombie_sieges");
private BiomeCategories() {
}
/**
* Gets the {@link BiomeCategory} associated with the given id.
*/
public static BiomeCategory get(String id) {
BiomeCategory entry = BiomeCategory.REGISTRY.get(id);
if (entry == null) {
return new BiomeCategory(id);
}
return entry;
}
}

Datei anzeigen

@ -0,0 +1,49 @@
/*
* 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.biome;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.registry.NamespacedRegistry;
import java.util.Set;
import java.util.function.Supplier;
/**
* A category of biomes.
*/
public class BiomeCategory extends Category<BiomeType> implements Keyed {
public static final NamespacedRegistry<BiomeCategory> REGISTRY = new NamespacedRegistry<>("biome tag", true);
public BiomeCategory(final String id) {
super(id);
}
public BiomeCategory(final String id, final Supplier<Set<BiomeType>> contentSupplier) {
super(id, contentSupplier);
}
@Override
protected Set<BiomeType> load() {
return Set.of();
}
}