3
0
Mirror von https://github.com/IntellectualSites/FastAsyncWorldEdit.git synchronisiert 2024-11-19 09:20:08 +01:00

Merge branch 'main' into feat/feature-placement

# Conflicts:
#	worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_19_R3/PaperweightAdapter.java
#	worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R1/PaperweightAdapter.java
#	worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java
#	worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R3/PaperweightAdapter.java
#	worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java
Dieser Commit ist enthalten in:
dordsor21 2024-06-27 15:17:37 +01:00
Commit 3e847d05a7
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 1E53E88969FFCF0B
25 geänderte Dateien mit 1022 neuen und 421 gelöschten Zeilen

Datei anzeigen

@ -58,7 +58,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
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.World; 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;
@ -71,6 +71,9 @@ import com.sk89q.worldedit.world.generation.StructureType;
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.SectionPos; import net.minecraft.core.SectionPos;
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;
@ -119,6 +122,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_19_R3.CraftServer; import org.bukkit.craftbukkit.v1_19_R3.CraftServer;
@ -305,6 +309,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();
@ -384,7 +396,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world) {
return new PaperweightWorldNativeAccess(this, return new PaperweightWorldNativeAccess(this,
new WeakReference<>(((CraftWorld) world).getHandle())); new WeakReference<>(((CraftWorld) world).getHandle()));
} }
@ -523,24 +535,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder
@Override .newBuilder()
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { .build(new CacheLoader<>() {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { @Override
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) {
} else if (state instanceof DirectionProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new DirectionalProperty(state.getName(), return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); } else if (state instanceof DirectionProperty) {
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { return new DirectionalProperty(
return new EnumProperty(state.getName(), state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); new ArrayList<>((List<Direction>) state
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { .getPossibleValues()
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); .stream()
} else { .map(e -> Direction.valueOf(((StringRepresentable) e)
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); .getSerializedName()
} .toUpperCase(Locale.ROOT)))
} .toList())
}); );
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(
state.getName(),
new ArrayList<>((List<String>) state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
}
}
});
@SuppressWarnings({ "rawtypes" }) @SuppressWarnings({ "rawtypes" })
@Override @Override
@ -596,7 +626,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
= 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(BukkitAdapter.adapt(item instanceof BaseItemStack ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack
@ -631,14 +661,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) {
@ -648,7 +678,7 @@ 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();
@ -711,7 +741,7 @@ 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("faweregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
@ -823,7 +853,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()));
@ -857,6 +887,23 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); 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) { public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) {

Datei anzeigen

@ -154,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
} }
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated // 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

