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

Merge branch 'main' into feat/feature-placement

Dieser Commit ist enthalten in:
dordsor21 2024-06-30 10:44:17 +01:00
Commit 5df7f49cfe
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: 1E53E88969FFCF0B
55 geänderte Dateien mit 8880 neuen und 73 gelöschten Zeilen

Datei anzeigen

@ -34,7 +34,7 @@ logger.lifecycle("""
******************************************* *******************************************
""") """)
var rootVersion by extra("2.10.1") var rootVersion by extra("2.11.1")
var snapshot by extra("SNAPSHOT") var snapshot by extra("SNAPSHOT")
var revision: String by extra("") var revision: String by extra("")
var buildNumber by extra("") var buildNumber by extra("")
@ -83,7 +83,7 @@ allprojects {
} }
applyCommonConfiguration() applyCommonConfiguration()
val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6") val supportedVersions = listOf("1.19.4", "1.20", "1.20.4", "1.20.5", "1.20.6", "1.21")
tasks { tasks {
supportedVersions.forEach { supportedVersions.forEach {

Datei anzeigen

@ -61,7 +61,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
"https://jd.advntr.dev/api/latest/", "https://jd.advntr.dev/api/latest/",
"https://logging.apache.org/log4j/2.x/javadoc/log4j-api/", "https://logging.apache.org/log4j/2.x/javadoc/log4j-api/",
"https://www.antlr.org/api/Java/", "https://www.antlr.org/api/Java/",
"https://jd.papermc.io/paper/1.20.6/", "https://jd.papermc.io/paper/1.21/",
"https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/" "https://intellectualsites.github.io/fastasyncworldedit-javadocs/worldedit-core/"
) )
docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}" docTitle = "${rootProject.name}-${project.description}" + " " + "${rootProject.version}"

Datei anzeigen

@ -1,6 +1,6 @@
[versions] [versions]
# Minecraft expectations # Minecraft expectations
paper = "1.20.6-R0.1-SNAPSHOT" paper = "1.21-R0.1-SNAPSHOT"
fastutil = "8.5.9" fastutil = "8.5.9"
guava = "31.1-jre" guava = "31.1-jre"
log4j = "2.19.0" log4j = "2.19.0"
@ -14,7 +14,7 @@ mapmanager = "1.8.0-SNAPSHOT"
griefprevention = "17.0.0" griefprevention = "17.0.0"
griefdefender = "2.1.0-SNAPSHOT" griefdefender = "2.1.0-SNAPSHOT"
residence = "4.5._13.1" residence = "4.5._13.1"
towny = "0.100.3.2" towny = "0.100.3.3"
plotsquared = "7.3.8" plotsquared = "7.3.8"
# Third party # Third party
@ -23,9 +23,9 @@ sparsebitset = "1.3"
parallelgzip = "1.0.5" parallelgzip = "1.0.5"
adventure = "4.17.0" adventure = "4.17.0"
adventure-bukkit = "4.3.3" adventure-bukkit = "4.3.3"
checkerqual = "3.43.0" checkerqual = "3.44.0"
truezip = "6.8.4" truezip = "6.8.4"
auto-value = "1.10.4" auto-value = "1.11.0"
findbugs = "3.0.2" findbugs = "3.0.2"
rhino-runtime = "1.7.15" rhino-runtime = "1.7.15"
zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs zstd-jni = "1.4.8-1" # Not latest as it can be difficult to obtain latest ZSTD libs
@ -40,7 +40,7 @@ paperlib = "1.0.8"
paster = "1.1.6" paster = "1.1.6"
vault = "1.7.1" vault = "1.7.1"
serverlib = "2.3.6" serverlib = "2.3.6"
linbus = "0.1.0" linbus = "0.1.2"
## Internal ## Internal
text-adapter = "3.0.6" text-adapter = "3.0.6"
text = "3.0.4" text = "3.0.4"

Datei anzeigen

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

Datei anzeigen

@ -2,7 +2,7 @@ rootProject.name = "FastAsyncWorldEdit"
include("worldedit-libs") include("worldedit-libs")
listOf("1_19_4", "1_20", "1_20_2", "1_20_4", "1_20_5").forEach { listOf("1_19_4", "1_20", "1_20_2", "1_20_4", "1_20_5", "1_21").forEach {
include("worldedit-bukkit:adapters:adapter-$it") include("worldedit-bukkit:adapters:adapter-$it")
} }

Datei anzeigen

@ -0,0 +1,17 @@
import io.papermc.paperweight.userdev.PaperweightUserDependenciesExtension
plugins {
java
}
applyPaperweightAdapterConfiguration()
repositories {
gradlePluginPortal()
}
dependencies {
// url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21-R0.1-SNAPSHOT/
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.21-R0.1-20240629.091304-42")
compileOnly(libs.paperlib)
}

Datei anzeigen

@ -0,0 +1,91 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1;
import com.mojang.authlib.GameProfile;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ClientInformation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.stats.Stat;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.player.ChatVisiblity;
import net.minecraft.world.level.block.entity.SignBlockEntity;
import net.minecraft.world.phys.Vec3;
import java.util.OptionalInt;
import java.util.UUID;
class PaperweightFakePlayer extends ServerPlayer {
private static final GameProfile FAKE_WORLDEDIT_PROFILE = new GameProfile(UUID.nameUUIDFromBytes("worldedit".getBytes()), "[WorldEdit]");
private static final Vec3 ORIGIN = new Vec3(0.0D, 0.0D, 0.0D);
private static final ClientInformation FAKE_CLIENT_INFO = new ClientInformation(
"en_US", 16, ChatVisiblity.FULL, true, 0, HumanoidArm.LEFT, false, false
);
PaperweightFakePlayer(ServerLevel world) {
super(world.getServer(), world, FAKE_WORLDEDIT_PROFILE, FAKE_CLIENT_INFO);
}
@Override
public Vec3 position() {
return ORIGIN;
}
@Override
public void tick() {
}
@Override
public void die(DamageSource damagesource) {
}
@Override
public OptionalInt openMenu(MenuProvider factory) {
return OptionalInt.empty();
}
@Override
public void updateOptions(ClientInformation clientOptions) {
}
@Override
public void displayClientMessage(Component message, boolean actionBar) {
}
@Override
public void awardStat(Stat<?> stat, int amount) {
}
@Override
public void awardStat(Stat<?> stat) {
}
@Override
public boolean isInvulnerableTo(DamageSource damageSource) {
return true;
}
@Override
public void openTextEdit(SignBlockEntity sign, boolean front) {
}
}

Datei anzeigen

@ -0,0 +1,191 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Objects;
public class PaperweightWorldNativeAccess implements WorldNativeAccess<LevelChunk, net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1;
private static final int NOTIFY = 2;
private final PaperweightAdapter adapter;
private final WeakReference<ServerLevel> world;
private SideEffectSet sideEffectSet;
public PaperweightWorldNativeAccess(PaperweightAdapter adapter, WeakReference<ServerLevel> world) {
this.adapter = adapter;
this.world = world;
}
private ServerLevel getWorld() {
return Objects.requireNonNull(world.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public LevelChunk getChunk(int x, int z) {
return getWorld().getChunk(x, z);
}
@Override
public net.minecraft.world.level.block.state.BlockState toNative(BlockState state) {
int stateId = BlockStateIdAccess.getBlockStateId(state);
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(state)).getState();
}
@Override
public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk chunk, BlockPos position) {
return chunk.getBlockState(position);
}
@Nullable
@Override
public net.minecraft.world.level.block.state.BlockState setBlockState(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState state) {
return chunk.setBlockState(position, state, false, this.sideEffectSet.shouldApply(SideEffect.UPDATE));
}
@Override
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(net.minecraft.world.level.block.state.BlockState block, BlockPos position) {
return Block.updateFromNeighbourShapes(block, getWorld(), position);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos position) {
getWorld().getChunkSource().getLightEngine().checkBlock(position);
}
@Override
public boolean updateTileEntity(BlockPos position, LinCompoundTag tag) {
// 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
public void notifyBlockUpdate(LevelChunk chunk, BlockPos position, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().sendBlockUpdated(position, oldState, newState, UPDATE | NOTIFY);
}
}
@Override
public boolean isChunkTicking(LevelChunk chunk) {
return chunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
}
@Override
public void markBlockChanged(LevelChunk chunk, BlockPos position) {
if (chunk.getSections()[getWorld().getSectionIndex(position.getY())] != null) {
getWorld().getChunkSource().blockChanged(position);
}
}
@Override
public void notifyNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
world.updateNeighborsAt(pos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
Block block = oldState.getBlock();
fireNeighborChanged(pos, world, block, pos.west());
fireNeighborChanged(pos, world, block, pos.east());
fireNeighborChanged(pos, world, block, pos.below());
fireNeighborChanged(pos, world, block, pos.above());
fireNeighborChanged(pos, world, block, pos.north());
fireNeighborChanged(pos, world, block, pos.south());
}
if (newState.hasAnalogOutputSignal()) {
world.updateNeighbourForOutputSignal(pos, newState.getBlock());
}
}
@Override
public void updateBlock(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
ServerLevel world = getWorld();
newState.onPlace(world, pos, oldState, false);
}
private void fireNeighborChanged(BlockPos pos, ServerLevel world, Block block, BlockPos neighborPos) {
world.getBlockState(neighborPos).handleNeighborChanged(world, neighborPos, block, pos, false);
}
@Override
public void updateNeighbors(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState, int recursionLimit) {
ServerLevel world = getWorld();
oldState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = world.getWorld();
BlockPhysicsEvent event = new BlockPhysicsEvent(craftWorld.getBlockAt(pos.getX(), pos.getY(), pos.getZ()), CraftBlockData.fromData(newState));
world.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
newState.updateNeighbourShapes(world, pos, NOTIFY, recursionLimit);
newState.updateIndirectNeighbourShapes(world, pos, NOTIFY, recursionLimit);
}
@Override
public void onBlockStateChange(BlockPos pos, net.minecraft.world.level.block.state.BlockState oldState, net.minecraft.world.level.block.state.BlockState newState) {
getWorld().onBlockStateChange(pos, oldState, newState);
}
@Override
public void flush() {
}
}

Datei anzeigen

@ -0,0 +1,90 @@
/*
* WorldEdit, a Minecraft world manipulation toolkit
* Copyright (C) sk89q <http://www.sk89q.com>
* Copyright (C) WorldEdit team and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
/**
* Dedicated class to map all names that we use.
*
* <p>
* Overloads are split into multiple fields, as they <em>CAN</em> have different obfuscated names.
* </p>
*/
public final class StaticRefraction {
public static final String GET_CHUNK_FUTURE_MAIN_THREAD = Refraction.pickName(
"getChunkFutureMainThread", "c"
);
public static final String MAIN_THREAD_PROCESSOR = Refraction.pickName(
"mainThreadProcessor", "g"
);
public static final String NEXT_TICK_TIME = Refraction.pickName("nextTickTime", "e");
public static final String GET_BLOCK_STATE = Refraction.pickName("getBlockState", "a_");
/**
* {@code addFreshEntityWithPassengers(Entity entity)}.
*/
public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY = Refraction.pickName(
"addFreshEntityWithPassengers", "a_"
);
/**
* {@code addFreshEntityWithPassengers(Entity entity, CreatureSpawnEvent.SpawnReason reason)}.
*/
public static final String ADD_FRESH_ENTITY_WITH_PASSENGERS_ENTITY_SPAWN_REASON =
Refraction.pickName("addFreshEntityWithPassengers", "a_");
/**
* {@code addFreshEntity(Entity entity)}.
*/
public static final String ADD_FRESH_ENTITY = Refraction.pickName("addFreshEntity", "b");
/**
* {@code addFreshEntity(Entity entity, CreatureSpawnEvent.SpawnReason reason)}.
*/
public static final String ADD_FRESH_ENTITY_SPAWN_REASON = Refraction.pickName(
"addFreshEntity", "b"
);
/**
* {@code getBlockEntity(BlockPos blockPos)}.
*/
public static final String GET_BLOCK_ENTITY = Refraction.pickName("getBlockEntity", "c_");
/**
* {@code setBlock(BlockPos blockPos, BlockState blockState, int flags)}.
*/
public static final String SET_BLOCK = Refraction.pickName("setBlock", "a");
/**
* {@code setBlock(BlockPos blockPos, BlockState blockState, int flags, int maxUpdateDepth)}.
*/
public static final String SET_BLOCK_MAX_UPDATE = Refraction.pickName("setBlock", "a");
public static final String REMOVE_BLOCK = Refraction.pickName("removeBlock", "a");
/**
* {@code destroyBlock(BlockPos blockPos, boolean drop)}.
*/
public static final String DESTROY_BLOCK = Refraction.pickName("destroyBlock", "b");
/**
* {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity)}.
*/
public static final String DESTROY_BLOCK_BREAKING_ENTITY = Refraction.pickName(
"destroyBlock", "a"
);
/**
* {@code destroyBlock(BlockPos blockPos, boolean drop, Entity breakingEntity, int maxUpdateDepth)}.
*/
public static final String DESTROY_BLOCK_BREAKING_ENTITY_MAX_UPDATE = Refraction.pickName(
"destroyBlock", "a"
);
}

Datei anzeigen

@ -0,0 +1,176 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import net.minecraft.core.BlockPos;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.EntityBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.material.Fluids;
import net.minecraft.world.level.material.PushReaction;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
public class PaperweightBlockMaterial implements BlockMaterial {
private final Block block;
private final BlockState blockState;
private final CraftBlockData craftBlockData;
private final org.bukkit.Material craftMaterial;
private final int opacity;
private final CompoundTag tile;
public PaperweightBlockMaterial(Block block) {
this(block, block.defaultBlockState());
}
public PaperweightBlockMaterial(Block block, BlockState blockState) {
this.block = block;
this.blockState = blockState;
this.craftBlockData = CraftBlockData.fromData(blockState);
this.craftMaterial = craftBlockData.getMaterial();
opacity = blockState.getLightBlock(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
BlockEntity tileEntity = !(block instanceof EntityBlock) ? null : ((EntityBlock) block).newBlockEntity(
BlockPos.ZERO,
blockState
);
tile = tileEntity == null ? null : new PaperweightLazyCompoundTag(
Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
);
}
public Block getBlock() {
return block;
}
public BlockState getState() {
return blockState;
}
public CraftBlockData getCraftBlockData() {
return craftBlockData;
}
@Override
public boolean isAir() {
return blockState.isAir();
}
@Override
public boolean isFullCube() {
return craftMaterial.isOccluding();
}
@Override
public boolean isOpaque() {
return blockState.canOcclude();
}
@Override
public boolean isPowerSource() {
return blockState.isSignalSource();
}
@Override
public boolean isLiquid() {
return !blockState.getFluidState().is(Fluids.EMPTY);
}
@Override
public boolean isSolid() {
// No access to world -> EmptyBlockGetter
return blockState.isSolidRender(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
}
@Override
public float getHardness() {
return craftBlockData.getState().destroySpeed;
}
@Override
public float getResistance() {
return block.getExplosionResistance();
}
@Override
public float getSlipperiness() {
return block.getFriction();
}
@Override
public int getLightValue() {
return blockState.getLightEmission();
}
@Override
public int getLightOpacity() {
return opacity;
}
@Override
public boolean isFragileWhenPushed() {
return blockState.getPistonPushReaction() == PushReaction.DESTROY;
}
@Override
public boolean isUnpushable() {
return blockState.getPistonPushReaction() == PushReaction.BLOCK;
}
@Override
public boolean isTicksRandomly() {
return blockState.isRandomlyTicking();
}
@Override
public boolean isMovementBlocker() {
return craftMaterial.isSolid();
}
@Override
public boolean isBurnable() {
return craftMaterial.isBurnable();
}
@Override
public boolean isToolRequired() {
// Removed in 1.16.1, this is not present in higher versions
return false;
}
@Override
public boolean isReplacedDuringPlacement() {
return blockState.canBeReplaced();
}
@Override
public boolean isTranslucent() {
return !blockState.canOcclude();
}
@Override
public boolean hasContainer() {
return block instanceof EntityBlock;
}
@Override
public boolean isTile() {
return block instanceof EntityBlock;
}
@Override
public CompoundTag getDefaultTile() {
return tile;
}
@Override
public int getMapColor() {
// rgb field
return block.defaultMapColor().col;
}
}

Datei anzeigen

@ -0,0 +1,639 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.bukkit.adapter.FaweAdapter;
import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
import com.fastasyncworldedit.core.util.NbtUtils;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.mojang.serialization.Codec;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.blocks.BaseItemStack;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen.PaperweightRegen;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.registry.state.BooleanProperty;
import com.sk89q.worldedit.registry.state.DirectionalProperty;
import com.sk89q.worldedit.registry.state.EnumProperty;
import com.sk89q.worldedit.registry.state.IntegerProperty;
import com.sk89q.worldedit.registry.state.Property;
import com.sk89q.worldedit.util.Direction;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import com.sk89q.worldedit.util.formatting.text.Component;
import com.sk89q.worldedit.world.RegenOptions;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockStateHolder;
import com.sk89q.worldedit.world.block.BlockType;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import com.sk89q.worldedit.world.entity.EntityType;
import com.sk89q.worldedit.world.item.ItemType;
import com.sk89q.worldedit.world.registry.BlockMaterial;
import io.papermc.lib.PaperLib;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Registry;
import net.minecraft.core.RegistryAccess;
import net.minecraft.core.WritableRegistry;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.StringRepresentable;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
import net.minecraft.world.level.block.state.properties.DirectionProperty;
import net.minecraft.world.level.chunk.LevelChunk;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.NamespacedKey;
import org.bukkit.World;
import org.bukkit.block.data.BlockData;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.entity.CraftEntity;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.util.CraftNamespacedKey;
import org.bukkit.entity.Player;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinStringTag;
import org.enginehub.linbus.tree.LinTag;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.OptionalInt;
import java.util.Set;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static net.minecraft.core.registries.Registries.BIOME;
public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.Tag, ServerLevel> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static Method CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE;
private static final Codec<DataComponentPatch> COMPONENTS_CODEC = DataComponentPatch.CODEC.optionalFieldOf(
"components", DataComponentPatch.EMPTY
).codec();
static {
try {
CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE = ChunkHolder.class.getDeclaredMethod("wasAccessibleSinceLastSave");
} catch (NoSuchMethodException ignored) { // may not be present in newer paper versions
}
}
private final com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter parent;
// ------------------------------------------------------------------------
// Code that may break between versions of Minecraft
// ------------------------------------------------------------------------
private final PaperweightMapChunkUtil mapUtil = new PaperweightMapChunkUtil();
private char[] ibdToStateOrdinal = null;
private int[] ordinalToIbdID = null;
private boolean initialised = false;
private Map<String, List<Property<?>>> allBlockProperties = null;
public PaperweightFaweAdapter() throws NoSuchFieldException, NoSuchMethodException {
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter();
}
@Nullable
private static String getEntityId(Entity entity) {
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
return resourceLocation == null ? null : resourceLocation.toString();
}
private static void readEntityIntoTag(Entity entity, net.minecraft.nbt.CompoundTag compoundTag) {
entity.save(compoundTag);
}
@Override
public BukkitImplAdapter<net.minecraft.nbt.Tag> getParent() {
return parent;
}
private synchronized boolean init() {
if (ibdToStateOrdinal != null && ibdToStateOrdinal[1] != 0) {
return false;
}
ibdToStateOrdinal = new char[BlockTypesCache.states.length]; // size
ordinalToIbdID = new int[ibdToStateOrdinal.length]; // size
for (int i = 0; i < ibdToStateOrdinal.length; i++) {
BlockState blockState = BlockTypesCache.states[i];
PaperweightBlockMaterial material = (PaperweightBlockMaterial) blockState.getMaterial();
int id = Block.BLOCK_STATE_REGISTRY.getId(material.getState());
char ordinal = blockState.getOrdinalChar();
ibdToStateOrdinal[id] = ordinal;
ordinalToIbdID[ordinal] = id;
}
Map<String, List<Property<?>>> properties = new HashMap<>();
try {
for (Field field : BlockStateProperties.class.getDeclaredFields()) {
Object obj = field.get(null);
if (!(obj instanceof net.minecraft.world.level.block.state.properties.Property<?> state)) {
continue;
}
Property<?> property;
if (state instanceof net.minecraft.world.level.block.state.properties.BooleanProperty) {
property = new BooleanProperty(
state.getName(),
(List<Boolean>) ImmutableList.copyOf(state.getPossibleValues())
);
} else if (state instanceof DirectionProperty) {
property = new DirectionalProperty(
state.getName(),
state
.getPossibleValues()
.stream()
.map(e -> Direction.valueOf(((StringRepresentable) e).getSerializedName().toUpperCase()))
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.EnumProperty) {
property = new EnumProperty(
state.getName(),
state
.getPossibleValues()
.stream()
.map(e -> ((StringRepresentable) e).getSerializedName())
.collect(Collectors.toList())
);
} else if (state instanceof net.minecraft.world.level.block.state.properties.IntegerProperty) {
property = new IntegerProperty(
state.getName(),
(List<Integer>) ImmutableList.copyOf(state.getPossibleValues())
);
} else {
throw new IllegalArgumentException("FastAsyncWorldEdit needs an update to support " + state
.getClass()
.getSimpleName());
}
properties.compute(property.getName().toLowerCase(Locale.ROOT), (k, v) -> {
if (v == null) {
v = new ArrayList<>(Collections.singletonList(property));
} else {
v.add(property);
}
return v;
});
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
allBlockProperties = ImmutableMap.copyOf(properties);
}
initialised = true;
return true;
}
@Override
public BlockMaterial getMaterial(BlockType blockType) {
Block block = getBlock(blockType);
return new PaperweightBlockMaterial(block);
}
@Override
public synchronized BlockMaterial getMaterial(BlockState state) {
net.minecraft.world.level.block.state.BlockState blockState = ((CraftBlockData) Bukkit.createBlockData(state.getAsString())).getState();
return new PaperweightBlockMaterial(blockState.getBlock(), blockState);
}
public Block getBlock(BlockType blockType) {
return DedicatedServer.getServer().registryAccess().registryOrThrow(Registries.BLOCK)
.get(ResourceLocation.fromNamespaceAndPath(blockType.getNamespace(), blockType.getResource()));
}
@Deprecated
@Override
public BlockState getBlock(Location location) {
Preconditions.checkNotNull(location);
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
BlockState state = adapt(blockData);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
return state;
}
@Override
public BaseBlock getFullBlock(final Location location) {
Preconditions.checkNotNull(location);
int x = location.getBlockX();
int y = location.getBlockY();
int z = location.getBlockZ();
final ServerLevel handle = getServerLevel(location.getWorld());
LevelChunk chunk = handle.getChunk(x >> 4, z >> 4);
final BlockPos blockPos = new BlockPos(x, y, z);
final net.minecraft.world.level.block.state.BlockState blockData = chunk.getBlockState(blockPos);
BlockState state = adapt(blockData);
if (state == null) {
org.bukkit.block.Block bukkitBlock = location.getBlock();
state = BukkitAdapter.adapt(bukkitBlock.getBlockData());
}
if (state.getBlockType().getMaterial().hasContainer()) {
// Read the NBT data
BlockEntity blockEntity = chunk.getBlockEntity(blockPos, LevelChunk.EntityCreationType.CHECK);
if (blockEntity != null) {
net.minecraft.nbt.CompoundTag tag = blockEntity.saveWithId(DedicatedServer.getServer().registryAccess());
return state.toBaseBlock((LinCompoundTag) toNativeLin(tag));
}
}
return state.toBaseBlock();
}
@Override
public Set<SideEffect> getSupportedSideEffects() {
return SideEffectSet.defaults().getSideEffectsToApply();
}
@Override
public WorldNativeAccess<?, ?, ?> createWorldNativeAccess(org.bukkit.World world) {
return new PaperweightFaweWorldNativeAccess(this, new WeakReference<>(getServerLevel(world)));
}
@Override
public BaseEntity getEntity(org.bukkit.entity.Entity entity) {
Preconditions.checkNotNull(entity);
CraftEntity craftEntity = ((CraftEntity) entity);
Entity mcEntity = craftEntity.getHandle();
String id = getEntityId(mcEntity);
if (id != null) {
EntityType type = com.sk89q.worldedit.world.entity.EntityTypes.get(id);
Supplier<LinCompoundTag> saveTag = () -> {
final net.minecraft.nbt.CompoundTag minecraftTag = new net.minecraft.nbt.CompoundTag();
readEntityIntoTag(mcEntity, minecraftTag);
//add Id for AbstractChangeSet to work
final LinCompoundTag tag = (LinCompoundTag) toNativeLin(minecraftTag);
final Map<String, LinTag<?>> tags = NbtUtils.getLinCompoundTagValues(tag);
tags.put("Id", LinStringTag.of(id));
return LinCompoundTag.of(tags);
};
return new LazyBaseEntity(type, saveTag);
} else {
return null;
}
}
@Override
public Component getRichBlockName(BlockType blockType) {
return parent.getRichBlockName(blockType);
}
@Override
public Component getRichItemName(ItemType itemType) {
return parent.getRichItemName(itemType);
}
@Override
public Component getRichItemName(BaseItemStack itemStack) {
return parent.getRichItemName(itemStack);
}
@Override
public OptionalInt getInternalBlockStateId(BlockState state) {
PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial();
net.minecraft.world.level.block.state.BlockState mcState = material.getCraftBlockData().getState();
return OptionalInt.of(Block.BLOCK_STATE_REGISTRY.getId(mcState));
}
@Override
public BlockState adapt(BlockData blockData) {
CraftBlockData cbd = ((CraftBlockData) blockData);
net.minecraft.world.level.block.state.BlockState ibd = cbd.getState();
return adapt(ibd);
}
public BlockState adapt(net.minecraft.world.level.block.state.BlockState blockState) {
return BlockTypesCache.states[adaptToChar(blockState)];
}
public char adaptToChar(net.minecraft.world.level.block.state.BlockState blockState) {
int id = Block.BLOCK_STATE_REGISTRY.getId(blockState);
if (initialised) {
return ibdToStateOrdinal[id];
}
synchronized (this) {
if (initialised) {
return ibdToStateOrdinal[id];
}
try {
init();
return ibdToStateOrdinal[id];
} catch (ArrayIndexOutOfBoundsException e1) {
LOGGER.error("Attempted to convert {} with ID {} to char. ibdToStateOrdinal length: {}. Defaulting to air!",
blockState.getBlock(), Block.BLOCK_STATE_REGISTRY.getId(blockState), ibdToStateOrdinal.length, e1
);
return BlockTypesCache.ReservedIDs.AIR;
}
}
}
public char ibdIDToOrdinal(int id) {
if (initialised) {
return ibdToStateOrdinal[id];
}
synchronized (this) {
if (initialised) {
return ibdToStateOrdinal[id];
}
init();
return ibdToStateOrdinal[id];
}
}
@Override
public char[] getIbdToStateOrdinal() {
if (initialised) {
return ibdToStateOrdinal;
}
synchronized (this) {
if (initialised) {
return ibdToStateOrdinal;
}
init();
return ibdToStateOrdinal;
}
}
public int ordinalToIbdID(char ordinal) {
if (initialised) {
return ordinalToIbdID[ordinal];
}
synchronized (this) {
if (initialised) {
return ordinalToIbdID[ordinal];
}
init();
return ordinalToIbdID[ordinal];
}
}
@Override
public int[] getOrdinalToIbdID() {
if (initialised) {
return ordinalToIbdID;
}
synchronized (this) {
if (initialised) {
return ordinalToIbdID;
}
init();
return ordinalToIbdID;
}
}
@Override
public <B extends BlockStateHolder<B>> BlockData adapt(B state) {
PaperweightBlockMaterial material = (PaperweightBlockMaterial) state.getMaterial();
return material.getCraftBlockData();
}
@Override
public void sendFakeChunk(org.bukkit.World world, Player player, ChunkPacket chunkPacket) {
ServerLevel nmsWorld = getServerLevel(world);
ChunkHolder map = PaperweightPlatformAdapter.getPlayerChunk(nmsWorld, chunkPacket.getChunkX(), chunkPacket.getChunkZ());
if (map != null && wasAccessibleSinceLastSave(map)) {
boolean flag = false;
// PlayerChunk.d players = map.players;
Stream<ServerPlayer> stream = /*players.a(new ChunkCoordIntPair(packet.getChunkX(), packet.getChunkZ()), flag)
*/ Stream.empty();
ServerPlayer checkPlayer = player == null ? null : ((CraftPlayer) player).getHandle();
stream.filter(entityPlayer -> checkPlayer == null || entityPlayer == checkPlayer)
.forEach(entityPlayer -> {
synchronized (chunkPacket) {
ClientboundLevelChunkWithLightPacket nmsPacket = (ClientboundLevelChunkWithLightPacket) chunkPacket.getNativePacket();
if (nmsPacket == null) {
nmsPacket = mapUtil.create(this, chunkPacket);
chunkPacket.setNativePacket(nmsPacket);
}
try {
FaweCache.INSTANCE.CHUNK_FLAG.get().set(true);
entityPlayer.connection.send(nmsPacket);
} finally {
FaweCache.INSTANCE.CHUNK_FLAG.get().set(false);
}
}
});
}
}
@Override
public Map<String, ? extends Property<?>> getProperties(BlockType blockType) {
return getParent().getProperties(blockType);
}
@Override
public boolean canPlaceAt(org.bukkit.World world, BlockVector3 blockVector3, BlockState blockState) {
int internalId = BlockStateIdAccess.getBlockStateId(blockState);
net.minecraft.world.level.block.state.BlockState blockState1 = Block.stateById(internalId);
return blockState1.hasPostProcess(
getServerLevel(world),
new BlockPos(blockVector3.x(), blockVector3.y(), blockVector3.z())
);
}
@Override
public org.bukkit.inventory.ItemStack adapt(BaseItemStack baseItemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
ItemStack stack = new ItemStack(
registryAccess.registryOrThrow(Registries.ITEM).get(ResourceLocation.tryParse(baseItemStack.getType().id())),
baseItemStack.getAmount()
);
final CompoundTag nbt = (net.minecraft.nbt.CompoundTag) fromNative(baseItemStack.getNbtData());
if (nbt != null) {
final DataComponentPatch patch = COMPONENTS_CODEC
.parse(registryAccess.createSerializationContext(NbtOps.INSTANCE), nbt)
.getOrThrow();
stack.applyComponents(patch);
}
return CraftItemStack.asCraftMirror(stack);
}
@Override
protected void preCaptureStates(final ServerLevel serverLevel) {
serverLevel.captureTreeGeneration = true;
serverLevel.captureBlockStates = true;
}
@Override
protected List<org.bukkit.block.BlockState> getCapturedBlockStatesCopy(final ServerLevel serverLevel) {
return new ArrayList<>(serverLevel.capturedBlockStates.values());
}
@Override
protected void postCaptureBlockStates(final ServerLevel serverLevel) {
serverLevel.captureBlockStates = false;
serverLevel.captureTreeGeneration = false;
serverLevel.capturedBlockStates.clear();
}
@Override
protected ServerLevel getServerLevel(final World world) {
return ((CraftWorld) world).getHandle();
}
@Override
public BaseItemStack adapt(org.bukkit.inventory.ItemStack itemStack) {
final RegistryAccess.Frozen registryAccess = DedicatedServer.getServer().registryAccess();
final ItemStack nmsStack = CraftItemStack.asNMSCopy(itemStack);
final net.minecraft.nbt.Tag tag = COMPONENTS_CODEC.encodeStart(
registryAccess.createSerializationContext(NbtOps.INSTANCE),
nmsStack.getComponentsPatch()
).getOrThrow();
return new BaseItemStack(
BukkitAdapter.asItemType(itemStack.getType()),
LazyReference.from(() -> (LinCompoundTag) toNativeLin(tag)),
itemStack.getAmount()
);
}
@Override
public Tag toNative(net.minecraft.nbt.Tag foreign) {
return parent.toNative(foreign);
}
@Override
public net.minecraft.nbt.Tag fromNative(Tag foreign) {
if (foreign instanceof PaperweightLazyCompoundTag) {
return ((PaperweightLazyCompoundTag) foreign).get();
}
return parent.fromNative(foreign);
}
@Override
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
return new PaperweightRegen(bukkitWorld, region, target, options).regenerate();
}
@Override
public IChunkGet get(org.bukkit.World world, int chunkX, int chunkZ) {
return new PaperweightGetBlocks(world, chunkX, chunkZ);
}
@Override
public int getInternalBiomeId(BiomeType biomeType) {
final Registry<Biome> registry = MinecraftServer
.getServer()
.registryAccess()
.registryOrThrow(BIOME);
ResourceLocation resourceLocation = ResourceLocation.tryParse(biomeType.id());
Biome biome = registry.get(resourceLocation);
return registry.getId(biome);
}
@Override
public Iterable<NamespacedKey> getRegisteredBiomes() {
WritableRegistry<Biome> biomeRegistry = (WritableRegistry<Biome>) ((CraftServer) Bukkit.getServer())
.getServer()
.registryAccess()
.registryOrThrow(BIOME);
List<ResourceLocation> keys = biomeRegistry.stream()
.map(biomeRegistry::getKey).filter(Objects::nonNull).toList();
List<NamespacedKey> namespacedKeys = new ArrayList<>();
for (ResourceLocation key : keys) {
try {
namespacedKeys.add(CraftNamespacedKey.fromMinecraft(key));
} catch (IllegalArgumentException e) {
LOGGER.error("Error converting biome key {}", key.toString(), e);
}
}
return namespacedKeys;
}
@Override
public RelighterFactory getRelighterFactory() {
if (PaperLib.isPaper()) {
return new PaperweightStarlightRelighterFactory();
} else {
return new NMSRelighterFactory();
}
}
@Override
public Map<String, List<Property<?>>> getAllProperties() {
if (initialised) {
return allBlockProperties;
}
synchronized (this) {
if (initialised) {
return allBlockProperties;
}
init();
return allBlockProperties;
}
}
@Override
public IBatchProcessor getTickingPostProcessor() {
return new PaperweightPostProcessor();
}
private boolean wasAccessibleSinceLastSave(ChunkHolder holder) {
if (!PaperLib.isPaper() || !PaperweightPlatformAdapter.POST_CHUNK_REWRITE) {
try {
return (boolean) CHUNK_HOLDER_WAS_ACCESSIBLE_SINCE_LAST_SAVE.invoke(holder);
} catch (IllegalAccessException | InvocationTargetException ignored) {
// fall-through
}
}
// Papers new chunk system has no related replacement - therefor we assume true.
return true;
}
}

Datei anzeigen

@ -0,0 +1,293 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.IntPair;
import com.fastasyncworldedit.core.util.TaskManager;
import com.fastasyncworldedit.core.util.task.RunnableVal;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
import com.sk89q.worldedit.internal.wna.WorldNativeAccess;
import com.sk89q.worldedit.util.SideEffect;
import com.sk89q.worldedit.util.SideEffectSet;
import com.sk89q.worldedit.world.block.BlockState;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.event.block.BlockPhysicsEvent;
import org.enginehub.linbus.tree.LinCompoundTag;
import javax.annotation.Nullable;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
public class PaperweightFaweWorldNativeAccess implements WorldNativeAccess<LevelChunk,
net.minecraft.world.level.block.state.BlockState, BlockPos> {
private static final int UPDATE = 1;
private static final int NOTIFY = 2;
private static final Direction[] NEIGHBOUR_ORDER = {
Direction.EAST,
Direction.WEST,
Direction.DOWN,
Direction.UP,
Direction.NORTH,
Direction.SOUTH
};
private final PaperweightFaweAdapter paperweightFaweAdapter;
private final WeakReference<Level> level;
private final AtomicInteger lastTick;
private final Set<CachedChange> cachedChanges = new HashSet<>();
private final Set<IntPair> cachedChunksToSend = new HashSet<>();
private SideEffectSet sideEffectSet;
public PaperweightFaweWorldNativeAccess(PaperweightFaweAdapter paperweightFaweAdapter, WeakReference<Level> level) {
this.paperweightFaweAdapter = paperweightFaweAdapter;
this.level = level;
// Use the actual tick as minecraft-defined so we don't try to force blocks into the world when the server's already lagging.
// - With the caveat that we don't want to have too many cached changed (1024) so we'd flush those at 1024 anyway.
this.lastTick = new AtomicInteger(MinecraftServer.currentTick);
}
private Level getLevel() {
return Objects.requireNonNull(level.get(), "The reference to the world was lost");
}
@Override
public void setCurrentSideEffectSet(SideEffectSet sideEffectSet) {
this.sideEffectSet = sideEffectSet;
}
@Override
public LevelChunk getChunk(int x, int z) {
return getLevel().getChunk(x, z);
}
@Override
public net.minecraft.world.level.block.state.BlockState toNative(BlockState blockState) {
int stateId = paperweightFaweAdapter.ordinalToIbdID(blockState.getOrdinalChar());
return BlockStateIdAccess.isValidInternalId(stateId)
? Block.stateById(stateId)
: ((CraftBlockData) BukkitAdapter.adapt(blockState)).getState();
}
@Override
public net.minecraft.world.level.block.state.BlockState getBlockState(LevelChunk levelChunk, BlockPos blockPos) {
return levelChunk.getBlockState(blockPos);
}
@Nullable
@Override
public synchronized net.minecraft.world.level.block.state.BlockState setBlockState(
LevelChunk levelChunk, BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState
) {
int currentTick = MinecraftServer.currentTick;
if (Fawe.isMainThread()) {
return levelChunk.setBlockState(blockPos, blockState,
this.sideEffectSet != null && this.sideEffectSet.shouldApply(SideEffect.UPDATE)
);
}
// Since FAWE is.. Async we need to do it on the main thread (wooooo.. :( )
cachedChanges.add(new CachedChange(levelChunk, blockPos, blockState));
cachedChunksToSend.add(new IntPair(levelChunk.locX, levelChunk.locZ));
boolean nextTick = lastTick.get() > currentTick;
if (nextTick || cachedChanges.size() >= 1024) {
if (nextTick) {
lastTick.set(currentTick);
}
flushAsync(nextTick);
}
return blockState;
}
@Override
public net.minecraft.world.level.block.state.BlockState getValidBlockForPosition(
net.minecraft.world.level.block.state.BlockState blockState,
BlockPos blockPos
) {
return Block.updateFromNeighbourShapes(blockState, getLevel(), blockPos);
}
@Override
public BlockPos getPosition(int x, int y, int z) {
return new BlockPos(x, y, z);
}
@Override
public void updateLightingForBlock(BlockPos blockPos) {
getLevel().getChunkSource().getLightEngine().checkBlock(blockPos);
}
@Override
public boolean updateTileEntity(BlockPos blockPos, LinCompoundTag tag) {
// We will assume that the tile entity was created for us,
// though we do not do this on the other versions
BlockEntity blockEntity = getLevel().getBlockEntity(blockPos);
if (blockEntity == null) {
return false;
}
net.minecraft.nbt.Tag nativeTag = paperweightFaweAdapter.fromNativeLin(tag);
blockEntity.loadWithComponents((CompoundTag) nativeTag, DedicatedServer.getServer().registryAccess());
return true;
}
@Override
public void notifyBlockUpdate(
LevelChunk levelChunk, BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) {
getLevel().sendBlockUpdated(blockPos, oldState, newState, UPDATE | NOTIFY);
}
}
@Override
public boolean isChunkTicking(LevelChunk levelChunk) {
return levelChunk.getFullStatus().isOrAfter(FullChunkStatus.BLOCK_TICKING);
}
@Override
public void markBlockChanged(LevelChunk levelChunk, BlockPos blockPos) {
if (levelChunk.getSections()[level.get().getSectionIndex(blockPos.getY())] != null) {
((ServerChunkCache) getLevel().getChunkSource()).blockChanged(blockPos);
}
}
@Override
public void notifyNeighbors(
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
Level level = getLevel();
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
level.blockUpdated(blockPos, oldState.getBlock());
} else {
// When we don't want events, manually run the physics without them.
// Un-nest neighbour updating
for (Direction direction : NEIGHBOUR_ORDER) {
BlockPos shifted = blockPos.relative(direction);
level.getBlockState(shifted).handleNeighborChanged(level, shifted, oldState.getBlock(), blockPos, false);
}
}
if (newState.hasAnalogOutputSignal()) {
level.updateNeighbourForOutputSignal(blockPos, newState.getBlock());
}
}
@Override
public void updateNeighbors(
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState,
int recursionLimit
) {
Level level = getLevel();
// a == updateNeighbors
// b == updateDiagonalNeighbors
oldState.updateIndirectNeighbourShapes(level, blockPos, NOTIFY, recursionLimit);
if (sideEffectSet.shouldApply(SideEffect.EVENTS)) {
CraftWorld craftWorld = level.getWorld();
if (craftWorld != null) {
BlockPhysicsEvent event = new BlockPhysicsEvent(
craftWorld.getBlockAt(blockPos.getX(), blockPos.getY(), blockPos.getZ()),
CraftBlockData.fromData(newState)
);
level.getCraftServer().getPluginManager().callEvent(event);
if (event.isCancelled()) {
return;
}
}
}
newState.triggerEvent(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
public void onBlockStateChange(
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState oldState,
net.minecraft.world.level.block.state.BlockState newState
) {
getLevel().onBlockStateChange(blockPos, oldState, newState);
}
private synchronized void flushAsync(final boolean sendChunks) {
final Set<CachedChange> changes = Set.copyOf(cachedChanges);
cachedChanges.clear();
final Set<IntPair> toSend;
if (sendChunks) {
toSend = Set.copyOf(cachedChunksToSend);
cachedChunksToSend.clear();
} else {
toSend = Collections.emptySet();
}
RunnableVal<Object> runnableVal = new RunnableVal<>() {
@Override
public void run(Object value) {
changes.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState,
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
));
if (!sendChunks) {
return;
}
for (IntPair chunk : toSend) {
PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
}
}
};
TaskManager.taskManager().async(() -> TaskManager.taskManager().sync(runnableVal));
}
@Override
public synchronized void flush() {
RunnableVal<Object> runnableVal = new RunnableVal<>() {
@Override
public void run(Object value) {
cachedChanges.forEach(cc -> cc.levelChunk.setBlockState(cc.blockPos, cc.blockState,
sideEffectSet != null && sideEffectSet.shouldApply(SideEffect.UPDATE)
));
for (IntPair chunk : cachedChunksToSend) {
PaperweightPlatformAdapter.sendChunk(chunk, getLevel().getWorld().getHandle(), chunk.x(), chunk.z());
}
}
};
if (Fawe.isMainThread()) {
runnableVal.run();
} else {
TaskManager.taskManager().sync(runnableVal);
}
cachedChanges.clear();
cachedChunksToSend.clear();
}
private record CachedChange(
LevelChunk levelChunk,
BlockPos blockPos,
net.minecraft.world.level.block.state.BlockState blockState
) {
}
}

Datei anzeigen

@ -0,0 +1,260 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
import com.fastasyncworldedit.core.queue.IBlocks;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.google.common.base.Suppliers;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.block.BaseBlock;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.Holder;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.PalettedContainerRO;
import org.apache.logging.log4j.Logger;
import javax.annotation.Nullable;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.Future;
public class PaperweightGetBlocks_Copy implements IChunkGet {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
private final Set<CompoundTag> entities = new HashSet<>();
private final char[][] blocks;
private final int minHeight;
private final int maxHeight;
final ServerLevel serverLevel;
final LevelChunk levelChunk;
private Holder<Biome>[][] biomes = null;
protected PaperweightGetBlocks_Copy(LevelChunk levelChunk) {
this.levelChunk = levelChunk;
this.serverLevel = levelChunk.level;
this.minHeight = serverLevel.getMinBuildHeight();
this.maxHeight = serverLevel.getMaxBuildHeight() - 1; // Minecraft max limit is exclusive.
this.blocks = new char[getSectionCount()][];
}
protected void storeTile(BlockEntity blockEntity) {
tiles.put(
BlockVector3.at(
blockEntity.getBlockPos().getX(),
blockEntity.getBlockPos().getY(),
blockEntity.getBlockPos().getZ()
),
new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())))
);
}
@Override
public Map<BlockVector3, CompoundTag> getTiles() {
return tiles;
}
@Override
@Nullable
public CompoundTag getTile(int x, int y, int z) {
return tiles.get(BlockVector3.at(x, y, z));
}
@SuppressWarnings({"unchecked", "rawtypes"})
protected void storeEntity(Entity entity) {
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
entity.save(compoundTag);
entities.add((CompoundTag) adapter.toNative(compoundTag));
}
@Override
public Set<CompoundTag> getEntities() {
return this.entities;
}
@Override
public CompoundTag getEntity(UUID uuid) {
for (CompoundTag tag : entities) {
if (uuid.equals(tag.getUUID())) {
return tag;
}
}
return null;
}
@Override
public boolean isCreateCopy() {
return false;
}
@Override
public int setCreateCopy(boolean createCopy) {
return -1;
}
@Override
public void setLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setSkyLightingToGet(char[][] lighting, int minSectionPosition, int maxSectionPosition) {
}
@Override
public void setHeightmapToGet(HeightMapType type, int[] data) {
}
@Override
public int getMaxY() {
return maxHeight;
}
@Override
public int getMinY() {
return minHeight;
}
@Override
public int getMaxSectionPosition() {
return maxHeight >> 4;
}
@Override
public int getMinSectionPosition() {
return minHeight >> 4;
}
@Override
public BiomeType getBiomeType(int x, int y, int z) {
Holder<Biome> biome = biomes[(y >> 4) - getMinSectionPosition()][(y & 12) << 2 | (z & 12) | (x & 12) >> 2];
return PaperweightPlatformAdapter.adapt(biome, serverLevel);
}
@Override
public void removeSectionLighting(int layer, boolean sky) {
}
@Override
public boolean trim(boolean aggressive, int layer) {
return false;
}
@Override
public IBlocks reset() {
return null;
}
@Override
public int getSectionCount() {
return serverLevel.getSectionsCount();
}
protected void storeSection(int layer, char[] data) {
blocks[layer] = data;
}
protected void storeBiomes(int layer, PalettedContainerRO<Holder<Biome>> biomeData) {
if (biomes == null) {
biomes = new Holder[getSectionCount()][];
}
if (biomes[layer] == null) {
biomes[layer] = new Holder[64];
}
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
for (int i = 0; i < 64; i++) {
biomes[layer][i] = palettedContainer.get(i);
}
} else {
LOGGER.error(
"Cannot correctly save biomes to history. Expected class type {} but got {}",
PalettedContainer.class.getSimpleName(),
biomeData.getClass().getSimpleName()
);
}
}
@Override
public BaseBlock getFullBlock(int x, int y, int z) {
BlockState state = BlockTypesCache.states[get(x, y, z)];
return state.toBaseBlock(this, x, y, z);
}
@Override
public boolean hasSection(int layer) {
layer -= getMinSectionPosition();
return blocks[layer] != null;
}
@Override
public char[] load(int layer) {
layer -= getMinSectionPosition();
if (blocks[layer] == null) {
blocks[layer] = new char[4096];
Arrays.fill(blocks[layer], (char) BlockTypesCache.ReservedIDs.AIR);
}
return blocks[layer];
}
@Override
public char[] loadIfPresent(int layer) {
layer -= getMinSectionPosition();
return blocks[layer];
}
@Override
public BlockState getBlock(int x, int y, int z) {
return BlockTypesCache.states[get(x, y, z)];
}
@Override
public int getSkyLight(int x, int y, int z) {
return 0;
}
@Override
public int getEmittedLight(int x, int y, int z) {
return 0;
}
@Override
public int[] getHeightMap(HeightMapType type) {
return new int[0];
}
@Override
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
return null;
}
public char get(int x, int y, int z) {
final int layer = (y >> 4) - getMinSectionPosition();
final int index = (y & 15) << 8 | z << 4 | x;
return blocks[layer][index];
}
@Override
public boolean trim(boolean aggressive) {
return false;
}
}

Datei anzeigen

@ -0,0 +1,34 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.bukkit.adapter.MapChunkUtil;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import net.minecraft.network.protocol.game.ClientboundLevelChunkPacketData;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
//TODO un-very-break-this
public class PaperweightMapChunkUtil extends MapChunkUtil<ClientboundLevelChunkWithLightPacket> {
public PaperweightMapChunkUtil() throws NoSuchFieldException {
fieldX = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("TWO_MEGABYTES", "a"));
fieldZ = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("x", "b"));
fieldBitMask = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("z", "c"));
fieldHeightMap = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("heightmaps", "b"));
fieldChunkData = ClientboundLevelChunkWithLightPacket.class.getDeclaredField(Refraction.pickName("chunkData", "d"));
fieldBlockEntities = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("buffer", "c"));
fieldFull = ClientboundLevelChunkPacketData.class.getDeclaredField(Refraction.pickName("blockEntitiesData", "d"));
fieldX.setAccessible(true);
fieldZ.setAccessible(true);
fieldBitMask.setAccessible(true);
fieldHeightMap.setAccessible(true);
fieldChunkData.setAccessible(true);
fieldBlockEntities.setAccessible(true);
fieldFull.setAccessible(true);
}
@Override
public ClientboundLevelChunkWithLightPacket createPacket() {
// TODO ??? return new ClientboundLevelChunkPacket();
throw new UnsupportedOperationException();
}
}

Datei anzeigen

@ -0,0 +1,727 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
import com.destroystokyo.paper.util.maplist.EntityList;
import com.fastasyncworldedit.bukkit.adapter.CachedBukkitAdapter;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.ReflectionUtils;
import com.fastasyncworldedit.core.util.TaskManager;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.world.biome.BiomeType;
import com.sk89q.worldedit.world.biome.BiomeTypes;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import io.papermc.lib.PaperLib;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Holder;
import net.minecraft.core.IdMap;
import net.minecraft.core.Registry;
import net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.BitStorage;
import net.minecraft.util.ExceptionCollector;
import net.minecraft.util.SimpleBitStorage;
import net.minecraft.util.ThreadingDetector;
import net.minecraft.util.Unit;
import net.minecraft.util.ZeroBitStorage;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.GlobalPalette;
import net.minecraft.world.level.chunk.HashMapPalette;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.LinearPalette;
import net.minecraft.world.level.chunk.Palette;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.chunk.SingleValuePalette;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.entity.PersistentEntitySectionManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftChunk;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import static java.lang.invoke.MethodType.methodType;
import static net.minecraft.core.registries.Registries.BIOME;
public final class PaperweightPlatformAdapter extends NMSAdapter {
public static final Field fieldData;
public static final Constructor<?> dataConstructor;
public static final Field fieldStorage;
public static final Field fieldPalette;
private static final Field fieldTickingFluidCount;
private static final Field fieldTickingBlockCount;
private static final Field fieldBiomes;
private static final MethodHandle methodGetVisibleChunk;
private static final Field fieldThreadingDetector;
private static final Field fieldLock;
private static final MethodHandle methodRemoveGameEventListener;
private static final MethodHandle methodremoveTickingBlockEntity;
/*
* This is a workaround for the changes from https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/1fddefce1cdce44010927b888432bf70c0e88cde#src/main/java/org/bukkit/craftbukkit/CraftChunk.java
* and is only needed to support 1.19.4 versions before *and* after this change.
*/
private static final MethodHandle CRAFT_CHUNK_GET_HANDLE;
private static final Field fieldRemove;
private static final Logger LOGGER = LogManagerCompat.getLogger();
static final boolean POST_CHUNK_REWRITE;
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
private static Field LEVEL_CHUNK_ENTITIES;
private static Field SERVER_LEVEL_ENTITY_MANAGER;
static {
final MethodHandles.Lookup lookup = MethodHandles.lookup();
try {
fieldData = PalettedContainer.class.getDeclaredField(Refraction.pickName("data", "d"));
fieldData.setAccessible(true);
Class<?> dataClazz = fieldData.getType();
dataConstructor = dataClazz.getDeclaredConstructors()[0];
dataConstructor.setAccessible(true);
fieldStorage = dataClazz.getDeclaredField(Refraction.pickName("storage", "b"));
fieldStorage.setAccessible(true);
fieldPalette = dataClazz.getDeclaredField(Refraction.pickName("palette", "c"));
fieldPalette.setAccessible(true);
fieldTickingFluidCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingFluidCount", "g"));
fieldTickingFluidCount.setAccessible(true);
fieldTickingBlockCount = LevelChunkSection.class.getDeclaredField(Refraction.pickName("tickingBlockCount", "f"));
fieldTickingBlockCount.setAccessible(true);
fieldBiomes = LevelChunkSection.class.getDeclaredField(Refraction.pickName("biomes", "i"));
fieldBiomes.setAccessible(true);
Method getVisibleChunkIfPresent = ChunkMap.class.getDeclaredMethod(Refraction.pickName(
"getVisibleChunkIfPresent",
"b"
), long.class);
getVisibleChunkIfPresent.setAccessible(true);
methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent);
if (!PaperLib.isPaper()) {
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetector.setAccessible(true);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLock.setAccessible(true);
} else {
// in paper, the used methods are synchronized properly
fieldThreadingDetector = null;
fieldLock = null;
}
Method removeGameEventListener = LevelChunk.class.getDeclaredMethod(
Refraction.pickName("removeGameEventListener", "a"),
BlockEntity.class,
ServerLevel.class
);
removeGameEventListener.setAccessible(true);
methodRemoveGameEventListener = lookup.unreflect(removeGameEventListener);
Method removeBlockEntityTicker = LevelChunk.class.getDeclaredMethod(
Refraction.pickName(
"removeBlockEntityTicker",
"k"
), BlockPos.class
);
removeBlockEntityTicker.setAccessible(true);
methodremoveTickingBlockEntity = lookup.unreflect(removeBlockEntityTicker);
fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p"));
fieldRemove.setAccessible(true);
boolean chunkRewrite;
try {
Level.class.getDeclaredMethod("moonrise$getEntityLookup");
chunkRewrite = true;
PAPER_CHUNK_GEN_ALL_ENTITIES = ChunkEntitySlices.class.getDeclaredMethod("getAllEntities");
PAPER_CHUNK_GEN_ALL_ENTITIES.setAccessible(true);
} catch (NoSuchMethodException ignored) {
chunkRewrite = false;
}
try {
// Paper - Pre-Chunk-Update
LEVEL_CHUNK_ENTITIES = LevelChunk.class.getDeclaredField("entities");
LEVEL_CHUNK_ENTITIES.setAccessible(true);
} catch (NoSuchFieldException ignored) {
}
try {
// Non-Paper
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "N"));
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
} catch (NoSuchFieldException ignored) {
}
POST_CHUNK_REWRITE = chunkRewrite;
} catch (RuntimeException | Error e) {
throw e;
} catch (Exception e) {
throw new RuntimeException(e);
}
MethodHandle craftChunkGetHandle;
final MethodType type = methodType(LevelChunk.class);
try {
craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", type);
} catch (NoSuchMethodException | IllegalAccessException e) {
try {
final MethodType newType = methodType(ChunkAccess.class, ChunkStatus.class);
craftChunkGetHandle = lookup.findVirtual(CraftChunk.class, "getHandle", newType);
craftChunkGetHandle = MethodHandles.insertArguments(craftChunkGetHandle, 1, ChunkStatus.FULL);
} catch (NoSuchMethodException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
}
CRAFT_CHUNK_GET_HANDLE = craftChunkGetHandle;
}
static boolean setSectionAtomic(
LevelChunkSection[] sections,
LevelChunkSection expected,
LevelChunkSection value,
int layer
) {
if (layer >= 0 && layer < sections.length) {
return ReflectionUtils.compareAndSet(sections, expected, value, layer);
}
return false;
}
// There is no point in having a functional semaphore for paper servers.
private static final ThreadLocal<DelegateSemaphore> SEMAPHORE_THREAD_LOCAL =
ThreadLocal.withInitial(() -> new DelegateSemaphore(1, null));
static DelegateSemaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) {
return SEMAPHORE_THREAD_LOCAL.get();
}
try {
synchronized (section) {
PalettedContainer<net.minecraft.world.level.block.state.BlockState> blocks = section.getStates();
ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks);
synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector);
if (currentLock instanceof DelegateSemaphore delegateSemaphore) {
return delegateSemaphore;
}
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
fieldLock.set(currentThreadingDetector, newLock);
return newLock;
}
}
} catch (Throwable e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public static LevelChunk ensureLoaded(ServerLevel serverLevel, int chunkX, int chunkZ) {
if (!PaperLib.isPaper()) {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunk(chunkX, chunkZ, false);
if (nmsChunk != null) {
return nmsChunk;
}
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
} else {
LevelChunk nmsChunk = serverLevel.getChunkSource().getChunkAtIfCachedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk;
}
nmsChunk = serverLevel.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
if (nmsChunk != null) {
addTicket(serverLevel, chunkX, chunkZ);
return nmsChunk;
}
// Avoid "async" methods from the main thread.
if (Fawe.isMainThread()) {
return serverLevel.getChunk(chunkX, chunkZ);
}
CompletableFuture<org.bukkit.Chunk> future = serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true);
try {
CraftChunk chunk;
try {
chunk = (CraftChunk) future.get(10, TimeUnit.SECONDS);
} catch (TimeoutException e) {
String world = serverLevel.getWorld().getName();
// We've already taken 10 seconds we can afford to wait a little here.
boolean loaded = TaskManager.taskManager().sync(() -> Bukkit.getWorld(world) != null);
if (loaded) {
LOGGER.warn("Chunk {},{} failed to load in 10 seconds in world {}. Retrying...", chunkX, chunkZ, world);
// Retry chunk load
chunk = (CraftChunk) serverLevel.getWorld().getChunkAtAsync(chunkX, chunkZ, true, true).get();
} else {
throw new UnsupportedOperationException("Cannot load chunk from unloaded world " + world + "!");
}
}
addTicket(serverLevel, chunkX, chunkZ);
return (LevelChunk) CRAFT_CHUNK_GET_HANDLE.invoke(chunk);
} catch (Throwable e) {
e.printStackTrace();
}
}
return TaskManager.taskManager().sync(() -> serverLevel.getChunk(chunkX, chunkZ));
}
private static void addTicket(ServerLevel serverLevel, int chunkX, int chunkZ) {
// Ensure chunk is definitely loaded before applying a ticket
io.papermc.paper.util.MCUtil.MAIN_EXECUTOR.execute(() -> serverLevel
.getChunkSource()
.addRegionTicket(ChunkHolderManager.UNLOAD_COOLDOWN, new ChunkPos(chunkX, chunkZ), 0, Unit.INSTANCE));
}
public static ChunkHolder getPlayerChunk(ServerLevel nmsWorld, final int chunkX, final int chunkZ) {
ChunkMap chunkMap = nmsWorld.getChunkSource().chunkMap;
try {
return (ChunkHolder) methodGetVisibleChunk.invoke(chunkMap, ChunkPos.asLong(chunkX, chunkZ));
} catch (Throwable thr) {
throw new RuntimeException(thr);
}
}
@SuppressWarnings("deprecation")
public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) {
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
if (chunkHolder == null) {
return;
}
ChunkPos coordIntPair = new ChunkPos(chunkX, chunkZ);
LevelChunk levelChunk;
if (PaperLib.isPaper()) {
// getChunkAtIfLoadedImmediately is paper only
levelChunk = nmsWorld
.getChunkSource()
.getChunkAtIfLoadedImmediately(chunkX, chunkZ);
} else {
levelChunk = chunkHolder.getTickingChunkFuture()
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null);
}
if (levelChunk == null) {
return;
}
MinecraftServer.getServer().execute(() -> {
ClientboundLevelChunkWithLightPacket packet;
if (PaperLib.isPaper()) {
synchronized (chunk) {
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null,
false // last false is to not bother with x-ray
);
}
} else {
synchronized (chunk) {
// deprecated on paper - deprecation suppressed
packet = new ClientboundLevelChunkWithLightPacket(
levelChunk,
nmsWorld.getChunkSource().getLightEngine(),
null,
null
);
}
}
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
});
}
private static List<ServerPlayer> nearbyPlayers(ServerLevel serverLevel, ChunkPos coordIntPair) {
return serverLevel.getChunkSource().chunkMap.getPlayers(coordIntPair, false);
}
/*
NMS conversion
*/
public static LevelChunkSection newChunkSection(
final int layer,
final char[] blocks,
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
return newChunkSection(layer, null, blocks, adapter, biomeRegistry, biomes);
}
public static LevelChunkSection newChunkSection(
final int layer,
final Function<Integer, char[]> get,
char[] set,
CachedBukkitAdapter adapter,
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (set == null) {
return newChunkSection(biomeRegistry, biomes);
}
final int[] blockToPalette = FaweCache.INSTANCE.BLOCK_TO_PALETTE.get();
final int[] paletteToBlock = FaweCache.INSTANCE.PALETTE_TO_BLOCK.get();
final long[] blockStates = FaweCache.INSTANCE.BLOCK_STATES.get();
final int[] blocksCopy = FaweCache.INSTANCE.SECTION_BLOCKS.get();
try {
int num_palette;
if (get == null) {
num_palette = createPalette(blockToPalette, paletteToBlock, blocksCopy, set, adapter, null);
} else {
num_palette = createPalette(layer, blockToPalette, paletteToBlock, blocksCopy, get, set, adapter, null);
}
int bitsPerEntry = MathMan.log2nlz(num_palette - 1);
if (bitsPerEntry > 0 && bitsPerEntry < 5) {
bitsPerEntry = 4;
} else if (bitsPerEntry > 8) {
bitsPerEntry = MathMan.log2nlz(Block.BLOCK_STATE_REGISTRY.size() - 1);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int blockBitArrayEnd = MathMan.ceilZero((float) 4096 / blocksPerLong);
if (num_palette == 1) {
for (int i = 0; i < blockBitArrayEnd; i++) {
blockStates[i] = 0;
}
} else {
final BitArrayUnstretched bitArray = new BitArrayUnstretched(bitsPerEntryNonZero, 4096, blockStates);
bitArray.fromRaw(blocksCopy);
}
final long[] bits = Arrays.copyOfRange(blockStates, 0, blockBitArrayEnd);
final BitStorage nmsBits;
if (bitsPerEntry == 0) {
nmsBits = new ZeroBitStorage(4096);
} else {
nmsBits = new SimpleBitStorage(bitsPerEntry, 4096, bits);
}
List<net.minecraft.world.level.block.state.BlockState> palette;
if (bitsPerEntry < 9) {
palette = new ArrayList<>();
for (int i = 0; i < num_palette; i++) {
int ordinal = paletteToBlock[i];
blockToPalette[ordinal] = Integer.MAX_VALUE;
final BlockState state = BlockTypesCache.states[ordinal];
palette.add(((PaperweightBlockMaterial) state.getMaterial()).getState());
}
} else {
palette = List.of();
}
// Create palette with data
@SuppressWarnings("deprecation") // constructor is deprecated on paper, but needed to keep compatibility with spigot
final PalettedContainer<net.minecraft.world.level.block.state.BlockState> blockStatePalettedContainer =
new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
PalettedContainer.Strategy.SECTION_STATES,
PalettedContainer.Strategy.SECTION_STATES.getConfiguration(Block.BLOCK_STATE_REGISTRY, bitsPerEntry),
nmsBits,
palette
);
if (biomes == null) {
IdMap<Holder<Biome>> biomeHolderIdMap = biomeRegistry.asHolderIdMap();
biomes = new PalettedContainer<>(
biomeHolderIdMap,
biomeHolderIdMap.byIdOrThrow(WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(
BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES
);
}
return new LevelChunkSection(blockStatePalettedContainer, biomes);
} catch (final Throwable e) {
throw e;
} finally {
Arrays.fill(blockToPalette, Integer.MAX_VALUE);
Arrays.fill(paletteToBlock, Integer.MAX_VALUE);
Arrays.fill(blockStates, 0);
Arrays.fill(blocksCopy, 0);
}
}
@SuppressWarnings("deprecation") // Only deprecated in paper
private static LevelChunkSection newChunkSection(
Registry<Biome> biomeRegistry,
@Nullable PalettedContainer<Holder<Biome>> biomes
) {
if (biomes == null) {
return new LevelChunkSection(biomeRegistry);
}
PalettedContainer<net.minecraft.world.level.block.state.BlockState> dataPaletteBlocks = new PalettedContainer<>(
Block.BLOCK_STATE_REGISTRY,
Blocks.AIR.defaultBlockState(),
PalettedContainer.Strategy.SECTION_STATES
);
return new LevelChunkSection(dataPaletteBlocks, biomes);
}
public static void setBiomesToChunkSection(LevelChunkSection section, PalettedContainer<Holder<Biome>> biomes) {
try {
fieldBiomes.set(section, biomes);
} catch (IllegalAccessException e) {
LOGGER.error("Could not set biomes to chunk section", e);
}
}
/**
* Create a new {@link PalettedContainer<Biome>}. Should only be used if no biome container existed beforehand.
*/
public static PalettedContainer<Holder<Biome>> getBiomePalettedContainer(
BiomeType[] biomes,
IdMap<Holder<Biome>> biomeRegistry
) {
if (biomes == null) {
return null;
}
BukkitImplAdapter<?> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
// Don't stream this as typically will see 1-4 biomes; stream overhead is large for the small length
Map<BiomeType, Holder<Biome>> palette = new HashMap<>();
for (BiomeType biomeType : new LinkedList<>(Arrays.asList(biomes))) {
Holder<Biome> biome;
if (biomeType == null) {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(BiomeTypes.PLAINS));
} else {
biome = biomeRegistry.byId(adapter.getInternalBiomeId(biomeType));
}
palette.put(biomeType, biome);
}
int biomeCount = palette.size();
int bitsPerEntry = MathMan.log2nlz(biomeCount - 1);
Object configuration = PalettedContainer.Strategy.SECTION_STATES.getConfiguration(
new FakeIdMapBiome(biomeCount),
bitsPerEntry
);
if (bitsPerEntry > 3) {
bitsPerEntry = MathMan.log2nlz(biomeRegistry.size() - 1);
}
PalettedContainer<Holder<Biome>> biomePalettedContainer = new PalettedContainer<>(
biomeRegistry,
biomeRegistry.byIdOrThrow(adapter.getInternalBiomeId(BiomeTypes.PLAINS)),
PalettedContainer.Strategy.SECTION_BIOMES
);
final Palette<Holder<Biome>> biomePalette;
if (bitsPerEntry == 0) {
biomePalette = new SingleValuePalette<>(
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry == 4) {
biomePalette = LinearPalette.create(
4,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else if (bitsPerEntry < 9) {
biomePalette = HashMapPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
new ArrayList<>(palette.values()) // Must be modifiable
);
} else {
biomePalette = GlobalPalette.create(
bitsPerEntry,
biomePalettedContainer.registry,
biomePalettedContainer,
null // unused
);
}
int bitsPerEntryNonZero = Math.max(bitsPerEntry, 1); // We do want to use zero sometimes
final int blocksPerLong = MathMan.floorZero((double) 64 / bitsPerEntryNonZero);
final int arrayLength = MathMan.ceilZero(64f / blocksPerLong);
BitStorage bitStorage = bitsPerEntry == 0 ? new ZeroBitStorage(64) : new SimpleBitStorage(
bitsPerEntry,
64,
new long[arrayLength]
);
try {
Object data = dataConstructor.newInstance(configuration, bitStorage, biomePalette);
fieldData.set(biomePalettedContainer, data);
int index = 0;
for (int y = 0; y < 4; y++) {
for (int z = 0; z < 4; z++) {
for (int x = 0; x < 4; x++, index++) {
BiomeType biomeType = biomes[index];
if (biomeType == null) {
continue;
}
Holder<Biome> biome = biomeRegistry.byId(WorldEditPlugin
.getInstance()
.getBukkitImplAdapter()
.getInternalBiomeId(biomeType));
if (biome == null) {
continue;
}
biomePalettedContainer.set(x, y, z, biome);
}
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
return biomePalettedContainer;
}
public static void clearCounts(final LevelChunkSection section) throws IllegalAccessException {
fieldTickingFluidCount.setShort(section, (short) 0);
fieldTickingBlockCount.setShort(section, (short) 0);
}
public static BiomeType adapt(Holder<Biome> biome, LevelAccessor levelAccessor) {
final Registry<Biome> biomeRegistry = levelAccessor.registryAccess().registryOrThrow(BIOME);
if (biomeRegistry.getKey(biome.value()) == null) {
return biomeRegistry.asHolderIdMap().getId(biome) == -1 ? BiomeTypes.OCEAN
: null;
}
return BiomeTypes.get(biome.unwrapKey().orElseThrow().location().toString());
}
static void removeBeacon(BlockEntity beacon, LevelChunk levelChunk) {
try {
if (levelChunk.loaded || levelChunk.level.isClientSide()) {
BlockEntity blockEntity = levelChunk.blockEntities.remove(beacon.getBlockPos());
if (blockEntity != null) {
if (!levelChunk.level.isClientSide) {
methodRemoveGameEventListener.invoke(levelChunk, beacon, levelChunk.level);
}
fieldRemove.set(beacon, true);
}
}
methodremoveTickingBlockEntity.invoke(levelChunk, beacon.getBlockPos());
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}
static List<Entity> getEntities(LevelChunk chunk) {
ExceptionCollector<RuntimeException> collector = new ExceptionCollector<>();
if (PaperLib.isPaper()) {
if (POST_CHUNK_REWRITE) {
try {
//noinspection unchecked
return (List<Entity>) PAPER_CHUNK_GEN_ALL_ENTITIES.invoke(chunk.level.moonrise$getEntityLookup().getChunk(chunk.locX, chunk.locZ));
} catch (IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=true]", e);
}
}
try {
EntityList entityList = (EntityList) LEVEL_CHUNK_ENTITIES.get(chunk);
return List.of(entityList.getRawData());
} catch (IllegalAccessException e) {
collector.add(new RuntimeException("Failed to lookup entities [POST_CHUNK_REWRITE=false]", e));
// fall through
}
}
try {
//noinspection unchecked
return ((PersistentEntitySectionManager<Entity>) (SERVER_LEVEL_ENTITY_MANAGER.get(chunk.level))).getEntities(chunk.getPos());
} catch (IllegalAccessException e) {
collector.add(new RuntimeException("Failed to lookup entities [PAPER=false]", e));
}
collector.throwIfPresent();
return List.of();
}
record FakeIdMapBlock(int size) implements IdMap<net.minecraft.world.level.block.state.BlockState> {
@Override
public int getId(final net.minecraft.world.level.block.state.BlockState entry) {
return 0;
}
@Nullable
@Override
public net.minecraft.world.level.block.state.BlockState byId(final int index) {
return null;
}
@Nonnull
@Override
public Iterator<net.minecraft.world.level.block.state.BlockState> iterator() {
return Collections.emptyIterator();
}
}
record FakeIdMapBiome(int size) implements IdMap<Biome> {
@Override
public int getId(final Biome entry) {
return 0;
}
@Nullable
@Override
public Biome byId(final int index) {
return null;
}
@Nonnull
@Override
public Iterator<Biome> iterator() {
return Collections.emptyIterator();
}
}
}

Datei anzeigen

@ -0,0 +1,175 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
import com.fastasyncworldedit.core.queue.IBatchProcessor;
import com.fastasyncworldedit.core.queue.IChunk;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.queue.IChunkSet;
import com.fastasyncworldedit.core.registry.state.PropertyKey;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.world.block.BlockState;
import com.sk89q.worldedit.world.block.BlockTypes;
import com.sk89q.worldedit.world.block.BlockTypesCache;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.material.Fluid;
import net.minecraft.world.level.material.Fluids;
import javax.annotation.Nullable;
public class PaperweightPostProcessor implements IBatchProcessor {
@Override
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
return set;
}
@SuppressWarnings("deprecation")
@Override
public void postProcess(final IChunk chunk, final IChunkGet iChunkGet, final IChunkSet iChunkSet) {
boolean tickFluid = Settings.settings().EXPERIMENTAL.ALLOW_TICK_FLUIDS;
// The PostProcessor shouldn't be added, but just in case
if (!tickFluid) {
return;
}
PaperweightGetBlocks_Copy getBlocks = (PaperweightGetBlocks_Copy) iChunkGet;
layer:
for (int layer = iChunkSet.getMinSectionPosition(); layer <= iChunkSet.getMaxSectionPosition(); layer++) {
char[] set = iChunkSet.loadIfPresent(layer);
if (set == null) {
// No edit means no need to process
continue;
}
char[] get = null;
for (int i = 0; i < 4096; i++) {
char ordinal = set[i];
char replacedOrdinal = BlockTypesCache.ReservedIDs.__RESERVED__;
boolean fromGet = false; // Used for liquids
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
if (get == null) {
get = getBlocks.load(layer);
}
// If this is null, then it's because we're loading a layer in the range of 0->15, but blocks aren't
// actually being set
if (get == null) {
continue layer;
}
fromGet = true;
ordinal = replacedOrdinal = get[i];
}
if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) {
continue;
} else if (!fromGet) { // if fromGet, don't do the same again
if (get == null) {
get = getBlocks.load(layer);
}
replacedOrdinal = get[i];
}
boolean ticking = BlockTypesCache.ticking[ordinal];
boolean replacedWasTicking = BlockTypesCache.ticking[replacedOrdinal];
boolean replacedWasLiquid = false;
BlockState replacedState = null;
if (!ticking) {
// If the block being replaced was not ticking, it cannot be a liquid
if (!replacedWasTicking) {
continue;
}
// If the block being replaced is not fluid, we do not need to worry
if (!(replacedWasLiquid =
(replacedState = BlockState.getFromOrdinal(replacedOrdinal)).getMaterial().isLiquid())) {
continue;
}
}
BlockState state = BlockState.getFromOrdinal(ordinal);
boolean liquid = state.getMaterial().isLiquid();
int x = i & 15;
int y = (i >> 8) & 15;
int z = (i >> 4) & 15;
BlockPos position = new BlockPos((chunk.getX() << 4) + x, (layer << 4) + y, (chunk.getZ() << 4) + z);
if (liquid || replacedWasLiquid) {
if (liquid) {
addFluid(getBlocks.serverLevel, state, position);
continue;
}
// If the replaced fluid (is?) adjacent to water. Do not bother to check adjacent chunks(sections) as this
// may be time consuming. Chances are any fluid blocks in adjacent chunks are being replaced or will end up
// being ticked anyway. We only need it to be "hit" once.
if (!wasAdjacentToWater(get, set, i, x, y, z)) {
continue;
}
addFluid(getBlocks.serverLevel, replacedState, position);
}
}
}
}
@Nullable
@Override
public Extent construct(final Extent child) {
throw new UnsupportedOperationException("Processing only");
}
@Override
public ProcessorScope getScope() {
return ProcessorScope.READING_SET_BLOCKS;
}
private boolean wasAdjacentToWater(char[] get, char[] set, int i, int x, int y, int z) {
if (set == null || get == null) {
return false;
}
char ordinal;
char reserved = BlockTypesCache.ReservedIDs.__RESERVED__;
if (x > 0 && set[i - 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 1])] && isFluid(ordinal)) {
return true;
}
}
if (x < 15 && set[i + 1] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 1])] && isFluid(ordinal)) {
return true;
}
}
if (z > 0 && set[i - 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 16])] && isFluid(ordinal)) {
return true;
}
}
if (z < 15 && set[i + 16] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i + 16])] && isFluid(ordinal)) {
return true;
}
}
if (y > 0 && set[i - 256] != reserved) {
if (BlockTypesCache.ticking[(ordinal = get[i - 256])] && isFluid(ordinal)) {
return true;
}
}
if (y < 15 && set[i + 256] != reserved) {
return BlockTypesCache.ticking[(ordinal = get[i + 256])] && isFluid(ordinal);
}
return false;
}
@SuppressWarnings("deprecation")
private boolean isFluid(char ordinal) {
return BlockState.getFromOrdinal(ordinal).getMaterial().isLiquid();
}
@SuppressWarnings("deprecation")
private void addFluid(final ServerLevel serverLevel, final BlockState replacedState, final BlockPos position) {
Fluid type;
if (replacedState.getBlockType() == BlockTypes.LAVA) {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.LAVA : Fluids.FLOWING_LAVA;
} else {
type = (int) replacedState.getState(PropertyKey.LEVEL) == 0 ? Fluids.WATER : Fluids.FLOWING_WATER;
}
serverLevel.scheduleTick(
position,
type,
type.getTickDelay(serverLevel)
);
}
}

Datei anzeigen

@ -0,0 +1,79 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
import com.fastasyncworldedit.core.configuration.Settings;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.TicketType;
import net.minecraft.util.Unit;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.status.ChunkPyramid;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLevel, ChunkPos> {
private static final TicketType<Unit> FAWE_TICKET = TicketType.create("fawe_ticket", (a, b) -> 0);
private static final int LIGHT_LEVEL = ChunkMap.MAX_VIEW_DISTANCE + ChunkPyramid.LOADING_PYRAMID
.getStepTo(ChunkStatus.FULL)
.getAccumulatedRadiusOf(ChunkStatus.LIGHT);
public PaperweightStarlightRelighter(ServerLevel serverLevel, IQueueExtent<?> queue) {
super(serverLevel, queue);
}
@Override
protected ChunkPos createChunkPos(final long chunkKey) {
return new ChunkPos(chunkKey);
}
@Override
protected long asLong(final int chunkX, final int chunkZ) {
return ChunkPos.asLong(chunkX, chunkZ);
}
@Override
protected CompletableFuture<?> chunkLoadFuture(final ChunkPos chunkPos) {
return serverLevel.getWorld().getChunkAtAsync(chunkPos.x, chunkPos.z)
.thenAccept(c -> serverLevel.getChunkSource().addTicketAtLevel(
FAWE_TICKET,
chunkPos,
LIGHT_LEVEL,
Unit.INSTANCE
));
}
protected void invokeRelight(
Set<ChunkPos> coords,
Consumer<ChunkPos> chunkCallback,
IntConsumer processCallback
) {
try {
serverLevel.getChunkSource().getLightEngine().starlight$serverRelightChunks(coords, chunkCallback, processCallback);
} catch (Exception e) {
LOGGER.error("Error occurred on relighting", e);
}
}
/*
* Allow the server to unload the chunks again.
* Also, if chunk packets are sent delayed, we need to do that here
*/
protected void postProcessChunks(Set<ChunkPos> coords) {
boolean delay = Settings.settings().LIGHTING.DELAY_PACKET_SENDING;
for (ChunkPos pos : coords) {
int x = pos.x;
int z = pos.z;
if (delay) { // we still need to send the block changes of that chunk
PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z);
}
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
}
}
}

Datei anzeigen

@ -0,0 +1,25 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
import com.fastasyncworldedit.core.extent.processor.lighting.NullRelighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelightMode;
import com.fastasyncworldedit.core.extent.processor.lighting.Relighter;
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
import com.fastasyncworldedit.core.queue.IQueueExtent;
import com.sk89q.worldedit.world.World;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftWorld;
import javax.annotation.Nonnull;
public class PaperweightStarlightRelighterFactory implements RelighterFactory {
@Override
public @Nonnull Relighter createRelighter(RelightMode relightMode, World world, IQueueExtent<?> queue) {
org.bukkit.World w = Bukkit.getWorld(world.getName());
if (w == null) {
return NullRelighter.INSTANCE;
}
return new PaperweightStarlightRelighter(((CraftWorld) w).getHandle(), queue);
}
}

Datei anzeigen

@ -0,0 +1,161 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.LazyCompoundTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.StringTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import net.minecraft.nbt.NumericTag;
import org.enginehub.linbus.tree.LinCompoundTag;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
public class PaperweightLazyCompoundTag extends LazyCompoundTag {
private final Supplier<net.minecraft.nbt.CompoundTag> compoundTagSupplier;
private CompoundTag compoundTag;
public PaperweightLazyCompoundTag(Supplier<net.minecraft.nbt.CompoundTag> compoundTagSupplier) {
super(new HashMap<>());
this.compoundTagSupplier = compoundTagSupplier;
}
public PaperweightLazyCompoundTag(net.minecraft.nbt.CompoundTag compoundTag) {
this(() -> compoundTag);
}
public net.minecraft.nbt.CompoundTag get() {
return compoundTagSupplier.get();
}
@Override
@SuppressWarnings("unchecked")
public Map<String, Tag<?, ?>> getValue() {
if (compoundTag == null) {
compoundTag = (CompoundTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(compoundTagSupplier.get());
}
return compoundTag.getValue();
}
@Override
public LinCompoundTag toLinTag() {
getValue();
return compoundTag.toLinTag();
}
public boolean containsKey(String key) {
return compoundTagSupplier.get().contains(key);
}
public byte[] getByteArray(String key) {
return compoundTagSupplier.get().getByteArray(key);
}
public byte getByte(String key) {
return compoundTagSupplier.get().getByte(key);
}
public double getDouble(String key) {
return compoundTagSupplier.get().getDouble(key);
}
public double asDouble(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) {
return numTag.getAsDouble();
}
return 0;
}
public float getFloat(String key) {
return compoundTagSupplier.get().getFloat(key);
}
public int[] getIntArray(String key) {
return compoundTagSupplier.get().getIntArray(key);
}
public int getInt(String key) {
return compoundTagSupplier.get().getInt(key);
}
public int asInt(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) {
return numTag.getAsInt();
}
return 0;
}
@SuppressWarnings("unchecked")
public List<? extends Tag<?, ?>> getList(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag nbtList) {
ArrayList<Tag<?, ?>> list = new ArrayList<>();
for (net.minecraft.nbt.Tag elem : nbtList) {
if (elem instanceof net.minecraft.nbt.CompoundTag compoundTag) {
list.add(new PaperweightLazyCompoundTag(compoundTag));
} else {
list.add(WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(elem));
}
}
return list;
}
return Collections.emptyList();
}
@SuppressWarnings("unchecked")
public ListTag getListTag(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof net.minecraft.nbt.ListTag) {
return (ListTag) WorldEditPlugin.getInstance().getBukkitImplAdapter().toNative(tag);
}
return new ListTag(StringTag.class, Collections.emptyList());
}
@SuppressWarnings("unchecked")
public <T extends Tag<?, ?>> List<T> getList(String key, Class<T> listType) {
ListTag listTag = getListTag(key);
if (listTag.getType().equals(listType)) {
return (List<T>) listTag.getValue();
} else {
return Collections.emptyList();
}
}
public long[] getLongArray(String key) {
return compoundTagSupplier.get().getLongArray(key);
}
public long getLong(String key) {
return compoundTagSupplier.get().getLong(key);
}
public long asLong(String key) {
net.minecraft.nbt.Tag tag = compoundTagSupplier.get().get(key);
if (tag instanceof NumericTag numTag) {
return numTag.getAsLong();
}
return 0;
}
public short getShort(String key) {
return compoundTagSupplier.get().getShort(key);
}
public String getString(String key) {
return compoundTagSupplier.get().getString(key);
}
@Override
public String toString() {
return compoundTagSupplier.get().toString();
}
}

Datei anzeigen

@ -0,0 +1,623 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
import com.fastasyncworldedit.bukkit.adapter.Regenerator;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.queue.IChunkCache;
import com.fastasyncworldedit.core.queue.IChunkGet;
import com.fastasyncworldedit.core.util.TaskManager;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Lifecycle;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.adapter.Refraction;
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.PaperweightGetBlocks;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.io.file.SafeFiles;
import com.sk89q.worldedit.world.RegenOptions;
import io.papermc.lib.PaperLib;
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
import net.minecraft.core.Holder;
import net.minecraft.core.Registry;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message;
import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ThreadedLevelLightEngine;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.StaticCache2D;
import net.minecraft.util.thread.ProcessorHandle;
import net.minecraft.util.thread.ProcessorMailbox;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.biome.Biome;
import net.minecraft.world.level.biome.BiomeSource;
import net.minecraft.world.level.biome.FixedBiomeSource;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.chunk.ChunkGeneratorStructureState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.UpgradeData;
import net.minecraft.world.level.chunk.status.ChunkPyramid;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.status.WorldGenContext;
import net.minecraft.world.level.dimension.LevelStem;
import net.minecraft.world.level.levelgen.FlatLevelSource;
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
import net.minecraft.world.level.levelgen.WorldOptions;
import net.minecraft.world.level.levelgen.blending.BlendingData;
import net.minecraft.world.level.levelgen.flat.FlatLevelGeneratorSettings;
import net.minecraft.world.level.levelgen.structure.placement.ConcentricRingsStructurePlacement;
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.storage.PrimaryLevelData;
import org.apache.logging.log4j.Logger;
import org.bukkit.Bukkit;
import org.bukkit.Chunk;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
import org.bukkit.generator.BiomeProvider;
import org.bukkit.generator.BlockPopulator;
import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.OptionalLong;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.function.BooleanSupplier;
import java.util.function.Supplier;
import static net.minecraft.core.registries.Registries.BIOME;
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
private static final Logger LOGGER = LogManagerCompat.getLogger();
private static final Field serverWorldsField;
private static final Field paperConfigField;
private static final Field flatBedrockField;
private static final Field generatorSettingFlatField;
private static final Field generatorSettingBaseSupplierField;
private static final Field delegateField;
private static final Field chunkSourceField;
private static final Field generatorStructureStateField;
private static final Field ringPositionsField;
private static final Field hasGeneratedPositionsField;
//list of chunk stati in correct order without FULL
private static final Map<ChunkStatus, Concurrency> chunkStati = new LinkedHashMap<>();
static {
chunkStati.put(ChunkStatus.EMPTY, Concurrency.FULL); // empty: radius -1, does nothing
chunkStati.put(ChunkStatus.STRUCTURE_STARTS, Concurrency.NONE); // structure starts: uses unsynchronized maps
chunkStati.put(
ChunkStatus.STRUCTURE_REFERENCES,
Concurrency.NONE
); // structure refs: radius 8, but only writes to current chunk
chunkStati.put(ChunkStatus.BIOMES, Concurrency.NONE); // biomes: radius 0
chunkStati.put(ChunkStatus.NOISE, Concurrency.RADIUS); // noise: radius 8
chunkStati.put(ChunkStatus.SURFACE, Concurrency.NONE); // surface: radius 0, requires NONE
chunkStati.put(ChunkStatus.CARVERS, Concurrency.NONE); // carvers: radius 0, but RADIUS and FULL change results
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
chunkStati.put(
ChunkStatus.INITIALIZE_LIGHT,
Concurrency.FULL
); // initialize_light: radius 0
chunkStati.put(
ChunkStatus.LIGHT,
Concurrency.FULL
); // light: radius 1, but no writes to other chunks, only current chunk
chunkStati.put(ChunkStatus.SPAWN, Concurrency.NONE); // spawn: radius 0
try {
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
serverWorldsField.setAccessible(true);
Field tmpPaperConfigField;
Field tmpFlatBedrockField;
try { //only present on paper
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
tmpPaperConfigField.setAccessible(true);
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
tmpFlatBedrockField.setAccessible(true);
} catch (Exception e) {
tmpPaperConfigField = null;
tmpFlatBedrockField = null;
}
paperConfigField = tmpPaperConfigField;
flatBedrockField = tmpFlatBedrockField;
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
"settings", "e"));
generatorSettingBaseSupplierField.setAccessible(true);
generatorSettingFlatField = FlatLevelSource.class.getDeclaredField(Refraction.pickName("settings", "d"));
generatorSettingFlatField.setAccessible(true);
delegateField = CustomChunkGenerator.class.getDeclaredField("delegate");
delegateField.setAccessible(true);
chunkSourceField = ServerLevel.class.getDeclaredField(Refraction.pickName("chunkSource", "I"));
chunkSourceField.setAccessible(true);
generatorStructureStateField = ChunkMap.class.getDeclaredField(Refraction.pickName("chunkGeneratorState", "w"));
generatorStructureStateField.setAccessible(true);
ringPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(Refraction.pickName("ringPositions", "g"));
ringPositionsField.setAccessible(true);
hasGeneratedPositionsField = ChunkGeneratorStructureState.class.getDeclaredField(
Refraction.pickName("hasGeneratedPositions", "h")
);
hasGeneratedPositionsField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
//runtime
private ServerLevel originalServerWorld;
private ServerChunkCache originalChunkProvider;
private ServerLevel freshWorld;
private ServerChunkCache freshChunkProvider;
private LevelStorageSource.LevelStorageAccess session;
private StructureTemplateManager structureTemplateManager;
private ThreadedLevelLightEngine threadedLevelLightEngine;
private ChunkGenerator chunkGenerator;
private WorldGenContext worldGenContext;
private Path tempDir;
private boolean generateFlatBedrock = false;
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
super(originalBukkitWorld, region, target, options);
if (PaperLib.isPaper()) {
throw new UnsupportedOperationException("Regeneration currently not support on Paper due to the new generation system");
}
}
@Override
protected boolean prepare() {
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
originalChunkProvider = originalServerWorld.getChunkSource();
//flat bedrock? (only on paper)
if (paperConfigField != null) {
try {
generateFlatBedrock = flatBedrockField.getBoolean(paperConfigField.get(originalServerWorld));
} catch (Exception ignored) {
}
}
seed = options.getSeed().orElse(originalServerWorld.getSeed());
chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c));
return true;
}
@Override
@SuppressWarnings("unchecked")
protected boolean initNewWorld() throws Exception {
//world folder
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
//prepare for world init (see upstream implementation for reference)
org.bukkit.World.Environment environment = originalBukkitWorld.getEnvironment();
org.bukkit.generator.ChunkGenerator generator = originalBukkitWorld.getGenerator();
LevelStorageSource levelStorageSource = LevelStorageSource.createDefault(tempDir);
ResourceKey<LevelStem> levelStemResourceKey = getWorldDimKey(environment);
session = levelStorageSource.createAccess("faweregentempworld", levelStemResourceKey);
PrimaryLevelData originalWorldData = originalServerWorld.serverLevelData;
MinecraftServer server = originalServerWorld.getCraftServer().getServer();
WorldOptions originalOpts = originalWorldData.worldGenOptions();
WorldOptions newOpts = options.getSeed().isPresent()
? originalOpts.withSeed(OptionalLong.of(seed))
: originalOpts;
LevelSettings newWorldSettings = new LevelSettings(
"faweregentempworld",
originalWorldData.settings.gameType(),
originalWorldData.settings.hardcore(),
originalWorldData.settings.difficulty(),
originalWorldData.settings.allowCommands(),
originalWorldData.settings.gameRules(),
originalWorldData.settings.getDataConfiguration()
);
PrimaryLevelData.SpecialWorldProperty specialWorldProperty =
originalWorldData.isFlatWorld()
? PrimaryLevelData.SpecialWorldProperty.FLAT
: originalWorldData.isDebugWorld()
? PrimaryLevelData.SpecialWorldProperty.DEBUG
: PrimaryLevelData.SpecialWorldProperty.NONE;
PrimaryLevelData newWorldData = new PrimaryLevelData(newWorldSettings, newOpts, specialWorldProperty, Lifecycle.stable());
BiomeProvider biomeProvider = getBiomeProvider();
//init world
freshWorld = Fawe.instance().getQueueHandler().sync((Supplier<ServerLevel>) () -> new ServerLevel(
server,
server.executor,
session,
newWorldData,
originalServerWorld.dimension(),
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
.getOrThrow(levelStemResourceKey),
new RegenNoOpWorldLoadListener(),
originalServerWorld.isDebug(),
seed,
ImmutableList.of(),
false,
originalServerWorld.getRandomSequences(),
environment,
generator,
biomeProvider
) {
private final Holder<Biome> singleBiome = options.hasBiomeType() ? DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
) : null;
@Override
public void tick(@NotNull BooleanSupplier shouldKeepTicking) { //no ticking
}
@Override
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
if (options.hasBiomeType()) {
return singleBiome;
}
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(
biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler()
);
}
}).get();
freshWorld.noSave = true;
removeWorldFromWorldsMap();
newWorldData.checkName(originalServerWorld.serverLevelData.getLevelName()); //rename to original world name
if (paperConfigField != null) {
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
}
ChunkGenerator originalGenerator = originalChunkProvider.getGenerator();
if (originalGenerator instanceof FlatLevelSource flatLevelSource) {
FlatLevelGeneratorSettings generatorSettingFlat = flatLevelSource.settings();
chunkGenerator = new FlatLevelSource(generatorSettingFlat);
} else if (originalGenerator instanceof NoiseBasedChunkGenerator noiseBasedChunkGenerator) {
Holder<NoiseGeneratorSettings> generatorSettingBaseSupplier = (Holder<NoiseGeneratorSettings>)
generatorSettingBaseSupplierField.get(noiseBasedChunkGenerator);
BiomeSource biomeSource;
if (options.hasBiomeType()) {
biomeSource = new FixedBiomeSource(
DedicatedServer.getServer().registryAccess()
.registryOrThrow(BIOME).asHolderIdMap().byIdOrThrow(
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
)
);
} else {
biomeSource = originalGenerator.getBiomeSource();
}
chunkGenerator = new NoiseBasedChunkGenerator(
biomeSource,
generatorSettingBaseSupplier
);
} else if (originalGenerator instanceof CustomChunkGenerator customChunkGenerator) {
chunkGenerator = customChunkGenerator.getDelegate();
} else {
LOGGER.error("Unsupported generator type {}", originalGenerator.getClass().getName());
return false;
}
if (generator != null) {
chunkGenerator = new CustomChunkGenerator(freshWorld, chunkGenerator, generator);
generateConcurrent = generator.isParallelCapable();
}
// chunkGenerator.conf = freshWorld.spigotConfig; - Does not exist anymore, may need to be re-addressed
freshChunkProvider = new ServerChunkCache(
freshWorld,
session,
server.getFixerUpper(),
server.getStructureManager(),
server.executor,
chunkGenerator,
freshWorld.spigotConfig.viewDistance,
freshWorld.spigotConfig.simulationDistance,
server.forceSynchronousWrites(),
new RegenNoOpWorldLoadListener(),
(chunkCoordIntPair, state) -> {
},
() -> server.overworld().getDataStorage()
) {
// redirect to LevelChunks created in #createChunks
@Override
public ChunkAccess getChunk(int x, int z, @NotNull ChunkStatus chunkstatus, boolean create) {
ChunkAccess chunkAccess = getChunkAt(x, z);
if (chunkAccess == null && create) {
chunkAccess = createChunk(getProtoChunkAt(x, z));
}
return chunkAccess;
}
};
if (seed == originalOpts.seed() && !options.hasBiomeType()) {
// Optimisation for needless ring position calculation when the seed and biome is the same.
ChunkGeneratorStructureState state = (ChunkGeneratorStructureState) generatorStructureStateField.get(
originalChunkProvider.chunkMap);
boolean hasGeneratedPositions = hasGeneratedPositionsField.getBoolean(state);
if (hasGeneratedPositions) {
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> origPositions =
(Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>>) ringPositionsField.get(state);
Map<ConcentricRingsStructurePlacement, CompletableFuture<List<ChunkPos>>> copy = new Object2ObjectArrayMap<>(
origPositions);
ChunkGeneratorStructureState newState = (ChunkGeneratorStructureState) generatorStructureStateField.get(
freshChunkProvider.chunkMap);
ringPositionsField.set(newState, copy);
hasGeneratedPositionsField.setBoolean(newState, true);
}
}
chunkSourceField.set(freshWorld, freshChunkProvider);
//let's start then
structureTemplateManager = server.getStructureManager();
threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider);
this.worldGenContext = new WorldGenContext(
freshWorld,
chunkGenerator,
structureTemplateManager,
threadedLevelLightEngine,
originalChunkProvider.chunkMap.worldGenContext.mainThreadMailBox()
);
return true;
}
@Override
protected void cleanup() {
try {
session.close();
} catch (Exception ignored) {
}
//shutdown chunk provider
try {
Fawe.instance().getQueueHandler().sync(() -> {
try {
freshChunkProvider.close(false);
} catch (Exception e) {
throw new RuntimeException(e);
}
});
} catch (Exception ignored) {
}
//remove world from server
try {
Fawe.instance().getQueueHandler().sync(this::removeWorldFromWorldsMap);
} catch (Exception ignored) {
}
//delete directory
try {
SafeFiles.tryHardToDeleteDir(tempDir);
} catch (Exception ignored) {
}
}
@Override
protected ProtoChunk createProtoChunk(int x, int z) {
return new FastProtoChunk(new ChunkPos(x, z), UpgradeData.EMPTY, freshWorld,
this.freshWorld.registryAccess().registryOrThrow(BIOME), null
);
}
@Override
protected LevelChunk createChunk(ProtoChunk protoChunk) {
return new LevelChunk(
freshWorld,
protoChunk,
null // we don't want to add entities
);
}
@Override
protected ChunkStatusWrap getFullChunkStatus() {
return new ChunkStatusWrap(ChunkStatus.FULL);
}
@Override
protected List<BlockPopulator> getBlockPopulators() {
return originalServerWorld.getWorld().getPopulators();
}
@Override
protected void populate(LevelChunk levelChunk, Random random, BlockPopulator blockPopulator) {
// BlockPopulator#populate has to be called synchronously for TileEntity access
TaskManager.taskManager().task(() -> {
final CraftWorld world = freshWorld.getWorld();
final Chunk chunk = world.getChunkAt(levelChunk.locX, levelChunk.locZ);
blockPopulator.populate(world, random, chunk);
});
}
@Override
protected IChunkCache<IChunkGet> initSourceQueueCache() {
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
@Override
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
return getChunkAt(x, z);
}
};
}
//util
@SuppressWarnings("unchecked")
private void removeWorldFromWorldsMap() {
try {
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
map.remove("faweregentempworld");
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
return switch (env) {
case NETHER -> LevelStem.NETHER;
case THE_END -> LevelStem.END;
default -> LevelStem.OVERWORLD;
};
}
private static class RegenNoOpWorldLoadListener implements ChunkProgressListener {
private RegenNoOpWorldLoadListener() {
}
@Override
public void updateSpawnPos(@NotNull ChunkPos spawnPos) {
}
@Override
public void onStatusChange(
final @NotNull ChunkPos pos,
@org.jetbrains.annotations.Nullable final net.minecraft.world.level.chunk.status.ChunkStatus status
) {
}
@Override
public void start() {
}
@Override
public void stop() {
}
// TODO Paper only(?) @Override
public void setChunkRadius(int radius) {
}
}
private class FastProtoChunk extends ProtoChunk {
public FastProtoChunk(
final ChunkPos pos,
final UpgradeData upgradeData,
final LevelHeightAccessor world,
final Registry<Biome> biomeRegistry,
@Nullable final BlendingData blendingData
) {
super(pos, upgradeData, world, biomeRegistry, blendingData);
}
// avoid warning on paper
@SuppressWarnings("unused") // compatibility with spigot
public boolean generateFlatBedrock() {
return generateFlatBedrock;
}
// no one will ever see the entities!
@Override
public @NotNull List<CompoundTag> getEntities() {
return Collections.emptyList();
}
}
protected class ChunkStatusWrap extends ChunkStatusWrapper<ChunkAccess> {
private final ChunkStatus chunkStatus;
public ChunkStatusWrap(ChunkStatus chunkStatus) {
this.chunkStatus = chunkStatus;
}
@Override
public int requiredNeighborChunkRadius() {
return ChunkPyramid.GENERATION_PYRAMID.getStepTo(ChunkStatus.FULL).getAccumulatedRadiusOf(chunkStatus);
}
@Override
public String name() {
return chunkStatus.toString();
}
@Override
public CompletableFuture<?> processChunk(List<ChunkAccess> accessibleChunks) {
ChunkAccess chunkAccess = accessibleChunks.get(accessibleChunks.size() / 2);
int chunkX = chunkAccess.getPos().x;
int chunkZ = chunkAccess.getPos().z;
getProtoChunkAt(chunkX, chunkZ);
StaticCache2D<GenerationChunkHolder> neighbours = StaticCache2D
.create(
chunkX,
chunkZ,
requiredNeighborChunkRadius(),
(final int nx, final int nz) -> new ChunkHolder(new ChunkPos(nx, nz),
ChunkHolderManager.MAX_TICKET_LEVEL,
freshWorld,
threadedLevelLightEngine,
null,
freshChunkProvider.chunkMap
)
);
return ChunkPyramid.GENERATION_PYRAMID.getStepTo(chunkStatus).apply(
worldGenContext,
neighbours,
chunkAccess
);
}
}
/**
* A light engine that does nothing. As light is calculated after pasting anyway, we can avoid
* work this way.
*/
static class NoOpLightEngine extends ThreadedLevelLightEngine {
private static final ProcessorMailbox<Runnable> MAILBOX = ProcessorMailbox.create(task -> {
}, "fawe-no-op");
private static final ProcessorHandle<Message<Runnable>> HANDLE = ProcessorHandle.of("fawe-no-op", m -> {
});
public NoOpLightEngine(final ServerChunkCache chunkProvider) {
super(chunkProvider, chunkProvider.chunkMap, false, MAILBOX, HANDLE);
}
@Override
public @NotNull CompletableFuture<ChunkAccess> lightChunk(final @NotNull ChunkAccess chunk, final boolean excludeBlocks) {
return CompletableFuture.completedFuture(chunk);
}
}
}

Datei anzeigen

@ -208,7 +208,7 @@ tasks {
versionNumber.set("${project.version}") versionNumber.set("${project.version}")
versionType.set("release") versionType.set("release")
uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar")) uploadFile.set(file("build/libs/${rootProject.name}-Bukkit-${project.version}.jar"))
gameVersions.addAll(listOf("1.20.6", "1.20.5", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4")) gameVersions.addAll(listOf("1.21", "1.20.6", "1.20.5", "1.20.3", "1.20.2", "1.20.1", "1.20", "1.19.4"))
loaders.addAll(listOf("paper", "spigot")) loaders.addAll(listOf("paper", "spigot"))
changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" + changelog.set("The changelog is available on GitHub: https://github.com/IntellectualSites/" +
"FastAsyncWorldEdit/releases/tag/${project.version}") "FastAsyncWorldEdit/releases/tag/${project.version}")

Datei anzeigen

@ -51,6 +51,7 @@ public abstract class Scroll implements ScrollTool {
parserContext.setActor(player); parserContext.setActor(player);
parserContext.setWorld(player.getWorld()); parserContext.setWorld(player.getWorld());
parserContext.setSession(session); parserContext.setSession(session);
parserContext.setTryLegacy(player.getLimit().ALLOW_LEGACY);
switch (mode) { switch (mode) {
case CLIPBOARD: case CLIPBOARD:
if (arguments.size() != 2) { if (arguments.size() != 2) {

Datei anzeigen

@ -224,7 +224,7 @@ public class Config {
/** /**
* Indicates that a field's default value should match another input if the config is otherwise already generated * Indicates that a field's default value should match another input if the config is otherwise already generated
* *
* @since TODO * @since 2.11.0
*/ */
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD}) @Target({ElementType.FIELD})

Datei anzeigen

@ -191,6 +191,7 @@ public class Settings extends Config {
} }
} }
limit.UNIVERSAL_DISALLOWED_BLOCKS &= newLimit.UNIVERSAL_DISALLOWED_BLOCKS; limit.UNIVERSAL_DISALLOWED_BLOCKS &= newLimit.UNIVERSAL_DISALLOWED_BLOCKS;
limit.ALLOW_LEGACY &= newLimit.ALLOW_LEGACY;
if (limit.DISALLOWED_BLOCKS == null) { if (limit.DISALLOWED_BLOCKS == null) {
limit.DISALLOWED_BLOCKS = newLimit.DISALLOWED_BLOCKS.isEmpty() ? Collections.emptySet() : new HashSet<>( limit.DISALLOWED_BLOCKS = newLimit.DISALLOWED_BLOCKS.isEmpty() ? Collections.emptySet() : new HashSet<>(
@ -439,6 +440,10 @@ public class Settings extends Config {
" - If fast-placement is disabled, this may cause edits to be slower." " - If fast-placement is disabled, this may cause edits to be slower."
}) })
public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; public boolean UNIVERSAL_DISALLOWED_BLOCKS = true;
@Comment({
"If legacy, mumerical, blocks IDs should be able to be used (i.e. 12:2),"
})
public boolean ALLOW_LEGACY = true;
@Comment({ @Comment({
"List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.", "List of blocks to deny use of. Can be either an entire block type or a block with a specific property value.",
"Where block properties are specified, any blockstate with the property will be disallowed (e.g. all directions", "Where block properties are specified, any blockstate with the property will be disallowed (e.g. all directions",

Datei anzeigen

@ -0,0 +1,17 @@
package com.fastasyncworldedit.core.exception;
import com.sk89q.worldedit.WorldEditException;
public class OutsideWorldBoundsException extends WorldEditException {
private final int y;
public OutsideWorldBoundsException(int y) {
this.y = y;
}
public int y() {
return y;
}
}

Datei anzeigen

@ -143,7 +143,7 @@ public class RichMaskParser extends FaweParser<Mask> {
int end = command.lastIndexOf(']'); int end = command.lastIndexOf(']');
mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context); mask = parseFromInput(command.substring(1, end == -1 ? command.length() : end), context);
} else { } else {
BlockMaskBuilder builder = new BlockMaskBuilder(); BlockMaskBuilder builder = new BlockMaskBuilder(context);
try { try {
builder.addRegex(full); builder.addRegex(full);
} catch (InputParseException ignored) { } catch (InputParseException ignored) {

Datei anzeigen

@ -200,6 +200,7 @@ public class ConsumeBindings extends Bindings {
public BaseBlock baseBlock(Actor actor, String argument) { public BaseBlock baseBlock(Actor actor, String argument) {
ParserContext parserContext = new ParserContext(); ParserContext parserContext = new ParserContext();
parserContext.setActor(actor); parserContext.setActor(actor);
parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY);
if (actor instanceof Entity) { if (actor instanceof Entity) {
Extent extent = ((Entity) actor).getExtent(); Extent extent = ((Entity) actor).getExtent();
if (extent instanceof World) { if (extent instanceof World) {

Datei anzeigen

@ -9,6 +9,7 @@ import com.fastasyncworldedit.core.util.MutableCharSequence;
import com.fastasyncworldedit.core.util.StringMan; import com.fastasyncworldedit.core.util.StringMan;
import com.fastasyncworldedit.core.world.block.BlanketBaseBlock; import com.fastasyncworldedit.core.world.block.BlanketBaseBlock;
import com.sk89q.worldedit.extension.input.InputParseException; import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockMask;
import com.sk89q.worldedit.registry.state.AbstractProperty; import com.sk89q.worldedit.registry.state.AbstractProperty;
@ -53,6 +54,7 @@ public class BlockMaskBuilder {
private static final long[] ALL = new long[0]; private static final long[] ALL = new long[0];
private final long[][] bitSets; private final long[][] bitSets;
private final ParserContext context;
private boolean[] ordinals; private boolean[] ordinals;
private boolean optimizedStates = true; private boolean optimizedStates = true;
@ -60,8 +62,28 @@ public class BlockMaskBuilder {
this(new long[BlockTypes.size()][]); this(new long[BlockTypes.size()][]);
} }
/**
* Create a new instance with a given {@link ParserContext} to use if parsing regex
*
* @since 2.11.0
*/
public BlockMaskBuilder(ParserContext context) {
this(new long[BlockTypes.size()][], context);
}
protected BlockMaskBuilder(long[][] bitSets) { protected BlockMaskBuilder(long[][] bitSets) {
this.bitSets = bitSets; this.bitSets = bitSets;
this.context = new ParserContext();
}
/**
* Create a new instance with a given {@link ParserContext} to use if parsing regex
*
* @since 2.11.0
*/
protected BlockMaskBuilder(long[][] bitSets, ParserContext context) {
this.bitSets = bitSets;
this.context = context;
} }
private boolean handleRegex(BlockType blockType, PropertyKey key, String regex, FuzzyStateAllowingBuilder builder) { private boolean handleRegex(BlockType blockType, PropertyKey key, String regex, FuzzyStateAllowingBuilder builder) {
@ -173,7 +195,7 @@ public class BlockMaskBuilder {
List<BlockType> blockTypeList; List<BlockType> blockTypeList;
List<FuzzyStateAllowingBuilder> builders; List<FuzzyStateAllowingBuilder> builders;
if (StringMan.isAlphanumericUnd(charSequence)) { if (StringMan.isAlphanumericUnd(charSequence)) {
BlockType type = BlockTypes.parse(charSequence.toString()); BlockType type = BlockTypes.parse(charSequence.toString(), context);
blockTypeList = Collections.singletonList(type); blockTypeList = Collections.singletonList(type);
builders = Collections.singletonList(new FuzzyStateAllowingBuilder(type)); builders = Collections.singletonList(new FuzzyStateAllowingBuilder(type));
add(type); add(type);
@ -280,7 +302,7 @@ public class BlockMaskBuilder {
} }
} else { } else {
if (StringMan.isAlphanumericUnd(input)) { if (StringMan.isAlphanumericUnd(input)) {
add(BlockTypes.parse(input)); add(BlockTypes.parse(input, context));
} else { } else {
boolean success = false; boolean success = false;
for (BlockType myType : BlockTypesCache.values) { for (BlockType myType : BlockTypesCache.values) {

Datei anzeigen

@ -28,6 +28,7 @@ public class FaweLimit {
public boolean FAST_PLACEMENT = false; public boolean FAST_PLACEMENT = false;
public boolean CONFIRM_LARGE = true; public boolean CONFIRM_LARGE = true;
public boolean RESTRICT_HISTORY_TO_REGIONS = true; public boolean RESTRICT_HISTORY_TO_REGIONS = true;
public boolean ALLOW_LEGACY = true;
public Set<String> STRIP_NBT = null; public Set<String> STRIP_NBT = null;
public boolean UNIVERSAL_DISALLOWED_BLOCKS = true; public boolean UNIVERSAL_DISALLOWED_BLOCKS = true;
public Set<String> DISALLOWED_BLOCKS = null; public Set<String> DISALLOWED_BLOCKS = null;
@ -127,6 +128,7 @@ public class FaweLimit {
MAX.RESTRICT_HISTORY_TO_REGIONS = false; MAX.RESTRICT_HISTORY_TO_REGIONS = false;
MAX.STRIP_NBT = Collections.emptySet(); MAX.STRIP_NBT = Collections.emptySet();
MAX.UNIVERSAL_DISALLOWED_BLOCKS = false; MAX.UNIVERSAL_DISALLOWED_BLOCKS = false;
MAX.ALLOW_LEGACY = true;
MAX.DISALLOWED_BLOCKS = Collections.emptySet(); MAX.DISALLOWED_BLOCKS = Collections.emptySet();
MAX.REMAP_PROPERTIES = Collections.emptySet(); MAX.REMAP_PROPERTIES = Collections.emptySet();
MAX.MAX_RADIUS = Integer.MAX_VALUE; MAX.MAX_RADIUS = Integer.MAX_VALUE;
@ -259,13 +261,13 @@ public class FaweLimit {
&& !RESTRICT_HISTORY_TO_REGIONS && !RESTRICT_HISTORY_TO_REGIONS
&& (STRIP_NBT == null || STRIP_NBT.isEmpty()) && (STRIP_NBT == null || STRIP_NBT.isEmpty())
// && !UNIVERSAL_DISALLOWED_BLOCKS --> do not include this, it effectively has no relevance // && !UNIVERSAL_DISALLOWED_BLOCKS --> do not include this, it effectively has no relevance
&& ALLOW_LEGACY
&& (DISALLOWED_BLOCKS == null || DISALLOWED_BLOCKS.isEmpty()) && (DISALLOWED_BLOCKS == null || DISALLOWED_BLOCKS.isEmpty())
&& (REMAP_PROPERTIES == null || REMAP_PROPERTIES.isEmpty()) && (REMAP_PROPERTIES == null || REMAP_PROPERTIES.isEmpty())
&& MAX_RADIUS == Integer.MAX_VALUE && MAX_RADIUS == Integer.MAX_VALUE
&& MAX_SUPER_PICKAXE_SIZE == Integer.MAX_VALUE && MAX_SUPER_PICKAXE_SIZE == Integer.MAX_VALUE
&& MAX_BRUSH_RADIUS == Integer.MAX_VALUE && MAX_BRUSH_RADIUS == Integer.MAX_VALUE
&& MAX_BUTCHER_RADIUS == Integer.MAX_VALUE; && MAX_BUTCHER_RADIUS == Integer.MAX_VALUE;
} }
public void set(FaweLimit limit) { public void set(FaweLimit limit) {
@ -286,6 +288,7 @@ public class FaweLimit {
RESTRICT_HISTORY_TO_REGIONS = limit.RESTRICT_HISTORY_TO_REGIONS; RESTRICT_HISTORY_TO_REGIONS = limit.RESTRICT_HISTORY_TO_REGIONS;
STRIP_NBT = limit.STRIP_NBT; STRIP_NBT = limit.STRIP_NBT;
UNIVERSAL_DISALLOWED_BLOCKS = limit.UNIVERSAL_DISALLOWED_BLOCKS; UNIVERSAL_DISALLOWED_BLOCKS = limit.UNIVERSAL_DISALLOWED_BLOCKS;
ALLOW_LEGACY = limit.ALLOW_LEGACY;
DISALLOWED_BLOCKS = limit.DISALLOWED_BLOCKS; DISALLOWED_BLOCKS = limit.DISALLOWED_BLOCKS;
REMAP_PROPERTIES = limit.REMAP_PROPERTIES; REMAP_PROPERTIES = limit.REMAP_PROPERTIES;
MAX_RADIUS = limit.MAX_RADIUS; MAX_RADIUS = limit.MAX_RADIUS;
@ -313,6 +316,7 @@ public class FaweLimit {
limit.RESTRICT_HISTORY_TO_REGIONS = RESTRICT_HISTORY_TO_REGIONS; limit.RESTRICT_HISTORY_TO_REGIONS = RESTRICT_HISTORY_TO_REGIONS;
limit.STRIP_NBT = STRIP_NBT; limit.STRIP_NBT = STRIP_NBT;
limit.UNIVERSAL_DISALLOWED_BLOCKS = UNIVERSAL_DISALLOWED_BLOCKS; limit.UNIVERSAL_DISALLOWED_BLOCKS = UNIVERSAL_DISALLOWED_BLOCKS;
limit.ALLOW_LEGACY = ALLOW_LEGACY;
limit.DISALLOWED_BLOCKS = DISALLOWED_BLOCKS; limit.DISALLOWED_BLOCKS = DISALLOWED_BLOCKS;
limit.REMAP_PROPERTIES = REMAP_PROPERTIES; limit.REMAP_PROPERTIES = REMAP_PROPERTIES;
limit.MAX_RADIUS = MAX_RADIUS; limit.MAX_RADIUS = MAX_RADIUS;

Datei anzeigen

@ -1352,7 +1352,7 @@ public class LocalSession implements TextureHolder {
* @param item the item type * @param item the item type
* @param tool the tool to set, which can be {@code null} * @param tool the tool to set, which can be {@code null}
* @throws InvalidToolBindException if the item can't be bound to that item * @throws InvalidToolBindException if the item can't be bound to that item
* @since TODO * @since 2.11.0
*/ */
public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException { public void setTool(BaseItem item, @Nullable Tool tool) throws InvalidToolBindException {
if (item.getType().hasBlockType()) { if (item.getType().hasBlockType()) {
@ -1919,7 +1919,7 @@ public class LocalSession implements TextureHolder {
* Get the preferred wand item for this user, or {@code null} to use the default * Get the preferred wand item for this user, or {@code null} to use the default
* *
* @return item id of wand item, or {@code null} * @return item id of wand item, or {@code null}
* @since TODO * @since 2.11.0
*/ */
public BaseItem getWandBaseItem() { public BaseItem getWandBaseItem() {
return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference()); return wandItem == null ? null : new BaseItem(wandItem.getType(), wandItem.getNbtReference());
@ -1929,7 +1929,7 @@ public class LocalSession implements TextureHolder {
* Get the preferred navigation wand item for this user, or {@code null} to use the default * Get the preferred navigation wand item for this user, or {@code null} to use the default
* *
* @return item id of nav wand item, or {@code null} * @return item id of nav wand item, or {@code null}
* @since TODO * @since 2.11.0
*/ */
public BaseItem getNavWandBaseItem() { public BaseItem getNavWandBaseItem() {
return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference()); return navWandItem == null ? null : new BaseItem(navWandItem.getType(), navWandItem.getNbtReference());

Datei anzeigen

@ -21,6 +21,7 @@ package com.sk89q.worldedit;
import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; import com.fastasyncworldedit.core.exception.BrushRadiusLimitException;
import com.fastasyncworldedit.core.exception.OutsideWorldBoundsException;
import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.exception.RadiusLimitException;
import com.fastasyncworldedit.core.extension.factory.TransformFactory; import com.fastasyncworldedit.core.extension.factory.TransformFactory;
import com.fastasyncworldedit.core.extent.ResettableExtent; import com.fastasyncworldedit.core.extent.ResettableExtent;
@ -46,6 +47,7 @@ import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Locatable; import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extension.platform.Platform; import com.sk89q.worldedit.extension.platform.Platform;
import com.sk89q.worldedit.extension.platform.PlatformManager; import com.sk89q.worldedit.extension.platform.PlatformManager;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.extent.inventory.BlockBag;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.function.pattern.Pattern;
@ -466,7 +468,7 @@ public final class WorldEdit {
/** /**
* @deprecated Use {@link WorldEdit#checkMaxBrushRadius(Expression, Actor)} * @deprecated Use {@link WorldEdit#checkMaxBrushRadius(Expression, Actor)}
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException { public void checkMaxBrushRadius(Expression radius) throws MaxBrushRadiusException {
double val = radius.evaluate(); double val = radius.evaluate();
checkArgument(val >= 0, "Radius must be a positive number."); checkArgument(val >= 0, "Radius must be a positive number.");
@ -483,7 +485,7 @@ public final class WorldEdit {
* @param radius Radius to check * @param radius Radius to check
* @param actor Actor to check for * @param actor Actor to check for
* @throws MaxRadiusException If given radius larger than allowed * @throws MaxRadiusException If given radius larger than allowed
* @since TODO * @since 2.11.0
*/ */
public void checkMaxRadius(double radius, Actor actor) { public void checkMaxRadius(double radius, Actor actor) {
int max = actor.getLimit().MAX_RADIUS; int max = actor.getLimit().MAX_RADIUS;
@ -498,7 +500,7 @@ public final class WorldEdit {
* @param radius Radius to check * @param radius Radius to check
* @param actor Actor to check for * @param actor Actor to check for
* @throws MaxRadiusException If given radius larger than allowed * @throws MaxRadiusException If given radius larger than allowed
* @since TODO * @since 2.11.0
*/ */
public void checkMaxBrushRadius(double radius, Actor actor) { public void checkMaxBrushRadius(double radius, Actor actor) {
int max = actor.getLimit().MAX_BRUSH_RADIUS; int max = actor.getLimit().MAX_BRUSH_RADIUS;
@ -513,7 +515,7 @@ public final class WorldEdit {
* @param expression Radius to check * @param expression Radius to check
* @param actor Actor to check for * @param actor Actor to check for
* @throws BrushRadiusLimitException If given radius larger than allowed * @throws BrushRadiusLimitException If given radius larger than allowed
* @since TODO * @since 2.11.0
*/ */
public void checkMaxBrushRadius(Expression expression, Actor actor) { public void checkMaxBrushRadius(Expression expression, Actor actor) {
double radius = expression.evaluate(); double radius = expression.evaluate();
@ -523,6 +525,20 @@ public final class WorldEdit {
throw new BrushRadiusLimitException(max); throw new BrushRadiusLimitException(max);
} }
} }
/**
* Check if the given position is contained by the extent's min/max height
*
* @param position Position to check
* @param extent Extent to check in
* @throws OutsideWorldBoundsException If the position is outside the world height limits
* @since 2.11.0
*/
public void checkExtentHeightBounds(BlockVector3 position, Extent extent) {
if (position.y() < extent.getMinY() || position.y() > extent.getMaxY()) {
throw new OutsideWorldBoundsException(position.y());
}
}
//FAWE end //FAWE end
/** /**

Datei anzeigen

@ -340,7 +340,7 @@ public class ClipboardCommands {
aliases = {"/download"}, aliases = {"/download"},
desc = "Downloads your clipboard through the configured web interface" desc = "Downloads your clipboard through the configured web interface"
) )
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
@CommandPermissions({"worldedit.clipboard.download"}) @CommandPermissions({"worldedit.clipboard.download"})
public void download( public void download(
final Actor actor, final Actor actor,

Datei anzeigen

@ -510,6 +510,7 @@ public class GeneralCommands {
parserContext.setWorld(worldArg); parserContext.setWorld(worldArg);
parserContext.setSession(session); parserContext.setSession(session);
parserContext.setExtent(editSession); parserContext.setExtent(editSession);
parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY);
Mask mask = worldEdit.getMaskFactory().parseFromInput(arg, parserContext); Mask mask = worldEdit.getMaskFactory().parseFromInput(arg, parserContext);
util = TextureUtil.fromMask(mask); util = TextureUtil.fromMask(mask);
} }

Datei anzeigen

@ -242,6 +242,7 @@ public class UtilityCommands {
we.checkMaxRadius(depth, actor); we.checkMaxRadius(depth, actor);
BlockVector3 pos = session.getPlacementPosition(actor); BlockVector3 pos = session.getPlacementPosition(actor);
we.checkExtentHeightBounds(pos, editSession);
int affected = editSession.fillDirection(pos, pattern, radius, depth, direction); int affected = editSession.fillDirection(pos, pattern, radius, depth, direction);
actor.print(Caption.of("worldedit.fill.created", TextComponent.of(affected))); actor.print(Caption.of("worldedit.fill.created", TextComponent.of(affected)));
return affected; return affected;
@ -330,6 +331,7 @@ public class UtilityCommands {
we.checkMaxRadius(radius, actor); we.checkMaxRadius(radius, actor);
BlockVector3 pos = session.getPlacementPosition(actor); BlockVector3 pos = session.getPlacementPosition(actor);
we.checkExtentHeightBounds(pos, editSession);
int affected = editSession.fillXZ(pos, pattern, radius, depth, true); int affected = editSession.fillXZ(pos, pattern, radius, depth, true);
actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected))); actor.print(Caption.of("worldedit.fillr.created", TextComponent.of(affected)));
return affected; return affected;
@ -357,7 +359,9 @@ public class UtilityCommands {
double radius = radiusExp.evaluate(); double radius = radiusExp.evaluate();
radius = Math.max(0, radius); radius = Math.max(0, radius);
we.checkMaxRadius(radius, actor); we.checkMaxRadius(radius, actor);
int affected = editSession.drainArea(session.getPlacementPosition(actor), radius, waterlogged, plants); BlockVector3 pos = session.getPlacementPosition(actor);
we.checkExtentHeightBounds(pos, editSession);
int affected = editSession.drainArea(pos, radius, waterlogged, plants);
actor.print(Caption.of("worldedit.drain.drained", TextComponent.of(affected))); actor.print(Caption.of("worldedit.drain.drained", TextComponent.of(affected)));
return affected; return affected;
} }
@ -376,7 +380,9 @@ public class UtilityCommands {
) throws WorldEditException { ) throws WorldEditException {
radius = Math.max(0, radius); radius = Math.max(0, radius);
we.checkMaxRadius(radius, actor); we.checkMaxRadius(radius, actor);
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.LAVA); BlockVector3 pos = session.getPlacementPosition(actor);
we.checkExtentHeightBounds(pos, editSession);
int affected = editSession.fixLiquid(pos, radius, BlockTypes.LAVA);
actor.print(Caption.of("worldedit.fixlava.fixed", TextComponent.of(affected))); actor.print(Caption.of("worldedit.fixlava.fixed", TextComponent.of(affected)));
return affected; return affected;
} }
@ -395,7 +401,9 @@ public class UtilityCommands {
) throws WorldEditException { ) throws WorldEditException {
radius = Math.max(0, radius); radius = Math.max(0, radius);
we.checkMaxRadius(radius, actor); we.checkMaxRadius(radius, actor);
int affected = editSession.fixLiquid(session.getPlacementPosition(actor), radius, BlockTypes.WATER); BlockVector3 pos = session.getPlacementPosition(actor);
we.checkExtentHeightBounds(pos, editSession);
int affected = editSession.fixLiquid(pos, radius, BlockTypes.WATER);
actor.print(Caption.of("worldedit.fixwater.fixed", TextComponent.of(affected))); actor.print(Caption.of("worldedit.fixwater.fixed", TextComponent.of(affected)));
return affected; return affected;
} }

Datei anzeigen

@ -133,6 +133,7 @@ public class FactoryConverter<T> implements ArgumentConverter<T> {
parserContext.setSession(session); parserContext.setSession(session);
parserContext.setRestricted(true); parserContext.setRestricted(true);
parserContext.setInjected(context); parserContext.setInjected(context);
parserContext.setTryLegacy(actor.getLimit().ALLOW_LEGACY);
if (contextTweaker != null) { if (contextTweaker != null) {
contextTweaker.accept(parserContext); contextTweaker.accept(parserContext);

Datei anzeigen

@ -49,6 +49,7 @@ public class BlocksMaskParser extends InputParser<Mask> {
ParserContext tempContext = new ParserContext(context); ParserContext tempContext = new ParserContext(context);
tempContext.setRestricted(false); tempContext.setRestricted(false);
tempContext.setPreferringWildcard(true); tempContext.setPreferringWildcard(true);
tempContext.setTryLegacy(context.isTryingLegacy());
try { try {
Set<BaseBlock> holders = worldEdit.getBlockFactory().parseFromListInput(component, tempContext); Set<BaseBlock> holders = worldEdit.getBlockFactory().parseFromListInput(component, tempContext);
if (holders.isEmpty()) { if (holders.isEmpty()) {

Datei anzeigen

@ -56,7 +56,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType
* @return the position * @return the position
* @deprecated Use {@link #position()}. * @deprecated Use {@link #position()}.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BlockVector3 getPosition() { public BlockVector3 getPosition() {
return position; return position;
} }
@ -67,7 +67,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType
* @return the previous biome * @return the previous biome
* @deprecated Use {@link #previous()}. * @deprecated Use {@link #previous()}.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BiomeType getPrevious() { public BiomeType getPrevious() {
return previous; return previous;
} }
@ -78,7 +78,7 @@ public record BiomeChange3D(BlockVector3 position, BiomeType previous, BiomeType
* @return the current biome * @return the current biome
* @deprecated Use {@link #current()}. * @deprecated Use {@link #current()}.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BiomeType getCurrent() { public BiomeType getCurrent() {
return current; return current;
} }

Datei anzeigen

@ -71,7 +71,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c
* @return the position * @return the position
* @deprecated use {@link #position()} * @deprecated use {@link #position()}
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BlockVector3 getPosition() { public BlockVector3 getPosition() {
return position; return position;
} }
@ -82,7 +82,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c
* @return the previous block * @return the previous block
* @deprecated use {@link #previous()} * @deprecated use {@link #previous()}
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BaseBlock getPrevious() { public BaseBlock getPrevious() {
return previous; return previous;
} }
@ -93,7 +93,7 @@ public record BlockChange(BlockVector3 position, BaseBlock previous, BaseBlock c
* @return the current block * @return the current block
* @deprecated use {@link #current()} * @deprecated use {@link #current()}
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BaseBlock getCurrent() { public BaseBlock getCurrent() {
return current; return current;
} }

Datei anzeigen

@ -21,6 +21,7 @@ package com.sk89q.worldedit.internal.command.exception;
import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.exception.BrushRadiusLimitException; import com.fastasyncworldedit.core.exception.BrushRadiusLimitException;
import com.fastasyncworldedit.core.exception.OutsideWorldBoundsException;
import com.fastasyncworldedit.core.exception.RadiusLimitException; import com.fastasyncworldedit.core.exception.RadiusLimitException;
import com.fastasyncworldedit.core.internal.exception.FaweException; import com.fastasyncworldedit.core.internal.exception.FaweException;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -146,6 +147,11 @@ public class WorldEditExceptionConverter extends ExceptionConverterHelper {
public void convert(RadiusLimitException e) throws CommandException { public void convert(RadiusLimitException e) throws CommandException {
throw newCommandException(Caption.of("fawe.error.limit.max-radius", TextComponent.of(e.getMaxRadius())), e); throw newCommandException(Caption.of("fawe.error.limit.max-radius", TextComponent.of(e.getMaxRadius())), e);
} }
@ExceptionMatch
public void convert(OutsideWorldBoundsException e) throws CommandException {
throw newCommandException(Caption.of("fawe.cancel.reason.world.limit", TextComponent.of(e.y())), e);
}
//FAWE end //FAWE end
@ExceptionMatch @ExceptionMatch

Datei anzeigen

@ -68,7 +68,7 @@ public abstract class AbstractFactory<E> {
* @param worldEdit the WorldEdit instance * @param worldEdit the WorldEdit instance
* @param defaultParser the parser to fall back to * @param defaultParser the parser to fall back to
* @param richParser the rich parser * @param richParser the rich parser
* @since TODO * @since 2.11.0
*/ */
protected AbstractFactory(WorldEdit worldEdit, InputParser<E> defaultParser, FaweParser<E> richParser) { protected AbstractFactory(WorldEdit worldEdit, InputParser<E> defaultParser, FaweParser<E> richParser) {
checkNotNull(worldEdit); checkNotNull(worldEdit);

Datei anzeigen

@ -122,7 +122,7 @@ public class BlockVector2 {
* Get the X coordinate. * Get the X coordinate.
* *
* @return the x coordinate * @return the x coordinate
* @since TODO * @since 2.11.0
*/ */
public int x() { public int x() {
return x; return x;
@ -134,7 +134,7 @@ public class BlockVector2 {
* @return the x coordinate * @return the x coordinate
* @deprecated use {@link #x()} instead * @deprecated use {@link #x()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getX() { public int getX() {
return x; return x;
} }
@ -145,7 +145,7 @@ public class BlockVector2 {
* @return the x coordinate * @return the x coordinate
* @deprecated use {@link #x()} instead * @deprecated use {@link #x()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getBlockX() { public int getBlockX() {
return x; return x;
} }
@ -164,7 +164,7 @@ public class BlockVector2 {
* Get the Z coordinate. * Get the Z coordinate.
* *
* @return the z coordinate * @return the z coordinate
* @since TODO * @since 2.11.0
*/ */
public int z() { public int z() {
return z; return z;
@ -176,7 +176,7 @@ public class BlockVector2 {
* @return the z coordinate * @return the z coordinate
* @deprecated use {@link #z()} instead * @deprecated use {@link #z()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getZ() { public int getZ() {
return z; return z;
} }
@ -187,7 +187,7 @@ public class BlockVector2 {
* @return the z coordinate * @return the z coordinate
* @deprecated use {@link #z()} instead * @deprecated use {@link #z()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getBlockZ() { public int getBlockZ() {
return z; return z;
} }

Datei anzeigen

@ -174,7 +174,7 @@ public abstract class BlockVector3 {
* Get the X coordinate. * Get the X coordinate.
* *
* @return the x coordinate * @return the x coordinate
* @since TODO * @since 2.11.0
*/ */
public abstract int x(); public abstract int x();
//FAWE end //FAWE end
@ -185,7 +185,7 @@ public abstract class BlockVector3 {
* @return the x coordinate * @return the x coordinate
* @deprecated use {@link #x()} instead * @deprecated use {@link #x()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getX() { public int getX() {
return this.x(); //FAWE - access abstract getter instead of local field return this.x(); //FAWE - access abstract getter instead of local field
} }
@ -196,7 +196,7 @@ public abstract class BlockVector3 {
* @return the x coordinate * @return the x coordinate
* @deprecated use {@link #x()} instead * @deprecated use {@link #x()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getBlockX() { public int getBlockX() {
return this.x(); //FAWE - access abstract getter instead of local field return this.x(); //FAWE - access abstract getter instead of local field
} }
@ -219,7 +219,7 @@ public abstract class BlockVector3 {
* Get the Y coordinate. * Get the Y coordinate.
* *
* @return the y coordinate * @return the y coordinate
* @since TODO * @since 2.11.0
*/ */
public abstract int y(); public abstract int y();
//FAWE end //FAWE end
@ -230,7 +230,7 @@ public abstract class BlockVector3 {
* @return the y coordinate * @return the y coordinate
* @deprecated use {@link #y()} instead * @deprecated use {@link #y()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getY() { public int getY() {
return this.y(); //FAWE - access abstract getter instead of local field return this.y(); //FAWE - access abstract getter instead of local field
} }
@ -241,7 +241,7 @@ public abstract class BlockVector3 {
* @return the y coordinate * @return the y coordinate
* @deprecated use {@link #y()} instead * @deprecated use {@link #y()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getBlockY() { public int getBlockY() {
return this.y(); //FAWE - access abstract getter instead of local field return this.y(); //FAWE - access abstract getter instead of local field
} }
@ -263,7 +263,7 @@ public abstract class BlockVector3 {
* Get the Z coordinate. * Get the Z coordinate.
* *
* @return the Z coordinate * @return the Z coordinate
* @since TODO * @since 2.11.0
*/ */
public abstract int z(); public abstract int z();
//FAWE end //FAWE end
@ -274,7 +274,7 @@ public abstract class BlockVector3 {
* @return the z coordinate * @return the z coordinate
* @deprecated use {@link #z()} instead * @deprecated use {@link #z()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getZ() { public int getZ() {
return this.z(); //FAWE - access abstract getter instead of local field return this.z(); //FAWE - access abstract getter instead of local field
} }
@ -285,7 +285,7 @@ public abstract class BlockVector3 {
* @return the z coordinate * @return the z coordinate
* @deprecated use {@link #z()} instead * @deprecated use {@link #z()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public int getBlockZ() { public int getBlockZ() {
return this.z(); //FAWE - access abstract getter instead of local field return this.z(); //FAWE - access abstract getter instead of local field
} }

Datei anzeigen

@ -57,7 +57,7 @@ public record Vector2(double x, double z) {
* @return the x coordinate * @return the x coordinate
* @deprecated use {@link #x()} instead * @deprecated use {@link #x()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public double getX() { public double getX() {
return x; return x;
} }
@ -66,7 +66,7 @@ public record Vector2(double x, double z) {
* Get the X coordinate, aligned to the block grid. * Get the X coordinate, aligned to the block grid.
* *
* @return the block-aligned x coordinate * @return the block-aligned x coordinate
* @since TODO * @since 2.11.0
*/ */
public int blockX() { public int blockX() {
return MathMan.roundInt(x); return MathMan.roundInt(x);
@ -86,7 +86,7 @@ public record Vector2(double x, double z) {
* Get the Z coordinate, aligned to the block grid. * Get the Z coordinate, aligned to the block grid.
* *
* @return the block-aligned z coordinate * @return the block-aligned z coordinate
* @since TODO * @since 2.11.0
*/ */
public int blockZ() { public int blockZ() {
return MathMan.roundInt(z); return MathMan.roundInt(z);
@ -98,7 +98,7 @@ public record Vector2(double x, double z) {
* @return the z coordinate * @return the z coordinate
* @deprecated use {@link #z()} instead * @deprecated use {@link #z()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public double getZ() { public double getZ() {
return z; return z;
} }

Datei anzeigen

@ -160,7 +160,7 @@ public abstract class Vector3 {
* Get the X coordinate. * Get the X coordinate.
* *
* @return the x coordinate * @return the x coordinate
* @since TODO * @since 2.11.0
*/ */
public abstract double x(); public abstract double x();
@ -179,7 +179,7 @@ public abstract class Vector3 {
* @return the x coordinate * @return the x coordinate
* @deprecated use {@link #x()} instead * @deprecated use {@link #x()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public double getX() { public double getX() {
return this.x(); return this.x();
} }
@ -201,7 +201,7 @@ public abstract class Vector3 {
* Get the Y coordinate. * Get the Y coordinate.
* *
* @return the y coordinate * @return the y coordinate
* @since TODO * @since 2.11.0
*/ */
public abstract double y(); public abstract double y();
@ -220,7 +220,7 @@ public abstract class Vector3 {
* @return the y coordinate * @return the y coordinate
* @deprecated use {@link #y()} instead * @deprecated use {@link #y()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public double getY() { public double getY() {
return this.y(); return this.y();
} }
@ -241,7 +241,7 @@ public abstract class Vector3 {
* Get the Z coordinate. * Get the Z coordinate.
* *
* @return the z coordinate * @return the z coordinate
* @since TODO * @since 2.11.0
*/ */
public abstract double z(); public abstract double z();
@ -260,7 +260,7 @@ public abstract class Vector3 {
* @return the z coordinate * @return the z coordinate
* @deprecated use {@link #z()} instead * @deprecated use {@link #z()} instead
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public double getZ() { public double getZ() {
return this.z(); return this.z();
} }

Datei anzeigen

@ -33,7 +33,7 @@ public interface Keyed {
* @return an id * @return an id
* @deprecated Use {@link #id()} instead. * @deprecated Use {@link #id()} instead.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
default String getId() { default String getId() {
return id(); return id();
} }
@ -43,7 +43,7 @@ public interface Keyed {
* may have additional restrictions. * may have additional restrictions.
* *
* @return an id * @return an id
* @since TODO * @since 2.11.0
*/ */
@NonAbstractForCompatibility(delegateName = "getId", delegateParams = {}) @NonAbstractForCompatibility(delegateName = "getId", delegateParams = {})
default String id() { default String id() {

Datei anzeigen

@ -183,6 +183,7 @@ public class CraftScriptContext extends CraftScriptEnvironment {
context.setSession(session); context.setSession(session);
context.setRestricted(!allAllowed); context.setRestricted(!allAllowed);
context.setPreferringWildcard(false); context.setPreferringWildcard(false);
context.setTryLegacy(player.getLimit().ALLOW_LEGACY);
return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null); return controller.getBlockFactory().parseFromListInput(input, context).stream().findFirst().orElse(null);
} }
@ -212,6 +213,7 @@ public class CraftScriptContext extends CraftScriptEnvironment {
context.setActor(player); context.setActor(player);
context.setWorld(player.getWorld()); context.setWorld(player.getWorld());
context.setSession(session); context.setSession(session);
context.setTryLegacy(player.getLimit().ALLOW_LEGACY);
return controller.getPatternFactory().parseFromInput(list, context); return controller.getPatternFactory().parseFromInput(list, context);
} }
@ -230,6 +232,7 @@ public class CraftScriptContext extends CraftScriptEnvironment {
context.setWorld(player.getWorld()); context.setWorld(player.getWorld());
context.setSession(session); context.setSession(session);
context.setRestricted(!allBlocksAllowed); context.setRestricted(!allBlocksAllowed);
context.setTryLegacy(player.getLimit().ALLOW_LEGACY);
return controller.getBlockFactory().parseFromListInput(list, context); return controller.getBlockFactory().parseFromListInput(list, context);
} }

Datei anzeigen

@ -40,7 +40,7 @@ public record LocatedBlock(BlockVector3 location, BaseBlock block) {
* @return The location * @return The location
* @deprecated This class is now a record. Use {@link #location()} instead. * @deprecated This class is now a record. Use {@link #location()} instead.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BlockVector3 getLocation() { public BlockVector3 getLocation() {
return this.location; return this.location;
} }
@ -51,7 +51,7 @@ public record LocatedBlock(BlockVector3 location, BaseBlock block) {
* @return The block * @return The block
* @deprecated This class is now a record. Use {@link #block()} instead. * @deprecated This class is now a record. Use {@link #block()} instead.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
public BaseBlock getBlock() { public BaseBlock getBlock() {
return this.block; return this.block;
} }

Datei anzeigen

@ -47,7 +47,7 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern {
* Gets the ID of this biome. * Gets the ID of this biome.
* *
* @return The id * @return The id
* @since TODO * @since 2.11.0
*/ */
@Override @Override
public String id() { public String id() {
@ -78,7 +78,7 @@ public class BiomeType implements RegistryItem, Keyed, BiomePattern {
* @return the id * @return the id
* @deprecated use {@link #id()} * @deprecated use {@link #id()}
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
@Override @Override
public String getId() { public String getId() {
return this.id; return this.id;

Datei anzeigen

@ -45,7 +45,7 @@ public class EntityType implements RegistryItem, Keyed {
* Gets the id of this entity type. * Gets the id of this entity type.
* *
* @return the id * @return the id
* @since TODO * @since 2.11.0
*/ */
public String id() { public String id() {
return this.id; return this.id;
@ -57,7 +57,7 @@ public class EntityType implements RegistryItem, Keyed {
* @return the id * @return the id
* @deprecated use {@link #id()} * @deprecated use {@link #id()}
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
@Override @Override
public String getId() { public String getId() {
return this.id; return this.id;

Datei anzeigen

@ -43,7 +43,7 @@ public class FluidType implements RegistryItem, Keyed {
* Gets the ID of this fluid. * Gets the ID of this fluid.
* *
* @return The id * @return The id
* @since TODO * @since 2.11.0
*/ */
@Override @Override
public String id() { public String id() {
@ -56,7 +56,7 @@ public class FluidType implements RegistryItem, Keyed {
* @return the id * @return the id
* @deprecated use {@link #id()} * @deprecated use {@link #id()}
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
@Override @Override
public String getId() { public String getId() {
return this.id; return this.id;

Datei anzeigen

@ -29,7 +29,7 @@ public interface ItemMaterial {
* @return the maximum quantity * @return the maximum quantity
* @deprecated Use {@link #maxStackSize()} instead. * @deprecated Use {@link #maxStackSize()} instead.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
default int getMaxStackSize() { default int getMaxStackSize() {
return maxStackSize(); return maxStackSize();
} }
@ -38,7 +38,7 @@ public interface ItemMaterial {
* Gets the the maximum quantity of this item that can be in a single stack. * Gets the the maximum quantity of this item that can be in a single stack.
* *
* @return the maximum quantity * @return the maximum quantity
* @since TODO * @since 2.11.0
*/ */
@NonAbstractForCompatibility(delegateName = "getMaxStackSize", delegateParams = {}) @NonAbstractForCompatibility(delegateName = "getMaxStackSize", delegateParams = {})
default int maxStackSize() { default int maxStackSize() {
@ -52,7 +52,7 @@ public interface ItemMaterial {
* @return the maximum damage, or 0 if not applicable * @return the maximum damage, or 0 if not applicable
* @deprecated Use {@link #maxDamage()} instead. * @deprecated Use {@link #maxDamage()} instead.
*/ */
@Deprecated(forRemoval = true, since = "TODO") @Deprecated(forRemoval = true, since = "2.11.0")
default int getMaxDamage() { default int getMaxDamage() {
return maxDamage(); return maxDamage();
} }
@ -61,7 +61,7 @@ public interface ItemMaterial {
* Gets the the maximum damage this item can take before being broken. * Gets the the maximum damage this item can take before being broken.
* *
* @return the maximum damage, or 0 if not applicable * @return the maximum damage, or 0 if not applicable
* @since TODO * @since 2.11.0
*/ */
@NonAbstractForCompatibility(delegateName = "getMaxDamage", delegateParams = {}) @NonAbstractForCompatibility(delegateName = "getMaxDamage", delegateParams = {})
default int maxDamage() { default int maxDamage() {

Datei anzeigen

@ -164,6 +164,7 @@
"fawe.cancel.reason.no.region.not.added": "Not added to region", "fawe.cancel.reason.no.region.not.added": "Not added to region",
"fawe.cancel.reason.player-only": "This operation requires a player, and cannot be executed from console, or without an actor.", "fawe.cancel.reason.player-only": "This operation requires a player, and cannot be executed from console, or without an actor.",
"fawe.cancel.reason.actor-required": "This operation requires an actor.", "fawe.cancel.reason.actor-required": "This operation requires an actor.",
"fawe.cancel.reason.world.limit": "This operation cannot be performed at y={0} as it is outside world limits.",
"fawe.cancel.worldedit.failed.load.chunk": "Skipped loading chunk: {0};{1}. Try increasing chunk-wait.", "fawe.cancel.worldedit.failed.load.chunk": "Skipped loading chunk: {0};{1}. Try increasing chunk-wait.",
"fawe.navigation.no.block": "No block in sight! (or too far)", "fawe.navigation.no.block": "No block in sight! (or too far)",
"fawe.selection.sel.max": "{0} points maximum.", "fawe.selection.sel.max": "{0} points maximum.",