mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2024-11-01 02:17:11 +00:00
This commit is contained in:
commit
778517f1ea
@ -7,7 +7,7 @@ import xyz.jpenilla.runpaper.task.RunServer
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
|
id("io.github.gradle-nexus.publish-plugin") version "2.0.0"
|
||||||
id("xyz.jpenilla.run-paper") version "2.3.0"
|
id("xyz.jpenilla.run-paper") version "2.3.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!File("$rootDir/.git").exists()) {
|
if (!File("$rootDir/.git").exists()) {
|
||||||
@ -34,7 +34,7 @@ logger.lifecycle("""
|
|||||||
*******************************************
|
*******************************************
|
||||||
""")
|
""")
|
||||||
|
|
||||||
var rootVersion by extra("2.11.2")
|
var rootVersion by extra("2.11.3")
|
||||||
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("")
|
||||||
@ -91,13 +91,13 @@ tasks {
|
|||||||
minecraftVersion(it)
|
minecraftVersion(it)
|
||||||
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
|
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
|
||||||
.toTypedArray())
|
.toTypedArray())
|
||||||
jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true")
|
jvmArgs("-DPaper.IgnoreJavaVersion=true", "-Dcom.mojang.eula.agree=true", "--add-modules=jdk.incubator.vector")
|
||||||
group = "run paper"
|
group = "run paper"
|
||||||
runDirectory.set(file("run-$it"))
|
runDirectory.set(file("run-$it"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
runServer {
|
runServer {
|
||||||
minecraftVersion("1.20.4")
|
minecraftVersion("1.21.1")
|
||||||
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
|
pluginJars(*project(":worldedit-bukkit").getTasksByName("shadowJar", false).map { (it as Jar).archiveFile }
|
||||||
.toTypedArray())
|
.toTypedArray())
|
||||||
|
|
||||||
|
@ -26,9 +26,9 @@ val properties = Properties().also { props ->
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(gradleApi())
|
implementation(gradleApi())
|
||||||
implementation("org.ajoberstar.grgit:grgit-gradle:5.2.2")
|
implementation("org.ajoberstar.grgit:grgit-gradle:5.3.0")
|
||||||
implementation("com.github.johnrengelman:shadow:8.1.1")
|
implementation("com.gradleup.shadow:shadow-gradle-plugin:8.3.3")
|
||||||
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.2")
|
implementation("io.papermc.paperweight.userdev:io.papermc.paperweight.userdev.gradle.plugin:1.7.3")
|
||||||
constraints {
|
constraints {
|
||||||
val asmVersion = "[9.7,)"
|
val asmVersion = "[9.7,)"
|
||||||
implementation("org.ow2.asm:asm:$asmVersion") {
|
implementation("org.ow2.asm:asm:$asmVersion") {
|
||||||
|
@ -28,6 +28,7 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
|
|||||||
options.isDeprecation = true
|
options.isDeprecation = true
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
options.compilerArgs.add("-parameters")
|
options.compilerArgs.add("-parameters")
|
||||||
|
options.compilerArgs.add("--add-modules=jdk.incubator.vector")
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations.all {
|
configurations.all {
|
||||||
@ -40,28 +41,30 @@ fun Project.applyCommonJavaConfiguration(sourcesJar: Boolean, banSlf4j: Boolean
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
"compileOnly"("com.google.code.findbugs:jsr305:3.0.2")
|
"compileOnly"("com.google.code.findbugs:jsr305:3.0.2")
|
||||||
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.10.0")
|
"testImplementation"("org.junit.jupiter:junit-jupiter-api:5.11.1")
|
||||||
"testImplementation"("org.junit.jupiter:junit-jupiter-params:5.10.0")
|
"testImplementation"("org.junit.jupiter:junit-jupiter-params:5.11.1")
|
||||||
"testImplementation"("org.mockito:mockito-core:5.4.0")
|
"testImplementation"("org.mockito:mockito-core:5.14.0")
|
||||||
"testImplementation"("org.mockito:mockito-junit-jupiter:5.4.0")
|
"testImplementation"("org.mockito:mockito-junit-jupiter:5.14.0")
|
||||||
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.10.0")
|
"testRuntimeOnly"("org.junit.jupiter:junit-jupiter-engine:5.11.1")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Java 8 turns on doclint which we fail
|
// Java 8 turns on doclint which we fail
|
||||||
tasks.withType<Javadoc>().configureEach {
|
tasks.withType<Javadoc>().configureEach {
|
||||||
(options as StandardJavadocDocletOptions).apply {
|
(options as StandardJavadocDocletOptions).apply {
|
||||||
addStringOption("Xdoclint:none", "-quiet")
|
addStringOption("Xdoclint:none", "-quiet")
|
||||||
|
addStringOption("-add-modules", "jdk.incubator.vector")
|
||||||
tags(
|
tags(
|
||||||
"apiNote:a:API Note:",
|
"apiNote:a:API Note:",
|
||||||
"implSpec:a:Implementation Requirements:",
|
"implSpec:a:Implementation Requirements:",
|
||||||
"implNote:a:Implementation Note:"
|
"implNote:a:Implementation Note:"
|
||||||
)
|
)
|
||||||
options.encoding = "UTF-8"
|
options.encoding = "UTF-8"
|
||||||
|
|
||||||
links(
|
links(
|
||||||
"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.21/",
|
"https://jd.papermc.io/paper/1.21.1/",
|
||||||
"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}"
|
||||||
|
@ -29,7 +29,7 @@ fun Project.applyLibrariesConfiguration() {
|
|||||||
applyCommonConfiguration()
|
applyCommonConfiguration()
|
||||||
apply(plugin = "java-base")
|
apply(plugin = "java-base")
|
||||||
apply(plugin = "maven-publish")
|
apply(plugin = "maven-publish")
|
||||||
apply(plugin = "com.github.johnrengelman.shadow")
|
apply(plugin = "com.gradleup.shadow")
|
||||||
apply(plugin = "signing")
|
apply(plugin = "signing")
|
||||||
|
|
||||||
configurations {
|
configurations {
|
||||||
|
@ -20,7 +20,7 @@ fun Project.applyPlatformAndCoreConfiguration() {
|
|||||||
apply(plugin = "eclipse")
|
apply(plugin = "eclipse")
|
||||||
apply(plugin = "idea")
|
apply(plugin = "idea")
|
||||||
apply(plugin = "maven-publish")
|
apply(plugin = "maven-publish")
|
||||||
apply(plugin = "com.github.johnrengelman.shadow")
|
apply(plugin = "com.gradleup.shadow")
|
||||||
apply(plugin = "signing")
|
apply(plugin = "signing")
|
||||||
|
|
||||||
applyCommonJavaConfiguration(
|
applyCommonJavaConfiguration(
|
||||||
|
@ -9,21 +9,21 @@ snakeyaml = "2.0"
|
|||||||
|
|
||||||
# Plugins
|
# Plugins
|
||||||
dummypermscompat = "1.10"
|
dummypermscompat = "1.10"
|
||||||
worldguard-bukkit = "7.0.10"
|
worldguard-bukkit = "7.0.12"
|
||||||
mapmanager = "1.8.0-SNAPSHOT"
|
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.12"
|
towny = "0.100.4.4"
|
||||||
plotsquared = "7.3.9"
|
plotsquared = "7.3.11"
|
||||||
|
|
||||||
# Third party
|
# Third party
|
||||||
bstats = "3.0.2"
|
bstats = "3.1.0"
|
||||||
sparsebitset = "1.3"
|
sparsebitset = "1.3"
|
||||||
parallelgzip = "1.0.5"
|
parallelgzip = "1.0.5"
|
||||||
adventure = "4.17.0"
|
adventure = "4.17.0"
|
||||||
adventure-bukkit = "4.3.4"
|
adventure-bukkit = "4.3.4"
|
||||||
checkerqual = "3.46.0"
|
checkerqual = "3.47.0"
|
||||||
truezip = "6.8.4"
|
truezip = "6.8.4"
|
||||||
auto-value = "1.11.0"
|
auto-value = "1.11.0"
|
||||||
findbugs = "3.0.2"
|
findbugs = "3.0.2"
|
||||||
@ -35,7 +35,7 @@ jlibnoise = "1.0.0"
|
|||||||
jchronic = "0.2.4a"
|
jchronic = "0.2.4a"
|
||||||
lz4-java = "1.8.0"
|
lz4-java = "1.8.0"
|
||||||
lz4-stream = "1.0.0"
|
lz4-stream = "1.0.0"
|
||||||
commons-cli = "1.8.0"
|
commons-cli = "1.9.0"
|
||||||
paperlib = "1.0.8"
|
paperlib = "1.0.8"
|
||||||
paster = "1.1.6"
|
paster = "1.1.6"
|
||||||
vault = "1.7.1"
|
vault = "1.7.1"
|
||||||
@ -47,7 +47,7 @@ text = "3.0.4"
|
|||||||
piston = "0.5.10"
|
piston = "0.5.10"
|
||||||
|
|
||||||
# Tests
|
# Tests
|
||||||
mockito = "5.12.0"
|
mockito = "5.14.1"
|
||||||
|
|
||||||
# Gradle plugins
|
# Gradle plugins
|
||||||
pluginyml = "0.6.0"
|
pluginyml = "0.6.0"
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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.9-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
7
gradlew
vendored
7
gradlew
vendored
@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@ -84,7 +86,8 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||||
|
' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
2
gradlew.bat
vendored
2
gradlew.bat
vendored
@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.util.ReflectionUtil;
|
import com.sk89q.util.ReflectionUtil;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
@ -17,6 +15,8 @@ import net.minecraft.world.level.block.state.BlockState;
|
|||||||
import net.minecraft.world.level.material.PushReaction;
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class PaperweightBlockMaterial implements BlockMaterial {
|
public class PaperweightBlockMaterial implements BlockMaterial {
|
||||||
|
|
||||||
private final Block block;
|
private final Block block;
|
||||||
@ -25,7 +25,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
private final CraftBlockData craftBlockData;
|
private final CraftBlockData craftBlockData;
|
||||||
private final org.bukkit.Material craftMaterial;
|
private final org.bukkit.Material craftMaterial;
|
||||||
private final int opacity;
|
private final int opacity;
|
||||||
private final CompoundTag tile;
|
private final FaweCompoundTag tile;
|
||||||
|
|
||||||
public PaperweightBlockMaterial(Block block) {
|
public PaperweightBlockMaterial(Block block) {
|
||||||
this(block, block.defaultBlockState());
|
this(block, block.defaultBlockState());
|
||||||
@ -48,7 +48,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
);
|
);
|
||||||
tile = tileEntity == null
|
tile = tileEntity == null
|
||||||
? null
|
? null
|
||||||
: new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId));
|
: PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block getBlock() {
|
public Block getBlock() {
|
||||||
@ -135,9 +135,10 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
return block.isRandomlyTicking(blockState);
|
return block.isRandomlyTicking(blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public boolean isMovementBlocker() {
|
public boolean isMovementBlocker() {
|
||||||
return craftMaterial.isSolid();
|
return blockState.blocksMotion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -172,7 +173,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getDefaultTile() {
|
public @Nullable FaweCompoundTag defaultTile() {
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
@ -97,6 +98,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -129,6 +131,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.
|
|||||||
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightAdapter();
|
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R2.PaperweightAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
|
||||||
|
return blockEntity -> FaweCompoundTag.of(
|
||||||
|
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getEntityId(Entity entity) {
|
private static String getEntityId(Entity entity) {
|
||||||
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
||||||
|
@ -7,20 +7,17 @@ import com.fastasyncworldedit.core.FaweCache;
|
|||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||||
import com.google.common.base.Suppliers;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.jnbt.ListTag;
|
|
||||||
import com.sk89q.jnbt.StringTag;
|
|
||||||
import com.sk89q.jnbt.Tag;
|
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
@ -34,6 +31,7 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.IdMap;
|
import net.minecraft.core.IdMap;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.IntTag;
|
import net.minecraft.nbt.IntTag;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@ -61,11 +59,19 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock;
|
import org.bukkit.craftbukkit.v1_20_R2.block.CraftBlock;
|
||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
import org.enginehub.linbus.tree.LinDoubleTag;
|
||||||
|
import org.enginehub.linbus.tree.LinFloatTag;
|
||||||
|
import org.enginehub.linbus.tree.LinListTag;
|
||||||
|
import org.enginehub.linbus.tree.LinStringTag;
|
||||||
|
import org.enginehub.linbus.tree.LinTagType;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.AbstractSet;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.AbstractCollection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -82,7 +88,6 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
@ -91,8 +96,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||||
private static final Function<BlockEntity, CompoundTag> nmsTile2We =
|
public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId));
|
.getInstance()
|
||||||
|
.getBukkitImplAdapter()).blockEntityToCompoundTag();
|
||||||
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
@ -101,6 +107,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
|
private final IntPair chunkPos;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final int minSectionPosition;
|
private final int minSectionPosition;
|
||||||
@ -135,6 +142,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.blockLight = new DataLayer[getSectionCount()];
|
this.blockLight = new DataLayer[getSectionCount()];
|
||||||
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
||||||
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
|
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
public int getChunkX() {
|
||||||
@ -256,23 +264,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getTile(int x, int y, int z) {
|
public FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
||||||
chunkX << 4), y, (z & 15) + (
|
chunkX << 4), y, (z & 15) + (
|
||||||
chunkZ << 4)));
|
chunkZ << 4)));
|
||||||
if (blockEntity == null) {
|
if (blockEntity == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId));
|
return NMS_TO_TILE.apply(blockEntity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
||||||
if (nmsTiles.isEmpty()) {
|
if (nmsTiles.isEmpty()) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -335,7 +344,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
Entity entity = null;
|
Entity entity = null;
|
||||||
@ -347,10 +356,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
|
||||||
}
|
}
|
||||||
for (CompoundTag tag : getEntities()) {
|
for (FaweCompoundTag tag : entities()) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,14 +367,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
int size = entities.size();
|
int size = entities.size();
|
||||||
return new AbstractSet<>() {
|
return new AbstractCollection<>() {
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return size;
|
return size;
|
||||||
@ -378,10 +387,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Object get) {
|
public boolean contains(Object get) {
|
||||||
if (!(get instanceof CompoundTag getTag)) {
|
if (!(get instanceof FaweCompoundTag getTag)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
UUID getUUID = getTag.getUUID();
|
UUID getUUID = NbtUtils.uuid(getTag);
|
||||||
for (Entity entity : entities) {
|
for (Entity entity : entities) {
|
||||||
UUID uuid = entity.getUUID();
|
UUID uuid = entity.getUUID();
|
||||||
if (uuid.equals(getUUID)) {
|
if (uuid.equals(getUUID)) {
|
||||||
@ -393,12 +402,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Iterator<CompoundTag> iterator() {
|
public Iterator<FaweCompoundTag> iterator() {
|
||||||
Iterable<CompoundTag> result = entities.stream().map(input -> {
|
Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
|
||||||
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
|
CompoundTag tag = new CompoundTag();
|
||||||
input.save(tag);
|
input.save(tag);
|
||||||
return (CompoundTag) adapter.toNative(tag);
|
return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
|
||||||
}).collect(Collectors.toList());
|
})::iterator;
|
||||||
return result.iterator();
|
return result.iterator();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -419,7 +428,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||||
}
|
}
|
||||||
forceLoadSections = false;
|
forceLoadSections = false;
|
||||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
|
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
|
||||||
if (createCopy) {
|
if (createCopy) {
|
||||||
if (copies.containsKey(copyKey)) {
|
if (copies.containsKey(copyKey)) {
|
||||||
throw new IllegalStateException("Copy key already used.");
|
throw new IllegalStateException("Copy key already used.");
|
||||||
@ -427,9 +437,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
copies.put(copyKey, copy);
|
copies.put(copyKey, copy);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
|
||||||
|
|
||||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||||
List<BlockEntity> beacons = null;
|
List<BlockEntity> beacons = null;
|
||||||
@ -501,6 +508,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -578,6 +587,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -643,6 +654,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||||
);
|
);
|
||||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
existingSection,
|
existingSection,
|
||||||
newSection,
|
newSection,
|
||||||
@ -716,7 +729,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
||||||
for (UUID uuid : entityRemoves) {
|
for (UUID uuid : entityRemoves) {
|
||||||
Entity entity = nmsWorld.getEntities().get(uuid);
|
Entity entity = serverLevel.getEntities().get(uuid);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
removeEntity(entity);
|
removeEntity(entity);
|
||||||
}
|
}
|
||||||
@ -728,48 +741,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<CompoundTag> entities = set.getEntities();
|
Collection<FaweCompoundTag> entities = set.entities();
|
||||||
if (entities != null && !entities.isEmpty()) {
|
if (entities != null && !entities.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[2];
|
syncTasks = new Runnable[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[1] = () -> {
|
syncTasks[1] = () -> {
|
||||||
Iterator<CompoundTag> iterator = entities.iterator();
|
Iterator<FaweCompoundTag> iterator = entities.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
final CompoundTag nativeTag = iterator.next();
|
final FaweCompoundTag nativeTag = iterator.next();
|
||||||
final Map<String, Tag<?, ?>> entityTagMap = nativeTag.getValue();
|
final LinCompoundTag linTag = nativeTag.linTag();
|
||||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
|
||||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
|
||||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
|
||||||
if (idTag == null || posTag == null || rotTag == null) {
|
if (idTag == null || posTag == null || rotTag == null) {
|
||||||
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final double x = posTag.getDouble(0);
|
final double x = posTag.get(0).valueAsDouble();
|
||||||
final double y = posTag.getDouble(1);
|
final double y = posTag.get(1).valueAsDouble();
|
||||||
final double z = posTag.getDouble(2);
|
final double z = posTag.get(2).valueAsDouble();
|
||||||
final float yaw = rotTag.getFloat(0);
|
final float yaw = rotTag.get(0).valueAsFloat();
|
||||||
final float pitch = rotTag.getFloat(1);
|
final float pitch = rotTag.get(1).valueAsFloat();
|
||||||
final String id = idTag.getValue();
|
final String id = idTag.value();
|
||||||
|
|
||||||
EntityType<?> type = EntityType.byString(id).orElse(null);
|
EntityType<?> type = EntityType.byString(id).orElse(null);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
Entity entity = type.create(nmsWorld);
|
Entity entity = type.create(serverLevel);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag);
|
||||||
nativeTag);
|
|
||||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
tag.remove(name);
|
tag.remove(name);
|
||||||
}
|
}
|
||||||
entity.load(tag);
|
entity.load(tag);
|
||||||
entity.absMoveTo(x, y, z, yaw, pitch);
|
entity.absMoveTo(x, y, z, yaw, pitch);
|
||||||
entity.setUUID(nativeTag.getUUID());
|
entity.setUUID(NbtUtils.uuid(nativeTag));
|
||||||
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
||||||
LOGGER.warn(
|
LOGGER.warn(
|
||||||
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
||||||
id,
|
id,
|
||||||
nmsWorld.getWorld().getName(),
|
serverLevel.getWorld().getName(),
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
z
|
z
|
||||||
@ -784,30 +796,29 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set tiles
|
// set tiles
|
||||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
|
||||||
if (tiles != null && !tiles.isEmpty()) {
|
if (tiles != null && !tiles.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[1];
|
syncTasks = new Runnable[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[0] = () -> {
|
syncTasks[0] = () -> {
|
||||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
|
||||||
final CompoundTag nativeTag = entry.getValue();
|
final FaweCompoundTag nativeTag = entry.getValue();
|
||||||
final BlockVector3 blockHash = entry.getKey();
|
final BlockVector3 blockHash = entry.getKey();
|
||||||
final int x = blockHash.x() + bx;
|
final int x = blockHash.x() + bx;
|
||||||
final int y = blockHash.y();
|
final int y = blockHash.y();
|
||||||
final int z = blockHash.z() + bz;
|
final int z = blockHash.z() + bz;
|
||||||
final BlockPos pos = new BlockPos(x, y, z);
|
final BlockPos pos = new BlockPos(x, y, z);
|
||||||
|
|
||||||
synchronized (nmsWorld) {
|
synchronized (serverLevel) {
|
||||||
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
|
BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||||
nmsWorld.removeBlockEntity(pos);
|
serverLevel.removeBlockEntity(pos);
|
||||||
tileEntity = nmsWorld.getBlockEntity(pos);
|
tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
}
|
}
|
||||||
if (tileEntity != null) {
|
if (tileEntity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
|
||||||
nativeTag);
|
|
||||||
tag.put("x", IntTag.valueOf(x));
|
tag.put("x", IntTag.valueOf(x));
|
||||||
tag.put("y", IntTag.valueOf(y));
|
tag.put("y", IntTag.valueOf(y));
|
||||||
tag.put("z", IntTag.valueOf(z));
|
tag.put("z", IntTag.valueOf(z));
|
||||||
@ -823,7 +834,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
callback = null;
|
callback = null;
|
||||||
} else {
|
} else {
|
||||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||||
boolean finalLightUpdate = lightUpdate;
|
|
||||||
callback = () -> {
|
callback = () -> {
|
||||||
// Set Modified
|
// Set Modified
|
||||||
nmsChunk.setLightCorrect(true); // Set Modified
|
nmsChunk.setLightCorrect(true); // Set Modified
|
||||||
@ -929,7 +939,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
public void send() {
|
public void send() {
|
||||||
synchronized (sendLock) {
|
synchronized (sendLock) {
|
||||||
PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
@ -24,9 +25,11 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|||||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -38,8 +41,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
|
||||||
private final Set<CompoundTag> entities = new HashSet<>();
|
private final Set<FaweCompoundTag> entities = new HashSet<>();
|
||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
@ -56,44 +59,35 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
tiles.put(
|
tiles.put(
|
||||||
BlockVector3.at(
|
BlockVector3.at(
|
||||||
blockEntity.getBlockPos().getX(),
|
blockEntity.getBlockPos().getX(),
|
||||||
blockEntity.getBlockPos().getY(),
|
blockEntity.getBlockPos().getY(),
|
||||||
blockEntity.getBlockPos().getZ()
|
blockEntity.getBlockPos().getZ()
|
||||||
),
|
),
|
||||||
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId))
|
FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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) {
|
protected void storeEntity(Entity entity) {
|
||||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
||||||
entity.save(compoundTag);
|
entity.save(compoundTag);
|
||||||
entities.add((CompoundTag) adapter.toNative(compoundTag));
|
entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (FaweCompoundTag tag : entities) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,8 +173,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
biomes[layer] = new Holder[64];
|
biomes[layer] = new Holder[64];
|
||||||
}
|
}
|
||||||
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||||
for (int i = 0; i < 64; i++) {
|
if (PaperLib.isPaper()) {
|
||||||
biomes[layer][i] = palettedContainer.get(i);
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
@ -194,7 +198,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||||
return state.toBaseBlock(this, x, y, z);
|
return state.toBaseBlock((IBlocks) this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -224,6 +228,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return BlockTypesCache.states[get(x, y, z)];
|
return BlockTypesCache.states[get(x, y, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
|
return tiles.get(BlockVector3.at(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -7,8 +7,8 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
@ -123,6 +123,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
private static Field LEVEL_CHUNK_ENTITIES;
|
private static Field LEVEL_CHUNK_ENTITIES;
|
||||||
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
||||||
|
|
||||||
|
static final MethodHandle PALETTED_CONTAINER_GET;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
try {
|
try {
|
||||||
@ -212,6 +214,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
} catch (NoSuchFieldException ignored) {
|
} catch (NoSuchFieldException ignored) {
|
||||||
}
|
}
|
||||||
POST_CHUNK_REWRITE = chunkRewrite;
|
POST_CHUNK_REWRITE = chunkRewrite;
|
||||||
|
|
||||||
|
Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
|
||||||
|
Refraction.pickName("get", "a"),
|
||||||
|
int.class
|
||||||
|
);
|
||||||
|
palettedContaienrGet.setAccessible(true);
|
||||||
|
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
|
||||||
} catch (RuntimeException | Error e) {
|
} catch (RuntimeException | Error e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -234,15 +243,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean setSectionAtomic(
|
static boolean setSectionAtomic(
|
||||||
|
String worldName,
|
||||||
|
IntPair pair,
|
||||||
LevelChunkSection[] sections,
|
LevelChunkSection[] sections,
|
||||||
LevelChunkSection expected,
|
LevelChunkSection expected,
|
||||||
LevelChunkSection value,
|
LevelChunkSection value,
|
||||||
int layer
|
int layer
|
||||||
) {
|
) {
|
||||||
if (layer >= 0 && layer < sections.length) {
|
return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
|
||||||
return ReflectionUtils.compareAndSet(sections, expected, value, layer);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no point in having a functional semaphore for paper servers.
|
// There is no point in having a functional semaphore for paper servers.
|
||||||
@ -340,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
||||||
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||||
if (chunkHolder == null) {
|
if (chunkHolder == null) {
|
||||||
return;
|
return;
|
||||||
@ -361,26 +369,35 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (levelChunk == null) {
|
if (levelChunk == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
StampLockHolder lockHolder = new StampLockHolder();
|
||||||
|
NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
|
if (lockHolder.chunkLock == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
MinecraftServer.getServer().execute(() -> {
|
MinecraftServer.getServer().execute(() -> {
|
||||||
ClientboundLevelChunkWithLightPacket packet;
|
try {
|
||||||
if (PaperLib.isPaper()) {
|
ClientboundLevelChunkWithLightPacket packet;
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
if (PaperLib.isPaper()) {
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null,
|
null,
|
||||||
false // last false is to not bother with x-ray
|
null,
|
||||||
);
|
false // last false is to not bother with x-ray
|
||||||
} else {
|
);
|
||||||
// deprecated on paper - deprecation suppressed
|
} else {
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
// deprecated on paper - deprecation suppressed
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null
|
null,
|
||||||
);
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||||
|
} finally {
|
||||||
|
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
}
|
}
|
||||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -67,7 +68,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLeve
|
|||||||
int x = pos.x;
|
int x = pos.x;
|
||||||
int z = pos.z;
|
int z = pos.z;
|
||||||
if (delay) { // we still need to send the block changes of that chunk
|
if (delay) { // we still need to send the block changes of that chunk
|
||||||
PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
|
||||||
}
|
}
|
||||||
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
||||||
}
|
}
|
||||||
|
@ -4,167 +4,74 @@ import com.fastasyncworldedit.bukkit.adapter.Regenerator;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkCache;
|
import com.fastasyncworldedit.core.queue.IChunkCache;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.datafixers.util.Either;
|
|
||||||
import com.mojang.serialization.Lifecycle;
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R2.PaperweightGetBlocks;
|
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||||
import com.sk89q.worldedit.world.RegenOptions;
|
import com.sk89q.worldedit.world.RegenOptions;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
|
||||||
import net.minecraft.core.Holder;
|
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.resources.ResourceKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
|
||||||
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message;
|
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
import net.minecraft.util.ProgressListener;
|
||||||
import net.minecraft.util.thread.ProcessorMailbox;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
|
||||||
import net.minecraft.world.level.LevelSettings;
|
import net.minecraft.world.level.LevelSettings;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
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.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
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.dimension.LevelStem;
|
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.NoiseBasedChunkGenerator;
|
||||||
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
|
|
||||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
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.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
|
import org.bukkit.craftbukkit.v1_20_R2.CraftServer;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R2.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R2.generator.CustomChunkGenerator;
|
|
||||||
import org.bukkit.generator.BiomeProvider;
|
import org.bukkit.generator.BiomeProvider;
|
||||||
import org.bukkit.generator.BlockPopulator;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.OptionalLong;
|
import java.util.OptionalLong;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
|
public class PaperweightRegen extends Regenerator {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
|
||||||
|
|
||||||
private static final Field serverWorldsField;
|
private static final Field serverWorldsField;
|
||||||
private static final Field paperConfigField;
|
private static final Field paperConfigField;
|
||||||
private static final Field flatBedrockField;
|
|
||||||
private static final Field generatorSettingFlatField;
|
|
||||||
private static final Field generatorSettingBaseSupplierField;
|
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 {
|
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.FULL
|
|
||||||
); // structure refs: radius 8, but only writes to current chunk
|
|
||||||
chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // 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.LIQUID_CARVERS,
|
|
||||||
Concurrency.NONE
|
|
||||||
); // liquid carvers: radius 0, but RADIUS and FULL change results*/
|
|
||||||
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
|
|
||||||
chunkStati.put(
|
|
||||||
ChunkStatus.LIGHT,
|
|
||||||
Concurrency.FULL
|
|
||||||
); // light: radius 1, but no writes to other chunks, only current chunk
|
|
||||||
chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0
|
|
||||||
// chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||||
serverWorldsField.setAccessible(true);
|
serverWorldsField.setAccessible(true);
|
||||||
|
|
||||||
Field tmpPaperConfigField;
|
Field tmpPaperConfigField;
|
||||||
Field tmpFlatBedrockField;
|
|
||||||
try { //only present on paper
|
try { //only present on paper
|
||||||
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
||||||
tmpPaperConfigField.setAccessible(true);
|
tmpPaperConfigField.setAccessible(true);
|
||||||
|
|
||||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
|
||||||
tmpFlatBedrockField.setAccessible(true);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
tmpPaperConfigField = null;
|
tmpPaperConfigField = null;
|
||||||
tmpFlatBedrockField = null;
|
|
||||||
}
|
}
|
||||||
paperConfigField = tmpPaperConfigField;
|
paperConfigField = tmpPaperConfigField;
|
||||||
flatBedrockField = tmpFlatBedrockField;
|
|
||||||
|
|
||||||
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
||||||
"settings", "e"));
|
"settings", "e"));
|
||||||
generatorSettingBaseSupplierField.setAccessible(true);
|
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", "v"));
|
|
||||||
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) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -172,43 +79,37 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
//runtime
|
//runtime
|
||||||
private ServerLevel originalServerWorld;
|
private ServerLevel originalServerWorld;
|
||||||
private ServerChunkCache originalChunkProvider;
|
|
||||||
private ServerLevel freshWorld;
|
private ServerLevel freshWorld;
|
||||||
private ServerChunkCache freshChunkProvider;
|
|
||||||
private LevelStorageSource.LevelStorageAccess session;
|
private LevelStorageSource.LevelStorageAccess session;
|
||||||
private StructureTemplateManager structureTemplateManager;
|
|
||||||
private ThreadedLevelLightEngine threadedLevelLightEngine;
|
|
||||||
private ChunkGenerator chunkGenerator;
|
|
||||||
|
|
||||||
private Path tempDir;
|
private Path tempDir;
|
||||||
|
|
||||||
private boolean generateFlatBedrock = false;
|
public PaperweightRegen(
|
||||||
|
World originalBukkitWorld,
|
||||||
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
Region region,
|
||||||
|
Extent target,
|
||||||
|
RegenOptions options
|
||||||
|
) {
|
||||||
super(originalBukkitWorld, region, target, options);
|
super(originalBukkitWorld, region, target, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void runTasks(final BooleanSupplier shouldKeepTicking) {
|
||||||
|
while (shouldKeepTicking.getAsBoolean()) {
|
||||||
|
if (!this.freshWorld.getChunkSource().pollTask()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepare() {
|
protected boolean prepare() {
|
||||||
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
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());
|
seed = options.getSeed().orElse(originalServerWorld.getSeed());
|
||||||
chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected boolean initNewWorld() throws Exception {
|
protected boolean initNewWorld() throws Exception {
|
||||||
//world folder
|
//world folder
|
||||||
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
||||||
@ -254,8 +155,10 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
session,
|
session,
|
||||||
newWorldData,
|
newWorldData,
|
||||||
originalServerWorld.dimension(),
|
originalServerWorld.dimension(),
|
||||||
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
|
new LevelStem(
|
||||||
.getOrThrow(levelStemResourceKey),
|
originalServerWorld.dimensionTypeRegistration(),
|
||||||
|
originalServerWorld.getChunkSource().getGenerator()
|
||||||
|
),
|
||||||
new RegenNoOpWorldLoadListener(),
|
new RegenNoOpWorldLoadListener(),
|
||||||
originalServerWorld.isDebug(),
|
originalServerWorld.isDebug(),
|
||||||
seed,
|
seed,
|
||||||
@ -273,17 +176,30 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick(BooleanSupplier shouldKeepTicking) { //no ticking
|
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
|
||||||
if (options.hasBiomeType()) {
|
if (options.hasBiomeType()) {
|
||||||
return singleBiome;
|
return singleBiome;
|
||||||
}
|
}
|
||||||
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(
|
return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ);
|
||||||
biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler()
|
}
|
||||||
);
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@org.jetbrains.annotations.Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled
|
||||||
|
) {
|
||||||
|
// noop, spigot
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled,
|
||||||
|
final boolean close
|
||||||
|
) {
|
||||||
|
// noop, paper
|
||||||
}
|
}
|
||||||
}).get();
|
}).get();
|
||||||
freshWorld.noSave = true;
|
freshWorld.noSave = true;
|
||||||
@ -292,89 +208,6 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
if (paperConfigField != null) {
|
if (paperConfigField != null) {
|
||||||
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
|
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(
|
|
||||||
originalGenerator);
|
|
||||||
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, 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);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,7 +222,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
try {
|
try {
|
||||||
Fawe.instance().getQueueHandler().sync(() -> {
|
Fawe.instance().getQueueHandler().sync(() -> {
|
||||||
try {
|
try {
|
||||||
freshChunkProvider.close(false);
|
freshWorld.getChunkSource().getDataStorage().cache.clear();
|
||||||
|
freshWorld.getChunkSource().close(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -410,63 +244,20 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||||
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
|
return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld()));
|
||||||
@Override
|
|
||||||
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
|
|
||||||
return getChunkAt(x, z);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//util
|
//util
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void removeWorldFromWorldsMap() {
|
private void removeWorldFromWorldsMap() {
|
||||||
Fawe.instance().getQueueHandler().sync(() -> {
|
try {
|
||||||
try {
|
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
map.remove("faweregentempworld");
|
||||||
map.remove("faweregentempworld");
|
} catch (IllegalAccessException e) {
|
||||||
} catch (IllegalAccessException e) {
|
throw new RuntimeException(e);
|
||||||
throw new RuntimeException(e);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
|
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
|
||||||
@ -483,11 +274,15 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSpawnPos(ChunkPos spawnPos) {
|
public void updateSpawnPos(@NotNull ChunkPos spawnPos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) {
|
public void onStatusChange(
|
||||||
|
final @NotNull ChunkPos pos,
|
||||||
|
@org.jetbrains.annotations.Nullable final ChunkStatus status
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -505,87 +300,4 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
// compatibility with spigot
|
|
||||||
|
|
||||||
public boolean generateFlatBedrock() {
|
|
||||||
return generateFlatBedrock;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no one will ever see the entities!
|
|
||||||
@Override
|
|
||||||
public 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 chunkStatus.getRange();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name() {
|
|
||||||
return chunkStatus.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<?> processChunk(List<ChunkAccess> accessibleChunks) {
|
|
||||||
return chunkStatus.generate(
|
|
||||||
Runnable::run, // TODO revisit, we might profit from this somehow?
|
|
||||||
freshWorld,
|
|
||||||
chunkGenerator,
|
|
||||||
structureTemplateManager,
|
|
||||||
threadedLevelLightEngine,
|
|
||||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
|
||||||
accessibleChunks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 CompletableFuture<ChunkAccess> lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) {
|
|
||||||
return CompletableFuture.completedFuture(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
@ -14,6 +12,8 @@ import net.minecraft.world.level.material.Fluids;
|
|||||||
import net.minecraft.world.level.material.PushReaction;
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class PaperweightBlockMaterial implements BlockMaterial {
|
public class PaperweightBlockMaterial implements BlockMaterial {
|
||||||
|
|
||||||
private final Block block;
|
private final Block block;
|
||||||
@ -21,7 +21,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
private final CraftBlockData craftBlockData;
|
private final CraftBlockData craftBlockData;
|
||||||
private final org.bukkit.Material craftMaterial;
|
private final org.bukkit.Material craftMaterial;
|
||||||
private final int opacity;
|
private final int opacity;
|
||||||
private final CompoundTag tile;
|
private final FaweCompoundTag tile;
|
||||||
|
|
||||||
public PaperweightBlockMaterial(Block block) {
|
public PaperweightBlockMaterial(Block block) {
|
||||||
this(block, block.defaultBlockState());
|
this(block, block.defaultBlockState());
|
||||||
@ -39,7 +39,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
);
|
);
|
||||||
tile = tileEntity == null
|
tile = tileEntity == null
|
||||||
? null
|
? null
|
||||||
: new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId));
|
: PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block getBlock() {
|
public Block getBlock() {
|
||||||
@ -125,9 +125,10 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
return block.isRandomlyTicking(blockState);
|
return block.isRandomlyTicking(blockState);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public boolean isMovementBlocker() {
|
public boolean isMovementBlocker() {
|
||||||
return craftMaterial.isSolid();
|
return blockState.blocksMotion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -162,7 +163,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getDefaultTile() {
|
public @Nullable FaweCompoundTag defaultTile() {
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
@ -97,6 +98,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -129,6 +131,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.
|
|||||||
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter();
|
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R3.PaperweightAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
|
||||||
|
return blockEntity -> FaweCompoundTag.of(
|
||||||
|
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getEntityId(Entity entity) {
|
private static String getEntityId(Entity entity) {
|
||||||
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
||||||
|
@ -7,20 +7,17 @@ import com.fastasyncworldedit.core.FaweCache;
|
|||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||||
import com.google.common.base.Suppliers;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.jnbt.ListTag;
|
|
||||||
import com.sk89q.jnbt.StringTag;
|
|
||||||
import com.sk89q.jnbt.Tag;
|
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
@ -34,6 +31,7 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.IdMap;
|
import net.minecraft.core.IdMap;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.IntTag;
|
import net.minecraft.nbt.IntTag;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
@ -61,11 +59,19 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;
|
import org.bukkit.craftbukkit.v1_20_R3.block.CraftBlock;
|
||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
import org.enginehub.linbus.tree.LinDoubleTag;
|
||||||
|
import org.enginehub.linbus.tree.LinFloatTag;
|
||||||
|
import org.enginehub.linbus.tree.LinListTag;
|
||||||
|
import org.enginehub.linbus.tree.LinStringTag;
|
||||||
|
import org.enginehub.linbus.tree.LinTagType;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.AbstractSet;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.AbstractCollection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -82,7 +88,6 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
@ -91,8 +96,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||||
private static final Function<BlockEntity, CompoundTag> nmsTile2We =
|
public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
tileEntity -> new PaperweightLazyCompoundTag(Suppliers.memoize(tileEntity::saveWithId));
|
.getInstance()
|
||||||
|
.getBukkitImplAdapter()).blockEntityToCompoundTag();
|
||||||
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
@ -101,6 +107,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
|
private final IntPair chunkPos;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final int minSectionPosition;
|
private final int minSectionPosition;
|
||||||
@ -108,6 +115,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final Registry<Biome> biomeRegistry;
|
private final Registry<Biome> biomeRegistry;
|
||||||
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
private final IdMap<Holder<Biome>> biomeHolderIdMap;
|
||||||
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<Integer, PaperweightGetBlocks_Copy> copies = new ConcurrentHashMap<>();
|
||||||
|
private final Object sendLock = new Object();
|
||||||
private LevelChunkSection[] sections;
|
private LevelChunkSection[] sections;
|
||||||
private LevelChunk levelChunk;
|
private LevelChunk levelChunk;
|
||||||
private DataLayer[] blockLight;
|
private DataLayer[] blockLight;
|
||||||
@ -134,6 +142,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.blockLight = new DataLayer[getSectionCount()];
|
this.blockLight = new DataLayer[getSectionCount()];
|
||||||
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
||||||
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
|
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
public int getChunkX() {
|
||||||
@ -255,23 +264,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getTile(int x, int y, int z) {
|
public FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
||||||
chunkX << 4), y, (z & 15) + (
|
chunkX << 4), y, (z & 15) + (
|
||||||
chunkZ << 4)));
|
chunkZ << 4)));
|
||||||
if (blockEntity == null) {
|
if (blockEntity == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId));
|
return NMS_TO_TILE.apply(blockEntity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
||||||
if (nmsTiles.isEmpty()) {
|
if (nmsTiles.isEmpty()) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -334,7 +344,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
Entity entity = null;
|
Entity entity = null;
|
||||||
@ -346,10 +356,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
|
||||||
}
|
}
|
||||||
for (CompoundTag tag : getEntities()) {
|
for (FaweCompoundTag tag : entities()) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,14 +367,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
int size = entities.size();
|
int size = entities.size();
|
||||||
return new AbstractSet<>() {
|
return new AbstractCollection<>() {
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return size;
|
return size;
|
||||||
@ -377,10 +387,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Object get) {
|
public boolean contains(Object get) {
|
||||||
if (!(get instanceof CompoundTag getTag)) {
|
if (!(get instanceof FaweCompoundTag getTag)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
UUID getUUID = getTag.getUUID();
|
UUID getUUID = NbtUtils.uuid(getTag);
|
||||||
for (Entity entity : entities) {
|
for (Entity entity : entities) {
|
||||||
UUID uuid = entity.getUUID();
|
UUID uuid = entity.getUUID();
|
||||||
if (uuid.equals(getUUID)) {
|
if (uuid.equals(getUUID)) {
|
||||||
@ -392,12 +402,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Iterator<CompoundTag> iterator() {
|
public Iterator<FaweCompoundTag> iterator() {
|
||||||
Iterable<CompoundTag> result = entities.stream().map(input -> {
|
Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
|
||||||
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
|
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
|
||||||
input.save(tag);
|
input.save(tag);
|
||||||
return (CompoundTag) adapter.toNative(tag);
|
return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
|
||||||
}).collect(Collectors.toList());
|
})::iterator;
|
||||||
return result.iterator();
|
return result.iterator();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -418,7 +428,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||||
}
|
}
|
||||||
forceLoadSections = false;
|
forceLoadSections = false;
|
||||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
|
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
|
||||||
if (createCopy) {
|
if (createCopy) {
|
||||||
if (copies.containsKey(copyKey)) {
|
if (copies.containsKey(copyKey)) {
|
||||||
throw new IllegalStateException("Copy key already used.");
|
throw new IllegalStateException("Copy key already used.");
|
||||||
@ -426,9 +437,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
copies.put(copyKey, copy);
|
copies.put(copyKey, copy);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
|
||||||
|
|
||||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||||
List<BlockEntity> beacons = null;
|
List<BlockEntity> beacons = null;
|
||||||
@ -500,6 +508,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -577,6 +587,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -642,6 +654,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||||
);
|
);
|
||||||
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
existingSection,
|
existingSection,
|
||||||
newSection,
|
newSection,
|
||||||
@ -715,7 +729,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
||||||
for (UUID uuid : entityRemoves) {
|
for (UUID uuid : entityRemoves) {
|
||||||
Entity entity = nmsWorld.getEntities().get(uuid);
|
Entity entity = serverLevel.getEntities().get(uuid);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
removeEntity(entity);
|
removeEntity(entity);
|
||||||
}
|
}
|
||||||
@ -727,48 +741,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<CompoundTag> entities = set.getEntities();
|
Collection<FaweCompoundTag> entities = set.entities();
|
||||||
if (entities != null && !entities.isEmpty()) {
|
if (entities != null && !entities.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[2];
|
syncTasks = new Runnable[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[1] = () -> {
|
syncTasks[1] = () -> {
|
||||||
Iterator<CompoundTag> iterator = entities.iterator();
|
Iterator<FaweCompoundTag> iterator = entities.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
final CompoundTag nativeTag = iterator.next();
|
final FaweCompoundTag nativeTag = iterator.next();
|
||||||
final Map<String, Tag<?, ?>> entityTagMap = nativeTag.getValue();
|
final LinCompoundTag linTag = nativeTag.linTag();
|
||||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
|
||||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
|
||||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
|
||||||
if (idTag == null || posTag == null || rotTag == null) {
|
if (idTag == null || posTag == null || rotTag == null) {
|
||||||
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final double x = posTag.getDouble(0);
|
final double x = posTag.get(0).valueAsDouble();
|
||||||
final double y = posTag.getDouble(1);
|
final double y = posTag.get(1).valueAsDouble();
|
||||||
final double z = posTag.getDouble(2);
|
final double z = posTag.get(2).valueAsDouble();
|
||||||
final float yaw = rotTag.getFloat(0);
|
final float yaw = rotTag.get(0).valueAsFloat();
|
||||||
final float pitch = rotTag.getFloat(1);
|
final float pitch = rotTag.get(1).valueAsFloat();
|
||||||
final String id = idTag.getValue();
|
final String id = idTag.value();
|
||||||
|
|
||||||
EntityType<?> type = EntityType.byString(id).orElse(null);
|
EntityType<?> type = EntityType.byString(id).orElse(null);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
Entity entity = type.create(nmsWorld);
|
Entity entity = type.create(serverLevel);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag);
|
||||||
nativeTag);
|
|
||||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
tag.remove(name);
|
tag.remove(name);
|
||||||
}
|
}
|
||||||
entity.load(tag);
|
entity.load(tag);
|
||||||
entity.absMoveTo(x, y, z, yaw, pitch);
|
entity.absMoveTo(x, y, z, yaw, pitch);
|
||||||
entity.setUUID(nativeTag.getUUID());
|
entity.setUUID(NbtUtils.uuid(nativeTag));
|
||||||
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
||||||
LOGGER.warn(
|
LOGGER.warn(
|
||||||
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
||||||
id,
|
id,
|
||||||
nmsWorld.getWorld().getName(),
|
serverLevel.getWorld().getName(),
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
z
|
z
|
||||||
@ -783,30 +796,29 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set tiles
|
// set tiles
|
||||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
|
||||||
if (tiles != null && !tiles.isEmpty()) {
|
if (tiles != null && !tiles.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[1];
|
syncTasks = new Runnable[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[0] = () -> {
|
syncTasks[0] = () -> {
|
||||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
|
||||||
final CompoundTag nativeTag = entry.getValue();
|
final FaweCompoundTag nativeTag = entry.getValue();
|
||||||
final BlockVector3 blockHash = entry.getKey();
|
final BlockVector3 blockHash = entry.getKey();
|
||||||
final int x = blockHash.x() + bx;
|
final int x = blockHash.x() + bx;
|
||||||
final int y = blockHash.y();
|
final int y = blockHash.y();
|
||||||
final int z = blockHash.z() + bz;
|
final int z = blockHash.z() + bz;
|
||||||
final BlockPos pos = new BlockPos(x, y, z);
|
final BlockPos pos = new BlockPos(x, y, z);
|
||||||
|
|
||||||
synchronized (nmsWorld) {
|
synchronized (serverLevel) {
|
||||||
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
|
BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||||
nmsWorld.removeBlockEntity(pos);
|
serverLevel.removeBlockEntity(pos);
|
||||||
tileEntity = nmsWorld.getBlockEntity(pos);
|
tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
}
|
}
|
||||||
if (tileEntity != null) {
|
if (tileEntity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
|
||||||
nativeTag);
|
|
||||||
tag.put("x", IntTag.valueOf(x));
|
tag.put("x", IntTag.valueOf(x));
|
||||||
tag.put("y", IntTag.valueOf(y));
|
tag.put("y", IntTag.valueOf(y));
|
||||||
tag.put("z", IntTag.valueOf(z));
|
tag.put("z", IntTag.valueOf(z));
|
||||||
@ -822,7 +834,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
callback = null;
|
callback = null;
|
||||||
} else {
|
} else {
|
||||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||||
boolean finalLightUpdate = lightUpdate;
|
|
||||||
callback = () -> {
|
callback = () -> {
|
||||||
// Set Modified
|
// Set Modified
|
||||||
nmsChunk.setLightCorrect(true); // Set Modified
|
nmsChunk.setLightCorrect(true); // Set Modified
|
||||||
@ -927,7 +938,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void send() {
|
public void send() {
|
||||||
PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
import net.minecraft.world.level.biome.Biome;
|
||||||
@ -24,9 +25,11 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|||||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -38,8 +41,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
|
||||||
private final Set<CompoundTag> entities = new HashSet<>();
|
private final Set<FaweCompoundTag> entities = new HashSet<>();
|
||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
@ -56,44 +59,35 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
tiles.put(
|
tiles.put(
|
||||||
BlockVector3.at(
|
BlockVector3.at(
|
||||||
blockEntity.getBlockPos().getX(),
|
blockEntity.getBlockPos().getX(),
|
||||||
blockEntity.getBlockPos().getY(),
|
blockEntity.getBlockPos().getY(),
|
||||||
blockEntity.getBlockPos().getZ()
|
blockEntity.getBlockPos().getZ()
|
||||||
),
|
),
|
||||||
new PaperweightLazyCompoundTag(Suppliers.memoize(blockEntity::saveWithId))
|
FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(blockEntity.saveWithId()))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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) {
|
protected void storeEntity(Entity entity) {
|
||||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
||||||
entity.save(compoundTag);
|
entity.save(compoundTag);
|
||||||
entities.add((CompoundTag) adapter.toNative(compoundTag));
|
entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (FaweCompoundTag tag : entities) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -179,8 +173,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
biomes[layer] = new Holder[64];
|
biomes[layer] = new Holder[64];
|
||||||
}
|
}
|
||||||
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||||
for (int i = 0; i < 64; i++) {
|
if (PaperLib.isPaper()) {
|
||||||
biomes[layer][i] = palettedContainer.get(i);
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
@ -194,7 +198,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||||
return state.toBaseBlock(this, x, y, z);
|
return state.toBaseBlock((IBlocks) this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -224,6 +228,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return BlockTypesCache.states[get(x, y, z)];
|
return BlockTypesCache.states[get(x, y, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
|
return tiles.get(BlockVector3.at(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -7,8 +7,8 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.mojang.datafixers.util.Either;
|
import com.mojang.datafixers.util.Either;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
@ -123,6 +123,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
private static Field LEVEL_CHUNK_ENTITIES;
|
private static Field LEVEL_CHUNK_ENTITIES;
|
||||||
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
||||||
|
|
||||||
|
static final MethodHandle PALETTED_CONTAINER_GET;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
try {
|
try {
|
||||||
@ -212,6 +214,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
} catch (NoSuchFieldException ignored) {
|
} catch (NoSuchFieldException ignored) {
|
||||||
}
|
}
|
||||||
POST_CHUNK_REWRITE = chunkRewrite;
|
POST_CHUNK_REWRITE = chunkRewrite;
|
||||||
|
|
||||||
|
Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
|
||||||
|
Refraction.pickName("get", "a"),
|
||||||
|
int.class
|
||||||
|
);
|
||||||
|
palettedContaienrGet.setAccessible(true);
|
||||||
|
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
|
||||||
} catch (RuntimeException | Error e) {
|
} catch (RuntimeException | Error e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -234,15 +243,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean setSectionAtomic(
|
static boolean setSectionAtomic(
|
||||||
|
String worldName,
|
||||||
|
IntPair pair,
|
||||||
LevelChunkSection[] sections,
|
LevelChunkSection[] sections,
|
||||||
LevelChunkSection expected,
|
LevelChunkSection expected,
|
||||||
LevelChunkSection value,
|
LevelChunkSection value,
|
||||||
int layer
|
int layer
|
||||||
) {
|
) {
|
||||||
if (layer >= 0 && layer < sections.length) {
|
return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
|
||||||
return ReflectionUtils.compareAndSet(sections, expected, value, layer);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no point in having a functional semaphore for paper servers.
|
// There is no point in having a functional semaphore for paper servers.
|
||||||
@ -340,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
||||||
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||||
if (chunkHolder == null) {
|
if (chunkHolder == null) {
|
||||||
return;
|
return;
|
||||||
@ -361,26 +369,35 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
if (levelChunk == null) {
|
if (levelChunk == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
StampLockHolder lockHolder = new StampLockHolder();
|
||||||
|
NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
|
if (lockHolder.chunkLock == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
MinecraftServer.getServer().execute(() -> {
|
MinecraftServer.getServer().execute(() -> {
|
||||||
ClientboundLevelChunkWithLightPacket packet;
|
try {
|
||||||
if (PaperLib.isPaper()) {
|
ClientboundLevelChunkWithLightPacket packet;
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
if (PaperLib.isPaper()) {
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null,
|
null,
|
||||||
false // last false is to not bother with x-ray
|
null,
|
||||||
);
|
false // last false is to not bother with x-ray
|
||||||
} else {
|
);
|
||||||
// deprecated on paper - deprecation suppressed
|
} else {
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
// deprecated on paper - deprecation suppressed
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null
|
null,
|
||||||
);
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||||
|
} finally {
|
||||||
|
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
}
|
}
|
||||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -67,7 +68,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLeve
|
|||||||
int x = pos.x;
|
int x = pos.x;
|
||||||
int z = pos.z;
|
int z = pos.z;
|
||||||
if (delay) { // we still need to send the block changes of that chunk
|
if (delay) { // we still need to send the block changes of that chunk
|
||||||
PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
|
||||||
}
|
}
|
||||||
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
||||||
}
|
}
|
||||||
|
@ -4,166 +4,74 @@ import com.fastasyncworldedit.bukkit.adapter.Regenerator;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkCache;
|
import com.fastasyncworldedit.core.queue.IChunkCache;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.datafixers.util.Either;
|
|
||||||
import com.mojang.serialization.Lifecycle;
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R3.PaperweightGetBlocks;
|
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||||
import com.sk89q.worldedit.world.RegenOptions;
|
import com.sk89q.worldedit.world.RegenOptions;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
|
||||||
import net.minecraft.core.Holder;
|
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.resources.ResourceKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
|
||||||
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message;
|
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
import net.minecraft.util.ProgressListener;
|
||||||
import net.minecraft.util.thread.ProcessorMailbox;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
|
||||||
import net.minecraft.world.level.LevelSettings;
|
import net.minecraft.world.level.LevelSettings;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
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.ChunkStatus;
|
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||||
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.dimension.LevelStem;
|
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.NoiseBasedChunkGenerator;
|
||||||
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
|
|
||||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
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.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftServer;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
import org.bukkit.craftbukkit.v1_20_R3.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.v1_20_R3.generator.CustomChunkGenerator;
|
|
||||||
import org.bukkit.generator.BiomeProvider;
|
import org.bukkit.generator.BiomeProvider;
|
||||||
import org.bukkit.generator.BlockPopulator;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.OptionalLong;
|
import java.util.OptionalLong;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
|
public class PaperweightRegen extends Regenerator {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
|
||||||
|
|
||||||
private static final Field serverWorldsField;
|
private static final Field serverWorldsField;
|
||||||
private static final Field paperConfigField;
|
private static final Field paperConfigField;
|
||||||
private static final Field flatBedrockField;
|
|
||||||
private static final Field generatorSettingFlatField;
|
|
||||||
private static final Field generatorSettingBaseSupplierField;
|
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 {
|
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.FULL
|
|
||||||
); // structure refs: radius 8, but only writes to current chunk
|
|
||||||
chunkStati.put(ChunkStatus.BIOMES, Concurrency.FULL); // 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.LIQUID_CARVERS,
|
|
||||||
Concurrency.NONE
|
|
||||||
); // liquid carvers: radius 0, but RADIUS and FULL change results*/
|
|
||||||
chunkStati.put(ChunkStatus.FEATURES, Concurrency.NONE); // features: uses unsynchronized maps
|
|
||||||
chunkStati.put(
|
|
||||||
ChunkStatus.LIGHT,
|
|
||||||
Concurrency.FULL
|
|
||||||
); // light: radius 1, but no writes to other chunks, only current chunk
|
|
||||||
chunkStati.put(ChunkStatus.SPAWN, Concurrency.FULL); // spawn: radius 0
|
|
||||||
// chunkStati.put(ChunkStatus.HEIGHTMAPS, Concurrency.FULL); // heightmaps: radius 0
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||||
serverWorldsField.setAccessible(true);
|
serverWorldsField.setAccessible(true);
|
||||||
|
|
||||||
Field tmpPaperConfigField;
|
Field tmpPaperConfigField;
|
||||||
Field tmpFlatBedrockField;
|
|
||||||
try { //only present on paper
|
try { //only present on paper
|
||||||
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
||||||
tmpPaperConfigField.setAccessible(true);
|
tmpPaperConfigField.setAccessible(true);
|
||||||
|
|
||||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
|
||||||
tmpFlatBedrockField.setAccessible(true);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
tmpPaperConfigField = null;
|
tmpPaperConfigField = null;
|
||||||
tmpFlatBedrockField = null;
|
|
||||||
}
|
}
|
||||||
paperConfigField = tmpPaperConfigField;
|
paperConfigField = tmpPaperConfigField;
|
||||||
flatBedrockField = tmpFlatBedrockField;
|
|
||||||
|
|
||||||
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
||||||
"settings", "e"));
|
"settings", "e"));
|
||||||
generatorSettingBaseSupplierField.setAccessible(true);
|
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", "v"));
|
|
||||||
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) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -171,43 +79,37 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
//runtime
|
//runtime
|
||||||
private ServerLevel originalServerWorld;
|
private ServerLevel originalServerWorld;
|
||||||
private ServerChunkCache originalChunkProvider;
|
|
||||||
private ServerLevel freshWorld;
|
private ServerLevel freshWorld;
|
||||||
private ServerChunkCache freshChunkProvider;
|
|
||||||
private LevelStorageSource.LevelStorageAccess session;
|
private LevelStorageSource.LevelStorageAccess session;
|
||||||
private StructureTemplateManager structureTemplateManager;
|
|
||||||
private ThreadedLevelLightEngine threadedLevelLightEngine;
|
|
||||||
private ChunkGenerator chunkGenerator;
|
|
||||||
|
|
||||||
private Path tempDir;
|
private Path tempDir;
|
||||||
|
|
||||||
private boolean generateFlatBedrock = false;
|
public PaperweightRegen(
|
||||||
|
World originalBukkitWorld,
|
||||||
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
Region region,
|
||||||
|
Extent target,
|
||||||
|
RegenOptions options
|
||||||
|
) {
|
||||||
super(originalBukkitWorld, region, target, options);
|
super(originalBukkitWorld, region, target, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void runTasks(final BooleanSupplier shouldKeepTicking) {
|
||||||
|
while (shouldKeepTicking.getAsBoolean()) {
|
||||||
|
if (!this.freshWorld.getChunkSource().pollTask()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepare() {
|
protected boolean prepare() {
|
||||||
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
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());
|
seed = options.getSeed().orElse(originalServerWorld.getSeed());
|
||||||
chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected boolean initNewWorld() throws Exception {
|
protected boolean initNewWorld() throws Exception {
|
||||||
//world folder
|
//world folder
|
||||||
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
||||||
@ -253,8 +155,10 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
session,
|
session,
|
||||||
newWorldData,
|
newWorldData,
|
||||||
originalServerWorld.dimension(),
|
originalServerWorld.dimension(),
|
||||||
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
|
new LevelStem(
|
||||||
.getOrThrow(levelStemResourceKey),
|
originalServerWorld.dimensionTypeRegistration(),
|
||||||
|
originalServerWorld.getChunkSource().getGenerator()
|
||||||
|
),
|
||||||
new RegenNoOpWorldLoadListener(),
|
new RegenNoOpWorldLoadListener(),
|
||||||
originalServerWorld.isDebug(),
|
originalServerWorld.isDebug(),
|
||||||
seed,
|
seed,
|
||||||
@ -272,17 +176,30 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void tick(BooleanSupplier shouldKeepTicking) { //no ticking
|
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
|
||||||
if (options.hasBiomeType()) {
|
if (options.hasBiomeType()) {
|
||||||
return singleBiome;
|
return singleBiome;
|
||||||
}
|
}
|
||||||
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(
|
return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ);
|
||||||
biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler()
|
}
|
||||||
);
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@org.jetbrains.annotations.Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled
|
||||||
|
) {
|
||||||
|
// noop, spigot
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled,
|
||||||
|
final boolean close
|
||||||
|
) {
|
||||||
|
// noop, paper
|
||||||
}
|
}
|
||||||
}).get();
|
}).get();
|
||||||
freshWorld.noSave = true;
|
freshWorld.noSave = true;
|
||||||
@ -291,89 +208,6 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
if (paperConfigField != null) {
|
if (paperConfigField != null) {
|
||||||
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
|
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(
|
|
||||||
originalGenerator);
|
|
||||||
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, 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);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +222,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
try {
|
try {
|
||||||
Fawe.instance().getQueueHandler().sync(() -> {
|
Fawe.instance().getQueueHandler().sync(() -> {
|
||||||
try {
|
try {
|
||||||
freshChunkProvider.close(false);
|
freshWorld.getChunkSource().getDataStorage().cache.clear();
|
||||||
|
freshWorld.getChunkSource().close(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -409,63 +244,20 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||||
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
|
return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld()));
|
||||||
@Override
|
|
||||||
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
|
|
||||||
return getChunkAt(x, z);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//util
|
//util
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private void removeWorldFromWorldsMap() {
|
private void removeWorldFromWorldsMap() {
|
||||||
Fawe.instance().getQueueHandler().sync(() -> {
|
try {
|
||||||
try {
|
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
||||||
Map<String, org.bukkit.World> map = (Map<String, org.bukkit.World>) serverWorldsField.get(Bukkit.getServer());
|
map.remove("faweregentempworld");
|
||||||
map.remove("faweregentempworld");
|
} catch (IllegalAccessException e) {
|
||||||
} catch (IllegalAccessException e) {
|
throw new RuntimeException(e);
|
||||||
throw new RuntimeException(e);
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
|
private ResourceKey<LevelStem> getWorldDimKey(org.bukkit.World.Environment env) {
|
||||||
@ -482,11 +274,15 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateSpawnPos(ChunkPos spawnPos) {
|
public void updateSpawnPos(@NotNull ChunkPos spawnPos) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onStatusChange(ChunkPos pos, @Nullable ChunkStatus status) {
|
public void onStatusChange(
|
||||||
|
final @NotNull ChunkPos pos,
|
||||||
|
@org.jetbrains.annotations.Nullable final ChunkStatus status
|
||||||
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -504,87 +300,4 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
// compatibility with spigot
|
|
||||||
|
|
||||||
public boolean generateFlatBedrock() {
|
|
||||||
return generateFlatBedrock;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no one will ever see the entities!
|
|
||||||
@Override
|
|
||||||
public 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 chunkStatus.getRange();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name() {
|
|
||||||
return chunkStatus.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<?> processChunk(List<ChunkAccess> accessibleChunks) {
|
|
||||||
return chunkStatus.generate(
|
|
||||||
Runnable::run, // TODO revisit, we might profit from this somehow?
|
|
||||||
freshWorld,
|
|
||||||
chunkGenerator,
|
|
||||||
structureTemplateManager,
|
|
||||||
threadedLevelLightEngine,
|
|
||||||
c -> CompletableFuture.completedFuture(Either.left(c)),
|
|
||||||
accessibleChunks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 CompletableFuture<ChunkAccess> lightChunk(final ChunkAccess chunk, final boolean excludeBlocks) {
|
|
||||||
return CompletableFuture.completedFuture(chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/
|
// url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.20.6-R0.1-SNAPSHOT/
|
||||||
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.6-R0.1-20240702.153951-123")
|
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.20.6-R0.1-20240916.192025-125")
|
||||||
compileOnly(libs.paperlib)
|
compileOnly(libs.paperlib)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
import com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
@ -15,6 +12,8 @@ import net.minecraft.world.level.material.Fluids;
|
|||||||
import net.minecraft.world.level.material.PushReaction;
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class PaperweightBlockMaterial implements BlockMaterial {
|
public class PaperweightBlockMaterial implements BlockMaterial {
|
||||||
|
|
||||||
private final Block block;
|
private final Block block;
|
||||||
@ -22,7 +21,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
private final CraftBlockData craftBlockData;
|
private final CraftBlockData craftBlockData;
|
||||||
private final org.bukkit.Material craftMaterial;
|
private final org.bukkit.Material craftMaterial;
|
||||||
private final int opacity;
|
private final int opacity;
|
||||||
private final CompoundTag tile;
|
private final FaweCompoundTag tile;
|
||||||
|
|
||||||
public PaperweightBlockMaterial(Block block) {
|
public PaperweightBlockMaterial(Block block) {
|
||||||
this(block, block.defaultBlockState());
|
this(block, block.defaultBlockState());
|
||||||
@ -38,9 +37,9 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
BlockPos.ZERO,
|
BlockPos.ZERO,
|
||||||
blockState
|
blockState
|
||||||
);
|
);
|
||||||
tile = tileEntity == null ? null : new PaperweightLazyCompoundTag(
|
tile = tileEntity == null
|
||||||
Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
|
? null
|
||||||
);
|
: PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block getBlock() {
|
public Block getBlock() {
|
||||||
@ -126,9 +125,10 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
return blockState.isRandomlyTicking();
|
return blockState.isRandomlyTicking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public boolean isMovementBlocker() {
|
public boolean isMovementBlocker() {
|
||||||
return craftMaterial.isSolid();
|
return blockState.blocksMotion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,7 +163,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getDefaultTile() {
|
public @Nullable FaweCompoundTag defaultTile() {
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
@ -103,6 +104,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -138,6 +140,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.
|
|||||||
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter();
|
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_20_R4.PaperweightAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
|
||||||
|
return blockEntity -> FaweCompoundTag.of(
|
||||||
|
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getEntityId(Entity entity) {
|
private static String getEntityId(Entity entity) {
|
||||||
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
||||||
|
@ -7,20 +7,17 @@ import com.fastasyncworldedit.core.FaweCache;
|
|||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||||
import com.google.common.base.Suppliers;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.jnbt.ListTag;
|
|
||||||
import com.sk89q.jnbt.StringTag;
|
|
||||||
import com.sk89q.jnbt.Tag;
|
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
@ -34,6 +31,7 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.IdMap;
|
import net.minecraft.core.IdMap;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.IntTag;
|
import net.minecraft.nbt.IntTag;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -62,11 +60,19 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.block.CraftBlock;
|
import org.bukkit.craftbukkit.block.CraftBlock;
|
||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
import org.enginehub.linbus.tree.LinDoubleTag;
|
||||||
|
import org.enginehub.linbus.tree.LinFloatTag;
|
||||||
|
import org.enginehub.linbus.tree.LinListTag;
|
||||||
|
import org.enginehub.linbus.tree.LinStringTag;
|
||||||
|
import org.enginehub.linbus.tree.LinTagType;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.AbstractSet;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.AbstractCollection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -83,7 +89,6 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
@ -92,9 +97,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||||
private static final Function<BlockEntity, CompoundTag> nmsTile2We = tileEntity -> new PaperweightLazyCompoundTag(
|
public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
|
.getInstance()
|
||||||
);
|
.getBukkitImplAdapter()).blockEntityToCompoundTag();
|
||||||
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
@ -103,6 +108,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
|
private final IntPair chunkPos;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final int minSectionPosition;
|
private final int minSectionPosition;
|
||||||
@ -137,6 +143,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.blockLight = new DataLayer[getSectionCount()];
|
this.blockLight = new DataLayer[getSectionCount()];
|
||||||
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
||||||
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
|
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
public int getChunkX() {
|
||||||
@ -258,23 +265,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getTile(int x, int y, int z) {
|
public FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
||||||
chunkX << 4), y, (z & 15) + (
|
chunkX << 4), y, (z & 15) + (
|
||||||
chunkZ << 4)));
|
chunkZ << 4)));
|
||||||
if (blockEntity == null) {
|
if (blockEntity == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())));
|
return NMS_TO_TILE.apply(blockEntity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
||||||
if (nmsTiles.isEmpty()) {
|
if (nmsTiles.isEmpty()) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -337,7 +345,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
Entity entity = null;
|
Entity entity = null;
|
||||||
@ -349,10 +357,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
|
||||||
}
|
}
|
||||||
for (CompoundTag tag : getEntities()) {
|
for (FaweCompoundTag tag : entities()) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,14 +368,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
int size = entities.size();
|
int size = entities.size();
|
||||||
return new AbstractSet<>() {
|
return new AbstractCollection<>() {
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return size;
|
return size;
|
||||||
@ -380,10 +388,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Object get) {
|
public boolean contains(Object get) {
|
||||||
if (!(get instanceof CompoundTag getTag)) {
|
if (!(get instanceof FaweCompoundTag getTag)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
UUID getUUID = getTag.getUUID();
|
UUID getUUID = NbtUtils.uuid(getTag);
|
||||||
for (Entity entity : entities) {
|
for (Entity entity : entities) {
|
||||||
UUID uuid = entity.getUUID();
|
UUID uuid = entity.getUUID();
|
||||||
if (uuid.equals(getUUID)) {
|
if (uuid.equals(getUUID)) {
|
||||||
@ -395,12 +403,12 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Iterator<CompoundTag> iterator() {
|
public Iterator<FaweCompoundTag> iterator() {
|
||||||
Iterable<CompoundTag> result = entities.stream().map(input -> {
|
Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
|
||||||
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
|
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
|
||||||
input.save(tag);
|
input.save(tag);
|
||||||
return (CompoundTag) adapter.toNative(tag);
|
return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
|
||||||
}).collect(Collectors.toList());
|
})::iterator;
|
||||||
return result.iterator();
|
return result.iterator();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -421,7 +429,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||||
}
|
}
|
||||||
forceLoadSections = false;
|
forceLoadSections = false;
|
||||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
|
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
|
||||||
if (createCopy) {
|
if (createCopy) {
|
||||||
if (copies.containsKey(copyKey)) {
|
if (copies.containsKey(copyKey)) {
|
||||||
throw new IllegalStateException("Copy key already used.");
|
throw new IllegalStateException("Copy key already used.");
|
||||||
@ -429,9 +438,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
copies.put(copyKey, copy);
|
copies.put(copyKey, copy);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
|
||||||
|
|
||||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||||
List<BlockEntity> beacons = null;
|
List<BlockEntity> beacons = null;
|
||||||
@ -503,6 +509,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -580,6 +588,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -644,7 +654,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||||
);
|
);
|
||||||
if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection,
|
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
|
levelChunkSections,
|
||||||
|
existingSection,
|
||||||
newSection,
|
newSection,
|
||||||
getSectionIndex
|
getSectionIndex
|
||||||
)) {
|
)) {
|
||||||
@ -716,7 +730,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
||||||
for (UUID uuid : entityRemoves) {
|
for (UUID uuid : entityRemoves) {
|
||||||
Entity entity = nmsWorld.getEntities().get(uuid);
|
Entity entity = serverLevel.getEntities().get(uuid);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
removeEntity(entity);
|
removeEntity(entity);
|
||||||
}
|
}
|
||||||
@ -728,48 +742,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<CompoundTag> entities = set.getEntities();
|
Collection<FaweCompoundTag> entities = set.entities();
|
||||||
if (entities != null && !entities.isEmpty()) {
|
if (entities != null && !entities.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[2];
|
syncTasks = new Runnable[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[1] = () -> {
|
syncTasks[1] = () -> {
|
||||||
Iterator<CompoundTag> iterator = entities.iterator();
|
Iterator<FaweCompoundTag> iterator = entities.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
final CompoundTag nativeTag = iterator.next();
|
final FaweCompoundTag nativeTag = iterator.next();
|
||||||
final Map<String, Tag<?, ?>> entityTagMap = nativeTag.getValue();
|
final LinCompoundTag linTag = nativeTag.linTag();
|
||||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
|
||||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
|
||||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
|
||||||
if (idTag == null || posTag == null || rotTag == null) {
|
if (idTag == null || posTag == null || rotTag == null) {
|
||||||
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final double x = posTag.getDouble(0);
|
final double x = posTag.get(0).valueAsDouble();
|
||||||
final double y = posTag.getDouble(1);
|
final double y = posTag.get(1).valueAsDouble();
|
||||||
final double z = posTag.getDouble(2);
|
final double z = posTag.get(2).valueAsDouble();
|
||||||
final float yaw = rotTag.getFloat(0);
|
final float yaw = rotTag.get(0).valueAsFloat();
|
||||||
final float pitch = rotTag.getFloat(1);
|
final float pitch = rotTag.get(1).valueAsFloat();
|
||||||
final String id = idTag.getValue();
|
final String id = idTag.value();
|
||||||
|
|
||||||
EntityType<?> type = EntityType.byString(id).orElse(null);
|
EntityType<?> type = EntityType.byString(id).orElse(null);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
Entity entity = type.create(nmsWorld);
|
Entity entity = type.create(serverLevel);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNativeLin(linTag);
|
||||||
nativeTag);
|
|
||||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
tag.remove(name);
|
tag.remove(name);
|
||||||
}
|
}
|
||||||
entity.load(tag);
|
entity.load(tag);
|
||||||
entity.absMoveTo(x, y, z, yaw, pitch);
|
entity.absMoveTo(x, y, z, yaw, pitch);
|
||||||
entity.setUUID(nativeTag.getUUID());
|
entity.setUUID(NbtUtils.uuid(nativeTag));
|
||||||
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
||||||
LOGGER.warn(
|
LOGGER.warn(
|
||||||
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
||||||
id,
|
id,
|
||||||
nmsWorld.getWorld().getName(),
|
serverLevel.getWorld().getName(),
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
z
|
z
|
||||||
@ -784,30 +797,29 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set tiles
|
// set tiles
|
||||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
|
||||||
if (tiles != null && !tiles.isEmpty()) {
|
if (tiles != null && !tiles.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[1];
|
syncTasks = new Runnable[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[0] = () -> {
|
syncTasks[0] = () -> {
|
||||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
|
||||||
final CompoundTag nativeTag = entry.getValue();
|
final FaweCompoundTag nativeTag = entry.getValue();
|
||||||
final BlockVector3 blockHash = entry.getKey();
|
final BlockVector3 blockHash = entry.getKey();
|
||||||
final int x = blockHash.x() + bx;
|
final int x = blockHash.x() + bx;
|
||||||
final int y = blockHash.y();
|
final int y = blockHash.y();
|
||||||
final int z = blockHash.z() + bz;
|
final int z = blockHash.z() + bz;
|
||||||
final BlockPos pos = new BlockPos(x, y, z);
|
final BlockPos pos = new BlockPos(x, y, z);
|
||||||
|
|
||||||
synchronized (nmsWorld) {
|
synchronized (serverLevel) {
|
||||||
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
|
BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||||
nmsWorld.removeBlockEntity(pos);
|
serverLevel.removeBlockEntity(pos);
|
||||||
tileEntity = nmsWorld.getBlockEntity(pos);
|
tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
}
|
}
|
||||||
if (tileEntity != null) {
|
if (tileEntity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final net.minecraft.nbt.CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
|
||||||
nativeTag);
|
|
||||||
tag.put("x", IntTag.valueOf(x));
|
tag.put("x", IntTag.valueOf(x));
|
||||||
tag.put("y", IntTag.valueOf(y));
|
tag.put("y", IntTag.valueOf(y));
|
||||||
tag.put("z", IntTag.valueOf(z));
|
tag.put("z", IntTag.valueOf(z));
|
||||||
@ -823,7 +835,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
callback = null;
|
callback = null;
|
||||||
} else {
|
} else {
|
||||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||||
boolean finalLightUpdate = lightUpdate;
|
|
||||||
callback = () -> {
|
callback = () -> {
|
||||||
// Set Modified
|
// Set Modified
|
||||||
nmsChunk.setLightCorrect(true); // Set Modified
|
nmsChunk.setLightCorrect(true); // Set Modified
|
||||||
@ -929,7 +940,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
public void send() {
|
public void send() {
|
||||||
synchronized (sendLock) {
|
synchronized (sendLock) {
|
||||||
PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
@ -25,9 +26,11 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|||||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -39,8 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
|
||||||
private final Set<CompoundTag> entities = new HashSet<>();
|
private final Set<FaweCompoundTag> entities = new HashSet<>();
|
||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
@ -57,44 +60,37 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
tiles.put(
|
tiles.put(
|
||||||
BlockVector3.at(
|
BlockVector3.at(
|
||||||
blockEntity.getBlockPos().getX(),
|
blockEntity.getBlockPos().getX(),
|
||||||
blockEntity.getBlockPos().getY(),
|
blockEntity.getBlockPos().getY(),
|
||||||
blockEntity.getBlockPos().getZ()
|
blockEntity.getBlockPos().getZ()
|
||||||
),
|
),
|
||||||
new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())))
|
FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(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) {
|
protected void storeEntity(Entity entity) {
|
||||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
||||||
entity.save(compoundTag);
|
entity.save(compoundTag);
|
||||||
entities.add((CompoundTag) adapter.toNative(compoundTag));
|
entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (FaweCompoundTag tag : entities) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,8 +176,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
biomes[layer] = new Holder[64];
|
biomes[layer] = new Holder[64];
|
||||||
}
|
}
|
||||||
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||||
for (int i = 0; i < 64; i++) {
|
if (PaperLib.isPaper()) {
|
||||||
biomes[layer][i] = palettedContainer.get(i);
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
@ -195,7 +201,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||||
return state.toBaseBlock(this, x, y, z);
|
return state.toBaseBlock((IBlocks) this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -225,6 +231,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return BlockTypesCache.states[get(x, y, z)];
|
return BlockTypesCache.states[get(x, y, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
|
return tiles.get(BlockVector3.at(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -7,9 +7,10 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
@ -76,6 +77,7 @@ import java.util.Iterator;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -121,6 +123,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
private static Field LEVEL_CHUNK_ENTITIES;
|
private static Field LEVEL_CHUNK_ENTITIES;
|
||||||
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
||||||
|
|
||||||
|
static final MethodHandle PALETTED_CONTAINER_GET;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
try {
|
try {
|
||||||
@ -210,6 +214,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
} catch (NoSuchFieldException ignored) {
|
} catch (NoSuchFieldException ignored) {
|
||||||
}
|
}
|
||||||
POST_CHUNK_REWRITE = chunkRewrite;
|
POST_CHUNK_REWRITE = chunkRewrite;
|
||||||
|
|
||||||
|
Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
|
||||||
|
Refraction.pickName("get", "a"),
|
||||||
|
int.class
|
||||||
|
);
|
||||||
|
palettedContaienrGet.setAccessible(true);
|
||||||
|
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
|
||||||
} catch (RuntimeException | Error e) {
|
} catch (RuntimeException | Error e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -232,15 +243,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean setSectionAtomic(
|
static boolean setSectionAtomic(
|
||||||
|
String worldName,
|
||||||
|
IntPair pair,
|
||||||
LevelChunkSection[] sections,
|
LevelChunkSection[] sections,
|
||||||
LevelChunkSection expected,
|
LevelChunkSection expected,
|
||||||
LevelChunkSection value,
|
LevelChunkSection value,
|
||||||
int layer
|
int layer
|
||||||
) {
|
) {
|
||||||
if (layer >= 0 && layer < sections.length) {
|
return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
|
||||||
return ReflectionUtils.compareAndSet(sections, expected, value, layer);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no point in having a functional semaphore for paper servers.
|
// There is no point in having a functional semaphore for paper servers.
|
||||||
@ -338,7 +348,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
||||||
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||||
if (chunkHolder == null) {
|
if (chunkHolder == null) {
|
||||||
return;
|
return;
|
||||||
@ -347,36 +357,42 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
LevelChunk levelChunk;
|
LevelChunk levelChunk;
|
||||||
if (PaperLib.isPaper()) {
|
if (PaperLib.isPaper()) {
|
||||||
// getChunkAtIfLoadedImmediately is paper only
|
// getChunkAtIfLoadedImmediately is paper only
|
||||||
levelChunk = nmsWorld
|
levelChunk = nmsWorld.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
|
||||||
.getChunkSource()
|
|
||||||
.getChunkAtIfLoadedImmediately(chunkX, chunkZ);
|
|
||||||
} else {
|
} else {
|
||||||
levelChunk = chunkHolder.getTickingChunkFuture()
|
levelChunk = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null);
|
||||||
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null);
|
|
||||||
}
|
}
|
||||||
if (levelChunk == null) {
|
if (levelChunk == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
StampLockHolder lockHolder = new StampLockHolder();
|
||||||
|
NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
|
if (lockHolder.chunkLock == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
MinecraftServer.getServer().execute(() -> {
|
MinecraftServer.getServer().execute(() -> {
|
||||||
ClientboundLevelChunkWithLightPacket packet;
|
try {
|
||||||
if (PaperLib.isPaper()) {
|
ClientboundLevelChunkWithLightPacket packet;
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
if (PaperLib.isPaper()) {
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null,
|
null,
|
||||||
false // last false is to not bother with x-ray
|
null,
|
||||||
);
|
false // last false is to not bother with x-ray
|
||||||
} else {
|
);
|
||||||
// deprecated on paper - deprecation suppressed
|
} else {
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
// deprecated on paper - deprecation suppressed
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null
|
null,
|
||||||
);
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||||
|
} finally {
|
||||||
|
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
}
|
}
|
||||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -67,7 +68,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLeve
|
|||||||
int x = pos.x;
|
int x = pos.x;
|
||||||
int z = pos.z;
|
int z = pos.z;
|
||||||
if (delay) { // we still need to send the block changes of that chunk
|
if (delay) { // we still need to send the block changes of that chunk
|
||||||
PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
|
||||||
}
|
}
|
||||||
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
||||||
}
|
}
|
||||||
|
@ -4,166 +4,73 @@ import com.fastasyncworldedit.bukkit.adapter.Regenerator;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkCache;
|
import com.fastasyncworldedit.core.queue.IChunkCache;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.serialization.Lifecycle;
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_20_R4.PaperweightGetBlocks;
|
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||||
import com.sk89q.worldedit.world.RegenOptions;
|
import com.sk89q.worldedit.world.RegenOptions;
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
|
||||||
import net.minecraft.core.Holder;
|
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.resources.ResourceKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
|
||||||
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter.Message;
|
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
import net.minecraft.util.ProgressListener;
|
||||||
import net.minecraft.util.thread.ProcessorMailbox;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
|
||||||
import net.minecraft.world.level.LevelSettings;
|
import net.minecraft.world.level.LevelSettings;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
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.ChunkStatus;
|
|
||||||
import net.minecraft.world.level.chunk.status.WorldGenContext;
|
|
||||||
import net.minecraft.world.level.dimension.LevelStem;
|
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.NoiseBasedChunkGenerator;
|
||||||
import net.minecraft.world.level.levelgen.NoiseGeneratorSettings;
|
|
||||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
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.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.CraftServer;
|
import org.bukkit.craftbukkit.CraftServer;
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
|
||||||
import org.bukkit.generator.BiomeProvider;
|
import org.bukkit.generator.BiomeProvider;
|
||||||
import org.bukkit.generator.BlockPopulator;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.OptionalLong;
|
import java.util.OptionalLong;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
|
public class PaperweightRegen extends Regenerator {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
|
||||||
|
|
||||||
private static final Field serverWorldsField;
|
private static final Field serverWorldsField;
|
||||||
private static final Field paperConfigField;
|
private static final Field paperConfigField;
|
||||||
private static final Field flatBedrockField;
|
|
||||||
private static final Field generatorSettingFlatField;
|
|
||||||
private static final Field generatorSettingBaseSupplierField;
|
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 {
|
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 {
|
try {
|
||||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||||
serverWorldsField.setAccessible(true);
|
serverWorldsField.setAccessible(true);
|
||||||
|
|
||||||
Field tmpPaperConfigField;
|
Field tmpPaperConfigField;
|
||||||
Field tmpFlatBedrockField;
|
|
||||||
try { //only present on paper
|
try { //only present on paper
|
||||||
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
||||||
tmpPaperConfigField.setAccessible(true);
|
tmpPaperConfigField.setAccessible(true);
|
||||||
|
|
||||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
|
||||||
tmpFlatBedrockField.setAccessible(true);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
tmpPaperConfigField = null;
|
tmpPaperConfigField = null;
|
||||||
tmpFlatBedrockField = null;
|
|
||||||
}
|
}
|
||||||
paperConfigField = tmpPaperConfigField;
|
paperConfigField = tmpPaperConfigField;
|
||||||
flatBedrockField = tmpFlatBedrockField;
|
|
||||||
|
|
||||||
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
||||||
"settings", "e"));
|
"settings", "e"));
|
||||||
generatorSettingBaseSupplierField.setAccessible(true);
|
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", "v"));
|
|
||||||
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) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -171,44 +78,37 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
//runtime
|
//runtime
|
||||||
private ServerLevel originalServerWorld;
|
private ServerLevel originalServerWorld;
|
||||||
private ServerChunkCache originalChunkProvider;
|
|
||||||
private ServerLevel freshWorld;
|
private ServerLevel freshWorld;
|
||||||
private ServerChunkCache freshChunkProvider;
|
|
||||||
private LevelStorageSource.LevelStorageAccess session;
|
private LevelStorageSource.LevelStorageAccess session;
|
||||||
private StructureTemplateManager structureTemplateManager;
|
|
||||||
private ThreadedLevelLightEngine threadedLevelLightEngine;
|
|
||||||
private ChunkGenerator chunkGenerator;
|
|
||||||
private WorldGenContext worldGenContext;
|
|
||||||
|
|
||||||
private Path tempDir;
|
private Path tempDir;
|
||||||
|
|
||||||
private boolean generateFlatBedrock = false;
|
public PaperweightRegen(
|
||||||
|
World originalBukkitWorld,
|
||||||
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
Region region,
|
||||||
|
Extent target,
|
||||||
|
RegenOptions options
|
||||||
|
) {
|
||||||
super(originalBukkitWorld, region, target, options);
|
super(originalBukkitWorld, region, target, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void runTasks(final BooleanSupplier shouldKeepTicking) {
|
||||||
|
while (shouldKeepTicking.getAsBoolean()) {
|
||||||
|
if (!this.freshWorld.getChunkSource().pollTask()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepare() {
|
protected boolean prepare() {
|
||||||
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
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());
|
seed = options.getSeed().orElse(originalServerWorld.getSeed());
|
||||||
chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected boolean initNewWorld() throws Exception {
|
protected boolean initNewWorld() throws Exception {
|
||||||
//world folder
|
//world folder
|
||||||
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
||||||
@ -254,8 +154,10 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
session,
|
session,
|
||||||
newWorldData,
|
newWorldData,
|
||||||
originalServerWorld.dimension(),
|
originalServerWorld.dimension(),
|
||||||
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
|
new LevelStem(
|
||||||
.getOrThrow(levelStemResourceKey),
|
originalServerWorld.dimensionTypeRegistration(),
|
||||||
|
originalServerWorld.getChunkSource().getGenerator()
|
||||||
|
),
|
||||||
new RegenNoOpWorldLoadListener(),
|
new RegenNoOpWorldLoadListener(),
|
||||||
originalServerWorld.isDebug(),
|
originalServerWorld.isDebug(),
|
||||||
seed,
|
seed,
|
||||||
@ -272,20 +174,32 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
|
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick(@NotNull BooleanSupplier shouldKeepTicking) { //no ticking
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
||||||
if (options.hasBiomeType()) {
|
if (options.hasBiomeType()) {
|
||||||
return singleBiome;
|
return singleBiome;
|
||||||
}
|
}
|
||||||
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(
|
return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ);
|
||||||
biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@org.jetbrains.annotations.Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled
|
||||||
|
) {
|
||||||
|
// noop, spigot
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled,
|
||||||
|
final boolean close
|
||||||
|
) {
|
||||||
|
// noop, paper
|
||||||
|
}
|
||||||
}).get();
|
}).get();
|
||||||
freshWorld.noSave = true;
|
freshWorld.noSave = true;
|
||||||
removeWorldFromWorldsMap();
|
removeWorldFromWorldsMap();
|
||||||
@ -293,93 +207,6 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
if (paperConfigField != null) {
|
if (paperConfigField != null) {
|
||||||
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
|
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
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,7 +221,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
try {
|
try {
|
||||||
Fawe.instance().getQueueHandler().sync(() -> {
|
Fawe.instance().getQueueHandler().sync(() -> {
|
||||||
try {
|
try {
|
||||||
freshChunkProvider.close(false);
|
freshWorld.getChunkSource().getDataStorage().cache.clear();
|
||||||
|
freshWorld.getChunkSource().close(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -415,50 +243,9 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||||
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
|
return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld()));
|
||||||
@Override
|
|
||||||
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
|
|
||||||
return getChunkAt(x, z);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//util
|
//util
|
||||||
@ -512,83 +299,4 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 chunkStatus.getRange();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String name() {
|
|
||||||
return chunkStatus.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public CompletableFuture<?> processChunk(List<ChunkAccess> accessibleChunks) {
|
|
||||||
return chunkStatus.generate(
|
|
||||||
worldGenContext,
|
|
||||||
Runnable::run,
|
|
||||||
CompletableFuture::completedFuture,
|
|
||||||
accessibleChunks
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,6 @@ repositories {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
// url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/
|
// url=https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/1.21.1-R0.1-SNAPSHOT/
|
||||||
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.21.1-R0.1-20240811.223934-9")
|
the<PaperweightUserDependenciesExtension>().paperDevBundle("1.21.1-R0.1-20241012.212042-119")
|
||||||
compileOnly(libs.paperlib)
|
compileOnly(libs.paperlib)
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
|
||||||
|
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
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 com.sk89q.worldedit.world.registry.BlockMaterial;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.EntityBlock;
|
import net.minecraft.world.level.block.EntityBlock;
|
||||||
@ -15,6 +12,8 @@ import net.minecraft.world.level.material.Fluids;
|
|||||||
import net.minecraft.world.level.material.PushReaction;
|
import net.minecraft.world.level.material.PushReaction;
|
||||||
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
import org.bukkit.craftbukkit.block.data.CraftBlockData;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class PaperweightBlockMaterial implements BlockMaterial {
|
public class PaperweightBlockMaterial implements BlockMaterial {
|
||||||
|
|
||||||
private final Block block;
|
private final Block block;
|
||||||
@ -22,7 +21,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
private final CraftBlockData craftBlockData;
|
private final CraftBlockData craftBlockData;
|
||||||
private final org.bukkit.Material craftMaterial;
|
private final org.bukkit.Material craftMaterial;
|
||||||
private final int opacity;
|
private final int opacity;
|
||||||
private final CompoundTag tile;
|
private final FaweCompoundTag tile;
|
||||||
|
|
||||||
public PaperweightBlockMaterial(Block block) {
|
public PaperweightBlockMaterial(Block block) {
|
||||||
this(block, block.defaultBlockState());
|
this(block, block.defaultBlockState());
|
||||||
@ -38,9 +37,9 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
BlockPos.ZERO,
|
BlockPos.ZERO,
|
||||||
blockState
|
blockState
|
||||||
);
|
);
|
||||||
tile = tileEntity == null ? null : new PaperweightLazyCompoundTag(
|
tile = tileEntity == null
|
||||||
Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
|
? null
|
||||||
);
|
: PaperweightGetBlocks.NMS_TO_TILE.apply(tileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Block getBlock() {
|
public Block getBlock() {
|
||||||
@ -126,9 +125,10 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
return blockState.isRandomlyTicking();
|
return blockState.isRandomlyTicking();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public boolean isMovementBlocker() {
|
public boolean isMovementBlocker() {
|
||||||
return craftMaterial.isSolid();
|
return blockState.blocksMotion();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,7 +163,7 @@ public class PaperweightBlockMaterial implements BlockMaterial {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getDefaultTile() {
|
public @Nullable FaweCompoundTag defaultTile() {
|
||||||
return tile;
|
return tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
import com.fastasyncworldedit.core.entity.LazyBaseEntity;
|
||||||
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
@ -18,6 +19,7 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
|
|||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
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.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.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
import com.sk89q.worldedit.internal.block.BlockStateIdAccess;
|
||||||
@ -102,6 +104,7 @@ import java.util.Map;
|
|||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.OptionalInt;
|
import java.util.OptionalInt;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
@ -137,6 +140,12 @@ public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.
|
|||||||
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter();
|
this.parent = new com.sk89q.worldedit.bukkit.adapter.ext.fawe.v1_21_R1.PaperweightAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Function<BlockEntity, FaweCompoundTag> blockEntityToCompoundTag() {
|
||||||
|
return blockEntity -> FaweCompoundTag.of(
|
||||||
|
() -> (LinCompoundTag) toNativeLin(blockEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static String getEntityId(Entity entity) {
|
private static String getEntityId(Entity entity) {
|
||||||
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
ResourceLocation resourceLocation = net.minecraft.world.entity.EntityType.getKey(entity.getType());
|
||||||
@ -557,7 +566,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter<net.minecraft.nbt.
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
public boolean regenerate(org.bukkit.World bukkitWorld, Region region, Extent target, RegenOptions options) throws Exception {
|
||||||
throw new UnsupportedOperationException("Regen support for 1.21 not yet implemented.");
|
return new PaperweightRegen(bukkitWorld, region, target, options).regenerate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -7,20 +7,17 @@ import com.fastasyncworldedit.core.FaweCache;
|
|||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
import com.fastasyncworldedit.core.queue.implementation.QueueHandler;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
import com.fastasyncworldedit.core.queue.implementation.blocks.CharGetBlocks;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
import com.fastasyncworldedit.core.util.collection.AdaptedMap;
|
||||||
import com.google.common.base.Suppliers;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.jnbt.ListTag;
|
|
||||||
import com.sk89q.jnbt.StringTag;
|
|
||||||
import com.sk89q.jnbt.Tag;
|
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.nbt.PaperweightLazyCompoundTag;
|
|
||||||
import com.sk89q.worldedit.internal.Constants;
|
import com.sk89q.worldedit.internal.Constants;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
@ -34,6 +31,7 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.IdMap;
|
import net.minecraft.core.IdMap;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.IntTag;
|
import net.minecraft.nbt.IntTag;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -62,11 +60,19 @@ import org.bukkit.World;
|
|||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.block.CraftBlock;
|
import org.bukkit.craftbukkit.block.CraftBlock;
|
||||||
import org.bukkit.event.entity.CreatureSpawnEvent;
|
import org.bukkit.event.entity.CreatureSpawnEvent;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
import org.enginehub.linbus.tree.LinDoubleTag;
|
||||||
|
import org.enginehub.linbus.tree.LinFloatTag;
|
||||||
|
import org.enginehub.linbus.tree.LinListTag;
|
||||||
|
import org.enginehub.linbus.tree.LinStringTag;
|
||||||
|
import org.enginehub.linbus.tree.LinTagType;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.AbstractSet;
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.AbstractCollection;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
@ -83,7 +89,6 @@ import java.util.concurrent.locks.ReadWriteLock;
|
|||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
@ -92,9 +97,9 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
private static final Function<BlockPos, BlockVector3> posNms2We = v -> BlockVector3.at(v.getX(), v.getY(), v.getZ());
|
||||||
private static final Function<BlockEntity, CompoundTag> nmsTile2We = tileEntity -> new PaperweightLazyCompoundTag(
|
public static final Function<BlockEntity, FaweCompoundTag> NMS_TO_TILE = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
Suppliers.memoize(() -> tileEntity.saveWithId(DedicatedServer.getServer().registryAccess()))
|
.getInstance()
|
||||||
);
|
.getBukkitImplAdapter()).blockEntityToCompoundTag();
|
||||||
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
private final PaperweightFaweAdapter adapter = ((PaperweightFaweAdapter) WorldEditPlugin
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.getBukkitImplAdapter());
|
.getBukkitImplAdapter());
|
||||||
@ -103,6 +108,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
private final ServerLevel serverLevel;
|
private final ServerLevel serverLevel;
|
||||||
private final int chunkX;
|
private final int chunkX;
|
||||||
private final int chunkZ;
|
private final int chunkZ;
|
||||||
|
private final IntPair chunkPos;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
private final int minSectionPosition;
|
private final int minSectionPosition;
|
||||||
@ -137,6 +143,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
this.blockLight = new DataLayer[getSectionCount()];
|
this.blockLight = new DataLayer[getSectionCount()];
|
||||||
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
this.biomeRegistry = serverLevel.registryAccess().registryOrThrow(BIOME);
|
||||||
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
this.biomeHolderIdMap = biomeRegistry.asHolderIdMap();
|
||||||
|
this.chunkPos = new IntPair(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getChunkX() {
|
public int getChunkX() {
|
||||||
@ -258,23 +265,24 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getTile(int x, int y, int z) {
|
public FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
BlockEntity blockEntity = getChunk().getBlockEntity(new BlockPos((x & 15) + (
|
||||||
chunkX << 4), y, (z & 15) + (
|
chunkX << 4), y, (z & 15) + (
|
||||||
chunkZ << 4)));
|
chunkZ << 4)));
|
||||||
if (blockEntity == null) {
|
if (blockEntity == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())));
|
return NMS_TO_TILE.apply(blockEntity);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Map<BlockVector3, CompoundTag> getTiles() {
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
Map<BlockPos, BlockEntity> nmsTiles = getChunk().getBlockEntities();
|
||||||
if (nmsTiles.isEmpty()) {
|
if (nmsTiles.isEmpty()) {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
return AdaptedMap.immutable(nmsTiles, posNms2We, nmsTile2We);
|
return AdaptedMap.immutable(nmsTiles, posNms2We, NMS_TO_TILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -337,7 +345,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
Entity entity = null;
|
Entity entity = null;
|
||||||
@ -349,10 +357,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
org.bukkit.entity.Entity bukkitEnt = entity.getBukkitEntity();
|
||||||
return BukkitAdapter.adapt(bukkitEnt).getState().getNbtData();
|
return FaweCompoundTag.of(BukkitAdapter.adapt(bukkitEnt).getState().getNbt());
|
||||||
}
|
}
|
||||||
for (CompoundTag tag : getEntities()) {
|
for (FaweCompoundTag tag : entities()) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -360,14 +368,14 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
ensureLoaded(serverLevel, chunkX, chunkZ);
|
ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
List<Entity> entities = PaperweightPlatformAdapter.getEntities(getChunk());
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
return Collections.emptySet();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
int size = entities.size();
|
int size = entities.size();
|
||||||
return new AbstractSet<>() {
|
return new AbstractCollection<>() {
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
return size;
|
return size;
|
||||||
@ -380,10 +388,10 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean contains(Object get) {
|
public boolean contains(Object get) {
|
||||||
if (!(get instanceof CompoundTag getTag)) {
|
if (!(get instanceof FaweCompoundTag getTag)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
UUID getUUID = getTag.getUUID();
|
UUID getUUID = NbtUtils.uuid(getTag);
|
||||||
for (Entity entity : entities) {
|
for (Entity entity : entities) {
|
||||||
UUID uuid = entity.getUUID();
|
UUID uuid = entity.getUUID();
|
||||||
if (uuid.equals(getUUID)) {
|
if (uuid.equals(getUUID)) {
|
||||||
@ -395,15 +403,16 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
|
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public Iterator<CompoundTag> iterator() {
|
public Iterator<FaweCompoundTag> iterator() {
|
||||||
Iterable<CompoundTag> result = entities.stream().map(input -> {
|
Iterable<FaweCompoundTag> result = entities.stream().map(input -> {
|
||||||
net.minecraft.nbt.CompoundTag tag = new net.minecraft.nbt.CompoundTag();
|
CompoundTag tag = new CompoundTag();
|
||||||
input.save(tag);
|
input.save(tag);
|
||||||
return (CompoundTag) adapter.toNative(tag);
|
return FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(tag));
|
||||||
}).collect(Collectors.toList());
|
})::iterator;
|
||||||
return result.iterator();
|
return result.iterator();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeEntity(Entity entity) {
|
private void removeEntity(Entity entity) {
|
||||||
@ -421,7 +430,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
throw new IllegalStateException("Attempted to call chunk GET but chunk was not call-locked.");
|
||||||
}
|
}
|
||||||
forceLoadSections = false;
|
forceLoadSections = false;
|
||||||
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(levelChunk) : null;
|
LevelChunk nmsChunk = ensureLoaded(serverLevel, chunkX, chunkZ);
|
||||||
|
PaperweightGetBlocks_Copy copy = createCopy ? new PaperweightGetBlocks_Copy(nmsChunk) : null;
|
||||||
if (createCopy) {
|
if (createCopy) {
|
||||||
if (copies.containsKey(copyKey)) {
|
if (copies.containsKey(copyKey)) {
|
||||||
throw new IllegalStateException("Copy key already used.");
|
throw new IllegalStateException("Copy key already used.");
|
||||||
@ -429,9 +439,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
copies.put(copyKey, copy);
|
copies.put(copyKey, copy);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
ServerLevel nmsWorld = serverLevel;
|
|
||||||
LevelChunk nmsChunk = ensureLoaded(nmsWorld, chunkX, chunkZ);
|
|
||||||
|
|
||||||
// Remove existing tiles. Create a copy so that we can remove blocks
|
// Remove existing tiles. Create a copy so that we can remove blocks
|
||||||
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
Map<BlockPos, BlockEntity> chunkTiles = new HashMap<>(nmsChunk.getBlockEntities());
|
||||||
List<BlockEntity> beacons = null;
|
List<BlockEntity> beacons = null;
|
||||||
@ -503,6 +510,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -577,6 +586,8 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeData
|
biomeData
|
||||||
);
|
);
|
||||||
if (PaperweightPlatformAdapter.setSectionAtomic(
|
if (PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
levelChunkSections,
|
levelChunkSections,
|
||||||
null,
|
null,
|
||||||
newSection,
|
newSection,
|
||||||
@ -638,7 +649,11 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
biomeRegistry,
|
biomeRegistry,
|
||||||
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
biomeData != null ? biomeData : (PalettedContainer<Holder<Biome>>) existingSection.getBiomes()
|
||||||
);
|
);
|
||||||
if (!PaperweightPlatformAdapter.setSectionAtomic(levelChunkSections, existingSection,
|
if (!PaperweightPlatformAdapter.setSectionAtomic(
|
||||||
|
serverLevel.getWorld().getName(),
|
||||||
|
chunkPos,
|
||||||
|
levelChunkSections,
|
||||||
|
existingSection,
|
||||||
newSection,
|
newSection,
|
||||||
getSectionIndex
|
getSectionIndex
|
||||||
)) {
|
)) {
|
||||||
@ -710,7 +725,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
if (Settings.settings().EXPERIMENTAL.REMOVE_ENTITY_FROM_WORLD_ON_CHUNK_FAIL) {
|
||||||
for (UUID uuid : entityRemoves) {
|
for (UUID uuid : entityRemoves) {
|
||||||
Entity entity = nmsWorld.getEntities().get(uuid);
|
Entity entity = serverLevel.getEntities().get(uuid);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
removeEntity(entity);
|
removeEntity(entity);
|
||||||
}
|
}
|
||||||
@ -722,48 +737,47 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<CompoundTag> entities = set.getEntities();
|
Collection<FaweCompoundTag> entities = set.entities();
|
||||||
if (entities != null && !entities.isEmpty()) {
|
if (entities != null && !entities.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[2];
|
syncTasks = new Runnable[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[1] = () -> {
|
syncTasks[1] = () -> {
|
||||||
Iterator<CompoundTag> iterator = entities.iterator();
|
Iterator<FaweCompoundTag> iterator = entities.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
final CompoundTag nativeTag = iterator.next();
|
final FaweCompoundTag nativeTag = iterator.next();
|
||||||
final Map<String, Tag<?, ?>> entityTagMap = nativeTag.getValue();
|
final LinCompoundTag linTag = nativeTag.linTag();
|
||||||
final StringTag idTag = (StringTag) entityTagMap.get("Id");
|
final LinStringTag idTag = linTag.findTag("Id", LinTagType.stringTag());
|
||||||
final ListTag posTag = (ListTag) entityTagMap.get("Pos");
|
final LinListTag<LinDoubleTag> posTag = linTag.findListTag("Pos", LinTagType.doubleTag());
|
||||||
final ListTag rotTag = (ListTag) entityTagMap.get("Rotation");
|
final LinListTag<LinFloatTag> rotTag = linTag.findListTag("Rotation", LinTagType.floatTag());
|
||||||
if (idTag == null || posTag == null || rotTag == null) {
|
if (idTag == null || posTag == null || rotTag == null) {
|
||||||
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
LOGGER.error("Unknown entity tag: {}", nativeTag);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final double x = posTag.getDouble(0);
|
final double x = posTag.get(0).valueAsDouble();
|
||||||
final double y = posTag.getDouble(1);
|
final double y = posTag.get(1).valueAsDouble();
|
||||||
final double z = posTag.getDouble(2);
|
final double z = posTag.get(2).valueAsDouble();
|
||||||
final float yaw = rotTag.getFloat(0);
|
final float yaw = rotTag.get(0).valueAsFloat();
|
||||||
final float pitch = rotTag.getFloat(1);
|
final float pitch = rotTag.get(1).valueAsFloat();
|
||||||
final String id = idTag.getValue();
|
final String id = idTag.value();
|
||||||
|
|
||||||
EntityType<?> type = EntityType.byString(id).orElse(null);
|
EntityType<?> type = EntityType.byString(id).orElse(null);
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
Entity entity = type.create(nmsWorld);
|
Entity entity = type.create(serverLevel);
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(linTag);
|
||||||
nativeTag);
|
|
||||||
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
for (final String name : Constants.NO_COPY_ENTITY_NBT_FIELDS) {
|
||||||
tag.remove(name);
|
tag.remove(name);
|
||||||
}
|
}
|
||||||
entity.load(tag);
|
entity.load(tag);
|
||||||
entity.absMoveTo(x, y, z, yaw, pitch);
|
entity.absMoveTo(x, y, z, yaw, pitch);
|
||||||
entity.setUUID(nativeTag.getUUID());
|
entity.setUUID(NbtUtils.uuid(nativeTag));
|
||||||
if (!nmsWorld.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
if (!serverLevel.addFreshEntity(entity, CreatureSpawnEvent.SpawnReason.CUSTOM)) {
|
||||||
LOGGER.warn(
|
LOGGER.warn(
|
||||||
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
"Error creating entity of type `{}` in world `{}` at location `{},{},{}`",
|
||||||
id,
|
id,
|
||||||
nmsWorld.getWorld().getName(),
|
serverLevel.getWorld().getName(),
|
||||||
x,
|
x,
|
||||||
y,
|
y,
|
||||||
z
|
z
|
||||||
@ -778,30 +792,29 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set tiles
|
// set tiles
|
||||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
|
||||||
if (tiles != null && !tiles.isEmpty()) {
|
if (tiles != null && !tiles.isEmpty()) {
|
||||||
if (syncTasks == null) {
|
if (syncTasks == null) {
|
||||||
syncTasks = new Runnable[1];
|
syncTasks = new Runnable[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
syncTasks[0] = () -> {
|
syncTasks[0] = () -> {
|
||||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
for (final Map.Entry<BlockVector3, FaweCompoundTag> entry : tiles.entrySet()) {
|
||||||
final CompoundTag nativeTag = entry.getValue();
|
final FaweCompoundTag nativeTag = entry.getValue();
|
||||||
final BlockVector3 blockHash = entry.getKey();
|
final BlockVector3 blockHash = entry.getKey();
|
||||||
final int x = blockHash.x() + bx;
|
final int x = blockHash.x() + bx;
|
||||||
final int y = blockHash.y();
|
final int y = blockHash.y();
|
||||||
final int z = blockHash.z() + bz;
|
final int z = blockHash.z() + bz;
|
||||||
final BlockPos pos = new BlockPos(x, y, z);
|
final BlockPos pos = new BlockPos(x, y, z);
|
||||||
|
|
||||||
synchronized (nmsWorld) {
|
synchronized (serverLevel) {
|
||||||
BlockEntity tileEntity = nmsWorld.getBlockEntity(pos);
|
BlockEntity tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
if (tileEntity == null || tileEntity.isRemoved()) {
|
if (tileEntity == null || tileEntity.isRemoved()) {
|
||||||
nmsWorld.removeBlockEntity(pos);
|
serverLevel.removeBlockEntity(pos);
|
||||||
tileEntity = nmsWorld.getBlockEntity(pos);
|
tileEntity = serverLevel.getBlockEntity(pos);
|
||||||
}
|
}
|
||||||
if (tileEntity != null) {
|
if (tileEntity != null) {
|
||||||
final net.minecraft.nbt.CompoundTag tag = (net.minecraft.nbt.CompoundTag) adapter.fromNative(
|
final CompoundTag tag = (CompoundTag) adapter.fromNativeLin(nativeTag.linTag());
|
||||||
nativeTag);
|
|
||||||
tag.put("x", IntTag.valueOf(x));
|
tag.put("x", IntTag.valueOf(x));
|
||||||
tag.put("y", IntTag.valueOf(y));
|
tag.put("y", IntTag.valueOf(y));
|
||||||
tag.put("z", IntTag.valueOf(z));
|
tag.put("z", IntTag.valueOf(z));
|
||||||
@ -817,7 +830,6 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
callback = null;
|
callback = null;
|
||||||
} else {
|
} else {
|
||||||
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
int finalMask = bitMask != 0 ? bitMask : lightUpdate ? set.getBitMask() : 0;
|
||||||
boolean finalLightUpdate = lightUpdate;
|
|
||||||
callback = () -> {
|
callback = () -> {
|
||||||
// Set Modified
|
// Set Modified
|
||||||
nmsChunk.setLightCorrect(true); // Set Modified
|
nmsChunk.setLightCorrect(true); // Set Modified
|
||||||
@ -923,7 +935,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
|
|||||||
@Override
|
@Override
|
||||||
public void send() {
|
public void send() {
|
||||||
synchronized (sendLock) {
|
synchronized (sendLock) {
|
||||||
PaperweightPlatformAdapter.sendChunk(this, serverLevel, chunkX, chunkZ);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(chunkX, chunkZ), serverLevel, chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
|
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBlocks;
|
import com.fastasyncworldedit.core.queue.IBlocks;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.google.common.base.Suppliers;
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
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.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockState;
|
import com.sk89q.worldedit.world.block.BlockState;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
|
import io.papermc.lib.PaperLib;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
@ -25,9 +26,11 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|||||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
import net.minecraft.world.level.chunk.PalettedContainerRO;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -39,8 +42,8 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
private final Map<BlockVector3, CompoundTag> tiles = new HashMap<>();
|
private final Map<BlockVector3, FaweCompoundTag> tiles = new HashMap<>();
|
||||||
private final Set<CompoundTag> entities = new HashSet<>();
|
private final Set<FaweCompoundTag> entities = new HashSet<>();
|
||||||
private final char[][] blocks;
|
private final char[][] blocks;
|
||||||
private final int minHeight;
|
private final int minHeight;
|
||||||
private final int maxHeight;
|
private final int maxHeight;
|
||||||
@ -57,44 +60,37 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void storeTile(BlockEntity blockEntity) {
|
protected void storeTile(BlockEntity blockEntity) {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
tiles.put(
|
tiles.put(
|
||||||
BlockVector3.at(
|
BlockVector3.at(
|
||||||
blockEntity.getBlockPos().getX(),
|
blockEntity.getBlockPos().getX(),
|
||||||
blockEntity.getBlockPos().getY(),
|
blockEntity.getBlockPos().getY(),
|
||||||
blockEntity.getBlockPos().getZ()
|
blockEntity.getBlockPos().getZ()
|
||||||
),
|
),
|
||||||
new PaperweightLazyCompoundTag(Suppliers.memoize(() -> blockEntity.saveWithId(DedicatedServer.getServer().registryAccess())))
|
FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(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) {
|
protected void storeEntity(Entity entity) {
|
||||||
BukkitImplAdapter adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
@SuppressWarnings("unchecked")
|
||||||
|
BukkitImplAdapter<Tag> adapter = WorldEditPlugin.getInstance().getBukkitImplAdapter();
|
||||||
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
net.minecraft.nbt.CompoundTag compoundTag = new net.minecraft.nbt.CompoundTag();
|
||||||
entity.save(compoundTag);
|
entity.save(compoundTag);
|
||||||
entities.add((CompoundTag) adapter.toNative(compoundTag));
|
entities.add(FaweCompoundTag.of((LinCompoundTag) adapter.toNativeLin(compoundTag)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Set<CompoundTag> getEntities() {
|
public Collection<FaweCompoundTag> entities() {
|
||||||
return this.entities;
|
return this.entities;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompoundTag getEntity(UUID uuid) {
|
public @Nullable FaweCompoundTag entity(final UUID uuid) {
|
||||||
for (CompoundTag tag : entities) {
|
for (FaweCompoundTag tag : entities) {
|
||||||
if (uuid.equals(tag.getUUID())) {
|
if (uuid.equals(NbtUtils.uuid(tag))) {
|
||||||
return tag;
|
return tag;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -180,8 +176,18 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
biomes[layer] = new Holder[64];
|
biomes[layer] = new Holder[64];
|
||||||
}
|
}
|
||||||
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
if (biomeData instanceof PalettedContainer<Holder<Biome>> palettedContainer) {
|
||||||
for (int i = 0; i < 64; i++) {
|
if (PaperLib.isPaper()) {
|
||||||
biomes[layer][i] = palettedContainer.get(i);
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = palettedContainer.get(i); // Only public on paper
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
for (int i = 0; i < 64; i++) {
|
||||||
|
biomes[layer][i] = (Holder<Biome>) PaperweightPlatformAdapter.PALETTED_CONTAINER_GET.invoke(i);
|
||||||
|
}
|
||||||
|
} catch (Throwable e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOGGER.error(
|
LOGGER.error(
|
||||||
@ -195,7 +201,7 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
@Override
|
@Override
|
||||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||||
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
BlockState state = BlockTypesCache.states[get(x, y, z)];
|
||||||
return state.toBaseBlock(this, x, y, z);
|
return state.toBaseBlock((IBlocks) this, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -225,6 +231,16 @@ public class PaperweightGetBlocks_Copy implements IChunkGet {
|
|||||||
return BlockTypesCache.states[get(x, y, z)];
|
return BlockTypesCache.states[get(x, y, z)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<BlockVector3, FaweCompoundTag> tiles() {
|
||||||
|
return tiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
|
||||||
|
return tiles.get(BlockVector3.at(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getSkyLight(int x, int y, int z) {
|
public int getSkyLight(int x, int y, int z) {
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -8,9 +8,10 @@ import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
|||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
import com.fastasyncworldedit.core.math.BitArrayUnstretched;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
|
import com.mojang.datafixers.util.Either;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
||||||
@ -31,7 +32,6 @@ import net.minecraft.server.level.ChunkMap;
|
|||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.util.BitStorage;
|
import net.minecraft.util.BitStorage;
|
||||||
import net.minecraft.util.ExceptionCollector;
|
|
||||||
import net.minecraft.util.SimpleBitStorage;
|
import net.minecraft.util.SimpleBitStorage;
|
||||||
import net.minecraft.util.ThreadingDetector;
|
import net.minecraft.util.ThreadingDetector;
|
||||||
import net.minecraft.util.Unit;
|
import net.minecraft.util.Unit;
|
||||||
@ -76,6 +76,7 @@ import java.util.Iterator;
|
|||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.Semaphore;
|
import java.util.concurrent.Semaphore;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
@ -119,6 +120,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
|
private static Method PAPER_CHUNK_GEN_ALL_ENTITIES;
|
||||||
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
private static Field SERVER_LEVEL_ENTITY_MANAGER;
|
||||||
|
|
||||||
|
static final MethodHandle PALETTED_CONTAINER_GET;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||||
try {
|
try {
|
||||||
@ -195,6 +198,13 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "N"));
|
SERVER_LEVEL_ENTITY_MANAGER = ServerLevel.class.getDeclaredField(Refraction.pickName("entityManager", "N"));
|
||||||
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
|
SERVER_LEVEL_ENTITY_MANAGER.setAccessible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Method palettedContaienrGet = PalettedContainer.class.getDeclaredMethod(
|
||||||
|
Refraction.pickName("get", "a"),
|
||||||
|
int.class
|
||||||
|
);
|
||||||
|
palettedContaienrGet.setAccessible(true);
|
||||||
|
PALETTED_CONTAINER_GET = lookup.unreflect(palettedContaienrGet);
|
||||||
} catch (RuntimeException | Error e) {
|
} catch (RuntimeException | Error e) {
|
||||||
throw e;
|
throw e;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -217,15 +227,14 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static boolean setSectionAtomic(
|
static boolean setSectionAtomic(
|
||||||
|
String worldName,
|
||||||
|
IntPair pair,
|
||||||
LevelChunkSection[] sections,
|
LevelChunkSection[] sections,
|
||||||
LevelChunkSection expected,
|
LevelChunkSection expected,
|
||||||
LevelChunkSection value,
|
LevelChunkSection value,
|
||||||
int layer
|
int layer
|
||||||
) {
|
) {
|
||||||
if (layer >= 0 && layer < sections.length) {
|
return NMSAdapter.setSectionAtomic(worldName, pair, sections, expected, value, layer);
|
||||||
return ReflectionUtils.compareAndSet(sections, expected, value, layer);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There is no point in having a functional semaphore for paper servers.
|
// There is no point in having a functional semaphore for paper servers.
|
||||||
@ -323,7 +332,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
public static void sendChunk(Object chunk, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
public static void sendChunk(IntPair pair, ServerLevel nmsWorld, int chunkX, int chunkZ) {
|
||||||
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
ChunkHolder chunkHolder = getPlayerChunk(nmsWorld, chunkX, chunkZ);
|
||||||
if (chunkHolder == null) {
|
if (chunkHolder == null) {
|
||||||
return;
|
return;
|
||||||
@ -332,36 +341,42 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
|
|||||||
LevelChunk levelChunk;
|
LevelChunk levelChunk;
|
||||||
if (PaperLib.isPaper()) {
|
if (PaperLib.isPaper()) {
|
||||||
// getChunkAtIfLoadedImmediately is paper only
|
// getChunkAtIfLoadedImmediately is paper only
|
||||||
levelChunk = nmsWorld
|
levelChunk = nmsWorld.getChunkSource().getChunkAtIfLoadedImmediately(chunkX, chunkZ);
|
||||||
.getChunkSource()
|
|
||||||
.getChunkAtIfLoadedImmediately(chunkX, chunkZ);
|
|
||||||
} else {
|
} else {
|
||||||
levelChunk = chunkHolder.getTickingChunkFuture()
|
levelChunk = chunkHolder.getTickingChunkFuture().getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null);
|
||||||
.getNow(ChunkHolder.UNLOADED_LEVEL_CHUNK).orElse(null);
|
|
||||||
}
|
}
|
||||||
if (levelChunk == null) {
|
if (levelChunk == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
StampLockHolder lockHolder = new StampLockHolder();
|
||||||
|
NMSAdapter.beginChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
|
if (lockHolder.chunkLock == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
MinecraftServer.getServer().execute(() -> {
|
MinecraftServer.getServer().execute(() -> {
|
||||||
ClientboundLevelChunkWithLightPacket packet;
|
try {
|
||||||
if (PaperLib.isPaper()) {
|
ClientboundLevelChunkWithLightPacket packet;
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
if (PaperLib.isPaper()) {
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null,
|
null,
|
||||||
false // last false is to not bother with x-ray
|
null,
|
||||||
);
|
false // last false is to not bother with x-ray
|
||||||
} else {
|
);
|
||||||
// deprecated on paper - deprecation suppressed
|
} else {
|
||||||
packet = new ClientboundLevelChunkWithLightPacket(
|
// deprecated on paper - deprecation suppressed
|
||||||
levelChunk,
|
packet = new ClientboundLevelChunkWithLightPacket(
|
||||||
nmsWorld.getChunkSource().getLightEngine(),
|
levelChunk,
|
||||||
null,
|
nmsWorld.getChunkSource().getLightEngine(),
|
||||||
null
|
null,
|
||||||
);
|
null
|
||||||
|
);
|
||||||
|
}
|
||||||
|
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
||||||
|
} finally {
|
||||||
|
NMSAdapter.endChunkPacketSend(nmsWorld.getWorld().getName(), pair, lockHolder);
|
||||||
}
|
}
|
||||||
nearbyPlayers(nmsWorld, coordIntPair).forEach(p -> p.connection.send(packet));
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
import com.fastasyncworldedit.bukkit.adapter.StarlightRelighter;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
import com.fastasyncworldedit.core.queue.IQueueExtent;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@ -70,7 +71,7 @@ public class PaperweightStarlightRelighter extends StarlightRelighter<ServerLeve
|
|||||||
int x = pos.x;
|
int x = pos.x;
|
||||||
int z = pos.z;
|
int z = pos.z;
|
||||||
if (delay) { // we still need to send the block changes of that chunk
|
if (delay) { // we still need to send the block changes of that chunk
|
||||||
PaperweightPlatformAdapter.sendChunk(pos, serverLevel, x, z);
|
PaperweightPlatformAdapter.sendChunk(new IntPair(x, z), serverLevel, x, z);
|
||||||
}
|
}
|
||||||
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
serverLevel.getChunkSource().removeTicketAtLevel(FAWE_TICKET, pos, LIGHT_LEVEL, Unit.INSTANCE);
|
||||||
}
|
}
|
||||||
|
@ -1,175 +1,76 @@
|
|||||||
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_21_R1.regen;
|
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.bukkit.adapter.Regenerator;
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkCache;
|
import com.fastasyncworldedit.core.queue.IChunkCache;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkCache;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.mojang.serialization.Lifecycle;
|
import com.mojang.serialization.Lifecycle;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
|
||||||
import com.sk89q.worldedit.bukkit.adapter.Refraction;
|
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.extent.Extent;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
import com.sk89q.worldedit.util.io.file.SafeFiles;
|
||||||
import com.sk89q.worldedit.world.RegenOptions;
|
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.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.resources.ResourceKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.dedicated.DedicatedServer;
|
import net.minecraft.server.dedicated.DedicatedServer;
|
||||||
import net.minecraft.server.level.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.ServerLevel;
|
||||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||||
import net.minecraft.util.StaticCache2D;
|
import net.minecraft.util.ProgressListener;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
|
||||||
import net.minecraft.util.thread.ProcessorMailbox;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelHeightAccessor;
|
|
||||||
import net.minecraft.world.level.LevelSettings;
|
import net.minecraft.world.level.LevelSettings;
|
||||||
import net.minecraft.world.level.biome.Biome;
|
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.dimension.LevelStem;
|
||||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
|
||||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
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.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.LevelStorageSource;
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Chunk;
|
import org.bukkit.World;
|
||||||
import org.bukkit.craftbukkit.CraftServer;
|
import org.bukkit.craftbukkit.CraftServer;
|
||||||
import org.bukkit.craftbukkit.CraftWorld;
|
import org.bukkit.craftbukkit.CraftWorld;
|
||||||
import org.bukkit.craftbukkit.generator.CustomChunkGenerator;
|
|
||||||
import org.bukkit.generator.BiomeProvider;
|
import org.bukkit.generator.BiomeProvider;
|
||||||
import org.bukkit.generator.BlockPopulator;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.OptionalLong;
|
import java.util.OptionalLong;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import static net.minecraft.core.registries.Registries.BIOME;
|
import static net.minecraft.core.registries.Registries.BIOME;
|
||||||
|
|
||||||
public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, LevelChunk, PaperweightRegen.ChunkStatusWrap> {
|
public class PaperweightRegen extends Regenerator {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
|
||||||
|
|
||||||
private static final Field serverWorldsField;
|
private static final Field serverWorldsField;
|
||||||
private static final Field paperConfigField;
|
private static final Field paperConfigField;
|
||||||
private static final Field flatBedrockField;
|
|
||||||
private static final Field generatorSettingFlatField;
|
|
||||||
private static final Field generatorSettingBaseSupplierField;
|
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 {
|
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 {
|
try {
|
||||||
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
serverWorldsField = CraftServer.class.getDeclaredField("worlds");
|
||||||
serverWorldsField.setAccessible(true);
|
serverWorldsField.setAccessible(true);
|
||||||
|
|
||||||
Field tmpPaperConfigField;
|
Field tmpPaperConfigField;
|
||||||
Field tmpFlatBedrockField;
|
|
||||||
try { //only present on paper
|
try { //only present on paper
|
||||||
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
tmpPaperConfigField = Level.class.getDeclaredField("paperConfig");
|
||||||
tmpPaperConfigField.setAccessible(true);
|
tmpPaperConfigField.setAccessible(true);
|
||||||
|
|
||||||
tmpFlatBedrockField = tmpPaperConfigField.getType().getDeclaredField("generateFlatBedrock");
|
|
||||||
tmpFlatBedrockField.setAccessible(true);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
tmpPaperConfigField = null;
|
tmpPaperConfigField = null;
|
||||||
tmpFlatBedrockField = null;
|
|
||||||
}
|
}
|
||||||
paperConfigField = tmpPaperConfigField;
|
paperConfigField = tmpPaperConfigField;
|
||||||
flatBedrockField = tmpFlatBedrockField;
|
|
||||||
|
|
||||||
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
generatorSettingBaseSupplierField = NoiseBasedChunkGenerator.class.getDeclaredField(Refraction.pickName(
|
||||||
"settings", "e"));
|
"settings", "e"));
|
||||||
generatorSettingBaseSupplierField.setAccessible(true);
|
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) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -177,47 +78,37 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
//runtime
|
//runtime
|
||||||
private ServerLevel originalServerWorld;
|
private ServerLevel originalServerWorld;
|
||||||
private ServerChunkCache originalChunkProvider;
|
|
||||||
private ServerLevel freshWorld;
|
private ServerLevel freshWorld;
|
||||||
private ServerChunkCache freshChunkProvider;
|
|
||||||
private LevelStorageSource.LevelStorageAccess session;
|
private LevelStorageSource.LevelStorageAccess session;
|
||||||
private StructureTemplateManager structureTemplateManager;
|
|
||||||
private ThreadedLevelLightEngine threadedLevelLightEngine;
|
|
||||||
private ChunkGenerator chunkGenerator;
|
|
||||||
private WorldGenContext worldGenContext;
|
|
||||||
|
|
||||||
private Path tempDir;
|
private Path tempDir;
|
||||||
|
|
||||||
private boolean generateFlatBedrock = false;
|
public PaperweightRegen(
|
||||||
|
World originalBukkitWorld,
|
||||||
public PaperweightRegen(org.bukkit.World originalBukkitWorld, Region region, Extent target, RegenOptions options) {
|
Region region,
|
||||||
|
Extent target,
|
||||||
|
RegenOptions options
|
||||||
|
) {
|
||||||
super(originalBukkitWorld, region, target, 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 void runTasks(final BooleanSupplier shouldKeepTicking) {
|
||||||
|
while (shouldKeepTicking.getAsBoolean()) {
|
||||||
|
if (!this.freshWorld.getChunkSource().pollTask()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean prepare() {
|
protected boolean prepare() {
|
||||||
this.originalServerWorld = ((CraftWorld) originalBukkitWorld).getHandle();
|
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());
|
seed = options.getSeed().orElse(originalServerWorld.getSeed());
|
||||||
chunkStati.forEach((s, c) -> super.chunkStatuses.put(new ChunkStatusWrap(s), c));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
protected boolean initNewWorld() throws Exception {
|
protected boolean initNewWorld() throws Exception {
|
||||||
//world folder
|
//world folder
|
||||||
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
tempDir = java.nio.file.Files.createTempDirectory("FastAsyncWorldEditWorldGen");
|
||||||
@ -263,8 +154,10 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
session,
|
session,
|
||||||
newWorldData,
|
newWorldData,
|
||||||
originalServerWorld.dimension(),
|
originalServerWorld.dimension(),
|
||||||
DedicatedServer.getServer().registryAccess().registry(Registries.LEVEL_STEM).orElseThrow()
|
new LevelStem(
|
||||||
.getOrThrow(levelStemResourceKey),
|
originalServerWorld.dimensionTypeRegistration(),
|
||||||
|
originalServerWorld.getChunkSource().getGenerator()
|
||||||
|
),
|
||||||
new RegenNoOpWorldLoadListener(),
|
new RegenNoOpWorldLoadListener(),
|
||||||
originalServerWorld.isDebug(),
|
originalServerWorld.isDebug(),
|
||||||
seed,
|
seed,
|
||||||
@ -281,20 +174,32 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
|
WorldEditPlugin.getInstance().getBukkitImplAdapter().getInternalBiomeId(options.getBiomeType())
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void tick(@NotNull BooleanSupplier shouldKeepTicking) { //no ticking
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
public @NotNull Holder<Biome> getUncachedNoiseBiome(int biomeX, int biomeY, int biomeZ) {
|
||||||
if (options.hasBiomeType()) {
|
if (options.hasBiomeType()) {
|
||||||
return singleBiome;
|
return singleBiome;
|
||||||
}
|
}
|
||||||
return PaperweightRegen.this.chunkGenerator.getBiomeSource().getNoiseBiome(
|
return super.getUncachedNoiseBiome(biomeX, biomeY, biomeZ);
|
||||||
biomeX, biomeY, biomeZ, getChunkSource().randomState().sampler()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled
|
||||||
|
) {
|
||||||
|
// noop, spigot
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void save(
|
||||||
|
@Nullable final ProgressListener progressListener,
|
||||||
|
final boolean flush,
|
||||||
|
final boolean savingDisabled,
|
||||||
|
final boolean close
|
||||||
|
) {
|
||||||
|
// noop, paper
|
||||||
|
}
|
||||||
}).get();
|
}).get();
|
||||||
freshWorld.noSave = true;
|
freshWorld.noSave = true;
|
||||||
removeWorldFromWorldsMap();
|
removeWorldFromWorldsMap();
|
||||||
@ -302,97 +207,6 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
if (paperConfigField != null) {
|
if (paperConfigField != null) {
|
||||||
paperConfigField.set(freshWorld, originalServerWorld.paperConfig());
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -407,7 +221,8 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
try {
|
try {
|
||||||
Fawe.instance().getQueueHandler().sync(() -> {
|
Fawe.instance().getQueueHandler().sync(() -> {
|
||||||
try {
|
try {
|
||||||
freshChunkProvider.close(false);
|
freshWorld.getChunkSource().getDataStorage().cache.clear();
|
||||||
|
freshWorld.getChunkSource().close(false);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
@ -428,50 +243,9 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@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
|
@Override
|
||||||
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
protected IChunkCache<IChunkGet> initSourceQueueCache() {
|
||||||
return (chunkX, chunkZ) -> new PaperweightGetBlocks(freshWorld, chunkX, chunkZ) {
|
return new ChunkCache<>(BukkitAdapter.adapt(freshWorld.getWorld()));
|
||||||
@Override
|
|
||||||
public LevelChunk ensureLoaded(ServerLevel nmsWorld, int x, int z) {
|
|
||||||
return getChunkAt(x, z);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//util
|
//util
|
||||||
@ -525,99 +299,4 @@ public class PaperweightRegen extends Regenerator<ChunkAccess, ProtoChunk, Level
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,67 @@
|
|||||||
|
package com.fastasyncworldedit.bukkit;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.bukkit.adapter.NMSAdapter;
|
||||||
|
import com.fastasyncworldedit.bukkit.util.WorldUnloadedException;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
|
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.World;
|
||||||
|
|
||||||
|
import java.lang.ref.WeakReference;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.WeakHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
public class FaweBukkitWorld extends BukkitWorld {
|
||||||
|
|
||||||
|
private static final Map<World, FaweBukkitWorld> CACHE = Collections.synchronizedMap(new WeakHashMap<>());
|
||||||
|
|
||||||
|
private final ConcurrentHashMap<IntPair, NMSAdapter.ChunkSendLock> SENDING_CHUNKS = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct the object.
|
||||||
|
*
|
||||||
|
* @param world the world
|
||||||
|
*/
|
||||||
|
private FaweBukkitWorld(final World world) {
|
||||||
|
super(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FaweBukkitWorld of(World world) {
|
||||||
|
return CACHE.compute(world, (__, val) -> {
|
||||||
|
if (val == null) {
|
||||||
|
return new FaweBukkitWorld(world);
|
||||||
|
}
|
||||||
|
val.updateReference();
|
||||||
|
return val;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FaweBukkitWorld of(String worldName) {
|
||||||
|
World world = Bukkit.getWorld(worldName);
|
||||||
|
if (world == null) {
|
||||||
|
throw new UnsupportedOperationException("Unable to find org.bukkit.World instance for " + worldName + ". Is it loaded?");
|
||||||
|
}
|
||||||
|
return of(world);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConcurrentHashMap<IntPair, NMSAdapter.ChunkSendLock> getWorldSendingChunksMap(FaweBukkitWorld world) {
|
||||||
|
return world.SENDING_CHUNKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ConcurrentHashMap<IntPair, NMSAdapter.ChunkSendLock> getWorldSendingChunksMap(String worldName) {
|
||||||
|
return of(worldName).SENDING_CHUNKS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateReference() {
|
||||||
|
World world = getWorld();
|
||||||
|
World bukkitWorld = Bukkit.getWorld(worldNameRef);
|
||||||
|
if (bukkitWorld == null) {
|
||||||
|
throw new WorldUnloadedException(worldNameRef);
|
||||||
|
} else if (bukkitWorld != world) {
|
||||||
|
worldRef = new WeakReference<>(bukkitWorld);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,12 +1,17 @@
|
|||||||
package com.fastasyncworldedit.bukkit.adapter;
|
package com.fastasyncworldedit.bukkit.adapter;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.bukkit.FaweBukkitWorld;
|
||||||
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
import com.fastasyncworldedit.core.FAWEPlatformAdapterImpl;
|
||||||
|
import com.fastasyncworldedit.core.math.IntPair;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.MathMan;
|
||||||
|
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.locks.StampedLock;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
||||||
@ -140,4 +145,118 @@ public class NMSAdapter implements FAWEPlatformAdapterImpl {
|
|||||||
((BukkitGetBlocks) chunk).send();
|
((BukkitGetBlocks) chunk).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Atomically set the given chunk section to the chunk section array stored in the chunk, given the expected existing chunk
|
||||||
|
* section instance at the given layer position.
|
||||||
|
* <p>
|
||||||
|
* Acquires a (FAWE-implemented only) write-lock on the chunk packet lock, waiting if required before writing, then freeing
|
||||||
|
* the lock. Also sets a boolean to indicate a write is waiting and therefore reads should not occur.
|
||||||
|
* <p>
|
||||||
|
* Utilises ConcurrentHashMap#compute for easy synchronisation for all of the above. Only tryWriteLock is used in blocks
|
||||||
|
* synchronised using ConcurrentHashMap methods.
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
protected static <LevelChunkSection> boolean setSectionAtomic(
|
||||||
|
String worldName,
|
||||||
|
IntPair pair,
|
||||||
|
LevelChunkSection[] sections,
|
||||||
|
LevelChunkSection expected,
|
||||||
|
LevelChunkSection value,
|
||||||
|
int layer
|
||||||
|
) {
|
||||||
|
if (layer < 0 || layer >= sections.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
StampLockHolder holder = new StampLockHolder();
|
||||||
|
ConcurrentHashMap<IntPair, ChunkSendLock> chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName);
|
||||||
|
chunks.compute(pair, (k, lock) -> {
|
||||||
|
if (lock == null) {
|
||||||
|
lock = new ChunkSendLock();
|
||||||
|
} else if (lock.writeWaiting) {
|
||||||
|
throw new IllegalStateException("Attempting to write chunk section when write is already ongoing?!");
|
||||||
|
}
|
||||||
|
holder.stamp = lock.lock.tryWriteLock();
|
||||||
|
holder.chunkLock = lock;
|
||||||
|
lock.writeWaiting = true;
|
||||||
|
return lock;
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
if (holder.stamp == 0) {
|
||||||
|
holder.stamp = holder.chunkLock.lock.writeLock();
|
||||||
|
}
|
||||||
|
return ReflectionUtils.compareAndSet(sections, expected, value, layer);
|
||||||
|
} finally {
|
||||||
|
chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName);
|
||||||
|
chunks.computeIfPresent(pair, (k, lock) -> {
|
||||||
|
if (lock != holder.chunkLock) {
|
||||||
|
throw new IllegalStateException("SENDING_CHUNKS stored lock does not equal lock attempted to be unlocked?!");
|
||||||
|
}
|
||||||
|
lock.lock.unlockWrite(holder.stamp);
|
||||||
|
lock.writeWaiting = false;
|
||||||
|
// Keep the lock, etc. in the map as we're going to be accessing again later when sending
|
||||||
|
return lock;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called before sending a chunk packet, filling the given stamp and stampedLock arrays' zeroth indices if the chunk packet
|
||||||
|
* send should go ahead.
|
||||||
|
* <p>
|
||||||
|
* Chunk packets should be sent if both of the following are met:
|
||||||
|
* - There is no more than one current packet send ongoing
|
||||||
|
* - There is no chunk section "write" waiting or ongoing,
|
||||||
|
* which are determined by the number of readers currently locking the StampedLock (i.e. the number of sends), if the
|
||||||
|
* stamped lock is currently write-locked and if the boolean for waiting write is true.
|
||||||
|
* <p>
|
||||||
|
* Utilises ConcurrentHashMap#compute for easy synchronisation
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
protected static void beginChunkPacketSend(String worldName, IntPair pair, StampLockHolder stampedLock) {
|
||||||
|
ConcurrentHashMap<IntPair, ChunkSendLock> chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName);
|
||||||
|
chunks.compute(pair, (k, lock) -> {
|
||||||
|
if (lock == null) {
|
||||||
|
lock = new ChunkSendLock();
|
||||||
|
}
|
||||||
|
// Allow twice-read-locking, so if the packets have been created but not sent, we can queue another read
|
||||||
|
if (lock.writeWaiting || lock.lock.getReadLockCount() > 1 || lock.lock.isWriteLocked()) {
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
stampedLock.stamp = lock.lock.readLock();
|
||||||
|
stampedLock.chunkLock = lock;
|
||||||
|
return lock;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Releases the read lock acquired when sending a chunk packet for a chunk
|
||||||
|
*
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
protected static void endChunkPacketSend(String worldName, IntPair pair, StampLockHolder lockHolder) {
|
||||||
|
ConcurrentHashMap<IntPair, ChunkSendLock> chunks = FaweBukkitWorld.getWorldSendingChunksMap(worldName);
|
||||||
|
chunks.computeIfPresent(pair, (k, lock) -> {
|
||||||
|
if (lock.lock != lockHolder.chunkLock.lock) {
|
||||||
|
throw new IllegalStateException("SENDING_CHUNKS stored lock does not equal lock attempted to be unlocked?!");
|
||||||
|
}
|
||||||
|
lock.lock.unlockRead(lockHolder.stamp);
|
||||||
|
// Do not continue to store the lock if we may not need it (i.e. chunk has been sent, may not be sent again)
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class StampLockHolder {
|
||||||
|
public long stamp;
|
||||||
|
public ChunkSendLock chunkLock = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final class ChunkSendLock {
|
||||||
|
|
||||||
|
public final StampedLock lock = new StampedLock();
|
||||||
|
public boolean writeWaiting = false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,67 +1,32 @@
|
|||||||
package com.fastasyncworldedit.bukkit.adapter;
|
package com.fastasyncworldedit.bukkit.adapter;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
|
||||||
import com.fastasyncworldedit.core.queue.IChunkCache;
|
import com.fastasyncworldedit.core.queue.IChunkCache;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent;
|
||||||
import com.fastasyncworldedit.core.util.MathMan;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||||
import com.sk89q.worldedit.extent.Extent;
|
import com.sk89q.worldedit.extent.Extent;
|
||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
|
||||||
import com.sk89q.worldedit.math.BlockVector2;
|
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.CuboidRegion;
|
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.world.RegenOptions;
|
import com.sk89q.worldedit.world.RegenOptions;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongList;
|
|
||||||
import jdk.jfr.Category;
|
|
||||||
import jdk.jfr.Event;
|
|
||||||
import jdk.jfr.Label;
|
|
||||||
import jdk.jfr.Name;
|
|
||||||
import org.apache.logging.log4j.Logger;
|
|
||||||
import org.bukkit.generator.BiomeProvider;
|
import org.bukkit.generator.BiomeProvider;
|
||||||
import org.bukkit.generator.BlockPopulator;
|
|
||||||
import org.bukkit.generator.WorldInfo;
|
import org.bukkit.generator.WorldInfo;
|
||||||
|
|
||||||
import java.util.AbstractList;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.Objects;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.Random;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
|
||||||
import java.util.concurrent.ExecutorService;
|
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an abstract regeneration handler.
|
* Represents an abstract regeneration handler.
|
||||||
*
|
|
||||||
* @param <IChunkAccess> the type of the {@code IChunkAccess} of the current Minecraft implementation
|
|
||||||
* @param <ProtoChunk> the type of the {@code ProtoChunk} of the current Minecraft implementation
|
|
||||||
* @param <Chunk> the type of the {@code Chunk} of the current Minecraft implementation
|
|
||||||
* @param <ChunkStatus> the type of the {@code ChunkStatusWrapper} wrapping the {@code ChunkStatus} enum
|
|
||||||
*/
|
*/
|
||||||
public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess, Chunk extends IChunkAccess, ChunkStatus extends Regenerator.ChunkStatusWrapper<IChunkAccess>> {
|
public abstract class Regenerator {
|
||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
|
||||||
|
|
||||||
protected final org.bukkit.World originalBukkitWorld;
|
protected final org.bukkit.World originalBukkitWorld;
|
||||||
protected final Region region;
|
protected final Region region;
|
||||||
@ -69,13 +34,8 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
protected final RegenOptions options;
|
protected final RegenOptions options;
|
||||||
|
|
||||||
//runtime
|
//runtime
|
||||||
protected final LinkedHashMap<ChunkStatus, Concurrency> chunkStatuses = new LinkedHashMap<>(); // TODO (j21): use SequencedMap
|
|
||||||
private final Long2ObjectLinkedOpenHashMap<ProtoChunk> protoChunks = new Long2ObjectLinkedOpenHashMap<>();
|
|
||||||
private final Long2ObjectOpenHashMap<Chunk> chunks = new Long2ObjectOpenHashMap<>();
|
|
||||||
protected boolean generateConcurrent = true;
|
|
||||||
protected long seed;
|
protected long seed;
|
||||||
private ExecutorService executor;
|
protected SingleThreadQueueExtent source;
|
||||||
private SingleThreadQueueExtent source;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initializes an abstract regeneration handler.
|
* Initializes an abstract regeneration handler.
|
||||||
@ -92,15 +52,6 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
this.options = options;
|
this.options = options;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Random getChunkRandom(long worldSeed, int x, int z) {
|
|
||||||
Random random = new Random();
|
|
||||||
random.setSeed(worldSeed);
|
|
||||||
long xRand = random.nextLong() / 2L * 2L + 1L;
|
|
||||||
long zRand = random.nextLong() / 2L * 2L + 1L;
|
|
||||||
random.setSeed((long) x * xRand + (long) z * zRand ^ worldSeed);
|
|
||||||
return random;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerates the selected {@code Region}.
|
* Regenerates the selected {@code Region}.
|
||||||
*
|
*
|
||||||
@ -122,16 +73,6 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
if (!generate()) {
|
|
||||||
cleanup0();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
cleanup0();
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
copyToWorld();
|
copyToWorld();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -144,193 +85,26 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@code ProtoChunk} at the given chunk coordinates.
|
* Execute tasks on the main thread during regen.
|
||||||
*
|
|
||||||
* @param x the chunk x coordinate
|
|
||||||
* @param z the chunk z coordinate
|
|
||||||
* @return the {@code ProtoChunk} at the given chunk coordinates or null if it is not part of the regeneration process or has not been initialized yet.
|
|
||||||
*/
|
*/
|
||||||
protected ProtoChunk getProtoChunkAt(int x, int z) {
|
protected abstract void runTasks(BooleanSupplier shouldKeepTicking);
|
||||||
return protoChunks.get(MathMan.pairInt(x, z));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
private void createSource() {
|
||||||
* Returns the {@code Chunk} at the given chunk coordinates.
|
|
||||||
*
|
|
||||||
* @param x the chunk x coordinate
|
|
||||||
* @param z the chunk z coordinate
|
|
||||||
* @return the {@code Chunk} at the given chunk coordinates or null if it is not part of the regeneration process or has not been converted yet.
|
|
||||||
*/
|
|
||||||
protected Chunk getChunkAt(int x, int z) {
|
|
||||||
return chunks.get(MathMan.pairInt(x, z));
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean generate() throws Exception {
|
|
||||||
ThreadFactory factory = new ThreadFactoryBuilder()
|
|
||||||
.setNameFormat("FAWE Regenerator - %d")
|
|
||||||
.build();
|
|
||||||
if (generateConcurrent) {
|
|
||||||
//Using concurrent chunk generation
|
|
||||||
executor = Executors.newFixedThreadPool(Settings.settings().QUEUE.PARALLEL_THREADS, factory);
|
|
||||||
} else { // else using sequential chunk generation, concurrent not supported
|
|
||||||
executor = Executors.newSingleThreadExecutor(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: can we get that required radius down without affecting chunk generation (e.g. strucures, features, ...)?
|
|
||||||
//for now it is working well and fast, if we are bored in the future we could do the research (a lot of it) to reduce the border radius
|
|
||||||
|
|
||||||
// to get the chunks we need to generate in the nth chunk status, we need to know how many chunks
|
|
||||||
// we need to generate in the n + 1 th chunk status. Summing up the margin solves that
|
|
||||||
LinkedHashMap<ChunkStatus, long[]> chunkCoordsForChunkStatus = new LinkedHashMap<>();
|
|
||||||
int borderSum = 1;
|
|
||||||
// TODO (j21): use SequencedMap#sequencedKeySet().reversed()
|
|
||||||
final List<ChunkStatus> reversedKeys = Lists.reverse(new ArrayList<>(chunkStatuses.keySet()));
|
|
||||||
for (final ChunkStatus status : reversedKeys) {
|
|
||||||
chunkCoordsForChunkStatus.put(status, getChunkCoordsRegen(region, borderSum));
|
|
||||||
borderSum += status.requiredNeighborChunkRadius();
|
|
||||||
}
|
|
||||||
|
|
||||||
//create chunks
|
|
||||||
// TODO (j21): use SequencedMap#firstEntry().getKey()
|
|
||||||
for (long xz : chunkCoordsForChunkStatus.get(chunkStatuses.keySet().iterator().next())) {
|
|
||||||
ProtoChunk chunk = createProtoChunk(MathMan.unpairIntX(xz), MathMan.unpairIntY(xz));
|
|
||||||
protoChunks.put(xz, chunk);
|
|
||||||
}
|
|
||||||
|
|
||||||
// a memory-efficient, lightweight "list" that calculates index -> ChunkAccess
|
|
||||||
// as needed when accessed
|
|
||||||
class LazyChunkList extends AbstractList<IChunkAccess> {
|
|
||||||
private final int size;
|
|
||||||
private final int minX;
|
|
||||||
private final int minZ;
|
|
||||||
private final int sizeSqrt;
|
|
||||||
|
|
||||||
LazyChunkList(int radius, int centerX, int centerZ) {
|
|
||||||
this.sizeSqrt = radius + 1 + radius; // length of one side
|
|
||||||
this.size = this.sizeSqrt * this.sizeSqrt;
|
|
||||||
this.minX = centerX - radius;
|
|
||||||
this.minZ = centerZ - radius;
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public IChunkAccess get(final int index) {
|
|
||||||
Objects.checkIndex(index, size);
|
|
||||||
int absX = (index % sizeSqrt) + minX;
|
|
||||||
int absZ = (index / sizeSqrt) + minZ;
|
|
||||||
return protoChunks.get(MathMan.pairInt(absX, absZ));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size() {
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@Label("Regeneration")
|
|
||||||
@Category("FAWE")
|
|
||||||
@Name("fawe.regen")
|
|
||||||
class RegenerationEvent extends Event {
|
|
||||||
private String chunkStatus;
|
|
||||||
private int chunksToProcess;
|
|
||||||
}
|
|
||||||
|
|
||||||
//run generation tasks excluding FULL chunk status
|
|
||||||
for (Map.Entry<ChunkStatus, Concurrency> entry : chunkStatuses.entrySet()) {
|
|
||||||
ChunkStatus chunkStatus = entry.getKey();
|
|
||||||
final RegenerationEvent event = new RegenerationEvent();
|
|
||||||
event.begin();
|
|
||||||
event.chunkStatus = chunkStatus.name();
|
|
||||||
int radius = Math.max(1, chunkStatus.requiredNeighborChunkRadius0());
|
|
||||||
|
|
||||||
long[] coords = chunkCoordsForChunkStatus.get(chunkStatus);
|
|
||||||
event.chunksToProcess = coords.length;
|
|
||||||
if (this.generateConcurrent && entry.getValue() == Concurrency.RADIUS) {
|
|
||||||
SequentialTasks<ConcurrentTasks<LongList>> tasks = getChunkStatusTaskRows(coords, radius);
|
|
||||||
for (ConcurrentTasks<LongList> para : tasks) {
|
|
||||||
List<Runnable> scheduled = new ArrayList<>(tasks.size());
|
|
||||||
for (LongList row : para) {
|
|
||||||
scheduled.add(() -> {
|
|
||||||
for (long xz : row) {
|
|
||||||
chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz),
|
|
||||||
MathMan.unpairIntY(xz)));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
runAndWait(scheduled);
|
|
||||||
}
|
|
||||||
} else if (this.generateConcurrent && entry.getValue() == Concurrency.FULL) {
|
|
||||||
// every chunk can be processed individually
|
|
||||||
List<Runnable> scheduled = new ArrayList<>(coords.length);
|
|
||||||
for (long xz : coords) {
|
|
||||||
scheduled.add(() -> chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz),
|
|
||||||
MathMan.unpairIntY(xz))));
|
|
||||||
}
|
|
||||||
runAndWait(scheduled);
|
|
||||||
} else { // Concurrency.NONE or generateConcurrent == false
|
|
||||||
// run sequential but submit to different thread
|
|
||||||
// running regen on the main thread otherwise triggers async-only events on the main thread
|
|
||||||
executor.submit(() -> {
|
|
||||||
for (long xz : coords) {
|
|
||||||
chunkStatus.processChunkSave(xz, new LazyChunkList(radius, MathMan.unpairIntX(xz),
|
|
||||||
MathMan.unpairIntY(xz)));
|
|
||||||
}
|
|
||||||
}).get(); // wait until finished this step
|
|
||||||
}
|
|
||||||
event.commit();
|
|
||||||
}
|
|
||||||
|
|
||||||
//convert to proper chunks
|
|
||||||
// TODO (j21): use SequencedMap#firstEntry().getValue()
|
|
||||||
for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) {
|
|
||||||
ProtoChunk proto = protoChunks.get(xz);
|
|
||||||
chunks.put(xz, createChunk(proto));
|
|
||||||
}
|
|
||||||
|
|
||||||
//final chunkstatus
|
|
||||||
ChunkStatus FULL = getFullChunkStatus();
|
|
||||||
// TODO (j21): use SequencedMap#firstEntry().getValue()
|
|
||||||
for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) { //FULL.requiredNeighbourChunkRadius() == 0!
|
|
||||||
Chunk chunk = chunks.get(xz);
|
|
||||||
FULL.processChunkSave(xz, List.of(chunk));
|
|
||||||
}
|
|
||||||
|
|
||||||
//populate
|
|
||||||
List<BlockPopulator> populators = getBlockPopulators();
|
|
||||||
// TODO (j21): use SequencedMap#firstEntry().getValue()
|
|
||||||
for (long xz : chunkCoordsForChunkStatus.values().iterator().next()) {
|
|
||||||
int x = MathMan.unpairIntX(xz);
|
|
||||||
int z = MathMan.unpairIntY(xz);
|
|
||||||
|
|
||||||
//prepare chunk seed
|
|
||||||
Random random = getChunkRandom(seed, x, z);
|
|
||||||
|
|
||||||
//actually populate
|
|
||||||
Chunk c = chunks.get(xz);
|
|
||||||
populators.forEach(pop -> {
|
|
||||||
populate(c, random, pop);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
source = new SingleThreadQueueExtent(
|
source = new SingleThreadQueueExtent(
|
||||||
BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMinHeight() : 0,
|
BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMinHeight() : 0,
|
||||||
BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMaxHeight() : 256
|
BukkitWorld.HAS_MIN_Y ? originalBukkitWorld.getMaxHeight() : 256
|
||||||
);
|
);
|
||||||
source.init(target, initSourceQueueCache(), null);
|
source.init(target, initSourceQueueCache(), null);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void runAndWait(final List<Runnable> tasks) {
|
|
||||||
try {
|
|
||||||
List<Future<?>> futures = new ArrayList<>();
|
|
||||||
tasks.forEach(task -> futures.add(executor.submit(task)));
|
|
||||||
for (Future<?> future : futures) {
|
|
||||||
future.get();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.catching(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyToWorld() {
|
private void copyToWorld() {
|
||||||
|
createSource();
|
||||||
|
final long timeoutPerTick = TimeUnit.MILLISECONDS.toNanos(10);
|
||||||
|
int taskId = TaskManager.taskManager().repeat(() -> {
|
||||||
|
final long startTime = System.nanoTime();
|
||||||
|
runTasks(() -> System.nanoTime() - startTime < timeoutPerTick);
|
||||||
|
}, 1);
|
||||||
//Setting Blocks
|
//Setting Blocks
|
||||||
boolean genbiomes = options.shouldRegenBiomes();
|
boolean genbiomes = options.shouldRegenBiomes();
|
||||||
boolean hasBiome = options.hasBiomeType();
|
boolean hasBiome = options.hasBiomeType();
|
||||||
@ -343,6 +117,7 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
} else if (genbiomes) {
|
} else if (genbiomes) {
|
||||||
target.setBlocks(region, new WithBiomePlacementPattern(vec -> source.getBiome(vec)));
|
target.setBlocks(region, new WithBiomePlacementPattern(vec -> source.getBiome(vec)));
|
||||||
}
|
}
|
||||||
|
TaskManager.taskManager().cancel(taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PlacementPattern implements Pattern {
|
private class PlacementPattern implements Pattern {
|
||||||
@ -382,9 +157,6 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
|
|
||||||
//functions to be implemented by sub class
|
//functions to be implemented by sub class
|
||||||
private void cleanup0() {
|
private void cleanup0() {
|
||||||
if (executor != null) {
|
|
||||||
executor.shutdownNow();
|
|
||||||
}
|
|
||||||
cleanup();
|
cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,47 +188,6 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
*/
|
*/
|
||||||
protected abstract void cleanup();
|
protected abstract void cleanup();
|
||||||
|
|
||||||
/**
|
|
||||||
* Implement the initialization of a {@code ProtoChunk} here.
|
|
||||||
*
|
|
||||||
* @param x the x coorinate of the {@code ProtoChunk} to create
|
|
||||||
* @param z the z coorinate of the {@code ProtoChunk} to create
|
|
||||||
* @return an initialized {@code ProtoChunk}
|
|
||||||
*/
|
|
||||||
protected abstract ProtoChunk createProtoChunk(int x, int z);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implement the convertion of a {@code ProtoChunk} to a {@code Chunk} here.
|
|
||||||
*
|
|
||||||
* @param protoChunk the {@code ProtoChunk} to be converted to a {@code Chunk}
|
|
||||||
* @return the converted {@code Chunk}
|
|
||||||
*/
|
|
||||||
protected abstract Chunk createChunk(ProtoChunk protoChunk);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the {@code ChunkStatus.FULL} here.
|
|
||||||
* ChunkStatus.FULL is the last step of vanilla chunk generation.
|
|
||||||
*
|
|
||||||
* @return {@code ChunkStatus.FULL}
|
|
||||||
*/
|
|
||||||
protected abstract ChunkStatus getFullChunkStatus();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return a list of {@code BlockPopulator} used to populate the original world here.
|
|
||||||
*
|
|
||||||
* @return {@code ChunkStatus.FULL}
|
|
||||||
*/
|
|
||||||
protected abstract List<BlockPopulator> getBlockPopulators();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implement the population of the {@code Chunk} with the given chunk random and {@code BlockPopulator} here.
|
|
||||||
*
|
|
||||||
* @param chunk the {@code Chunk} to populate
|
|
||||||
* @param random the chunk random to use for population
|
|
||||||
* @param pop the {@code BlockPopulator} to use
|
|
||||||
*/
|
|
||||||
protected abstract void populate(Chunk chunk, Random random, BlockPopulator pop);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implement the initialization an {@code IChunkCache<IChunkGet>} here. Use will need the {@code getChunkAt} function
|
* Implement the initialization an {@code IChunkCache<IChunkGet>} here. Use will need the {@code getChunkAt} function
|
||||||
*
|
*
|
||||||
@ -464,106 +195,6 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
*/
|
*/
|
||||||
protected abstract IChunkCache<IChunkGet> initSourceQueueCache();
|
protected abstract IChunkCache<IChunkGet> initSourceQueueCache();
|
||||||
|
|
||||||
//algorithms
|
|
||||||
private long[] getChunkCoordsRegen(Region region, int border) { //needs to be square num of chunks
|
|
||||||
BlockVector3 oldMin = region.getMinimumPoint();
|
|
||||||
BlockVector3 newMin = BlockVector3.at(
|
|
||||||
(oldMin.x() >> 4 << 4) - border * 16,
|
|
||||||
oldMin.y(),
|
|
||||||
(oldMin.z() >> 4 << 4) - border * 16
|
|
||||||
);
|
|
||||||
BlockVector3 oldMax = region.getMaximumPoint();
|
|
||||||
BlockVector3 newMax = BlockVector3.at(
|
|
||||||
(oldMax.x() >> 4 << 4) + (border + 1) * 16 - 1,
|
|
||||||
oldMax.y(),
|
|
||||||
(oldMax.z() >> 4 << 4) + (border + 1) * 16 - 1
|
|
||||||
);
|
|
||||||
Region adjustedRegion = new CuboidRegion(newMin, newMax);
|
|
||||||
return adjustedRegion.getChunks().stream()
|
|
||||||
.sorted(Comparator
|
|
||||||
.comparingInt(BlockVector2::z)
|
|
||||||
.thenComparingInt(BlockVector2::x)) //needed for RegionLimitedWorldAccess
|
|
||||||
.mapToLong(c -> MathMan.pairInt(c.x(), c.z()))
|
|
||||||
.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a list of chunkcoord rows that may be executed concurrently
|
|
||||||
*
|
|
||||||
* @param allCoords the coords that should be sorted into rows, must be sorted by z and x
|
|
||||||
* @param requiredNeighborChunkRadius the radius of neighbor chunks that may not be written to concurrently (ChunkStatus
|
|
||||||
* .requiredNeighborRadius)
|
|
||||||
* @return a list of chunkcoords rows that may be executed concurrently
|
|
||||||
*/
|
|
||||||
private SequentialTasks<ConcurrentTasks<LongList>> getChunkStatusTaskRows(
|
|
||||||
long[] allCoords,
|
|
||||||
int requiredNeighborChunkRadius
|
|
||||||
) {
|
|
||||||
int requiredNeighbors = Math.max(0, requiredNeighborChunkRadius);
|
|
||||||
|
|
||||||
final int coordsCount = allCoords.length;
|
|
||||||
long first = coordsCount == 0 ? 0 : allCoords[0];
|
|
||||||
long last = coordsCount == 0 ? 0 : allCoords[coordsCount - 1];
|
|
||||||
int minX = MathMan.unpairIntX(first);
|
|
||||||
int maxX = MathMan.unpairIntX(last);
|
|
||||||
int minZ = MathMan.unpairIntY(first);
|
|
||||||
int maxZ = MathMan.unpairIntY(last);
|
|
||||||
SequentialTasks<ConcurrentTasks<LongList>> tasks;
|
|
||||||
if (maxZ - minZ > maxX - minX) {
|
|
||||||
int numlists = Math.min(requiredNeighbors * 2 + 1, maxX - minX + 1);
|
|
||||||
|
|
||||||
Int2ObjectOpenHashMap<LongList> byX = new Int2ObjectOpenHashMap<>();
|
|
||||||
int expectedListLength = (coordsCount + 1) / (maxX - minX);
|
|
||||||
|
|
||||||
//init lists
|
|
||||||
for (int i = minX; i <= maxX; i++) {
|
|
||||||
byX.put(i, new LongArrayList(expectedListLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
//sort into lists by x coord
|
|
||||||
for (long allCoord : allCoords) {
|
|
||||||
byX.get(MathMan.unpairIntX(allCoord)).add(allCoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
//create parallel tasks
|
|
||||||
tasks = new SequentialTasks<>(numlists);
|
|
||||||
for (int offset = 0; offset < numlists; offset++) {
|
|
||||||
ConcurrentTasks<LongList> para = new ConcurrentTasks<>((maxZ - minZ + 1) / numlists + 1);
|
|
||||||
for (int i = 0; minX + i * numlists + offset <= maxX; i++) {
|
|
||||||
para.add(byX.get(minX + i * numlists + offset));
|
|
||||||
}
|
|
||||||
tasks.add(para);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
int numlists = Math.min(requiredNeighbors * 2 + 1, maxZ - minZ + 1);
|
|
||||||
|
|
||||||
Int2ObjectOpenHashMap<LongList> byZ = new Int2ObjectOpenHashMap<>();
|
|
||||||
int expectedListLength = (coordsCount + 1) / (maxZ - minZ + 2);
|
|
||||||
|
|
||||||
//init lists
|
|
||||||
for (int i = minZ; i <= maxZ; i++) {
|
|
||||||
byZ.put(i, new LongArrayList(expectedListLength));
|
|
||||||
}
|
|
||||||
|
|
||||||
//sort into lists by x coord
|
|
||||||
for (long allCoord : allCoords) {
|
|
||||||
byZ.get(MathMan.unpairIntY(allCoord)).add(allCoord);
|
|
||||||
}
|
|
||||||
|
|
||||||
//create parallel tasks
|
|
||||||
tasks = new SequentialTasks<>(numlists);
|
|
||||||
for (int offset = 0; offset < numlists; offset++) {
|
|
||||||
ConcurrentTasks<LongList> para = new ConcurrentTasks<>((maxX - minX + 1) / numlists + 1);
|
|
||||||
for (int i = 0; minZ + i * numlists + offset <= maxZ; i++) {
|
|
||||||
para.add(byZ.get(minZ + i * numlists + offset));
|
|
||||||
}
|
|
||||||
tasks.add(para);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected BiomeProvider getBiomeProvider() {
|
protected BiomeProvider getBiomeProvider() {
|
||||||
if (options.hasBiomeType()) {
|
if (options.hasBiomeType()) {
|
||||||
return new SingleBiomeProvider();
|
return new SingleBiomeProvider();
|
||||||
@ -579,103 +210,6 @@ public abstract class Regenerator<IChunkAccess, ProtoChunk extends IChunkAccess,
|
|||||||
NONE
|
NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This class is used to wrap the ChunkStatus of the current Minecraft implementation and as the implementation to execute a chunk generation step.
|
|
||||||
*
|
|
||||||
* @param <IChunkAccess> the IChunkAccess class of the current Minecraft implementation
|
|
||||||
*/
|
|
||||||
public static abstract class ChunkStatusWrapper<IChunkAccess> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the required neighbor chunk radius the wrapped {@code ChunkStatus} requires.
|
|
||||||
*
|
|
||||||
* @return the radius of required neighbor chunks
|
|
||||||
*/
|
|
||||||
public abstract int requiredNeighborChunkRadius();
|
|
||||||
|
|
||||||
int requiredNeighborChunkRadius0() {
|
|
||||||
return Math.max(0, requiredNeighborChunkRadius());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the name of the wrapped {@code ChunkStatus}.
|
|
||||||
*
|
|
||||||
* @return the radius of required neighbor chunks
|
|
||||||
*/
|
|
||||||
public abstract String name();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the name of the wrapped {@code ChunkStatus}.
|
|
||||||
*
|
|
||||||
* @param accessibleChunks a list of chunks that will be used during the execution of the wrapped {@code ChunkStatus}.
|
|
||||||
* This list is order in the correct order required by the {@code ChunkStatus}, unless Mojang suddenly decides to do things differently.
|
|
||||||
*/
|
|
||||||
public abstract CompletableFuture<?> processChunk(List<IChunkAccess> accessibleChunks);
|
|
||||||
|
|
||||||
void processChunkSave(long xz, List<IChunkAccess> accessibleChunks) {
|
|
||||||
try {
|
|
||||||
processChunk(accessibleChunks).get();
|
|
||||||
} catch (Exception e) {
|
|
||||||
LOGGER.error("Error while running {} on chunk {}/{}",
|
|
||||||
name(), MathMan.unpairIntX(xz), MathMan.unpairIntY(xz), e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return name();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class SequentialTasks<T> extends Tasks<T> {
|
|
||||||
|
|
||||||
public SequentialTasks(int expectedSize) {
|
|
||||||
super(expectedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ConcurrentTasks<T> extends Tasks<T> {
|
|
||||||
|
|
||||||
public ConcurrentTasks(int expectedSize) {
|
|
||||||
super(expectedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class Tasks<T> implements Iterable<T> {
|
|
||||||
|
|
||||||
private final List<T> tasks;
|
|
||||||
|
|
||||||
public Tasks(int expectedSize) {
|
|
||||||
tasks = new ArrayList<>(expectedSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void add(T task) {
|
|
||||||
tasks.add(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<T> list() {
|
|
||||||
return tasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
|
||||||
return tasks.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<T> iterator() {
|
|
||||||
return tasks.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return tasks.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SingleBiomeProvider extends BiomeProvider {
|
public class SingleBiomeProvider extends BiomeProvider {
|
||||||
|
|
||||||
private final org.bukkit.block.Biome biome = BukkitAdapter.adapt(options.getBiomeType());
|
private final org.bukkit.block.Biome biome = BukkitAdapter.adapt(options.getBiomeType());
|
||||||
|
@ -3,7 +3,9 @@ package com.fastasyncworldedit.bukkit.regions;
|
|||||||
import com.fastasyncworldedit.core.regions.FaweMask;
|
import com.fastasyncworldedit.core.regions.FaweMask;
|
||||||
import com.griefdefender.api.GriefDefender;
|
import com.griefdefender.api.GriefDefender;
|
||||||
import com.griefdefender.api.claim.Claim;
|
import com.griefdefender.api.claim.Claim;
|
||||||
|
import com.griefdefender.api.claim.ClaimManager;
|
||||||
import com.griefdefender.api.claim.TrustTypes;
|
import com.griefdefender.api.claim.TrustTypes;
|
||||||
|
import com.griefdefender.lib.flowpowered.math.vector.Vector3i;
|
||||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
@ -17,8 +19,8 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener
|
|||||||
|
|
||||||
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
private static final Logger LOGGER = LogManagerCompat.getLogger();
|
||||||
|
|
||||||
public GriefDefenderFeature(final Plugin GriefDefenderPlugin) {
|
public GriefDefenderFeature(final Plugin plugin) {
|
||||||
super(GriefDefenderPlugin.getName());
|
super(plugin.getName());
|
||||||
LOGGER.info("Plugin 'GriefDefender' found. Using it now.");
|
LOGGER.info("Plugin 'GriefDefender' found. Using it now.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -44,9 +46,14 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener
|
|||||||
);
|
);
|
||||||
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
return new FaweMask(new CuboidRegion(pos1, pos2)) {
|
||||||
|
|
||||||
|
private final int[] bounds = new int[]{
|
||||||
|
pos1.x(), pos1.y(), pos1.z(),
|
||||||
|
pos2.x(), pos2.y(), pos2.z()
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isValid(com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
public boolean isValid(com.sk89q.worldedit.entity.Player wePlayer, MaskType type) {
|
||||||
return isAllowed(player, claim, type);
|
return validateClaimAgainstCache(claim, bounds) && isAllowed(player, claim, type);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -54,4 +61,20 @@ public class GriefDefenderFeature extends BukkitMaskManager implements Listener
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean validateClaimAgainstCache(Claim claim, int[] bounds) {
|
||||||
|
Vector3i min = claim.getLesserBoundaryCorner();
|
||||||
|
Vector3i max = claim.getGreaterBoundaryCorner();
|
||||||
|
if (min.getX() != bounds[0] || min.getY() != bounds[1] || min.getZ() != bounds[2]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (max.getX() != bounds[3] || max.getY() != bounds[4] || max.getZ() != bounds[5]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
final ClaimManager manager = GriefDefender.getCore().getClaimManager(claim.getWorldUniqueId());
|
||||||
|
if (manager == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return manager.getClaimByUUID(claim.getUniqueId()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,12 @@ import com.fastasyncworldedit.core.Fawe;
|
|||||||
import com.fastasyncworldedit.core.FaweCache;
|
import com.fastasyncworldedit.core.FaweCache;
|
||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.fastasyncworldedit.core.util.TaskManager;
|
import com.fastasyncworldedit.core.util.TaskManager;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.blocks.BaseItem;
|
import com.sk89q.worldedit.blocks.BaseItem;
|
||||||
@ -118,9 +118,9 @@ public class BukkitWorld extends AbstractWorld {
|
|||||||
HAS_MIN_Y = temp;
|
HAS_MIN_Y = temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
private WeakReference<World> worldRef;
|
protected WeakReference<World> worldRef;
|
||||||
//FAWE start
|
//FAWE start
|
||||||
private final String worldNameRef;
|
protected final String worldNameRef;
|
||||||
//FAWE end
|
//FAWE end
|
||||||
private final WorldNativeAccess<?, ?, ?> worldNativeAccess;
|
private final WorldNativeAccess<?, ?, ?> worldNativeAccess;
|
||||||
|
|
||||||
@ -665,7 +665,7 @@ public class BukkitWorld extends AbstractWorld {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +165,11 @@ public class BukkitImplLoader {
|
|||||||
* @throws AdapterLoadException thrown if no adapter could be found
|
* @throws AdapterLoadException thrown if no adapter could be found
|
||||||
*/
|
*/
|
||||||
public BukkitImplAdapter loadAdapter() throws AdapterLoadException {
|
public BukkitImplAdapter loadAdapter() throws AdapterLoadException {
|
||||||
|
// FAWE - do not initialize classes on lookup
|
||||||
|
final ClassLoader classLoader = this.getClass().getClassLoader();
|
||||||
for (String className : adapterCandidates) {
|
for (String className : adapterCandidates) {
|
||||||
try {
|
try {
|
||||||
Class<?> cls = Class.forName(className);
|
Class<?> cls = Class.forName(className, false, classLoader);
|
||||||
if (cls.isSynthetic()) {
|
if (cls.isSynthetic()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
|
|
||||||
package com.sk89q.worldedit.cli.schematic;
|
package com.sk89q.worldedit.cli.schematic;
|
||||||
|
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
import com.fastasyncworldedit.core.queue.implementation.packet.ChunkPacket;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
@ -193,7 +193,7 @@ public class ClipboardWorld extends AbstractWorld implements Clipboard, CLIWorld
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
public boolean tile(int x, int y, int z, FaweCompoundTag tile) throws WorldEditException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,6 +365,18 @@ public class Fawe {
|
|||||||
Settings.settings().QUEUE.PARALLEL_THREADS
|
Settings.settings().QUEUE.PARALLEL_THREADS
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (Settings.settings().HISTORY.DELETE_DISK_ON_LOGOUT && Settings.settings().HISTORY.USE_DATABASE) {
|
||||||
|
LOGGER.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||||
|
LOGGER.warn("!!! !!!");
|
||||||
|
LOGGER.warn("!!! Using history database whilst deleting disk history! !!!");
|
||||||
|
LOGGER.warn("!!! You will not be able to rollback edits after a user logs !!!");
|
||||||
|
LOGGER.warn("!!! out, recommended to disable delete-disk-on-logout if you !!!");
|
||||||
|
LOGGER.warn("!!! you want to have full history rollback functionality. !!!");
|
||||||
|
LOGGER.warn("!!! Disable use-database if you do not need to have rollback !!!");
|
||||||
|
LOGGER.warn("!!! functionality and wish to disable this warning. !!!");
|
||||||
|
LOGGER.warn("!!! !!!");
|
||||||
|
LOGGER.warn("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
byte[] in = new byte[0];
|
byte[] in = new byte[0];
|
||||||
byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in);
|
byte[] compressed = LZ4Factory.fastestJavaInstance().fastCompressor().compress(in);
|
||||||
|
@ -192,17 +192,22 @@ public enum FaweCache implements Trimable {
|
|||||||
Type.OUTSIDE_REGION
|
Type.OUTSIDE_REGION
|
||||||
);
|
);
|
||||||
public static final FaweException MAX_CHECKS = new FaweException(
|
public static final FaweException MAX_CHECKS = new FaweException(
|
||||||
Caption.of("fawe.cancel.reason.max" + ".checks"),
|
Caption.of("fawe.cancel.reason.max.checks"),
|
||||||
|
Type.MAX_CHECKS,
|
||||||
|
true
|
||||||
|
);
|
||||||
|
public static final FaweException MAX_FAILS = new FaweException(
|
||||||
|
Caption.of("fawe.cancel.reason.max.fails"),
|
||||||
Type.MAX_CHECKS,
|
Type.MAX_CHECKS,
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
public static final FaweException MAX_CHANGES = new FaweException(
|
public static final FaweException MAX_CHANGES = new FaweException(
|
||||||
Caption.of("fawe.cancel.reason.max" + ".changes"),
|
Caption.of("fawe.cancel.reason.max.changes"),
|
||||||
Type.MAX_CHANGES,
|
Type.MAX_CHANGES,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
public static final FaweException LOW_MEMORY = new FaweException(
|
public static final FaweException LOW_MEMORY = new FaweException(
|
||||||
Caption.of("fawe.cancel.reason.low" + ".memory"),
|
Caption.of("fawe.cancel.reason.low.memory"),
|
||||||
Type.LOW_MEMORY,
|
Type.LOW_MEMORY,
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
@ -123,29 +123,31 @@ public class Settings extends Config {
|
|||||||
limit.MAX_ACTIONS,
|
limit.MAX_ACTIONS,
|
||||||
newLimit.MAX_ACTIONS != -1 ? newLimit.MAX_ACTIONS : Integer.MAX_VALUE
|
newLimit.MAX_ACTIONS != -1 ? newLimit.MAX_ACTIONS : Integer.MAX_VALUE
|
||||||
);
|
);
|
||||||
limit.MAX_CHANGES = Math.max(
|
limit.MAX_CHANGES.set(Math.max(
|
||||||
limit.MAX_CHANGES,
|
limit.MAX_CHANGES.get(),
|
||||||
newLimit.MAX_CHANGES != -1 ? newLimit.MAX_CHANGES : Long.MAX_VALUE
|
newLimit.MAX_CHANGES != -1 ? newLimit.MAX_CHANGES : Long.MAX_VALUE
|
||||||
);
|
));
|
||||||
limit.MAX_BLOCKSTATES = Math.max(
|
limit.MAX_BLOCKSTATES.set(Math.max(
|
||||||
limit.MAX_BLOCKSTATES,
|
limit.MAX_BLOCKSTATES.get(),
|
||||||
newLimit.MAX_BLOCKSTATES != -1 ? newLimit.MAX_BLOCKSTATES : Integer.MAX_VALUE
|
newLimit.MAX_BLOCKSTATES != -1 ? newLimit.MAX_BLOCKSTATES : Integer.MAX_VALUE
|
||||||
);
|
));
|
||||||
limit.MAX_CHECKS = Math.max(
|
limit.MAX_CHECKS.set(Math.max(
|
||||||
limit.MAX_CHECKS,
|
limit.MAX_CHECKS.get(),
|
||||||
newLimit.MAX_CHECKS != -1 ? newLimit.MAX_CHECKS : Long.MAX_VALUE
|
newLimit.MAX_CHECKS != -1 ? newLimit.MAX_CHECKS : Long.MAX_VALUE
|
||||||
);
|
));
|
||||||
limit.MAX_ENTITIES = Math.max(
|
limit.MAX_ENTITIES.set(Math.max(
|
||||||
limit.MAX_ENTITIES,
|
limit.MAX_ENTITIES.get(),
|
||||||
newLimit.MAX_ENTITIES != -1 ? newLimit.MAX_ENTITIES : Integer.MAX_VALUE
|
newLimit.MAX_ENTITIES != -1 ? newLimit.MAX_ENTITIES : Integer.MAX_VALUE
|
||||||
);
|
));
|
||||||
limit.MAX_FAILS = Math.max(limit.MAX_FAILS, newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE);
|
limit.MAX_FAILS.set(Math.max(
|
||||||
limit.MAX_ITERATIONS = Math.max(
|
limit.MAX_FAILS.get(),
|
||||||
limit.MAX_ITERATIONS, newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE);
|
newLimit.MAX_FAILS != -1 ? newLimit.MAX_FAILS : Integer.MAX_VALUE
|
||||||
limit.MAX_RADIUS = Math.max(
|
));
|
||||||
limit.MAX_RADIUS,
|
limit.MAX_ITERATIONS.set(Math.max(
|
||||||
newLimit.MAX_RADIUS != -1 ? newLimit.MAX_RADIUS : Integer.MAX_VALUE
|
limit.MAX_ITERATIONS.get(),
|
||||||
);
|
newLimit.MAX_ITERATIONS != -1 ? newLimit.MAX_ITERATIONS : Integer.MAX_VALUE
|
||||||
|
));
|
||||||
|
limit.MAX_RADIUS = Math.max(limit.MAX_RADIUS, newLimit.MAX_RADIUS != -1 ? newLimit.MAX_RADIUS : Integer.MAX_VALUE);
|
||||||
limit.MAX_SUPER_PICKAXE_SIZE = Math.max(
|
limit.MAX_SUPER_PICKAXE_SIZE = Math.max(
|
||||||
limit.MAX_SUPER_PICKAXE_SIZE,
|
limit.MAX_SUPER_PICKAXE_SIZE,
|
||||||
newLimit.MAX_SUPER_PICKAXE_SIZE != -1 ? newLimit.MAX_SUPER_PICKAXE_SIZE : Integer.MAX_VALUE
|
newLimit.MAX_SUPER_PICKAXE_SIZE != -1 ? newLimit.MAX_SUPER_PICKAXE_SIZE : Integer.MAX_VALUE
|
||||||
@ -622,6 +624,13 @@ public class Settings extends Config {
|
|||||||
})
|
})
|
||||||
public static class EXPERIMENTAL {
|
public static class EXPERIMENTAL {
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Undo operation batch size",
|
||||||
|
" - The size defines the number of changes read at once.",
|
||||||
|
" - Larger numbers might reduce overhead but increase latency for edits with only few changes.",
|
||||||
|
" - 0 means undo operations are not batched."})
|
||||||
|
public int UNDO_BATCH_SIZE = 128;
|
||||||
|
|
||||||
@Comment({
|
@Comment({
|
||||||
"[UNSAFE] Directly modify the region files. (OBSOLETE - USE ANVIL COMMANDS)",
|
"[UNSAFE] Directly modify the region files. (OBSOLETE - USE ANVIL COMMANDS)",
|
||||||
" - IMPROPER USE CAN CAUSE WORLD CORRUPTION!",
|
" - IMPROPER USE CAN CAUSE WORLD CORRUPTION!",
|
||||||
@ -668,6 +677,11 @@ public class Settings extends Config {
|
|||||||
})
|
})
|
||||||
public boolean ALLOW_TICK_FLUIDS = false;
|
public boolean ALLOW_TICK_FLUIDS = false;
|
||||||
|
|
||||||
|
@Comment({
|
||||||
|
"Whether FAWE should use the incubator Vector API to accelerate some operations"
|
||||||
|
})
|
||||||
|
public boolean USE_VECTOR_API = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Comment({"Web/HTTP connection related settings"})
|
@Comment({"Web/HTTP connection related settings"})
|
||||||
|
@ -19,9 +19,9 @@ public class AdjacentMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
|
||||||
} else if (index == 1 || index == 2) {
|
} else if (index == 1 || index == 2) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class AngleMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0 || index == 1) {
|
if (index == 0 || index == 1) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
|
||||||
} else if (index > 1 && index <= 1 + flags.length) {
|
} else if (index > 1 && index <= 1 + flags.length) {
|
||||||
|
@ -18,9 +18,9 @@ public class BesideMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(final String argumentInput, final int index) {
|
protected Stream<String> getSuggestions(final String argumentInput, final int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
|
||||||
} else if (index == 1 || index == 2) {
|
} else if (index == 1 || index == 2) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ public class ExtremaMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0 || index == 1) {
|
if (index == 0 || index == 1) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
|
||||||
} else if (index > 1 && index <= 1 + flags.length) {
|
} else if (index > 1 && index <= 1 + flags.length) {
|
||||||
|
@ -22,7 +22,7 @@ public class ROCAngleMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0 || index == 1) {
|
if (index == 0 || index == 1) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput).flatMap(s -> Stream.of(s, s + "d"));
|
||||||
} else if (index > 1 && index <= 1 + flags.length) {
|
} else if (index > 1 && index <= 1 + flags.length) {
|
||||||
|
@ -18,7 +18,7 @@ public class RadiusMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0 || index == 1) {
|
if (index == 0 || index == 1) {
|
||||||
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
}
|
}
|
||||||
|
@ -24,12 +24,12 @@ public class RichOffsetMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index < 3) {
|
if (index < 3) {
|
||||||
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
}
|
}
|
||||||
if (index == 3) {
|
if (index == 3) {
|
||||||
return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ public class SimplexMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index < 3) {
|
if (index < 3) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ public class SurfaceAngleMaskParser extends RichParser<Mask> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index <= 2) {
|
if (index <= 2) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public class AngleColorPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index != 0) {
|
if (index != 0) {
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public class AverageColorPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index > 4) {
|
if (index > 4) {
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ public class BiomePatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return BiomeType.REGISTRY.getSuggestions(argumentInput);
|
return BiomeType.REGISTRY.getSuggestions(argumentInput);
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ public class BufferedPattern2DParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -26,9 +26,9 @@ public class BufferedPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public class ColorPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index > 4) {
|
if (index > 4) {
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public class DesaturatePatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
}
|
}
|
||||||
|
@ -28,9 +28,9 @@ public class Linear2DPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1, 2 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
case 1, 2 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
|
@ -28,9 +28,9 @@ public class Linear3DPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
|
@ -28,9 +28,9 @@ public class LinearPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
|
@ -25,10 +25,10 @@ public class MaskedPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getMaskFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getMaskFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1, 2 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 1, 2 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,9 @@ public class NoXPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,9 @@ public class NoYPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -24,9 +24,9 @@ public class NoZPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -36,12 +36,12 @@ public abstract class NoisePatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
}
|
}
|
||||||
if (index == 1) {
|
if (index == 1) {
|
||||||
return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ public class OffsetPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@ import com.fastasyncworldedit.core.configuration.Caption;
|
|||||||
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
|
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
|
||||||
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
|
import com.fastasyncworldedit.core.extent.clipboard.MultiClipboardHolder;
|
||||||
import com.fastasyncworldedit.core.function.pattern.RandomFullClipboardPattern;
|
import com.fastasyncworldedit.core.function.pattern.RandomFullClipboardPattern;
|
||||||
|
import com.google.common.base.Function;
|
||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.command.util.SuggestionHelper;
|
import com.sk89q.worldedit.command.util.SuggestionHelper;
|
||||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||||
@ -33,7 +34,7 @@ public class RandomFullClipboardPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
if (argumentInput.equals("#") || argumentInput.equals("#c")) {
|
if (argumentInput.equals("#") || argumentInput.equals("#c")) {
|
||||||
|
@ -25,9 +25,9 @@ public class RandomOffsetPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
|
@ -24,9 +24,9 @@ public class RelativePatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ public class SaturatePatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index > 3) {
|
if (index > 3) {
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,9 @@ public class SolidRandomOffsetPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
case 1, 2, 3 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
|
@ -25,9 +25,9 @@ public class SurfaceRandomOffsetPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
return switch (index) {
|
return switch (index) {
|
||||||
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
case 0 -> this.worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
case 1 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
case 1 -> SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
default -> Stream.empty();
|
default -> Stream.empty();
|
||||||
};
|
};
|
||||||
|
@ -28,7 +28,7 @@ public class TypeSwapPatternParser extends RichParser<Pattern> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Stream<String> getSuggestions(String argumentInput, int index) {
|
public Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index > 2) {
|
if (index > 2) {
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,9 @@ public class Linear3DTransformParser extends RichParser<ResettableExtent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,9 @@ public class LinearTransformParser extends RichParser<ResettableExtent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -26,11 +26,11 @@ public class OffsetTransformParser extends RichParser<ResettableExtent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index < 3) {
|
if (index < 3) {
|
||||||
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
} else if (index == 3) {
|
} else if (index == 3) {
|
||||||
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@ public class PatternTransformParser extends RichParser<ResettableExtent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index == 0) {
|
if (index == 0) {
|
||||||
return worldEdit.getPatternFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getPatternFactory().getSuggestions(argumentInput, context).stream();
|
||||||
} else if (index == 1) {
|
} else if (index == 1) {
|
||||||
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -25,12 +25,12 @@ public class RotateTransformParser extends RichParser<ResettableExtent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index < 3) {
|
if (index < 3) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
}
|
}
|
||||||
if (index == 3) {
|
if (index == 3) {
|
||||||
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@ public class ScaleTransformParser extends RichParser<ResettableExtent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index < 3) {
|
if (index < 3) {
|
||||||
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
return SuggestionHelper.suggestPositiveDoubles(argumentInput);
|
||||||
} else if (index == 3) {
|
} else if (index == 3) {
|
||||||
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -24,11 +24,11 @@ public class SpreadTransformParser extends RichParser<ResettableExtent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Stream<String> getSuggestions(String argumentInput, int index) {
|
protected Stream<String> getSuggestions(String argumentInput, int index, ParserContext context) {
|
||||||
if (index < 3) {
|
if (index < 3) {
|
||||||
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
return SuggestionHelper.suggestPositiveIntegers(argumentInput);
|
||||||
} else if (index == 3) {
|
} else if (index == 3) {
|
||||||
return worldEdit.getTransformFactory().getSuggestions(argumentInput).stream();
|
return worldEdit.getTransformFactory().getSuggestions(argumentInput, context).stream();
|
||||||
}
|
}
|
||||||
return Stream.empty();
|
return Stream.empty();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.fastasyncworldedit.core.extension.platform.binding;
|
||||||
|
|
||||||
|
import com.sk89q.worldedit.EditSession;
|
||||||
|
|
||||||
|
public record EditSessionHolder(EditSession session) {
|
||||||
|
|
||||||
|
}
|
@ -3,7 +3,11 @@ package com.fastasyncworldedit.core.extension.platform.binding;
|
|||||||
import com.fastasyncworldedit.core.configuration.Caption;
|
import com.fastasyncworldedit.core.configuration.Caption;
|
||||||
import com.fastasyncworldedit.core.database.DBHandler;
|
import com.fastasyncworldedit.core.database.DBHandler;
|
||||||
import com.fastasyncworldedit.core.database.RollbackDatabase;
|
import com.fastasyncworldedit.core.database.RollbackDatabase;
|
||||||
|
import com.fastasyncworldedit.core.extent.LimitExtent;
|
||||||
|
import com.fastasyncworldedit.core.extent.processor.ExtentBatchProcessorHolder;
|
||||||
|
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||||
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
import com.fastasyncworldedit.core.regions.FaweMaskManager;
|
||||||
|
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||||
import com.fastasyncworldedit.core.util.TextureUtil;
|
import com.fastasyncworldedit.core.util.TextureUtil;
|
||||||
import com.fastasyncworldedit.core.util.image.ImageUtil;
|
import com.fastasyncworldedit.core.util.image.ImageUtil;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
@ -11,6 +15,7 @@ import com.sk89q.worldedit.LocalSession;
|
|||||||
import com.sk89q.worldedit.WorldEdit;
|
import com.sk89q.worldedit.WorldEdit;
|
||||||
import com.sk89q.worldedit.command.argument.Arguments;
|
import com.sk89q.worldedit.command.argument.Arguments;
|
||||||
import com.sk89q.worldedit.command.util.annotation.AllowedRegion;
|
import com.sk89q.worldedit.command.util.annotation.AllowedRegion;
|
||||||
|
import com.sk89q.worldedit.command.util.annotation.SynchronousSettingExpected;
|
||||||
import com.sk89q.worldedit.entity.Player;
|
import com.sk89q.worldedit.entity.Player;
|
||||||
import com.sk89q.worldedit.extension.input.InputParseException;
|
import com.sk89q.worldedit.extension.input.InputParseException;
|
||||||
import com.sk89q.worldedit.extension.platform.Actor;
|
import com.sk89q.worldedit.extension.platform.Actor;
|
||||||
@ -25,6 +30,7 @@ import org.enginehub.piston.inject.Key;
|
|||||||
import org.enginehub.piston.util.ValueProvider;
|
import org.enginehub.piston.util.ValueProvider;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@ -52,11 +58,33 @@ public class ProvideBindings extends Bindings {
|
|||||||
|
|
||||||
@Binding
|
@Binding
|
||||||
public EditSession editSession(LocalSession localSession, Actor actor, InjectedValueAccess context) {
|
public EditSession editSession(LocalSession localSession, Actor actor, InjectedValueAccess context) {
|
||||||
|
Method commandMethod =
|
||||||
|
context.injectedValue(Key.of(InjectedValueStore.class)).get().injectedValue(Key.of(Method.class)).get();
|
||||||
|
|
||||||
Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null);
|
Arguments arguments = context.injectedValue(Key.of(Arguments.class)).orElse(null);
|
||||||
String command = arguments == null ? null : arguments.get();
|
String command = arguments == null ? null : arguments.get();
|
||||||
EditSession editSession = localSession.createEditSession(actor, command);
|
boolean synchronousSetting = commandMethod.getAnnotation(SynchronousSettingExpected.class) != null;
|
||||||
editSession.enableStandardMode();
|
EditSessionHolder holder = context.injectedValue(Key.of(EditSessionHolder.class)).orElse(null);
|
||||||
Request.request().setEditSession(editSession);
|
EditSession editSession = holder != null ? holder.session() : null;
|
||||||
|
if (editSession == null) {
|
||||||
|
editSession = localSession.createEditSession(actor, command);
|
||||||
|
editSession.enableStandardMode();
|
||||||
|
} else {
|
||||||
|
LimitExtent limitExtent = new ExtentTraverser<>(editSession).findAndGet(LimitExtent.class);
|
||||||
|
if (limitExtent != null) {
|
||||||
|
limitExtent.setProcessing(!synchronousSetting);
|
||||||
|
if (!synchronousSetting) {
|
||||||
|
ExtentBatchProcessorHolder processorHolder = new ExtentTraverser<>(editSession).findAndGet(
|
||||||
|
ExtentBatchProcessorHolder.class);
|
||||||
|
if (processorHolder != null) {
|
||||||
|
processorHolder.addProcessor(limitExtent);
|
||||||
|
} else {
|
||||||
|
throw new FaweException(Caption.of("fawe.error.no-process-non-synchronous-edit"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Request.request().setEditSession(editSession);
|
||||||
|
}
|
||||||
return editSession;
|
return editSession;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package com.fastasyncworldedit.core.extent;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet;
|
import com.fastasyncworldedit.core.history.changeset.AbstractChangeSet;
|
||||||
import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
import com.fastasyncworldedit.core.math.MutableBlockVector3;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
@ -74,7 +75,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
|||||||
public Entity createEntity(Location location, BaseEntity state) {
|
public Entity createEntity(Location location, BaseEntity state) {
|
||||||
final Entity entity = super.createEntity(location, state);
|
final Entity entity = super.createEntity(location, state);
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
this.changeSet.addEntityCreate(state.getNbtData());
|
this.changeSet.addEntityCreate(FaweCompoundTag.of(state.getNbt()));
|
||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
@ -84,7 +85,7 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
|||||||
public Entity createEntity(Location location, BaseEntity state, UUID uuid) {
|
public Entity createEntity(Location location, BaseEntity state, UUID uuid) {
|
||||||
final Entity entity = super.createEntity(location, state, uuid);
|
final Entity entity = super.createEntity(location, state, uuid);
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
this.changeSet.addEntityCreate(state.getNbtData());
|
this.changeSet.addEntityCreate(FaweCompoundTag.of(state.getNbt()));
|
||||||
}
|
}
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
@ -154,11 +155,10 @@ public class HistoryExtent extends AbstractDelegateExtent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean remove() {
|
public boolean remove() {
|
||||||
final Location location = this.entity.getLocation();
|
|
||||||
final BaseEntity state = this.entity.getState();
|
final BaseEntity state = this.entity.getState();
|
||||||
final boolean success = this.entity.remove();
|
final boolean success = this.entity.remove();
|
||||||
if (state != null && success) {
|
if (state != null && success) {
|
||||||
HistoryExtent.this.changeSet.addEntityRemove(state.getNbtData());
|
HistoryExtent.this.changeSet.addEntityRemove(FaweCompoundTag.of(state.getNbt()));
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,15 @@
|
|||||||
package com.fastasyncworldedit.core.extent;
|
package com.fastasyncworldedit.core.extent;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.filter.block.ExtentFilterBlock;
|
import com.fastasyncworldedit.core.extent.filter.block.ExtentFilterBlock;
|
||||||
import com.fastasyncworldedit.core.function.generator.GenBase;
|
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
||||||
import com.fastasyncworldedit.core.function.generator.Resource;
|
|
||||||
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
import com.fastasyncworldedit.core.internal.exception.FaweException;
|
||||||
import com.fastasyncworldedit.core.limit.FaweLimit;
|
import com.fastasyncworldedit.core.limit.FaweLimit;
|
||||||
import com.fastasyncworldedit.core.queue.Filter;
|
import com.fastasyncworldedit.core.queue.Filter;
|
||||||
|
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.util.ExtentTraverser;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
@ -17,7 +21,6 @@ import com.sk89q.worldedit.function.mask.Mask;
|
|||||||
import com.sk89q.worldedit.function.pattern.Pattern;
|
import com.sk89q.worldedit.function.pattern.Pattern;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.session.ClipboardHolder;
|
|
||||||
import com.sk89q.worldedit.util.Countable;
|
import com.sk89q.worldedit.util.Countable;
|
||||||
import com.sk89q.worldedit.util.Location;
|
import com.sk89q.worldedit.util.Location;
|
||||||
import com.sk89q.worldedit.util.formatting.text.Component;
|
import com.sk89q.worldedit.util.formatting.text.Component;
|
||||||
@ -37,18 +40,22 @@ import java.util.Set;
|
|||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class LimitExtent extends AbstractDelegateExtent {
|
public class LimitExtent extends AbstractDelegateExtent implements IBatchProcessor {
|
||||||
|
|
||||||
private final FaweLimit limit;
|
private final FaweLimit limit;
|
||||||
private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length];
|
private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length];
|
||||||
private final Consumer<Component> onErrorMessage;
|
private final Consumer<Component> onErrorMessage;
|
||||||
|
private final int chunk_size;
|
||||||
|
private boolean processing;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance.
|
* Create a new instance.
|
||||||
*
|
*
|
||||||
* @param extent the extent
|
* @param extent the extent
|
||||||
* @param limit the limit
|
* @param limit the limit
|
||||||
|
* @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "TODO")
|
||||||
public LimitExtent(Extent extent, FaweLimit limit) {
|
public LimitExtent(Extent extent, FaweLimit limit) {
|
||||||
this(extent, limit, c -> {
|
this(extent, limit, c -> {
|
||||||
});
|
});
|
||||||
@ -60,11 +67,33 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
* @param extent the extent
|
* @param extent the extent
|
||||||
* @param limit the limit
|
* @param limit the limit
|
||||||
* @param onErrorMessage consumer to handle a component generated by exceptions
|
* @param onErrorMessage consumer to handle a component generated by exceptions
|
||||||
|
* @deprecated Use {@link LimitExtent#LimitExtent(Extent, FaweLimit, Consumer, boolean)}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "TODO")
|
||||||
public LimitExtent(Extent extent, FaweLimit limit, Consumer<Component> onErrorMessage) {
|
public LimitExtent(Extent extent, FaweLimit limit, Consumer<Component> onErrorMessage) {
|
||||||
|
this(extent, limit, onErrorMessage, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance.
|
||||||
|
*
|
||||||
|
* @param extent the extent
|
||||||
|
* @param limit the limit
|
||||||
|
* @param onErrorMessage consumer to handle a component generated by exceptions
|
||||||
|
* @param processing if this limit extent is expected to be processing
|
||||||
|
* @since TODO
|
||||||
|
*/
|
||||||
|
public LimitExtent(
|
||||||
|
Extent extent,
|
||||||
|
FaweLimit limit,
|
||||||
|
Consumer<Component> onErrorMessage,
|
||||||
|
boolean processing
|
||||||
|
) {
|
||||||
super(extent);
|
super(extent);
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
this.onErrorMessage = onErrorMessage;
|
this.onErrorMessage = onErrorMessage;
|
||||||
|
this.chunk_size = 16 * 16 * (extent.getMaxY() - extent.getMinY());
|
||||||
|
this.processing = processing;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleException(FaweException e) {
|
private void handleException(FaweException e) {
|
||||||
@ -81,7 +110,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public List<? extends Entity> getEntities(Region region) {
|
public List<? extends Entity> getEntities(Region region) {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
try {
|
try {
|
||||||
return super.getEntities(region);
|
return extent.getEntities(region);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@ -92,7 +121,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public List<? extends Entity> getEntities() {
|
public List<? extends Entity> getEntities() {
|
||||||
limit.THROW_MAX_CHECKS();
|
limit.THROW_MAX_CHECKS();
|
||||||
try {
|
try {
|
||||||
return super.getEntities();
|
return extent.getEntities();
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
@ -105,7 +134,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
limit.THROW_MAX_CHANGES();
|
limit.THROW_MAX_CHANGES();
|
||||||
limit.THROW_MAX_ENTITIES();
|
limit.THROW_MAX_ENTITIES();
|
||||||
try {
|
try {
|
||||||
return super.createEntity(location, entity);
|
return extent.createEntity(location, entity);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return null;
|
return null;
|
||||||
@ -118,7 +147,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
limit.THROW_MAX_CHANGES();
|
limit.THROW_MAX_CHANGES();
|
||||||
limit.THROW_MAX_ENTITIES();
|
limit.THROW_MAX_ENTITIES();
|
||||||
try {
|
try {
|
||||||
return super.createEntity(location, entity, uuid);
|
return extent.createEntity(location, entity, uuid);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return null;
|
return null;
|
||||||
@ -130,7 +159,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
limit.THROW_MAX_CHANGES();
|
limit.THROW_MAX_CHANGES();
|
||||||
limit.THROW_MAX_ENTITIES();
|
limit.THROW_MAX_ENTITIES();
|
||||||
try {
|
try {
|
||||||
super.removeEntity(x, y, z, uuid);
|
extent.removeEntity(x, y, z, uuid);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
}
|
}
|
||||||
@ -138,9 +167,9 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
|
public boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
|
||||||
limit.THROW_MAX_CHANGES(Character.MAX_VALUE);
|
limit.THROW_MAX_CHANGES(chunk_size);
|
||||||
try {
|
try {
|
||||||
return super.regenerateChunk(x, z, type, seed);
|
return extent.regenerateChunk(x, z, type, seed);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return false;
|
return false;
|
||||||
@ -151,7 +180,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
|
public int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getHighestTerrainBlock(x, z, minY, maxY);
|
return extent.getHighestTerrainBlock(x, z, minY, maxY);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
@ -162,7 +191,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
|
public int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getHighestTerrainBlock(x, z, minY, maxY, filter);
|
return extent.getHighestTerrainBlock(x, z, minY, maxY, filter);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
@ -173,7 +202,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
public int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getNearestSurfaceLayer(x, z, y, minY, maxY);
|
return extent.getNearestSurfaceLayer(x, z, y, minY, maxY);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
@ -184,7 +213,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
|
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
@ -195,7 +224,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
@ -206,7 +235,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
|
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
@ -217,7 +246,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
public int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
|
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
@ -237,91 +266,47 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
) {
|
) {
|
||||||
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
limit.THROW_MAX_CHECKS(maxY - minY + 1);
|
||||||
try {
|
try {
|
||||||
return super.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
|
return extent.getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return minY;
|
return minY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addCaves(Region region) throws WorldEditException {
|
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
|
||||||
super.addCaves(region);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void generate(Region region, GenBase gen) throws WorldEditException {
|
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
|
||||||
super.generate(region, gen);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws
|
|
||||||
WorldEditException {
|
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
|
||||||
super.addSchems(region, mask, clipboards, rarity, rotate);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
|
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
|
||||||
super.spawnResource(region, gen, rarity, frequency);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws
|
|
||||||
WorldEditException {
|
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
|
||||||
super.addOre(region, mask, material, size, frequency, rarity, minY, maxY);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addOres(Region region, Mask mask) throws WorldEditException {
|
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
|
||||||
super.addOres(region, mask);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Countable<BlockType>> getBlockDistribution(Region region) {
|
public List<Countable<BlockType>> getBlockDistribution(Region region) {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
return super.getBlockDistribution(region);
|
return extent.getBlockDistribution(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
|
public List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
return super.getBlockDistributionWithData(region);
|
return extent.getBlockDistributionWithData(region);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
|
public int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
return super.countBlocks(region, searchBlocks);
|
return extent.countBlocks(region, searchBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int countBlocks(Region region, Mask searchMask) {
|
public int countBlocks(Region region, Mask searchMask) {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
return super.countBlocks(region, searchMask);
|
return extent.countBlocks(region, searchMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
|
public <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
limit.THROW_MAX_CHANGES(region.getVolume());
|
||||||
return super.setBlocks(region, block);
|
return extent.setBlocks(region, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
limit.THROW_MAX_CHANGES(region.getVolume());
|
||||||
return super.setBlocks(region, pattern);
|
return extent.setBlocks(region, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -329,41 +314,34 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
MaxChangedBlocksException {
|
MaxChangedBlocksException {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
limit.THROW_MAX_CHANGES(region.getVolume());
|
||||||
return super.replaceBlocks(region, filter, replacement);
|
return extent.replaceBlocks(region, filter, replacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
|
public int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
limit.THROW_MAX_CHANGES(region.getVolume());
|
||||||
return super.replaceBlocks(region, filter, pattern);
|
return extent.replaceBlocks(region, filter, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
|
public int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
limit.THROW_MAX_CHANGES(region.getVolume());
|
||||||
return super.replaceBlocks(region, mask, pattern);
|
return extent.replaceBlocks(region, mask, pattern);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
|
||||||
return super.center(region, pattern);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
|
public int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
|
||||||
limit.THROW_MAX_CHANGES(vset.size());
|
limit.THROW_MAX_CHANGES(vset.size());
|
||||||
return super.setBlocks(vset, pattern);
|
return extent.setBlocks(vset, pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends Filter> T apply(Region region, T filter, boolean full) {
|
public <T extends Filter> T apply(Region region, T filter, boolean full) {
|
||||||
limit.THROW_MAX_CHECKS(region.getVolume());
|
limit.THROW_MAX_CHECKS(region.getVolume());
|
||||||
limit.THROW_MAX_CHANGES(region.getVolume());
|
limit.THROW_MAX_CHANGES(region.getVolume());
|
||||||
return super.apply(region, filter, full);
|
return extent.apply(region, filter, full);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -393,14 +371,14 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
}
|
}
|
||||||
limit.THROW_MAX_CHECKS(size);
|
limit.THROW_MAX_CHECKS(size);
|
||||||
limit.THROW_MAX_CHANGES(size);
|
limit.THROW_MAX_CHANGES(size);
|
||||||
return super.apply(positions, filter);
|
return extent.apply(positions, filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState getBlock(BlockVector3 position) {
|
public BlockState getBlock(BlockVector3 position) {
|
||||||
limit.THROW_MAX_CHECKS();
|
limit.THROW_MAX_CHECKS();
|
||||||
try {
|
try {
|
||||||
return super.getBlock(position);
|
return extent.getBlock(position);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return BlockTypes.AIR.getDefaultState();
|
return BlockTypes.AIR.getDefaultState();
|
||||||
@ -411,7 +389,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public BlockState getBlock(int x, int y, int z) {
|
public BlockState getBlock(int x, int y, int z) {
|
||||||
limit.THROW_MAX_CHECKS();
|
limit.THROW_MAX_CHECKS();
|
||||||
try {
|
try {
|
||||||
return super.getBlock(x, y, z);
|
return extent.getBlock(x, y, z);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return BlockTypes.AIR.getDefaultState();
|
return BlockTypes.AIR.getDefaultState();
|
||||||
@ -422,7 +400,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public BaseBlock getFullBlock(BlockVector3 position) {
|
public BaseBlock getFullBlock(BlockVector3 position) {
|
||||||
limit.THROW_MAX_CHECKS();
|
limit.THROW_MAX_CHECKS();
|
||||||
try {
|
try {
|
||||||
return super.getFullBlock(position);
|
return extent.getFullBlock(position);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||||
@ -433,7 +411,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||||
limit.THROW_MAX_CHECKS();
|
limit.THROW_MAX_CHECKS();
|
||||||
try {
|
try {
|
||||||
return super.getFullBlock(x, y, z);
|
return extent.getFullBlock(x, y, z);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||||
@ -444,7 +422,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public BiomeType getBiome(BlockVector3 position) {
|
public BiomeType getBiome(BlockVector3 position) {
|
||||||
limit.THROW_MAX_CHECKS();
|
limit.THROW_MAX_CHECKS();
|
||||||
try {
|
try {
|
||||||
return super.getBiome(position);
|
return extent.getBiome(position);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return BiomeTypes.FOREST;
|
return BiomeTypes.FOREST;
|
||||||
@ -455,7 +433,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public BiomeType getBiomeType(int x, int y, int z) {
|
public BiomeType getBiomeType(int x, int y, int z) {
|
||||||
limit.THROW_MAX_CHECKS();
|
limit.THROW_MAX_CHECKS();
|
||||||
try {
|
try {
|
||||||
return super.getBiomeType(x, y, z);
|
return extent.getBiomeType(x, y, z);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return BiomeTypes.FOREST;
|
return BiomeTypes.FOREST;
|
||||||
@ -470,7 +448,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
limit.THROW_MAX_BLOCKSTATES();
|
limit.THROW_MAX_BLOCKSTATES();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return super.setBlock(position, block);
|
return extent.setBlock(position, block);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return false;
|
return false;
|
||||||
@ -484,7 +462,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
limit.THROW_MAX_BLOCKSTATES();
|
limit.THROW_MAX_BLOCKSTATES();
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return super.setBlock(x, y, z, block);
|
return extent.setBlock(x, y, z, block);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return false;
|
return false;
|
||||||
@ -494,9 +472,9 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
@Override
|
@Override
|
||||||
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
public boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
||||||
limit.THROW_MAX_CHANGES();
|
limit.THROW_MAX_CHANGES();
|
||||||
limit.MAX_BLOCKSTATES();
|
limit.THROW_MAX_BLOCKSTATES();
|
||||||
try {
|
try {
|
||||||
return super.setTile(x, y, z, tile);
|
return extent.setTile(x, y, z, tile);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return false;
|
return false;
|
||||||
@ -507,7 +485,7 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public boolean setBiome(BlockVector3 position, BiomeType biome) {
|
public boolean setBiome(BlockVector3 position, BiomeType biome) {
|
||||||
limit.THROW_MAX_CHANGES();
|
limit.THROW_MAX_CHANGES();
|
||||||
try {
|
try {
|
||||||
return super.setBiome(position, biome);
|
return extent.setBiome(position, biome);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return false;
|
return false;
|
||||||
@ -518,11 +496,41 @@ public class LimitExtent extends AbstractDelegateExtent {
|
|||||||
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
public boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||||
limit.THROW_MAX_CHANGES();
|
limit.THROW_MAX_CHANGES();
|
||||||
try {
|
try {
|
||||||
return super.setBiome(x, y, z, biome);
|
return extent.setBiome(x, y, z, biome);
|
||||||
} catch (FaweException e) {
|
} catch (FaweException e) {
|
||||||
handleException(e);
|
handleException(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setProcessing(boolean processing) {
|
||||||
|
this.processing = processing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IChunkSet processSet(IChunk chunk, IChunkGet get, IChunkSet set) {
|
||||||
|
if (!processing) {
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
int tiles = set.tiles().size();
|
||||||
|
int ents = set.entities().size() + set.getEntityRemoves().size();
|
||||||
|
limit.THROW_MAX_CHANGES(tiles + ents);
|
||||||
|
limit.THROW_MAX_BLOCKSTATES(tiles);
|
||||||
|
limit.THROW_MAX_ENTITIES(ents);
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Extent construct(final Extent child) {
|
||||||
|
if (extent != child) {
|
||||||
|
new ExtentTraverser<Extent>(this).setNext(child);
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ProcessorScope getScope() {
|
||||||
|
return ProcessorScope.READING_SET_BLOCKS;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,12 @@ package com.fastasyncworldedit.core.extent;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
import com.fastasyncworldedit.core.extent.processor.ProcessorScope;
|
||||||
import com.fastasyncworldedit.core.math.BlockVector3ChunkMap;
|
import com.fastasyncworldedit.core.math.BlockVector3ChunkMap;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
import com.fastasyncworldedit.core.queue.IBatchProcessor;
|
||||||
import com.fastasyncworldedit.core.queue.IChunk;
|
import com.fastasyncworldedit.core.queue.IChunk;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkGet;
|
import com.fastasyncworldedit.core.queue.IChunkGet;
|
||||||
import com.fastasyncworldedit.core.queue.IChunkSet;
|
import com.fastasyncworldedit.core.queue.IChunkSet;
|
||||||
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
import com.fastasyncworldedit.core.util.ExtentTraverser;
|
||||||
import com.google.common.collect.ImmutableMap;
|
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
|
||||||
import com.sk89q.jnbt.Tag;
|
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
@ -20,16 +18,17 @@ import com.sk89q.worldedit.util.Location;
|
|||||||
import com.sk89q.worldedit.world.NbtValued;
|
import com.sk89q.worldedit.world.NbtValued;
|
||||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
import org.enginehub.linbus.tree.LinTag;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.HashMap;
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProcessor {
|
public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProcessor {
|
||||||
@ -75,79 +74,82 @@ public class StripNBTExtent extends AbstractDelegateExtent implements IBatchProc
|
|||||||
if (!(block instanceof BaseBlock localBlock)) {
|
if (!(block instanceof BaseBlock localBlock)) {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
if (!localBlock.hasNbtData()) {
|
final LinCompoundTag nbt = localBlock.getNbt();
|
||||||
|
if (nbt == null) {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
CompoundTag nbt = localBlock.getNbtData();
|
LinCompoundTag.Builder nbtBuilder = nbt.toBuilder();
|
||||||
Map<String, Tag<?, ?>> value = new HashMap<>(nbt.getValue());
|
|
||||||
for (String key : strip) {
|
for (String key : strip) {
|
||||||
value.remove(key);
|
nbtBuilder.remove(key);
|
||||||
}
|
}
|
||||||
return (B) localBlock.toBaseBlock(new CompoundTag(value));
|
return (B) localBlock.toBaseBlock(nbtBuilder.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T extends NbtValued> T stripEntityNBT(T entity) {
|
public <T extends NbtValued> T stripEntityNBT(T entity) {
|
||||||
if (!entity.hasNbtData()) {
|
LinCompoundTag nbt = entity.getNbt();
|
||||||
|
if (nbt == null) {
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
CompoundTag nbt = entity.getNbtData();
|
LinCompoundTag.Builder nbtBuilder = nbt.toBuilder();
|
||||||
Map<String, Tag<?, ?>> value = new HashMap<>(nbt.getValue());
|
|
||||||
for (String key : strip) {
|
for (String key : strip) {
|
||||||
value.remove(key);
|
nbtBuilder.remove(key);
|
||||||
}
|
}
|
||||||
entity.setNbtData(new CompoundTag(value));
|
entity.setNbt(nbtBuilder.build());
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
public IChunkSet processSet(final IChunk chunk, final IChunkGet get, final IChunkSet set) {
|
||||||
Map<BlockVector3, CompoundTag> tiles = set.getTiles();
|
Map<BlockVector3, FaweCompoundTag> tiles = set.tiles();
|
||||||
Set<CompoundTag> entities = set.getEntities();
|
Collection<FaweCompoundTag> entities = set.entities();
|
||||||
if (tiles.isEmpty() && entities.isEmpty()) {
|
if (tiles.isEmpty() && entities.isEmpty()) {
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap;
|
boolean isBv3ChunkMap = tiles instanceof BlockVector3ChunkMap;
|
||||||
for (final Map.Entry<BlockVector3, CompoundTag> entry : tiles.entrySet()) {
|
for (final var entry : tiles.entrySet()) {
|
||||||
ImmutableMap.Builder<String, Tag<?, ?>> map = ImmutableMap.builder();
|
FaweCompoundTag original = entry.getValue();
|
||||||
final AtomicBoolean isStripped = new AtomicBoolean(false);
|
FaweCompoundTag result = stripNbt(original);
|
||||||
entry.getValue().getValue().forEach((k, v) -> {
|
if (original != result) {
|
||||||
if (strip.contains(k.toLowerCase())) {
|
|
||||||
isStripped.set(true);
|
|
||||||
} else {
|
|
||||||
map.put(k, v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isStripped.get()) {
|
|
||||||
if (isBv3ChunkMap) {
|
if (isBv3ChunkMap) {
|
||||||
// Replace existing value with stripped value
|
// Replace existing value with stripped value
|
||||||
tiles.put(entry.getKey(), new CompoundTag(map.build()));
|
tiles.put(entry.getKey(), result);
|
||||||
} else {
|
} else {
|
||||||
entry.setValue(new CompoundTag(map.build()));
|
entry.setValue(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Set<CompoundTag> stripped = new HashSet<>();
|
Set<FaweCompoundTag> stripped = new HashSet<>();
|
||||||
Iterator<CompoundTag> iterator = entities.iterator();
|
Iterator<FaweCompoundTag> iterator = entities.iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
CompoundTag entity = iterator.next();
|
FaweCompoundTag original = iterator.next();
|
||||||
ImmutableMap.Builder<String, Tag<?, ?>> map = ImmutableMap.builder();
|
FaweCompoundTag result = stripNbt(original);
|
||||||
final AtomicBoolean isStripped = new AtomicBoolean(false);
|
if (original != result) {
|
||||||
entity.getValue().forEach((k, v) -> {
|
|
||||||
if (strip.contains(k.toUpperCase(Locale.ROOT))) {
|
|
||||||
isStripped.set(true);
|
|
||||||
} else {
|
|
||||||
map.put(k, v);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (isStripped.get()) {
|
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
stripped.add(new CompoundTag(map.build()));
|
stripped.add(result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
set.getEntities().addAll(stripped);
|
// this relies on entities.addAll(...) not throwing an exception if empty+unmodifiable (=> stripped is empty too)
|
||||||
|
entities.addAll(stripped);
|
||||||
return set;
|
return set;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FaweCompoundTag stripNbt(
|
||||||
|
FaweCompoundTag compoundTag
|
||||||
|
) {
|
||||||
|
LinCompoundTag.Builder builder = LinCompoundTag.builder();
|
||||||
|
boolean stripped = false;
|
||||||
|
for (var entry : compoundTag.linTag().value().entrySet()) {
|
||||||
|
String k = entry.getKey();
|
||||||
|
LinTag<?> v = entry.getValue();
|
||||||
|
if (strip.contains(k.toLowerCase(Locale.ROOT))) {
|
||||||
|
stripped = true;
|
||||||
|
} else {
|
||||||
|
builder.put(k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return stripped ? FaweCompoundTag.of(builder.build()) : compoundTag;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public Extent construct(final Extent child) {
|
public Extent construct(final Extent child) {
|
||||||
|
@ -2,9 +2,11 @@ package com.fastasyncworldedit.core.extent.clipboard;
|
|||||||
|
|
||||||
import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader;
|
import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader;
|
||||||
import com.fastasyncworldedit.core.math.IntTriple;
|
import com.fastasyncworldedit.core.math.IntTriple;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.IntTag;
|
import com.sk89q.jnbt.IntTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
@ -175,6 +177,12 @@ public class CPUOptimizedClipboard extends LinearClipboard {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException {
|
||||||
|
// TODO replace
|
||||||
|
return setTile(x, y, z, new CompoundTag(tile.linTag()));
|
||||||
|
}
|
||||||
|
|
||||||
private boolean setTile(int index, CompoundTag tag) {
|
private boolean setTile(int index, CompoundTag tag) {
|
||||||
final Map<String, Tag<?, ?>> values = new HashMap<>(tag.getValue());
|
final Map<String, Tag<?, ?>> values = new HashMap<>(tag.getValue());
|
||||||
values.remove("x");
|
values.remove("x");
|
||||||
|
@ -6,15 +6,18 @@ import com.fastasyncworldedit.core.internal.exception.FaweClipboardVersionMismat
|
|||||||
import com.fastasyncworldedit.core.internal.io.ByteBufferInputStream;
|
import com.fastasyncworldedit.core.internal.io.ByteBufferInputStream;
|
||||||
import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader;
|
import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader;
|
||||||
import com.fastasyncworldedit.core.math.IntTriple;
|
import com.fastasyncworldedit.core.math.IntTriple;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.util.MainUtil;
|
import com.fastasyncworldedit.core.util.MainUtil;
|
||||||
|
import com.fastasyncworldedit.core.util.NbtUtils;
|
||||||
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
import com.fastasyncworldedit.core.util.ReflectionUtils;
|
||||||
|
import com.google.common.collect.Collections2;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.DoubleTag;
|
import com.sk89q.jnbt.DoubleTag;
|
||||||
import com.sk89q.jnbt.IntTag;
|
|
||||||
import com.sk89q.jnbt.ListTag;
|
import com.sk89q.jnbt.ListTag;
|
||||||
import com.sk89q.jnbt.NBTInputStream;
|
import com.sk89q.jnbt.NBTInputStream;
|
||||||
import com.sk89q.jnbt.NBTOutputStream;
|
import com.sk89q.jnbt.NBTOutputStream;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||||
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
import com.sk89q.worldedit.internal.util.LogManagerCompat;
|
||||||
@ -28,6 +31,8 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
|
|||||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||||
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
import com.sk89q.worldedit.world.block.BlockTypesCache;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
|
import org.enginehub.linbus.tree.LinCompoundTag;
|
||||||
|
import org.enginehub.linbus.tree.LinTagType;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
@ -64,7 +69,7 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
|||||||
private static final int VERSION_2_HEADER_SIZE = 27; // Header size of "version 2" i.e. when NBT/entities could be saved
|
private static final int VERSION_2_HEADER_SIZE = 27; // Header size of "version 2" i.e. when NBT/entities could be saved
|
||||||
private static final Map<String, LockHolder> LOCK_HOLDER_CACHE = new ConcurrentHashMap<>();
|
private static final Map<String, LockHolder> LOCK_HOLDER_CACHE = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final HashMap<IntTriple, CompoundTag> nbtMap;
|
private final HashMap<IntTriple, FaweCompoundTag> nbtMap;
|
||||||
private final File file;
|
private final File file;
|
||||||
private final int headerSize;
|
private final int headerSize;
|
||||||
|
|
||||||
@ -248,12 +253,12 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
|||||||
try (NBTInputStream nbtIS = new NBTInputStream(MainUtil.getCompressedIS(new ByteBufferInputStream(tmp)))) {
|
try (NBTInputStream nbtIS = new NBTInputStream(MainUtil.getCompressedIS(new ByteBufferInputStream(tmp)))) {
|
||||||
Iterator<CompoundTag> iter = nbtIS.toIterator();
|
Iterator<CompoundTag> iter = nbtIS.toIterator();
|
||||||
while (nbtCount > 0 && iter.hasNext()) { // TileEntities are stored "before" entities
|
while (nbtCount > 0 && iter.hasNext()) { // TileEntities are stored "before" entities
|
||||||
CompoundTag tag = iter.next();
|
LinCompoundTag tag = iter.next().toLinTag();
|
||||||
int x = tag.getInt("x");
|
int x = tag.getTag("x", LinTagType.intTag()).valueAsInt();
|
||||||
int y = tag.getInt("y");
|
int y = tag.getTag("y", LinTagType.intTag()).valueAsInt();
|
||||||
int z = tag.getInt("z");
|
int z = tag.getTag("z", LinTagType.intTag()).valueAsInt();
|
||||||
IntTriple pos = new IntTriple(x, y, z);
|
IntTriple pos = new IntTriple(x, y, z);
|
||||||
nbtMap.put(pos, tag);
|
nbtMap.put(pos, FaweCompoundTag.of(tag));
|
||||||
nbtCount--;
|
nbtCount--;
|
||||||
}
|
}
|
||||||
while (entitiesCount > 0 && iter.hasNext()) {
|
while (entitiesCount > 0 && iter.hasNext()) {
|
||||||
@ -559,8 +564,8 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
|||||||
))) {
|
))) {
|
||||||
if (!nbtMap.isEmpty()) {
|
if (!nbtMap.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
for (CompoundTag tag : nbtMap.values()) {
|
for (FaweCompoundTag tag : nbtMap.values()) {
|
||||||
nbtOS.writeTag(tag);
|
nbtOS.writeTag(new CompoundTag(tag.linTag()));
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
@ -638,7 +643,7 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<CompoundTag> getTileEntities() {
|
public Collection<CompoundTag> getTileEntities() {
|
||||||
return nbtMap.values();
|
return Collections2.transform(nbtMap.values(), fct -> new CompoundTag(fct.linTag()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getIndex(int x, int y, int z) {
|
public int getIndex(int x, int y, int z) {
|
||||||
@ -656,10 +661,10 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
|||||||
|
|
||||||
private BaseBlock toBaseBlock(BlockState state, int i) {
|
private BaseBlock toBaseBlock(BlockState state, int i) {
|
||||||
if (state.getMaterial().hasContainer() && !nbtMap.isEmpty()) {
|
if (state.getMaterial().hasContainer() && !nbtMap.isEmpty()) {
|
||||||
CompoundTag nbt;
|
FaweCompoundTag nbt;
|
||||||
if (nbtMap.size() < 4) {
|
if (nbtMap.size() < 4) {
|
||||||
nbt = null;
|
nbt = null;
|
||||||
for (Map.Entry<IntTriple, CompoundTag> entry : nbtMap.entrySet()) {
|
for (Map.Entry<IntTriple, FaweCompoundTag> entry : nbtMap.entrySet()) {
|
||||||
IntTriple key = entry.getKey();
|
IntTriple key = entry.getKey();
|
||||||
int index = getIndex(key.x(), key.y(), key.z());
|
int index = getIndex(key.x(), key.y(), key.z());
|
||||||
if (index == i) {
|
if (index == i) {
|
||||||
@ -674,15 +679,15 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
|||||||
int x = newI - z * getWidth();
|
int x = newI - z * getWidth();
|
||||||
nbt = nbtMap.get(new IntTriple(x, y, z));
|
nbt = nbtMap.get(new IntTriple(x, y, z));
|
||||||
}
|
}
|
||||||
return state.toBaseBlock(nbt);
|
return state.toBaseBlock(nbt == null ? null : nbt.linTag());
|
||||||
}
|
}
|
||||||
return state.toBaseBlock();
|
return state.toBaseBlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
private BaseBlock toBaseBlock(BlockState state, int x, int y, int z) {
|
private BaseBlock toBaseBlock(BlockState state, int x, int y, int z) {
|
||||||
if (state.getMaterial().hasContainer() && !nbtMap.isEmpty()) {
|
if (state.getMaterial().hasContainer() && !nbtMap.isEmpty()) {
|
||||||
CompoundTag nbt = nbtMap.get(new IntTriple(x, y, z));
|
FaweCompoundTag nbt = nbtMap.get(new IntTriple(x, y, z));
|
||||||
return state.toBaseBlock(nbt);
|
return state.toBaseBlock(nbt == null ? null : nbt.linTag());
|
||||||
}
|
}
|
||||||
return state.toBaseBlock();
|
return state.toBaseBlock();
|
||||||
}
|
}
|
||||||
@ -709,12 +714,8 @@ public class DiskOptimizedClipboard extends LinearClipboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException {
|
||||||
final Map<String, Tag<?, ?>> values = new HashMap<>(tag.getValue());
|
nbtMap.put(new IntTriple(x, y, z), NbtUtils.withPosition(tile, x, y, z));
|
||||||
values.put("x", new IntTag(x));
|
|
||||||
values.put("y", new IntTag(y));
|
|
||||||
values.put("z", new IntTag(z));
|
|
||||||
nbtMap.put(new IntTriple(x, y, z), new CompoundTag(values));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.fastasyncworldedit.core.extent.clipboard;
|
package com.fastasyncworldedit.core.extent.clipboard;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.sk89q.worldedit.WorldEditException;
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
import com.sk89q.worldedit.extent.clipboard.Clipboard;
|
||||||
@ -84,7 +84,8 @@ public final class EmptyClipboard implements Clipboard {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean setTile(int x, int y, int z, @Nonnull CompoundTag tile) throws WorldEditException {
|
@Override
|
||||||
|
public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,10 @@ public abstract class LinearClipboard extends SimpleClipboard {
|
|||||||
*/
|
*/
|
||||||
public abstract void streamBiomes(IntValueReader task);
|
public abstract void streamBiomes(IntValueReader task);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated will be removed as it is unused and uses outdated types
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "TODO")
|
||||||
public abstract Collection<CompoundTag> getTileEntities();
|
public abstract Collection<CompoundTag> getTileEntities();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -3,10 +3,12 @@ package com.fastasyncworldedit.core.extent.clipboard;
|
|||||||
import com.fastasyncworldedit.core.configuration.Settings;
|
import com.fastasyncworldedit.core.configuration.Settings;
|
||||||
import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader;
|
import com.fastasyncworldedit.core.jnbt.streamer.IntValueReader;
|
||||||
import com.fastasyncworldedit.core.math.IntTriple;
|
import com.fastasyncworldedit.core.math.IntTriple;
|
||||||
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.fastasyncworldedit.core.util.MainUtil;
|
import com.fastasyncworldedit.core.util.MainUtil;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.sk89q.jnbt.CompoundTag;
|
||||||
import com.sk89q.jnbt.IntTag;
|
import com.sk89q.jnbt.IntTag;
|
||||||
import com.sk89q.jnbt.Tag;
|
import com.sk89q.jnbt.Tag;
|
||||||
|
import com.sk89q.worldedit.WorldEditException;
|
||||||
import com.sk89q.worldedit.math.BlockVector3;
|
import com.sk89q.worldedit.math.BlockVector3;
|
||||||
import com.sk89q.worldedit.regions.Region;
|
import com.sk89q.worldedit.regions.Region;
|
||||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||||
@ -262,6 +264,12 @@ public class MemoryOptimizedClipboard extends LinearClipboard {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tile) throws WorldEditException {
|
||||||
|
// TODO replace
|
||||||
|
return setTile(x, y, z, new CompoundTag(tile.linTag()));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <B extends BlockStateHolder<B>> boolean setBlock(int x, int y, int z, B block) {
|
public <B extends BlockStateHolder<B>> boolean setBlock(int x, int y, int z, B block) {
|
||||||
return setBlock(getIndex(x, y, z), block);
|
return setBlock(getIndex(x, y, z), block);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.fastasyncworldedit.core.extent.clipboard;
|
package com.fastasyncworldedit.core.extent.clipboard;
|
||||||
|
|
||||||
import com.fastasyncworldedit.core.Fawe;
|
import com.fastasyncworldedit.core.Fawe;
|
||||||
import com.sk89q.jnbt.CompoundTag;
|
import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
|
||||||
import com.sk89q.worldedit.EditSession;
|
import com.sk89q.worldedit.EditSession;
|
||||||
import com.sk89q.worldedit.entity.BaseEntity;
|
import com.sk89q.worldedit.entity.BaseEntity;
|
||||||
import com.sk89q.worldedit.entity.Entity;
|
import com.sk89q.worldedit.entity.Entity;
|
||||||
@ -106,7 +106,7 @@ public abstract class ReadOnlyClipboard extends SimpleClipboard {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
public boolean tile(int x, int y, int z, FaweCompoundTag tag) {
|
||||||
throw new UnsupportedOperationException("Clipboard is immutable");
|
throw new UnsupportedOperationException("Clipboard is immutable");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user