@ -58,6 +58,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
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;
@ -71,6 +72,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.SectionPos; import net.minecraft.core.SectionPos;
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;
@ -333,6 +336,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return state; 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) { public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
return Block.stateById(internalId); return Block.stateById(internalId);
@ -417,7 +428,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
}*/ }*/
@Override @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(World world) {
return new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightWorldNativeAccess(this, return new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R1.PaperweightWorldNativeAccess(this,
new WeakReference<>(((CraftWorld) world).getHandle())); new WeakReference<>(((CraftWorld) world).getHandle()));
} }
@ -556,24 +567,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder
@Override .newBuilder()
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { .build(new CacheLoader<>() {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { @Override
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) {
} else if (state instanceof DirectionProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new DirectionalProperty(state.getName(), return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); } else if (state instanceof DirectionProperty) {
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { return new DirectionalProperty(
return new EnumProperty(state.getName(), state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); new ArrayList<>((List<Direction>) state
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { .getPossibleValues()
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); .stream()
} else { .map(e -> Direction.valueOf(((StringRepresentable) e)
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); .getSerializedName()
} .toUpperCase(Locale.ROOT)))
} .toList())
}); );
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(
state.getName(),
new ArrayList<>((List<String>) state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
}
}
});
@SuppressWarnings({ "rawtypes" }) @SuppressWarnings({ "rawtypes" })
@Override @Override
@ -600,17 +629,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(
@ -640,7 +658,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
= 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(BukkitAdapter.adapt(item instanceof BaseItemStack ItemStack stack = CraftItemStack.asNMSCopy(BukkitAdapter.adapt(item instanceof BaseItemStack
@ -675,14 +693,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) {
@ -692,7 +710,7 @@ 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();
@ -756,7 +774,7 @@ 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("faweregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
@ -868,7 +886,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()));
@ -879,7 +897,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return false; return false;
} }
/*@Override @Override
public void initializeRegistries() { public void initializeRegistries() {
DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer(); DedicatedServer server = ((CraftServer) Bukkit.getServer()).getServer();
// Biomes // Biomes
@ -902,7 +920,24 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); 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()))
);
}
});
}
@Override @Override
public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) { public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) {
@ -913,6 +948,7 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z())); return k != null && k.place(proxyLevel, chunkManager.getGenerator(), random, new BlockPos(pt.x(), pt.y(), pt.z()));
} }
@Override
public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) { public boolean generateStructure(StructureType type, World world, EditSession session, BlockVector3 pt) {
ServerLevel originalWorld = ((CraftWorld) world).getHandle(); ServerLevel originalWorld = ((CraftWorld) world).getHandle();
Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.id())); Structure k = originalWorld.registryAccess().registryOrThrow(Registries.STRUCTURE).get(ResourceLocation.tryParse(type.id()));

Datei anzeigen

@ -154,6 +154,12 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
} }
} }
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
// Not sure why neighborChanged is deprecated // 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

@ -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;
@ -58,6 +59,7 @@ import com.sk89q.worldedit.util.io.file.SafeFiles;
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.World; import com.sk89q.worldedit.world.World;
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;
@ -71,6 +73,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.SectionPos; import net.minecraft.core.SectionPos;
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;
@ -158,6 +162,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;
@ -204,13 +209,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);
@ -295,7 +300,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()));
} }
@ -330,6 +334,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return state; 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) { public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
return Block.stateById(internalId); return Block.stateById(internalId);
@ -348,14 +360,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
@ -384,9 +389,41 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
private static final HashMap<BiomeType, Holder<Biome>> biomeTypeToNMSCache = new HashMap<>(); private static final HashMap<BiomeType, Holder<Biome>> biomeTypeToNMSCache = new HashMap<>();
private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>(); private static final HashMap<Holder<Biome>, BiomeType> biomeTypeFromNMSCache = new HashMap<>();
@Override
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 @Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) { public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightWorldNativeAccess(this, new WeakReference<>(((CraftWorld) world).getHandle())); 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) {
@ -409,13 +446,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 +461,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;
@ -523,24 +560,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder
@Override .newBuilder()
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { .build(new CacheLoader<>() {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { @Override
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) {
} else if (state instanceof DirectionProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new DirectionalProperty(state.getName(), return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); } else if (state instanceof DirectionProperty) {
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { return new DirectionalProperty(
return new EnumProperty(state.getName(), state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); new ArrayList<>((List<Direction>) state
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { .getPossibleValues()
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); .stream()
} else { .map(e -> Direction.valueOf(((StringRepresentable) e)
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); .getSerializedName()
} .toUpperCase(Locale.ROOT)))
} .toList())
}); );
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(
state.getName(),
new ArrayList<>((List<String>) state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
}
}
});
@SuppressWarnings({ "rawtypes" }) @SuppressWarnings({ "rawtypes" })
@Override @Override
@ -548,7 +603,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);
@ -570,15 +625,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);
@ -593,7 +648,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) {
@ -611,7 +666,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);
@ -658,51 +713,52 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", 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", "faweregentempworld",
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);
@ -712,7 +768,7 @@ 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("faweregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
@ -740,7 +796,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;
} }
@ -786,9 +842,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);
@ -810,12 +866,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
@ -858,6 +914,23 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); 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) { public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) {
@ -891,6 +964,17 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
} }
@Override
public void sendBiomeUpdates(org.bukkit.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
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -1062,7 +1146,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

@ -26,9 +26,11 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
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;
@ -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 LinCompoundTag tag) { public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) {
return false; // We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false;
}
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
} }
@Override @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

@ -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.datafixers.util.Either; import com.mojang.datafixers.util.Either;
@ -57,7 +58,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
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.World; 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;
@ -71,6 +72,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.SectionPos; import net.minecraft.core.SectionPos;
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;
@ -119,6 +122,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;
@ -158,6 +162,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;
@ -204,13 +209,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);
@ -295,7 +300,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()));
} }
@ -330,6 +334,14 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
return state; 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) { public net.minecraft.world.level.block.state.BlockState adapt(BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState); int internalId = BlockStateIdAccess.getBlockStateId(blockState);
return Block.stateById(internalId); return Block.stateById(internalId);
@ -348,14 +360,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 +390,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 +445,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 +460,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;
@ -523,24 +559,42 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({ "unchecked", "rawtypes" })
private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder.newBuilder().build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { private static final LoadingCache<net.minecraft.world.level.block.state.properties.Property, Property<?>> PROPERTY_CACHE = CacheBuilder
@Override .newBuilder()
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { .build(new CacheLoader<>() {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { @Override
return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) {
} else if (state instanceof DirectionProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
return new DirectionalProperty(state.getName(), return new BooleanProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
(List<Direction>) state.getPossibleValues().stream().map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase(Locale.ROOT))).collect(Collectors.toList())); } else if (state instanceof DirectionProperty) {
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) { return new DirectionalProperty(
return new EnumProperty(state.getName(), state.getName(),
(List<String>) state.getPossibleValues().stream().map(e -> ((StringRepresentable) e).getSerializedName()).collect(Collectors.toList())); new ArrayList<>((List<Direction>) state
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) { .getPossibleValues()
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues())); .stream()
} else { .map(e -> Direction.valueOf(((StringRepresentable) e)
throw new IllegalArgumentException("WorldEdit needs an update to support " + state.getClass().getSimpleName()); .getSerializedName()
} .toUpperCase(Locale.ROOT)))
} .toList())
}); );
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
return new EnumProperty(
state.getName(),
new ArrayList<>((List<String>) state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
return new IntegerProperty(state.getName(), ImmutableList.copyOf(state.getPossibleValues()));
} else {
throw new IllegalArgumentException("WorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
}
}
});
@SuppressWarnings({ "rawtypes" }) @SuppressWarnings({ "rawtypes" })
@Override @Override
@ -548,7 +602,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);
@ -570,15 +624,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);
@ -611,7 +665,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);
@ -631,14 +685,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) {
@ -648,7 +702,7 @@ 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();
@ -658,51 +712,52 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", 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", "faweregentempworld",
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);
@ -712,7 +767,7 @@ 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("faweregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
@ -740,7 +795,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;
} }
@ -786,9 +841,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);
@ -810,12 +865,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
@ -824,7 +879,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()));
@ -858,6 +913,23 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
StructureType.REGISTRY.register(name.toString(), new StructureType(name.toString())); 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) { public boolean generateFeature(ConfiguredFeatureType type, World world, EditSession session, BlockVector3 pt) {
@ -891,6 +963,16 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
} }
@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
@ -1063,7 +1145,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

@ -19,7 +19,6 @@
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3; package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3;
import com.sk89q.jnbt.CompoundTag;
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;
@ -73,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
@ -110,7 +109,7 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
if (tileEntity == null) { if (tileEntity == null) {
return false; return false;
} }
Tag nativeTag = adapter.fromNative(new CompoundTag(tag)); Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity); PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true; return true;
} }
@ -154,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) {
@ -163,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();
@ -187,5 +190,4 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public void flush() { public void flush() {
} }
} }

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

@ -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;
@ -56,6 +57,7 @@ import com.sk89q.worldedit.util.formatting.text.TranslatableComponent;
import com.sk89q.worldedit.util.io.file.SafeFiles; import com.sk89q.worldedit.util.io.file.SafeFiles;
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;
@ -67,12 +69,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;
@ -83,6 +86,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;
@ -113,6 +117,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;
@ -152,6 +157,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;
@ -183,6 +189,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
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -200,13 +208,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);
@ -241,7 +249,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());
@ -261,7 +269,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
*/ */
@ -274,7 +282,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);
@ -284,21 +292,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
@ -329,14 +334,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);
@ -350,14 +359,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
@ -387,7 +389,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()));
} }
@ -411,13 +444,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) {
@ -426,16 +459,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;
@ -486,7 +519,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;
@ -527,30 +560,30 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@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() .newBuilder()
.build(new CacheLoader<net.minecraft.world.level.block.state.properties.Property, Property<?>>() { .build(new CacheLoader<>() {
@Override @Override
public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) throws Exception { public Property<?> load(net.minecraft.world.level.block.state.properties.Property state) {
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) { if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
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( return new DirectionalProperty(
state.getName(), state.getName(),
(List<Direction>) state new ArrayList<>((List<Direction>) state
.getPossibleValues() .getPossibleValues()
.stream() .stream()
.map(e -> Direction.valueOf(((StringRepresentable) e) .map(e -> Direction.valueOf(((StringRepresentable) e)
.getSerializedName() .getSerializedName()
.toUpperCase(Locale.ROOT))) .toUpperCase(Locale.ROOT)))
.collect(Collectors.toList()) .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( return new EnumProperty(
state.getName(), state.getName(),
(List<String>) state new ArrayList<>((List<String>) state
.getPossibleValues() .getPossibleValues()
.stream() .stream()
.map(e -> ((StringRepresentable) e).getSerializedName()) .map(e -> ((StringRepresentable) e).getSerializedName())
.collect(Collectors.toList()) .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()));
@ -562,13 +595,13 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
} }
}); });
@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);
@ -579,8 +612,8 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
@Override @Override
public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag nbtData) { public void sendFakeNBT(Player player, BlockVector3 pos, LinCompoundTag 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(
@ -592,18 +625,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();
@ -613,11 +646,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()),
@ -627,16 +660,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;
@ -647,8 +680,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);
@ -657,10 +689,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();
@ -671,17 +700,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) {
@ -691,7 +717,7 @@ 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();
@ -701,56 +727,52 @@ public final class PaperweightAdapter implements BukkitImplAdapter<net.minecraft
try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", worldDimKey)) { try (LevelStorageSource.LevelStorageAccess session = levelStorage.createAccess("faweregentempworld", 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", "faweregentempworld",
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);
@ -760,7 +782,7 @@ 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("faweregentempworld");
} catch (IllegalAccessException ignored) { } catch (IllegalAccessException ignored) {
} }
@ -777,8 +799,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 {
@ -789,7 +810,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;
} }
@ -835,9 +856,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);
@ -859,12 +880,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
@ -873,7 +894,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()));
@ -884,6 +905,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
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
@ -1022,7 +1082,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;
@ -1047,18 +1106,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");
@ -1074,21 +1131,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
@ -1100,5 +1151,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

