3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-10-01 19:30:06 +02:00

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
Dieser Commit ist enthalten in:
Maddy Miller 2023-06-24 15:11:31 +10:00 committet von dordsor21
Ursprung 9843bb0188
Commit e2a6e0a4b6
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 1E53E88969FFCF0B
21 geänderte Dateien mit 870 neuen und 390 gelöschten Zeilen

Datei anzeigen

@ -71,6 +71,7 @@ import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions; 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.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -81,6 +82,9 @@ import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.item.ItemType; import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; 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.core.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -137,6 +141,7 @@ import org.bukkit.generator.ChunkGenerator;
import org.spigotmc.SpigotConfig; import org.spigotmc.SpigotConfig;
import org.spigotmc.WatchdogThread; import org.spigotmc.WatchdogThread;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -158,7 +163,6 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
@ -290,6 +294,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id())); 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 @Override
public OptionalInt getInternalBlockStateId(BlockData data) { public OptionalInt getInternalBlockStateId(BlockData data) {
net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState(); net.minecraft.world.level.block.state.BlockState state = ((CraftBlockData) data).getState();
@ -804,6 +816,34 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; 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 // Code that is less likely to break
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

Datei anzeigen

@ -35,9 +35,9 @@ import org.bukkit.craftbukkit.v1_19_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_19_R3.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
@ -144,6 +144,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 // Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { 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); 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 @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, BlockPos blockPos,

Datei anzeigen

@ -308,6 +308,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); 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 @Override
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
checkNotNull(location); checkNotNull(location);
@ -577,17 +600,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 @Override
public void sendFakeOP(Player player) { public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
@ -865,7 +877,73 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString())); BiomeType.REGISTRY.register(name.toString(), new BiomeType(name.toString()));
} }
} }
<<<<<<< HEAD:worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java
}* }*
=======
// Features
for (ResourceLocation name: server.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).keySet()) {
if (ConfiguredFeatureType.REGISTRY.get(name.toString()) == null) {
ConfiguredFeatureType.REGISTRY.register(name.toString(), new ConfiguredFeatureType(name.toString()));
}
}
// Structures
for (ResourceLocation name : server.registryAccess().registryOrThrow(Registries.STRUCTURE).keySet()) {
if (StructureType.REGISTRY.get(name.toString()) == null) {
StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString()));
}
}
// BiomeCategories
Registry<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()))
);
}
});
}
public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
ConfiguredFeature<?, ?> k = originalWorld.registryAccess().registryOrThrow(Registries.CONFIGURED_FEATURE).get(ResourceLocation.tryParse(type.getId()));
ServerChunkCache chunkManager = originalWorld.getChunkSource();
WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this);
return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()));
}
public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle();
Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.getId()));
if (k == null) {
return false;
}
ServerChunkCache chunkManager = originalWorld.getChunkSource();
WorldGenLevel proxyLevel = PaperweightServerLevelDelegateProxy.newInstance(session, originalWorld, this);
ChunkPos chunkPos = new ChunkPos(new BlockPos(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()));
StructureStart structureStart = k.generate(originalWorld.registryAccess(), chunkManager.getGenerator(), chunkManager.getGenerator().getBiomeSource(), chunkManager.randomState(), originalWorld.getStructureManager(), originalWorld.getSeed(), chunkPos, 0, proxyLevel, biome -> true);
if (!structureStart.isValid()) {
return false;
} else {
BoundingBox boundingBox = structureStart.getBoundingBox();
ChunkPos min = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.minX()), SectionPos.blockToSectionCoord(boundingBox.minZ()));
ChunkPos max = new ChunkPos(SectionPos.blockToSectionCoord(boundingBox.maxX()), SectionPos.blockToSectionCoord(boundingBox.maxZ()));
ChunkPos.rangeClosed(min, max).forEach((chunkPosx) -> structureStart.placeInChunk(proxyLevel, originalWorld.structureManager(), chunkManager.getGenerator(), originalWorld.getRandom(), new BoundingBox(chunkPosx.getMinBlockX(), originalWorld.getMinBuildHeight(), chunkPosx.getMinBlockZ(), chunkPosx.getMaxBlockX(), originalWorld.getMaxBuildHeight(), chunkPosx.getMaxBlockZ()), chunkPosx));
return true;
}
}
>>>>>>> 61363821b (Add a BiomeCategories API (#2338)):worldedit-bukkit/adapters/adapter-1.20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_20_R1/PaperweightAdapter.java
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that is less likely to break // Code that is less likely to break

Datei anzeigen

@ -19,12 +19,12 @@
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess; import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
@ -35,9 +35,9 @@ import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
@ -144,6 +144,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 // Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {

Datei anzeigen

@ -15,9 +15,8 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -218,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); 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 @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, 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.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
@ -70,6 +71,7 @@ import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions; 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.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -81,6 +83,8 @@ import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -92,6 +96,7 @@ import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.Clearable; import net.minecraft.world.Clearable;
@ -122,6 +127,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R2.CraftServer; import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
@ -137,6 +143,7 @@ import org.bukkit.generator.ChunkGenerator;
import org.spigotmc.SpigotConfig; import org.spigotmc.SpigotConfig;
import org.spigotmc.WatchdogThread; import org.spigotmc.WatchdogThread;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -144,6 +151,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -158,7 +166,6 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
@ -172,6 +179,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private final Field chunkProviderExecutorField; private final Field chunkProviderExecutorField;
private final Watchdog watchdog; private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that may break between versions of Minecraft // Code that may break between versions of Minecraft
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -189,13 +198,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
serverWorldsField.setAccessible(true); serverWorldsField.setAccessible(true);
getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod(
Refraction.pickName("getChunkFutureMainThread", "c"), Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class int.class, int.class, ChunkStatus.class, boolean.class
); );
getChunkFutureMethod.setAccessible(true); getChunkFutureMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "g") Refraction.pickName("mainThreadProcessor", "g")
); );
chunkProviderExecutorField.setAccessible(true); chunkProviderExecutorField.setAccessible(true);
@ -216,7 +225,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
Class.forName("org.spigotmc.SpigotConfig"); Class.forName("org.spigotmc.SpigotConfig");
SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
} }
} }
@ -280,7 +289,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private static Block getBlockFromType(BlockType blockType) { 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()));
} }
@ -305,6 +313,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); 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 @Override
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
checkNotNull(location); checkNotNull(location);
@ -318,14 +349,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
int internalId = Block.getId(blockData); return adapt(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
} }
@Override @Override
@ -355,8 +379,40 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public BiomeType getBiome(Location location) {
return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); 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) { private static net.minecraft.core.Direction adapt(Direction face) {
@ -379,13 +435,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
private net.minecraft.world.level.block.state.BlockState applyProperties( private net.minecraft.world.level.block.state.BlockState applyProperties(
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer, StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState, net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states Map<Property<?>, Object> states
) { ) {
for (Map.Entry<Property<?>, Object> state : states.entrySet()) { for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
net.minecraft.world.level.block.state.properties.Property<?> property = net.minecraft.world.level.block.state.properties.Property<?> property =
stateContainer.getProperty(state.getKey().getName()); stateContainer.getProperty(state.getKey().getName());
Comparable<?> value = (Comparable) state.getValue(); Comparable<?> value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop // we may need to adapt this value, depending on the source prop
if (property instanceof DirectionProperty) { if (property instanceof DirectionProperty) {
@ -394,16 +450,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { } else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
String enumName = (String) value; String enumName = (String) value;
value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property) value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property)
.getValue(enumName).orElseThrow(() -> .getValue(enumName).orElseThrow(() ->
new IllegalStateException( new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName "Enum property " + property.getName() + " does not contain " + enumName
) )
); );
} }
newState = newState.setValue( newState = newState.setValue(
(net.minecraft.world.level.block.state.properties.Property) property, (net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value (Comparable) value
); );
} }
return newState; return newState;
@ -500,10 +556,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) { } else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(), 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) { } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(), 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) { } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else { } else {
@ -518,7 +574,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
Map<String, Property<?>> properties = new TreeMap<>(); Map<String, Property<?>> properties = new TreeMap<>();
Block block = getBlockFromType(blockType); Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList = 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()) { for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state); Property<?> property = PROPERTY_CACHE.getUnchecked(state);
properties.put(property.getName(), property); properties.put(property.getName(), property);
@ -540,15 +596,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public void sendFakeOP(Player player) { public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
((CraftPlayer) player).getHandle(), (byte) 28 ((CraftPlayer) player).getHandle(), (byte) 28
)); ));
} }
@Override @Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())), DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount() item.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())));
return CraftItemStack.asCraftMirror(stack); return CraftItemStack.asCraftMirror(stack);
@ -563,7 +619,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private final LoadingCache<ServerLevel, PaperweightFakePlayer> fakePlayers 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 @Override
public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) { public boolean simulateItemUse(org.bukkit.World world, BlockVector3 position, BaseItem item, Direction face) {
@ -581,7 +637,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.x(), position.y(), position.z(), 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 BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
@ -601,14 +657,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @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); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); 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 @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 { try {
doRegen(bukkitWorld, region, extent, options); doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) { } catch (Exception e) {
@ -618,61 +674,62 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true; 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(); Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator(); ChunkGenerator gen = bukkitWorld.getGenerator();
Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); Path tempDir = Files.createTempDirectory("WorldEditWorldGen");
LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env); ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env);
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData(); .getWorldData().overworldData();
WorldOptions originalOpts = levelProperties.worldGenOptions(); WorldOptions originalOpts = levelProperties.worldGenOptions();
long seed = options.getSeed().orElse(originalWorld.getSeed()); long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldOptions newOpts = options.getSeed().isPresent() WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed)) ? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts; : originalOpts;
LevelSettings newWorldSettings = new LevelSettings( LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld", "worldeditregentempworld",
levelProperties.settings.gameType(), levelProperties.settings.gameType(),
levelProperties.settings.hardcore(), levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(), levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(), levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(), levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration() levelProperties.settings.getDataConfiguration()
); );
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty = PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld() levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT ? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld() : levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG ? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE; : 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( ServerLevel freshWorld = new ServerLevel(
originalWorld.getServer(), originalWorld.getServer(),
originalWorld.getServer().executor, originalWorld.getServer().executor,
session, newWorldData, session, newWorldData,
originalWorld.dimension(), originalWorld.dimension(),
new LevelStem( new LevelStem(
originalWorld.dimensionTypeRegistration(), originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator() originalWorld.getChunkSource().getGenerator()
), ),
new NoOpWorldLoadListener(), new NoOpWorldLoadListener(),
originalWorld.isDebug(), originalWorld.isDebug(),
seed, seed,
ImmutableList.of(), ImmutableList.of(),
false, false,
originalWorld.getRandomSequences(), originalWorld.getRandomSequences(),
env, env,
gen, gen,
bukkitWorld.getBiomeProvider() bukkitWorld.getBiomeProvider()
); );
try { try {
regenForWorld(region, extent, freshWorld, options); regenForWorld(region, extent, freshWorld, options);
@ -682,8 +739,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally { } finally {
try { try {
@SuppressWarnings("unchecked") @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"); map.remove("worldeditregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
SafeFiles.tryHardToDeleteDir(tempDir); SafeFiles.tryHardToDeleteDir(tempDir);
@ -710,7 +767,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
executor.managedBlock(() -> { executor.managedBlock(() -> {
// bail out early if a future fails // bail out early if a future fails
if (chunkLoadings.stream().anyMatch(ftr -> if (chunkLoadings.stream().anyMatch(ftr ->
ftr.isDone() && Futures.getUnchecked(ftr) == null ftr.isDone() && Futures.getUnchecked(ftr) == null
)) { )) {
return false; return false;
} }
@ -756,9 +813,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
//noinspection unchecked //noinspection unchecked
chunkLoadings.add( chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>) ((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null)) .thenApply(either -> either.left().orElse(null))
); );
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Couldn't load chunk for regen.", e); throw new IllegalStateException("Couldn't load chunk for regen.", e);
@ -780,12 +837,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS, SideEffect.NEIGHBORS,
SideEffect.LIGHTING, SideEffect.LIGHTING,
SideEffect.VALIDATION, SideEffect.VALIDATION,
SideEffect.ENTITY_AI, SideEffect.ENTITY_AI,
SideEffect.EVENTS, SideEffect.EVENTS,
SideEffect.UPDATE SideEffect.UPDATE
); );
@Override @Override
@ -794,7 +851,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle(); ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
@ -805,6 +862,45 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; 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 // Code that is less likely to break
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -977,7 +1073,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server; this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField( Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah") Refraction.pickName("nextTickTime", "ag")
); );
if (tickField.getType() != long.class) { if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); 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 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 Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( 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) { PaperweightFakePlayer(ServerLevel world) {

Datei anzeigen

@ -27,17 +27,19 @@ import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld; import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state); int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId) return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId) ? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); : ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
} }
@Override @Override
@ -102,7 +104,14 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag 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.fromNativeBinary(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
} }
@Override @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 // Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
@ -153,8 +168,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { 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(); ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld(); CraftWorld craftWorld = world.getWorld();

Datei anzeigen

@ -15,9 +15,8 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -218,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); 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 @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, 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.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.datafixers.util.Either; import com.mojang.datafixers.util.Either;
@ -70,6 +71,7 @@ import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions; 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.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -81,6 +83,8 @@ import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
@ -92,6 +96,7 @@ import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.Clearable; import net.minecraft.world.Clearable;
@ -122,6 +127,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.v1_20_R3.CraftServer; import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
@ -137,6 +143,7 @@ import org.bukkit.generator.ChunkGenerator;
import org.spigotmc.SpigotConfig; import org.spigotmc.SpigotConfig;
import org.spigotmc.WatchdogThread; import org.spigotmc.WatchdogThread;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -144,6 +151,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -158,7 +166,6 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
@ -172,6 +179,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private final Field chunkProviderExecutorField; private final Field chunkProviderExecutorField;
private final Watchdog watchdog; private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that may break between versions of Minecraft // Code that may break between versions of Minecraft
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -189,13 +198,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
serverWorldsField.setAccessible(true); serverWorldsField.setAccessible(true);
getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod(
Refraction.pickName("getChunkFutureMainThread", "c"), Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class int.class, int.class, ChunkStatus.class, boolean.class
); );
getChunkFutureMethod.setAccessible(true); getChunkFutureMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "g") Refraction.pickName("mainThreadProcessor", "g")
); );
chunkProviderExecutorField.setAccessible(true); chunkProviderExecutorField.setAccessible(true);
@ -216,7 +225,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
Class.forName("org.spigotmc.SpigotConfig"); Class.forName("org.spigotmc.SpigotConfig");
SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
} }
} }
@ -280,7 +289,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private static Block getBlockFromType(BlockType blockType) { 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()));
} }
@ -305,6 +313,29 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return combinedId == 0 && state.getBlockType() != BlockTypes.AIR ? OptionalInt.empty() : OptionalInt.of(combinedId); 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 @Override
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
checkNotNull(location); checkNotNull(location);
@ -318,14 +349,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
int internalId = Block.getId(blockData); return adapt(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
} }
@Override @Override
@ -355,7 +379,38 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override @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())); return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle()));
} }
@ -379,13 +434,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
private net.minecraft.world.level.block.state.BlockState applyProperties( private net.minecraft.world.level.block.state.BlockState applyProperties(
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer, StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState, net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states Map<Property<?>, Object> states
) { ) {
for (Map.Entry<Property<?>, Object> state : states.entrySet()) { for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
net.minecraft.world.level.block.state.properties.Property<?> property = net.minecraft.world.level.block.state.properties.Property<?> property =
stateContainer.getProperty(state.getKey().getName()); stateContainer.getProperty(state.getKey().getName());
Comparable<?> value = (Comparable) state.getValue(); Comparable<?> value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop // we may need to adapt this value, depending on the source prop
if (property instanceof DirectionProperty) { if (property instanceof DirectionProperty) {
@ -394,16 +449,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { } else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
String enumName = (String) value; String enumName = (String) value;
value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property) value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property)
.getValue(enumName).orElseThrow(() -> .getValue(enumName).orElseThrow(() ->
new IllegalStateException( new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName "Enum property " + property.getName() + " does not contain " + enumName
) )
); );
} }
newState = newState.setValue( newState = newState.setValue(
(net.minecraft.world.level.block.state.properties.Property) property, (net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value (Comparable) value
); );
} }
return newState; return newState;
@ -500,10 +555,10 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else if (state instanceof DirectionProperty) { } else if (state instanceof DirectionProperty) {
return new DirectionalProperty(state.getName(), 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) { } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(state.getName(), 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) { } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else { } else {
@ -518,7 +573,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
Map<String, Property<?>> properties = new TreeMap<>(); Map<String, Property<?>> properties = new TreeMap<>();
Block block = getBlockFromType(blockType); Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList = 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()) { for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state); Property<?> property = PROPERTY_CACHE.getUnchecked(state);
properties.put(property.getName(), property); properties.put(property.getName(), property);
@ -540,15 +595,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public void sendFakeOP(Player player) { public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
((CraftPlayer) player).getHandle(), (byte) 28 ((CraftPlayer) player).getHandle(), (byte) 28
)); ));
} }
@Override @Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) {
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())), DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())),
item.getAmount() item.getAmount()
); );
stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData()))); stack.setTag(((net.minecraft.nbt.CompoundTag) fromNative(item.getNbtData())));
return CraftItemStack.asCraftMirror(stack); return CraftItemStack.asCraftMirror(stack);
@ -581,7 +636,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.x(), position.y(), position.z(), 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 BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
@ -601,14 +656,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @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); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); 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 @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 { try {
doRegen(bukkitWorld, region, extent, options); doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) { } catch (Exception e) {
@ -618,61 +673,62 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true; 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(); Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator(); ChunkGenerator gen = bukkitWorld.getGenerator();
Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); Path tempDir = Files.createTempDirectory("WorldEditWorldGen");
LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env); ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env);
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData(); .getWorldData().overworldData();
WorldOptions originalOpts = levelProperties.worldGenOptions(); WorldOptions originalOpts = levelProperties.worldGenOptions();
long seed = options.getSeed().orElse(originalWorld.getSeed()); long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldOptions newOpts = options.getSeed().isPresent() WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed)) ? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts; : originalOpts;
LevelSettings newWorldSettings = new LevelSettings( LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld", "worldeditregentempworld",
levelProperties.settings.gameType(), levelProperties.settings.gameType(),
levelProperties.settings.hardcore(), levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(), levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(), levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(), levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration() levelProperties.settings.getDataConfiguration()
); );
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty = PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld() levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT ? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld() : levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG ? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE; : 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( ServerLevel freshWorld = new ServerLevel(
originalWorld.getServer(), originalWorld.getServer(),
originalWorld.getServer().executor, originalWorld.getServer().executor,
session, newWorldData, session, newWorldData,
originalWorld.dimension(), originalWorld.dimension(),
new LevelStem( new LevelStem(
originalWorld.dimensionTypeRegistration(), originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator() originalWorld.getChunkSource().getGenerator()
), ),
new NoOpWorldLoadListener(), new NoOpWorldLoadListener(),
originalWorld.isDebug(), originalWorld.isDebug(),
seed, seed,
ImmutableList.of(), ImmutableList.of(),
false, false,
originalWorld.getRandomSequences(), originalWorld.getRandomSequences(),
env, env,
gen, gen,
bukkitWorld.getBiomeProvider() bukkitWorld.getBiomeProvider()
); );
try { try {
regenForWorld(region, extent, freshWorld, options); regenForWorld(region, extent, freshWorld, options);
@ -682,8 +738,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally { } finally {
try { try {
@SuppressWarnings("unchecked") @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"); map.remove("worldeditregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
SafeFiles.tryHardToDeleteDir(tempDir); SafeFiles.tryHardToDeleteDir(tempDir);
@ -710,7 +766,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
executor.managedBlock(() -> { executor.managedBlock(() -> {
// bail out early if a future fails // bail out early if a future fails
if (chunkLoadings.stream().anyMatch(ftr -> if (chunkLoadings.stream().anyMatch(ftr ->
ftr.isDone() && Futures.getUnchecked(ftr) == null ftr.isDone() && Futures.getUnchecked(ftr) == null
)) { )) {
return false; return false;
} }
@ -756,9 +812,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
//noinspection unchecked //noinspection unchecked
chunkLoadings.add( chunkLoadings.add(
((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>) ((CompletableFuture<Either<ChunkAccess, ChunkHolder.ChunkLoadingFailure>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.left().orElse(null)) .thenApply(either -> either.left().orElse(null))
); );
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Couldn't load chunk for regen.", e); throw new IllegalStateException("Couldn't load chunk for regen.", e);
@ -780,12 +836,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS, SideEffect.NEIGHBORS,
SideEffect.LIGHTING, SideEffect.LIGHTING,
SideEffect.VALIDATION, SideEffect.VALIDATION,
SideEffect.ENTITY_AI, SideEffect.ENTITY_AI,
SideEffect.EVENTS, SideEffect.EVENTS,
SideEffect.UPDATE SideEffect.UPDATE
); );
@Override @Override
@ -794,7 +850,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle(); ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
@ -805,6 +861,45 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; 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 // Code that is less likely to break
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -977,7 +1072,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server; this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField( Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah") Refraction.pickName("nextTickTime", "ag")
); );
if (tickField.getType() != long.class) { if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); 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 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 Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( 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) { PaperweightFakePlayer(ServerLevel world) {

Datei anzeigen

@ -27,17 +27,19 @@ import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state); int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId) return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId) ? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); : ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
} }
@Override @Override
@ -102,7 +104,14 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag 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.fromNativeBinary(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
} }
@Override @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 // Not sure why neighborChanged is deprecated
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
@ -153,8 +168,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { 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(); ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld(); CraftWorld craftWorld = world.getWorld();
@ -177,5 +190,4 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public void flush() { public void flush() {
} }
} }

Datei anzeigen

@ -15,8 +15,8 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction; import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -217,6 +217,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); 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 @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, 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.CacheLoader;
import com.google.common.cache.LoadingCache; import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets; import com.google.common.collect.Sets;
import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.Futures;
import com.mojang.serialization.Codec; import com.mojang.serialization.Codec;
@ -70,6 +71,7 @@ import com.sk89q.worldedit.util.nbt.ShortBinaryTag;
import com.sk89q.worldedit.util.nbt.StringBinaryTag; import com.sk89q.worldedit.util.nbt.StringBinaryTag;
import com.sk89q.worldedit.world.DataFixer; import com.sk89q.worldedit.world.DataFixer;
import com.sk89q.worldedit.world.RegenOptions; 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.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes; import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BaseBlock;
@ -81,12 +83,13 @@ import com.sk89q.worldedit.world.item.ItemType;
import net.minecraft.Util; import net.minecraft.Util;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder; import net.minecraft.core.Holder;
import net.minecraft.core.HolderSet;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess; import net.minecraft.core.RegistryAccess;
import net.minecraft.core.component.DataComponentPatch; import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.registries.Registries; import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps; import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.Tag;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.network.protocol.game.ClientboundEntityEventPacket; import net.minecraft.network.protocol.game.ClientboundEntityEventPacket;
import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceKey;
@ -97,6 +100,7 @@ import net.minecraft.server.level.ChunkResult;
import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.progress.ChunkProgressListener; import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.RandomSource;
import net.minecraft.util.StringRepresentable; import net.minecraft.util.StringRepresentable;
import net.minecraft.util.thread.BlockableEventLoop; import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.world.Clearable; import net.minecraft.world.Clearable;
@ -127,6 +131,7 @@ import net.minecraft.world.phys.BlockHitResult;
import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.World.Environment; import org.bukkit.World.Environment;
import org.bukkit.block.data.BlockData; import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftServer;
@ -142,6 +147,7 @@ import org.bukkit.generator.ChunkGenerator;
import org.spigotmc.SpigotConfig; import org.spigotmc.SpigotConfig;
import org.spigotmc.WatchdogThread; import org.spigotmc.WatchdogThread;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -149,6 +155,7 @@ import java.lang.reflect.Method;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
@ -163,7 +170,6 @@ import java.util.concurrent.ExecutionException;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.annotation.Nullable;
import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState; import static com.google.common.base.Preconditions.checkState;
@ -181,6 +187,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private final Field chunkProviderExecutorField; private final Field chunkProviderExecutorField;
private final Watchdog watchdog; private final Watchdog watchdog;
private static final RandomSource random = RandomSource.create();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Code that may break between versions of Minecraft // Code that may break between versions of Minecraft
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -198,13 +206,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
serverWorldsField.setAccessible(true); serverWorldsField.setAccessible(true);
getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod( getChunkFutureMethod = ServerChunkCache.class.getDeclaredMethod(
Refraction.pickName("getChunkFutureMainThread", "c"), Refraction.pickName("getChunkFutureMainThread", "c"),
int.class, int.class, ChunkStatus.class, boolean.class int.class, int.class, ChunkStatus.class, boolean.class
); );
getChunkFutureMethod.setAccessible(true); getChunkFutureMethod.setAccessible(true);
chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField( chunkProviderExecutorField = ServerChunkCache.class.getDeclaredField(
Refraction.pickName("mainThreadProcessor", "g") Refraction.pickName("mainThreadProcessor", "g")
); );
chunkProviderExecutorField.setAccessible(true); chunkProviderExecutorField.setAccessible(true);
@ -225,7 +233,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
Class.forName("org.spigotmc.SpigotConfig"); Class.forName("org.spigotmc.SpigotConfig");
SpigotConfig.config.set("world-settings.faweregentempworld.verbose", false); SpigotConfig.config.set("world-settings.worldeditregentempworld.verbose", false);
} catch (ClassNotFoundException ignored) { } catch (ClassNotFoundException ignored) {
} }
} }
@ -239,7 +247,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* Read the given NBT data into the given tile entity. * Read the given NBT data into the given tile entity.
* *
* @param tileEntity the 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) { static void readTagIntoTileEntity(net.minecraft.nbt.CompoundTag tag, BlockEntity tileEntity) {
tileEntity.loadWithComponents(tag, MinecraftServer.getServer().registryAccess()); tileEntity.loadWithComponents(tag, MinecraftServer.getServer().registryAccess());
@ -259,7 +267,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
/** /**
* Create an entity using the given entity ID. * Create an entity using the given entity ID.
* *
* @param id the entity ID * @param id the entity ID
* @param world the world * @param world the world
* @return an entity or null * @return an entity or null
*/ */
@ -272,7 +280,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* Write the given NBT data into the given entity. * Write the given NBT data into the given entity.
* *
* @param entity the entity * @param entity the entity
* @param tag the tag * @param tag the tag
*/ */
private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) { private static void readTagIntoEntity(net.minecraft.nbt.CompoundTag tag, Entity entity) {
entity.load(tag); entity.load(tag);
@ -282,21 +290,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
* Write the entity's NBT data to the given tag. * Write the entity's NBT data to the given tag.
* *
* @param entity the entity * @param entity the entity
* @param tag the tag * @param tag the tag
*/ */
private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) { private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag tag) {
entity.save(tag); entity.save(tag);
} }
private static Block getBlockFromType(BlockType blockType) { 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) { private static Item getItemFromType(ItemType itemType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse( return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(itemType.id()));
itemType.id()));
} }
@Override @Override
@ -327,14 +332,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
public BiomeType adapt(Biome biome) { public BiomeType adapt(Biome biome) {
var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey( var mcBiome = ((CraftServer) Bukkit.getServer()).getServer().registryAccess().registryOrThrow(Registries.BIOME).getKey(biome);
biome);
if (mcBiome == null) { if (mcBiome == null) {
return null; return null;
} }
return BiomeType.REGISTRY.get(mcBiome.toString()); 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 @Override
public BlockState getBlock(Location location) { public BlockState getBlock(Location location) {
checkNotNull(location); checkNotNull(location);
@ -348,14 +357,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4); LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z); final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos); final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
int internalId = Block.getId(blockData); return adapt(blockData);
BlockState state = BlockStateIdAccess.getBlockStateById(internalId);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
} }
@Override @Override
@ -385,7 +387,38 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override @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())); return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle()));
} }
@ -409,13 +442,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
private net.minecraft.world.level.block.state.BlockState applyProperties( private net.minecraft.world.level.block.state.BlockState applyProperties(
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer, StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> stateContainer,
net.minecraft.world.level.block.state.BlockState newState, net.minecraft.world.level.block.state.BlockState newState,
Map<Property<?>, Object> states Map<Property<?>, Object> states
) { ) {
for (Map.Entry<Property<?>, Object> state : states.entrySet()) { for (Map.Entry<Property<?>, Object> state : states.entrySet()) {
net.minecraft.world.level.block.state.properties.Property<?> property = net.minecraft.world.level.block.state.properties.Property<?> property =
stateContainer.getProperty(state.getKey().getName()); stateContainer.getProperty(state.getKey().getName());
Comparable<?> value = (Comparable) state.getValue(); Comparable<?> value = (Comparable) state.getValue();
// we may need to adapt this value, depending on the source prop // we may need to adapt this value, depending on the source prop
if (property instanceof DirectionProperty) { if (property instanceof DirectionProperty) {
@ -424,16 +457,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { } else if (property instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
String enumName = (String) value; String enumName = (String) value;
value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property) value = ((net.minecraft.world.level.block.state.properties.EnumProperty<?>) property)
.getValue(enumName).orElseThrow(() -> .getValue(enumName).orElseThrow(() ->
new IllegalStateException( new IllegalStateException(
"Enum property " + property.getName() + " does not contain " + enumName "Enum property " + property.getName() + " does not contain " + enumName
) )
); );
} }
newState = newState.setValue( newState = newState.setValue(
(net.minecraft.world.level.block.state.properties.Property) property, (net.minecraft.world.level.block.state.properties.Property) property,
(Comparable) value (Comparable) value
); );
} }
return newState; return newState;
@ -484,7 +517,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
createdEntity.absMoveTo(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); 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(); return createdEntity.getBukkitEntity();
} else { } else {
return null; return null;
@ -522,51 +555,33 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId()); return TranslatableComponent.of(CraftItemStack.asNMSCopy(BukkitAdapter.adapt(itemStack)).getDescriptionId());
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder 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<?>>() {
.newBuilder() @Override
.build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception {
@Override if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { } else if (state instanceof DirectionProperty) {
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); return new DirectionalProperty(state.getName(),
} else if (state instanceof DirectionProperty) { (List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).toList());
return new DirectionalProperty( } else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
state.getName(), return new EnumProperty(state.getName(),
(List<Direction>) state (List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).toList());
.getPossibleValues() } else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
.stream() return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
.map(e -> Direction.valueOf(((StringRepresentable) e) } else {
.getSerializedName() throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName());
.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({"rawtypes"}) @SuppressWarnings({ "rawtypes" })
@Override @Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) { public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
Map<String, Property<?>> properties = new TreeMap<>(); Map<String, Property<?>> properties = new TreeMap<>();
Block block = getBlockFromType(blockType); Block block = getBlockFromType(blockType);
StateDefinition<Block, net.minecraft.world.level.block.state.BlockState> blockStateList = 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()) { for (net.minecraft.world.level.block.state.properties.Property state : blockStateList.getProperties()) {
Property<?> property = PROPERTY_CACHE.getUnchecked(state); Property<?> property = PROPERTY_CACHE.getUnchecked(state);
properties.put(property.getName(), property); properties.put(property.getName(), property);
@ -577,8 +592,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) { public void sendFakeNBT(Player player, BlockVector3 pos, CompoundBinaryTag nbtData) {
var structureBlock = new StructureBlockEntity( var structureBlock = new StructureBlockEntity(
new BlockPos(pos.x(), pos.y(), pos.z()), new BlockPos(pos.x(), pos.y(), pos.z()),
Blocks.STRUCTURE_BLOCK.defaultBlockState() Blocks.STRUCTURE_BLOCK.defaultBlockState()
); );
structureBlock.setLevel(((CraftPlayer) player).getHandle().level()); structureBlock.setLevel(((CraftPlayer) player).getHandle().level());
((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create( ((CraftPlayer) player).getHandle().connection.send(ClientboundBlockEntityDataPacket.create(
@ -590,18 +605,18 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public void sendFakeOP(Player player) { public void sendFakeOP(Player player) {
((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket( ((CraftPlayer) player).getHandle().connection.send(new ClientboundEntityEventPacket(
((CraftPlayer) player).getHandle(), (byte) 28 ((CraftPlayer) player).getHandle(), (byte) 28
)); ));
} }
@Override @Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack item) { public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess(); final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
ItemStack stack = new ItemStack( ItemStack stack = new ItemStack(
registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(item.getType().id())), registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())),
item.getAmount() 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 final DataComponentPatch patch = COMPONENTS_CODEC
.parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt) .parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt)
.getOrThrow(); .getOrThrow();
@ -611,11 +626,11 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) { 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 ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final Tag tag = COMPONENTS_CODEC.encodeStart( CompoundTag tag = (CompoundTag) COMPONENTS_CODEC.encodeStart(
registryAccess.createSerializationContext(NbtOps.INSTANCE), registryAccess.createSerializationContext(NbtOps.INSTANCE),
nmsStack.getComponentsPatch() nmsStack.getComponentsPatch()
).getOrThrow(); ).getOrThrow();
return new BaseItemStack( return new BaseItemStack(
BukkitAdapter.asItemType(itemStack.getType()), BukkitAdapter.asItemType(itemStack.getType()),
@ -625,16 +640,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private final LoadingCache<ServerLevel, PaperweightFakePlayer> fakePlayers 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 @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; CraftWorld craftWorld = (CraftWorld) world;
ServerLevel worldServer = craftWorld.getHandle(); ServerLevel worldServer = craftWorld.getHandle();
ItemStack stack = CraftItemStack.asNMSCopy(adapt( ItemStack stack = CraftItemStack.asNMSCopy(adapt(
item instanceof BaseItemStack item instanceof BaseItemStack
? ((BaseItemStack) item) ? ((BaseItemStack) item)
: new BaseItemStack(item.getType(), item.getNbtReference(), 1) : new BaseItemStack(item.getType(), item.getNbtReference(), 1)
)); ));
PaperweightFakePlayer fakePlayer; PaperweightFakePlayer fakePlayer;
@ -645,8 +660,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack); fakePlayer.setItemInHand(InteractionHand.MAIN_HAND, stack);
fakePlayer.absMoveTo(position.x(), position.y(), position.z(), 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 BlockPos blockPos = new BlockPos(position.x(), position.y(), position.z());
final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos); final Vec3 blockVec = Vec3.atLowerCornerOf(blockPos);
@ -655,10 +669,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace); UseOnContext context = new UseOnContext(fakePlayer, InteractionHand.MAIN_HAND, rayTrace);
InteractionResult result = stack.useOn(context); InteractionResult result = stack.useOn(context);
if (result != InteractionResult.SUCCESS) { if (result != InteractionResult.SUCCESS) {
if (worldServer if (worldServer.getBlockState(blockPos).useItemOn(stack, worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace).consumesAction()) {
.getBlockState(blockPos)
.useItemOn(stack, worldServer, fakePlayer, InteractionHand.MAIN_HAND, rayTrace)
.consumesAction()) {
result = InteractionResult.SUCCESS; result = InteractionResult.SUCCESS;
} else { } else {
result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult(); result = stack.getItem().use(worldServer, fakePlayer, InteractionHand.MAIN_HAND).getResult();
@ -669,17 +680,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @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); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId); net.minecraft.world.level.block.state.BlockState blockData = Block.stateById(internalId);
return blockData.canSurvive( return blockData.canSurvive(((CraftWorld) world).getHandle(), new BlockPos(position.x(), position.y(), position.z()));
((CraftWorld) world).getHandle(),
new BlockPos(position.x(), position.y(), position.z())
);
} }
@Override @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 { try {
doRegen(bukkitWorld, region, extent, options); doRegen(bukkitWorld, region, extent, options);
} catch (Exception e) { } catch (Exception e) {
@ -689,66 +697,62 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return true; 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(); Environment env = bukkitWorld.getEnvironment();
ChunkGenerator gen = bukkitWorld.getGenerator(); ChunkGenerator gen = bukkitWorld.getGenerator();
Path tempDir = Files.createTempDirectory("WorldEditWorldGen"); Path tempDir = Files.createTempDirectory("WorldEditWorldGen");
LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir); LevelStorageSource levelStorage = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env); ResourceKey<LevelStem> worldDimKey = getWorldDimKey(env);
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("worldeditregentempworld", worldDimKey)) {
ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle(); ServerLevel originalWorld = ((CraftWorld) bukkitWorld).getHandle();
PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer() PrimaryLevelData levelProperties = (PrimaryLevelData) originalWorld.getServer()
.getWorldData().overworldData(); .getWorldData().overworldData();
WorldOptions originalOpts = levelProperties.worldGenOptions(); WorldOptions originalOpts = levelProperties.worldGenOptions();
long seed = options.getSeed().orElse(originalWorld.getSeed()); long seed = options.getSeed().orElse(originalWorld.getSeed());
WorldOptions newOpts = options.getSeed().isPresent() WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed)) ? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts; : originalOpts;
LevelSettings newWorldSettings = new LevelSettings( LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld", "worldeditregentempworld",
levelProperties.settings.gameType(), levelProperties.settings.gameType(),
levelProperties.settings.hardcore(), levelProperties.settings.hardcore(),
levelProperties.settings.difficulty(), levelProperties.settings.difficulty(),
levelProperties.settings.allowCommands(), levelProperties.settings.allowCommands(),
levelProperties.settings.gameRules(), levelProperties.settings.gameRules(),
levelProperties.settings.getDataConfiguration() levelProperties.settings.getDataConfiguration()
); );
@SuppressWarnings("deprecation")
PrimaryLevelData.SpecialWorldProperty specialWorldProperty = PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
levelProperties.isFlatWorld() levelProperties.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT ? PrimaryLevelData.SpecialWorldProperty.FLAT
: levelProperties.isDebugWorld() : levelProperties.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG ? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE; : PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData( PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
newWorldSettings,
newOpts,
specialWorldProperty,
Lifecycle.stable()
);
ServerLevel freshWorld = new ServerLevel( ServerLevel freshWorld = new ServerLevel(
originalWorld.getServer(), originalWorld.getServer(),
originalWorld.getServer().executor, originalWorld.getServer().executor,
session, newWorldData, session, newWorldData,
originalWorld.dimension(), originalWorld.dimension(),
new LevelStem( new LevelStem(
originalWorld.dimensionTypeRegistration(), originalWorld.dimensionTypeRegistration(),
originalWorld.getChunkSource().getGenerator() originalWorld.getChunkSource().getGenerator()
), ),
new NoOpWorldLoadListener(), new NoOpWorldLoadListener(),
originalWorld.isDebug(), originalWorld.isDebug(),
seed, seed,
ImmutableList.of(), ImmutableList.of(),
false, false,
originalWorld.getRandomSequences(), originalWorld.getRandomSequences(),
env, env,
gen, gen,
bukkitWorld.getBiomeProvider() bukkitWorld.getBiomeProvider()
); );
try { try {
regenForWorld(region, extent, freshWorld, options); regenForWorld(region, extent, freshWorld, options);
@ -758,8 +762,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} finally { } finally {
try { try {
@SuppressWarnings("unchecked") @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"); map.remove("worldeditregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
SafeFiles.tryHardToDeleteDir(tempDir); SafeFiles.tryHardToDeleteDir(tempDir);
@ -775,8 +779,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws private void regenForWorld(Region region, Extent extent, ServerLevel serverWorld, RegenOptions options) throws WorldEditException {
WorldEditException {
List<CompletableFuture<ChunkAccess>> chunkLoadings = submitChunkLoadTasks(region, serverWorld); List<CompletableFuture<ChunkAccess>> chunkLoadings = submitChunkLoadTasks(region, serverWorld);
BlockableEventLoop<Runnable> executor; BlockableEventLoop<Runnable> executor;
try { try {
@ -787,7 +790,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
executor.managedBlock(() -> { executor.managedBlock(() -> {
// bail out early if a future fails // bail out early if a future fails
if (chunkLoadings.stream().anyMatch(ftr -> if (chunkLoadings.stream().anyMatch(ftr ->
ftr.isDone() && Futures.getUnchecked(ftr) == null ftr.isDone() && Futures.getUnchecked(ftr) == null
)) { )) {
return false; return false;
} }
@ -833,9 +836,9 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try { try {
//noinspection unchecked //noinspection unchecked
chunkLoadings.add( chunkLoadings.add(
((CompletableFuture<ChunkResult<ChunkAccess>>) ((CompletableFuture<ChunkResult<ChunkAccess>>)
getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true)) getChunkFutureMethod.invoke(chunkManager, chunk.x(), chunk.z(), ChunkStatus.FEATURES, true))
.thenApply(either -> either.orElse(null)) .thenApply(either -> either.orElse(null))
); );
} catch (IllegalAccessException | InvocationTargetException e) { } catch (IllegalAccessException | InvocationTargetException e) {
throw new IllegalStateException("Couldn't load chunk for regen.", e); throw new IllegalStateException("Couldn't load chunk for regen.", e);
@ -857,12 +860,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( private static final Set<SideEffect> SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet(
SideEffect.NEIGHBORS, SideEffect.NEIGHBORS,
SideEffect.LIGHTING, SideEffect.LIGHTING,
SideEffect.VALIDATION, SideEffect.VALIDATION,
SideEffect.ENTITY_AI, SideEffect.ENTITY_AI,
SideEffect.EVENTS, SideEffect.EVENTS,
SideEffect.UPDATE SideEffect.UPDATE
); );
@Override @Override
@ -871,7 +874,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public boolean clearContainerBlockContents(org.bukkit.World world, BlockVector3 pt) { public boolean clearContainerBlockContents(World world, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle(); ServerLevel originalWorld = ((CraftWorld) world).getHandle();
BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z())); BlockEntity entity = originalWorld.getBlockEntity(new BlockPos(pt.x(), pt.y(), pt.z()));
@ -882,6 +885,45 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; 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 // Code that is less likely to break
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -1021,7 +1063,6 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
private class SpigotWatchdog implements Watchdog { private class SpigotWatchdog implements Watchdog {
private final Field instanceField; private final Field instanceField;
private final Field lastTickField; private final Field lastTickField;
@ -1046,18 +1087,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
logger.log(Level.WARNING, "Failed to tick watchdog", e); logger.log(Level.WARNING, "Failed to tick watchdog", e);
} }
} }
} }
private static class MojangWatchdog implements Watchdog { private static class MojangWatchdog implements Watchdog {
private final DedicatedServer server; private final DedicatedServer server;
private final Field tickField; private final Field tickField;
MojangWatchdog(DedicatedServer server) throws NoSuchFieldException { MojangWatchdog(DedicatedServer server) throws NoSuchFieldException {
this.server = server; this.server = server;
Field tickField = MinecraftServer.class.getDeclaredField( Field tickField = MinecraftServer.class.getDeclaredField(
Refraction.pickName("nextTickTime", "ah") Refraction.pickName("nextTickTime", "ag")
); );
if (tickField.getType() != long.class) { if (tickField.getType() != long.class) {
throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect"); throw new IllegalStateException("nextTickTime is not a long field, mapping is likely incorrect");
@ -1073,21 +1112,15 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
} }
} }
private static class NoOpWorldLoadListener implements ChunkProgressListener { private static class NoOpWorldLoadListener implements ChunkProgressListener {
@Override @Override
public void updateSpawnPos(ChunkPos spawnPos) { public void updateSpawnPos(ChunkPos spawnPos) {
} }
@Override @Override
public void onStatusChange( public void onStatusChange(ChunkPos pos, @org.jetbrains.annotations.Nullable ChunkStatus status) {
final ChunkPos pos,
@org.jetbrains.annotations.Nullable final net.minecraft.world.level.chunk.status.ChunkStatus status
) {
} }
@Override @Override
@ -1099,5 +1132,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 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 Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation( 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) { PaperweightFakePlayer(ServerLevel world) {

Datei anzeigen

@ -27,17 +27,19 @@ import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.nbt.CompoundBinaryTag; import com.sk89q.worldedit.util.nbt.CompoundBinaryTag;
import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk; import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent; import org.bukkit.event.block.BlockPhysicsEvent;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.Objects; import java.util.Objects;
import javax.annotation.Nullable;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> { public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1; private static final int UPDATE = 1;
@ -70,8 +72,8 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) { public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state); int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId) return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId) ? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState(); : ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
} }
@Override @Override
@ -102,7 +104,14 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag tag) { public boolean updateTileEntity(final BlockPos position, final CompoundBinaryTag 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.fromNativeBinary(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
} }
@Override @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) { private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false); world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false);
} }
@ -152,8 +166,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) { 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(); ServerLevel world = getWorld();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit); oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) { if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld(); CraftWorld craftWorld = world.getWorld();
@ -174,7 +186,6 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
@Override @Override
public void flush() { public void flush() {
} }
} }

Datei anzeigen

@ -16,8 +16,8 @@ import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer; import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.FullChunkStatus; import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level; import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntity;
@ -218,6 +218,12 @@ public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<Level
newState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit); 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 @Override
public void onBlockStateChange( public void onBlockStateChange(
BlockPos blockPos, BlockPos blockPos,

Datei anzeigen

@ -35,6 +35,7 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess; import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.registry.state.Property;
@ -110,7 +111,7 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
BlockState getBlock(Location location); 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 * @param location the location
* @return the block * @return the block
@ -280,6 +281,46 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
throw new UnsupportedOperationException("This adapter does not support clearing block contents."); 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 //FAWE start
default BlockMaterial getMaterial(BlockType blockType) { default BlockMaterial getMaterial(BlockType blockType) {
return getMaterial(blockType.getDefaultState()); return getMaterial(blockType.getDefaultState());

Datei anzeigen

@ -151,7 +151,9 @@ public interface WorldNativeAccess<NC, NBS, NP> {
void markBlockChanged(NC chunk, NP position); 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); 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.HashSet;
import java.util.Set; import java.util.Set;
import java.util.function.Supplier;
//FAWE start - implements RegistryItem //FAWE start - implements RegistryItem
public abstract class Category<T extends Keyed> implements RegistryItem, Keyed { public abstract class Category<T extends Keyed> implements RegistryItem, Keyed {
//FAWE end //FAWE end
private final Set<T> set = new HashSet<>(); private final Set<T> set = new HashSet<>();
private final Supplier<Set<T>> supplier;
protected final String id; protected final String id;
private boolean empty = true; private boolean empty = true;
protected Category(final String id) { public Category(final String id) {
this.id = id; this.id = id;
this.supplier = null;
}
public Category(final String id, final Supplier<Set<T>> contentSupplier) {
this.id = id;
this.supplier = contentSupplier;
} }
@Override @Override
@ -43,7 +51,11 @@ public abstract class Category<T extends Keyed> implements RegistryItem, Keyed {
public final Set<T> getAll() { public final Set<T> getAll() {
if (this.empty) { 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; this.empty = false;
} }
return this.set; return this.set;
@ -62,6 +74,14 @@ public abstract class Category<T extends Keyed> implements RegistryItem, Keyed {
return internalId; 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(); protected abstract Set<T> load();
//FAWE end //FAWE end