@ -26,9 +26,11 @@ import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.SideEffectSet;
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;
@ -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 LinCompoundTag tag) { public boolean updateTileEntity(final BlockPos position, final LinCompoundTag tag) {
return false; // We will assume that the tile entity was created for us
BlockEntity tileEntity = getWorld().getBlockEntity(position);
if (tileEntity == null) {
return false;
}
Tag nativeTag = adapter.fromNativeLin(tag);
PaperweightAdapter.readTagIntoTileEntity((net.minecraft.nbt.CompoundTag) nativeTag, tileEntity);
return true;
} }
@Override @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();
@ -176,5 +188,4 @@ public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChun
public void flush() { public void flush() {
} }
} }

Datei anzeigen

@ -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

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

Datei anzeigen

@ -36,6 +36,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;
@ -113,7 +114,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
@ -313,6 +314,26 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
throw new UnsupportedOperationException("This adapter does not support generating features."); throw new UnsupportedOperationException("This adapter does not support generating features.");
} }
/**
* 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. * Initialize registries that require NMS access.
*/ */
@ -320,6 +341,19 @@ public interface BukkitImplAdapter<T> extends IBukkitAdapter {
} }
/**
* 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

@ -9,9 +9,9 @@ import com.fastasyncworldedit.core.internal.io.FaweInputStream;
import com.fastasyncworldedit.core.internal.io.FaweOutputStream; import com.fastasyncworldedit.core.internal.io.FaweOutputStream;
import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate; import com.fastasyncworldedit.core.jnbt.streamer.StreamDelegate;
import com.fastasyncworldedit.core.jnbt.streamer.ValueReader; import com.fastasyncworldedit.core.jnbt.streamer.ValueReader;
import com.sk89q.jnbt.LinBusConverter;
import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.IntTag; import com.sk89q.jnbt.IntTag;
import com.sk89q.jnbt.LinBusConverter;
import com.sk89q.jnbt.NBTInputStream; import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.StringTag; import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag; import com.sk89q.jnbt.Tag;
@ -109,26 +109,22 @@ public class FastSchematicReader extends NBTSchematicReader {
if (fixer == null || dataVersion == -1) { if (fixer == null || dataVersion == -1) {
return tag; return tag;
} }
//FAWE start - LinTag
return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp(
DataFixer.FixTypes.BLOCK_ENTITY, DataFixer.FixTypes.BLOCK_ENTITY,
tag.toLinTag(), tag.toLinTag(),
dataVersion dataVersion
)); ));
//FAWE end
} }
private CompoundTag fixEntity(CompoundTag tag) { private CompoundTag fixEntity(CompoundTag tag) {
if (fixer == null || dataVersion == -1) { if (fixer == null || dataVersion == -1) {
return tag; return tag;
} }
//FAWE start - LinTag
return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp( return (CompoundTag) LinBusConverter.fromLinBus(fixer.fixUp(
DataFixer.FixTypes.ENTITY, DataFixer.FixTypes.ENTITY,
tag.toLinTag(), tag.toLinTag(),
dataVersion dataVersion
)); ));
//FAWE end
} }
private String fixBiome(String biomePalettePart) { private String fixBiome(String biomePalettePart) {

Datei anzeigen

@ -146,7 +146,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(String id, 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

Datei anzeigen

@ -0,0 +1,112 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.biome;
/**
* Stores a list of common {@link BiomeCategory BiomeCategories}.
*
* @see BiomeCategory
*/
@SuppressWarnings("unused")
public final class BiomeCategories {
public static final BiomeCategory ALLOWS_SURFACE_SLIME_SPAWNS = get("minecraft:allows_surface_slime_spawns");
public static final BiomeCategory ALLOWS_TROPICAL_FISH_SPAWNS_AT_ANY_HEIGHT = get("minecraft:allows_tropical_fish_spawns_at_any_height");
public static final BiomeCategory HAS_CLOSER_WATER_FOG = get("minecraft:has_closer_water_fog");
public static final BiomeCategory HAS_STRUCTURE_ANCIENT_CITY = get("minecraft:has_structure/ancient_city");
public static final BiomeCategory HAS_STRUCTURE_BASTION_REMNANT = get("minecraft:has_structure/bastion_remnant");
public static final BiomeCategory HAS_STRUCTURE_BURIED_TREASURE = get("minecraft:has_structure/buried_treasure");
public static final BiomeCategory HAS_STRUCTURE_DESERT_PYRAMID = get("minecraft:has_structure/desert_pyramid");
public static final BiomeCategory HAS_STRUCTURE_END_CITY = get("minecraft:has_structure/end_city");
public static final BiomeCategory HAS_STRUCTURE_IGLOO = get("minecraft:has_structure/igloo");
public static final BiomeCategory HAS_STRUCTURE_JUNGLE_TEMPLE = get("minecraft:has_structure/jungle_temple");
public static final BiomeCategory HAS_STRUCTURE_MINESHAFT = get("minecraft:has_structure/mineshaft");
public static final BiomeCategory HAS_STRUCTURE_MINESHAFT_MESA = get("minecraft:has_structure/mineshaft_mesa");
public static final BiomeCategory HAS_STRUCTURE_NETHER_FORTRESS = get("minecraft:has_structure/nether_fortress");
public static final BiomeCategory HAS_STRUCTURE_NETHER_FOSSIL = get("minecraft:has_structure/nether_fossil");
public static final BiomeCategory HAS_STRUCTURE_OCEAN_MONUMENT = get("minecraft:has_structure/ocean_monument");
public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_COLD = get("minecraft:has_structure/ocean_ruin_cold");
public static final BiomeCategory HAS_STRUCTURE_OCEAN_RUIN_WARM = get("minecraft:has_structure/ocean_ruin_warm");
public static final BiomeCategory HAS_STRUCTURE_PILLAGER_OUTPOST = get("minecraft:has_structure/pillager_outpost");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_DESERT = get("minecraft:has_structure/ruined_portal_desert");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_JUNGLE = get("minecraft:has_structure/ruined_portal_jungle");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_MOUNTAIN = get("minecraft:has_structure/ruined_portal_mountain");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_NETHER = get("minecraft:has_structure/ruined_portal_nether");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_OCEAN = get("minecraft:has_structure/ruined_portal_ocean");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_STANDARD = get("minecraft:has_structure/ruined_portal_standard");
public static final BiomeCategory HAS_STRUCTURE_RUINED_PORTAL_SWAMP = get("minecraft:has_structure/ruined_portal_swamp");
public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK = get("minecraft:has_structure/shipwreck");
public static final BiomeCategory HAS_STRUCTURE_SHIPWRECK_BEACHED = get("minecraft:has_structure/shipwreck_beached");
public static final BiomeCategory HAS_STRUCTURE_STRONGHOLD = get("minecraft:has_structure/stronghold");
public static final BiomeCategory HAS_STRUCTURE_SWAMP_HUT = get("minecraft:has_structure/swamp_hut");
public static final BiomeCategory HAS_STRUCTURE_TRAIL_RUINS = get("minecraft:has_structure/trail_ruins");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_DESERT = get("minecraft:has_structure/village_desert");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_PLAINS = get("minecraft:has_structure/village_plains");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SAVANNA = get("minecraft:has_structure/village_savanna");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_SNOWY = get("minecraft:has_structure/village_snowy");
public static final BiomeCategory HAS_STRUCTURE_VILLAGE_TAIGA = get("minecraft:has_structure/village_taiga");
public static final BiomeCategory HAS_STRUCTURE_WOODLAND_MANSION = get("minecraft:has_structure/woodland_mansion");
public static final BiomeCategory INCREASED_FIRE_BURNOUT = get("minecraft:increased_fire_burnout");
public static final BiomeCategory IS_BADLANDS = get("minecraft:is_badlands");
public static final BiomeCategory IS_BEACH = get("minecraft:is_beach");
public static final BiomeCategory IS_DEEP_OCEAN = get("minecraft:is_deep_ocean");
public static final BiomeCategory IS_END = get("minecraft:is_end");
public static final BiomeCategory IS_FOREST = get("minecraft:is_forest");
public static final BiomeCategory IS_HILL = get("minecraft:is_hill");
public static final BiomeCategory IS_JUNGLE = get("minecraft:is_jungle");
public static final BiomeCategory IS_MOUNTAIN = get("minecraft:is_mountain");
public static final BiomeCategory IS_NETHER = get("minecraft:is_nether");
public static final BiomeCategory IS_OCEAN = get("minecraft:is_ocean");
public static final BiomeCategory IS_OVERWORLD = get("minecraft:is_overworld");
public static final BiomeCategory IS_RIVER = get("minecraft:is_river");
public static final BiomeCategory IS_SAVANNA = get("minecraft:is_savanna");
public static final BiomeCategory IS_TAIGA = get("minecraft:is_taiga");
public static final BiomeCategory MINESHAFT_BLOCKING = get("minecraft:mineshaft_blocking");
public static final BiomeCategory MORE_FREQUENT_DROWNED_SPAWNS = get("minecraft:more_frequent_drowned_spawns");
public static final BiomeCategory PLAYS_UNDERWATER_MUSIC = get("minecraft:plays_underwater_music");
public static final BiomeCategory POLAR_BEARS_SPAWN_ON_ALTERNATE_BLOCKS = get("minecraft:polar_bears_spawn_on_alternate_blocks");
public static final BiomeCategory PRODUCES_CORALS_FROM_BONEMEAL = get("minecraft:produces_corals_from_bonemeal");
public static final BiomeCategory REDUCE_WATER_AMBIENT_SPAWNS = get("minecraft:reduce_water_ambient_spawns");
public static final BiomeCategory REQUIRED_OCEAN_MONUMENT_SURROUNDING = get("minecraft:required_ocean_monument_surrounding");
public static final BiomeCategory SNOW_GOLEM_MELTS = get("minecraft:snow_golem_melts");
public static final BiomeCategory SPAWNS_COLD_VARIANT_FROGS = get("minecraft:spawns_cold_variant_frogs");
public static final BiomeCategory SPAWNS_GOLD_RABBITS = get("minecraft:spawns_gold_rabbits");
public static final BiomeCategory SPAWNS_SNOW_FOXES = get("minecraft:spawns_snow_foxes");
public static final BiomeCategory SPAWNS_WARM_VARIANT_FROGS = get("minecraft:spawns_warm_variant_frogs");
public static final BiomeCategory SPAWNS_WHITE_RABBITS = get("minecraft:spawns_white_rabbits");
public static final BiomeCategory STRONGHOLD_BIASED_TO = get("minecraft:stronghold_biased_to");
public static final BiomeCategory WATER_ON_MAP_OUTLINES = get("minecraft:water_on_map_outlines");
public static final BiomeCategory WITHOUT_PATROL_SPAWNS = get("minecraft:without_patrol_spawns");
public static final BiomeCategory WITHOUT_WANDERING_TRADER_SPAWNS = get("minecraft:without_wandering_trader_spawns");
public static final BiomeCategory WITHOUT_ZOMBIE_SIEGES = get("minecraft:without_zombie_sieges");
private BiomeCategories() {
}
/**
* Gets the {@link BiomeCategory} associated with the given id.
*/
public static BiomeCategory get(String id) {
BiomeCategory entry = BiomeCategory.REGISTRY.get(id);
if (entry == null) {
return new BiomeCategory(id);
}
return entry;
}
}

Datei anzeigen

@ -0,0 +1,49 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.world.biome;
import com.sk89q.worldedit.registry.Category;
import com.sk89q.worldedit.registry.Keyed;
import com.sk89q.worldedit.registry.NamespacedRegistry;
import java.util.Set;
import java.util.function.Supplier;
/**
* A category of biomes.
*/
public class BiomeCategory extends Category<BiomeType> implements Keyed {
public static final NamespacedRegistry<BiomeCategory> REGISTRY = new NamespacedRegistry<>("biome tag", true);
public BiomeCategory(final String id) {
super(id);
}
public BiomeCategory(final String id, final Supplier<Set<BiomeType>> contentSupplier) {
super(id, contentSupplier);
}
@Override
protected Set<BiomeType> load() {
return Set.of();
}
}