From 838465ab2411a644bd09527c0ecefb09ed0eebd9 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Sat, 11 Jan 2025 05:26:16 -0800 Subject: [PATCH] Begin hard fork --- .editorconfig | 6 - .gitattributes | 15 +- .github/workflows/build.yml | 8 +- .gitignore | 59 +- build-data/dev-imports.txt | 4 + build-data/fork.at | 3 + build-data/reobf-mappings-patch.tiny | 18 - build.gradle.kts | 132 +- folia-api/build.gradle.kts.patch | 44 + .../0001-Force-disable-timings.patch | 0 .../features}/0002-Region-scheduler-API.patch | 0 ...to-be-explicitly-marked-as-Folia-sup.patch | 0 .../RegionizedServerInitEvent.java | 26 + folia-server/build.gradle.kts.patch | 73 + .../features/0001-Threaded-Regions.patch | 10830 +++++++--------- .../features/0002-Max-pending-logins.patch | 20 +- ...nk-system-throughput-counters-to-tps.patch | 12 +- ...-getHandle-and-overrides-perform-thr.patch | 45 + ...dates-in-non-loaded-or-non-owned-chu.patch | 111 + ...-world-tile-entities-on-worldgen-thr.patch | 8 +- ...access-when-waking-players-up-during.patch | 39 + ...ccess-POI-data-for-lodestone-compass.patch | 16 +- .../0009-Fix-off-region-raid-heroes.patch | 41 + ...ition-to-player-position-on-player-d.patch | 32 + .../features/0011-Region-profiler.patch | 587 +- .../features/0012-Add-watchdog-thread.patch | 29 +- .../features/0001-Update-Logo.patch | 790 +- .../features/0002-Build-changes.patch | 84 + .../features/0003-Threaded-Regions.patch | 1622 +++ ...-getHandle-and-overrides-perform-thr.patch | 68 +- ...edOperationException-for-broken-APIs.patch | 4 +- .../0006-Fix-tests-by-removing-them.patch | 0 ...to-be-explicitly-marked-as-Folia-sup.patch | 0 ...8-Synchronize-PaperPermissionManager.patch | 0 .../0009-Disable-spark-profiler.patch | 0 .../features/0010-Region-profiler.patch | 90 + .../features/0011-Add-watchdog-thread.patch | 21 + .../resources/data/.paperassetsroot.patch | 3 + gradle.properties | 5 +- gradle/libs.versions.toml | 2 + gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 3 +- gradlew.bat | 0 install.bat | 1 - jar.bat | 1 - notes.txt | 2 + patch.bat | 1 - patch.sh | 1 + .../0004-Add-RegionizedServerInitEvent.patch | 42 - patches/server/0002-MC-Dev-fixes.patch | 49 - ...dates-in-non-loaded-or-non-owned-chu.patch | 112 - ...access-when-waking-players-up-during.patch | 39 - .../0015-Fix-off-region-raid-heroes.patch | 40 - ...ition-to-player-position-on-player-d.patch | 26 - rb.bat | 1 - rb.sh | 3 + regiontodo.txt | 33 - settings.gradle.kts | 30 +- 58 files changed, 7586 insertions(+), 7647 deletions(-) delete mode 100644 .editorconfig create mode 100644 build-data/fork.at delete mode 100644 build-data/reobf-mappings-patch.tiny create mode 100644 folia-api/build.gradle.kts.patch rename {patches/api => folia-api/paper-patches/features}/0001-Force-disable-timings.patch (100%) rename {patches/api => folia-api/paper-patches/features}/0002-Region-scheduler-API.patch (100%) rename {patches/api => folia-api/paper-patches/features}/0003-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch (100%) create mode 100644 folia-api/src/main/java/io/papermc/paper/threadedregions/RegionizedServerInitEvent.java create mode 100644 folia-server/build.gradle.kts.patch rename patches/server/0003-Threaded-Regions.patch => folia-server/minecraft-patches/features/0001-Threaded-Regions.patch (65%) rename patches/server/0004-Max-pending-logins.patch => folia-server/minecraft-patches/features/0002-Max-pending-logins.patch (62%) rename patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch => folia-server/minecraft-patches/features/0003-Add-chunk-system-throughput-counters-to-tps.patch (84%) create mode 100644 folia-server/minecraft-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch create mode 100644 folia-server/minecraft-patches/features/0005-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch rename patches/server/0011-Block-reading-in-world-tile-entities-on-worldgen-thr.patch => folia-server/minecraft-patches/features/0006-Block-reading-in-world-tile-entities-on-worldgen-thr.patch (69%) create mode 100644 folia-server/minecraft-patches/features/0007-Skip-worldstate-access-when-waking-players-up-during.patch rename patches/server/0013-Do-not-access-POI-data-for-lodestone-compass.patch => folia-server/minecraft-patches/features/0008-Do-not-access-POI-data-for-lodestone-compass.patch (61%) create mode 100644 folia-server/minecraft-patches/features/0009-Fix-off-region-raid-heroes.patch create mode 100644 folia-server/minecraft-patches/features/0010-Sync-vehicle-position-to-player-position-on-player-d.patch rename patches/server/0017-Region-profiler.patch => folia-server/minecraft-patches/features/0011-Region-profiler.patch (79%) rename patches/server/0019-Add-watchdog-thread.patch => folia-server/minecraft-patches/features/0012-Add-watchdog-thread.patch (82%) rename patches/server/0001-Build-changes.patch => folia-server/paper-patches/features/0001-Update-Logo.patch (60%) create mode 100644 folia-server/paper-patches/features/0002-Build-changes.patch create mode 100644 folia-server/paper-patches/features/0003-Threaded-Regions.patch rename patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch => folia-server/paper-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch (97%) rename patches/server/0007-Throw-UnsupportedOperationException-for-broken-APIs.patch => folia-server/paper-patches/features/0005-Throw-UnsupportedOperationException-for-broken-APIs.patch (96%) rename patches/server/0008-Fix-tests-by-removing-them.patch => folia-server/paper-patches/features/0006-Fix-tests-by-removing-them.patch (100%) rename patches/server/0009-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch => folia-server/paper-patches/features/0007-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch (100%) rename patches/server/0014-Synchronize-PaperPermissionManager.patch => folia-server/paper-patches/features/0008-Synchronize-PaperPermissionManager.patch (100%) rename patches/server/0018-Disable-spark-profiler.patch => folia-server/paper-patches/features/0009-Disable-spark-profiler.patch (100%) create mode 100644 folia-server/paper-patches/features/0010-Region-profiler.patch create mode 100644 folia-server/paper-patches/features/0011-Add-watchdog-thread.patch create mode 100644 folia-server/paper-patches/files/src/main/resources/data/.paperassetsroot.patch create mode 100644 gradle/libs.versions.toml mode change 100755 => 100644 gradlew.bat delete mode 100755 install.bat delete mode 100755 jar.bat create mode 100644 notes.txt delete mode 100755 patch.bat create mode 100755 patch.sh delete mode 100644 patches/api/0004-Add-RegionizedServerInitEvent.patch delete mode 100644 patches/server/0002-MC-Dev-fixes.patch delete mode 100644 patches/server/0010-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch delete mode 100644 patches/server/0012-Skip-worldstate-access-when-waking-players-up-during.patch delete mode 100644 patches/server/0015-Fix-off-region-raid-heroes.patch delete mode 100644 patches/server/0016-Sync-vehicle-position-to-player-position-on-player-d.patch delete mode 100755 rb.bat create mode 100755 rb.sh delete mode 100644 regiontodo.txt diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 210d3ca..0000000 --- a/.editorconfig +++ /dev/null @@ -1,6 +0,0 @@ -[*.java] -charset=utf-8 -end_of_line=lf -insert_final_newline=true -indent_style=space -indent_size=4 diff --git a/.gitattributes b/.gitattributes index 2fb638f..f91f646 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,12 @@ -* text=auto +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf -*.sh text eol=lf -gradlew text eol=lf -*.bat text eol=crlf +# These are Windows script files and should use crlf +*.bat text eol=crlf + +# Binary files should be left untouched +*.jar binary -*.jar binary diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 740d9dd..4434243 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,18 +13,16 @@ jobs: steps: - name: Checkout Git Repository uses: actions/checkout@v4 - - name: Validate Gradle wrapper - uses: gradle/actions/wrapper-validation@v4 - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v4 - name: Set up JDK uses: actions/setup-java@v4 with: distribution: 'temurin' java-version: '21' + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Configure Git User Details run: git config --global user.email "actions@github.com" && git config --global user.name "Github Actions" - name: Apply Patches - run: ./gradlew applyPatches + run: ./gradlew applyAllPatches --stacktrace - name: Build run: ./gradlew build diff --git a/.gitignore b/.gitignore index be5d096..b0b71e1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,53 +1,16 @@ -.gradle/ -build/ +# Ignore Gradle project-specific cache directory +.gradle -# Eclipse stuff -.classpath -.project -.settings/ +# Ignore Gradle build output directory +build -# VSCode stuff -.vscode/ +/run -# netbeans -nbproject/ -nbactions.xml +/folia-server/build.gradle.kts +/folia-server/src/minecraft +/paper-server +/folia-api/build.gradle.kts +/paper-api +/paper-api-generator -# we use maven! -build.xml - -# maven -target/ -dependency-reduced-pom.xml - -# vim -.*.sw[a-p] - -# various other potential build files -build/ -bin/ -dist/ -manifest.mf - -# Mac filesystem dust -.DS_Store/ -.DS_Store - -# intellij -*.iml -*.ipr -*.iws .idea/ -out/ - -# Linux temp files -*~ - -# other stuff -run/ - -Folia-Server -Folia-API -paper-api-generator - -!gradle/wrapper/gradle-wrapper.jar diff --git a/build-data/dev-imports.txt b/build-data/dev-imports.txt index b818b96..1d9862a 100644 --- a/build-data/dev-imports.txt +++ b/build-data/dev-imports.txt @@ -8,3 +8,7 @@ # To import classes from the vanilla Minecraft jar use `minecraft` as the artifactId: # minecraft net.minecraft.world.level.entity.LevelEntityGetterAdapter # minecraft net/minecraft/world/level/entity/LevelEntityGetter.java +# To import minecraft data files, like the default chat type, use `mc_data` as the prefix: +# mc_data chat_type/chat.json +# mc_data dimension_type/overworld.json +# diff --git a/build-data/fork.at b/build-data/fork.at new file mode 100644 index 0000000..3d7a00c --- /dev/null +++ b/build-data/fork.at @@ -0,0 +1,3 @@ +# This file is auto generated, any changes may be overridden! +# See CONTRIBUTING.md on how to add access transformers. +public net.minecraft.data.registries.TradeRebalanceRegistries BUILDER diff --git a/build-data/reobf-mappings-patch.tiny b/build-data/reobf-mappings-patch.tiny deleted file mode 100644 index e975a3c..0000000 --- a/build-data/reobf-mappings-patch.tiny +++ /dev/null @@ -1,18 +0,0 @@ -# We would like for paperweight to generate 100% perfect reobf mappings (and deobf mappings for that matter). -# But unfortunately it's not quite there yet - and it may be some time before that happens. Generating perfect mappings -# from Spigot's mappings is extremely difficult due to Spigot's bad tooling and bad mappings. To add insult to injury -# we remap Spigot's _source code_ which is a lot more complex and error-prone than bytecode remapping. So with all that -# said, this file exists to help fill in the gap. -# -# We will continue to improve paperweight and will work on fixing these issues so they don't come up in the first place, -# but these mappings exist to prevent these issues from holding everything else in Paper up while we work through all -# of these issues. Due to the complex nature of mappings generation and the debugging difficulty involved it may take -# a significant amount of time for us to track down every possible issue, so this file will likely be around and in -# use - at least in some capacity - for a long time. -# -# If you are adding mappings patches which are correcting for issues in paperweight's reobf mappings generation, -# unrelated to any changes in your patches, we ask that you PR the mapping to Paper so more users can benefit rather -# than keep the fix for your own fork. If the mappings patch is there to correct reobf for changes made in your patches, -# then obviously it doesn't make any sense to PR them upstream. - -tiny 2 0 mojang+yarn spigot diff --git a/build.gradle.kts b/build.gradle.kts index 26cf160..21f0654 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,41 +1,68 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent import io.papermc.paperweight.tasks.RebuildGitPatches plugins { - java - `maven-publish` - id("io.papermc.paperweight.patcher") version "1.7.7" + java // TODO java launcher tasks + id("io.papermc.paperweight.patcher") version "2.0.0-beta.13" } -val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" +paperweight { + upstreams.paper { + ref = providers.gradleProperty("paperRef") -repositories { - mavenCentral() - maven(paperMavenPublicUrl) { - content { onlyForConfigurations(configurations.paperclip.name) } - } -} - -dependencies { - remapper("net.fabricmc:tiny-remapper:0.10.3:fat") - decompiler("org.vineflower:vineflower:1.10.1") - paperclip("io.papermc:paperclip:3.0.3") -} - -allprojects { - apply(plugin = "java") - apply(plugin = "maven-publish") - - java { - toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) + patchFile { + path = "paper-server/build.gradle.kts" + outputFile = file("folia-server/build.gradle.kts") + patchFile = file("folia-server/build.gradle.kts.patch") + } + patchFile { + path = "paper-api/build.gradle.kts" + outputFile = file("folia-api/build.gradle.kts") + patchFile = file("folia-api/build.gradle.kts.patch") + } + patchDir("paperApi") { + upstreamPath = "paper-api" + excludes = setOf("build.gradle.kts") + patchesDir = file("folia-api/paper-patches") + outputDir = file("paper-api") + } + patchDir("paperApiGenerator") { + upstreamPath = "paper-api-generator" + patchesDir = file("folia-api-generator/paper-patches") + outputDir = file("paper-api-generator") } } } +val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" + subprojects { + apply(plugin = "java-library") + apply(plugin = "maven-publish") + + extensions.configure { + toolchain { + languageVersion = JavaLanguageVersion.of(21) + } + } + + repositories { + mavenCentral() + maven(paperMavenPublicUrl) + } + + dependencies { + "testRuntimeOnly"("org.junit.platform:junit-platform-launcher") + } + + tasks.withType().configureEach { + isPreserveFileTimestamps = false + isReproducibleFileOrder = true + } tasks.withType { options.encoding = Charsets.UTF_8.name() - options.release.set(21) + options.release = 21 options.isFork = true } tasks.withType { @@ -44,61 +71,22 @@ subprojects { tasks.withType { filteringCharset = Charsets.UTF_8.name() } - - repositories { - mavenCentral() - maven(paperMavenPublicUrl) - } -} - -paperweight { - serverProject.set(project(":folia-server")) - - remapRepo.set(paperMavenPublicUrl) - decompileRepo.set(paperMavenPublicUrl) - - usePaperUpstream(providers.gradleProperty("paperRef")) { - withPaperPatcher { - apiPatchDir.set(layout.projectDirectory.dir("patches/api")) - apiOutputDir.set(layout.projectDirectory.dir("Folia-API")) - - serverPatchDir.set(layout.projectDirectory.dir("patches/server")) - serverOutputDir.set(layout.projectDirectory.dir("Folia-Server")) - } - patchTasks.register("generatedApi") { - isBareDirectory = true - upstreamDirPath = "paper-api-generator/generated" - patchDir = layout.projectDirectory.dir("patches/generatedApi") - outputDir = layout.projectDirectory.dir("paper-api-generator/generated") + tasks.withType { + testLogging { + showStackTraces = true + exceptionFormat = TestExceptionFormat.FULL + events(TestLogEvent.STANDARD_OUT) } } -} -tasks.generateDevelopmentBundle { - apiCoordinates.set("dev.folia:folia-api") - libraryRepositories.addAll( - "https://repo.maven.apache.org/maven2/", - paperMavenPublicUrl, - ) -} - -allprojects { - publishing { + extensions.configure { repositories { + /* maven("https://repo.papermc.io/repository/maven-snapshots/") { name = "paperSnapshots" credentials(PasswordCredentials::class) } - } - } -} - -publishing { - if (project.hasProperty("publishDevBundle")) { - publications.create("devBundle") { - artifact(tasks.generateDevelopmentBundle) { - artifactId = "dev-bundle" - } + */ } } } diff --git a/folia-api/build.gradle.kts.patch b/folia-api/build.gradle.kts.patch new file mode 100644 index 0000000..4fe51fc --- /dev/null +++ b/folia-api/build.gradle.kts.patch @@ -0,0 +1,44 @@ +--- a/paper-api/build.gradle.kts ++++ b/paper-api/build.gradle.kts +@@ -103,6 +_,18 @@ + main { + java { + srcDir(generatedApiPath) ++ srcDir(file("../paper-api/src/main/java")) ++ } ++ resources { ++ srcDir(file("../paper-api/src/main/resources")) ++ } ++ } ++ test { ++ java { ++ srcDir(file("../paper-api/src/test/java")) ++ } ++ resources { ++ srcDir(file("../paper-api/src/test/resources")) + } + } + } +@@ -169,7 +_,7 @@ + + tasks.withType { + val options = options as StandardJavadocDocletOptions +- options.overview = "src/main/javadoc/overview.html" ++ options.overview = "../paper-api/src/main/javadoc/overview.html" + options.use() + options.isDocFilesSubDirs = true + options.links( +@@ -202,11 +_,11 @@ + } + + // workaround for https://github.com/gradle/gradle/issues/4046 +- inputs.dir("src/main/javadoc").withPropertyName("javadoc-sourceset") ++ inputs.dir("../paper-api/src/main/javadoc").withPropertyName("javadoc-sourceset") + val fsOps = services.fileSystemOperations + doLast { + fsOps.copy { +- from("src/main/javadoc") { ++ from("../paper-api/src/main/javadoc") { + include("**/doc-files/**") + } + into("build/docs/javadoc") diff --git a/patches/api/0001-Force-disable-timings.patch b/folia-api/paper-patches/features/0001-Force-disable-timings.patch similarity index 100% rename from patches/api/0001-Force-disable-timings.patch rename to folia-api/paper-patches/features/0001-Force-disable-timings.patch diff --git a/patches/api/0002-Region-scheduler-API.patch b/folia-api/paper-patches/features/0002-Region-scheduler-API.patch similarity index 100% rename from patches/api/0002-Region-scheduler-API.patch rename to folia-api/paper-patches/features/0002-Region-scheduler-API.patch diff --git a/patches/api/0003-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch b/folia-api/paper-patches/features/0003-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch similarity index 100% rename from patches/api/0003-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch rename to folia-api/paper-patches/features/0003-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch diff --git a/folia-api/src/main/java/io/papermc/paper/threadedregions/RegionizedServerInitEvent.java b/folia-api/src/main/java/io/papermc/paper/threadedregions/RegionizedServerInitEvent.java new file mode 100644 index 0000000..aabbbb4 --- /dev/null +++ b/folia-api/src/main/java/io/papermc/paper/threadedregions/RegionizedServerInitEvent.java @@ -0,0 +1,26 @@ +package io.papermc.paper.threadedregions; + +import org.bukkit.event.HandlerList; +import org.bukkit.event.server.ServerEvent; +import org.jetbrains.annotations.NotNull; + +/** + * This event is called after the server is initialised but before the server begins ticking regions in parallel. + * Plugins may use this as a hook to run post initialisation logic without worrying about the possibility that + * regions are ticking in parallel. + */ +public class RegionizedServerInitEvent extends ServerEvent { + + private static final HandlerList handlers = new HandlerList(); + + @NotNull + @Override + public HandlerList getHandlers() { + return handlers; + } + + @NotNull + public static HandlerList getHandlerList() { + return handlers; + } +} \ No newline at end of file diff --git a/folia-server/build.gradle.kts.patch b/folia-server/build.gradle.kts.patch new file mode 100644 index 0000000..bb2808d --- /dev/null +++ b/folia-server/build.gradle.kts.patch @@ -0,0 +1,73 @@ +--- a/paper-server/build.gradle.kts ++++ b/paper-server/build.gradle.kts +@@ -21,8 +_,19 @@ + // macheOldPath = file("F:\\Projects\\PaperTooling\\mache\\versions\\1.21.4\\src\\main\\java") + // gitFilePatches = true + ++ val fork = forks.register("folia") { ++ upstream.patchDir("paperServer") { ++ upstreamPath = "paper-server" ++ excludes = setOf("src/minecraft", "patches", "build.gradle.kts") ++ patchesDir = rootDirectory.dir("folia-server/paper-patches") ++ outputDir = rootDirectory.dir("paper-server") ++ } ++ } ++ ++ activeFork = fork ++ + paper { +- reobfMappingsPatch = layout.projectDirectory.file("../build-data/reobf-mappings-patch.tiny") ++ paperServerDir = upstreamsDirectory().map { it.dir("paper/paper-server") } + } + + spigot { +@@ -105,7 +_,20 @@ + } + } + +-val log4jPlugins = sourceSets.create("log4jPlugins") ++sourceSets { ++ main { ++ java { srcDir("../paper-server/src/main/java") } ++ resources { srcDir("../paper-server/src/main/resources") } ++ } ++ test { ++ java { srcDir("../paper-server/src/test/java") } ++ resources { srcDir("../paper-server/src/test/resources") } ++ } ++} ++ ++val log4jPlugins = sourceSets.create("log4jPlugins") { ++ java { srcDir("../paper-server/src/log4jPlugins/java") } ++} + configurations.named(log4jPlugins.compileClasspathConfigurationName) { + extendsFrom(configurations.compileClasspath.get()) + } +@@ -123,7 +_,7 @@ + } + + dependencies { +- implementation(project(":paper-api")) ++ implementation(project(":folia-api")) + implementation("ca.spottedleaf:concurrentutil:0.0.2") + implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ + implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21 +@@ -192,14 +_,14 @@ + val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() + attributes( + "Main-Class" to "org.bukkit.craftbukkit.Main", +- "Implementation-Title" to "Paper", ++ "Implementation-Title" to "Folia", // Folia + "Implementation-Version" to implementationVersion, + "Implementation-Vendor" to date, +- "Specification-Title" to "Paper", ++ "Specification-Title" to "Folia", // Folia + "Specification-Version" to project.version, + "Specification-Vendor" to "Paper Team", +- "Brand-Id" to "papermc:paper", +- "Brand-Name" to "Paper", ++ "Brand-Id" to "papermc:folia", // Folia ++ "Brand-Name" to "Folia", // Folia + "Build-Number" to (build ?: ""), + "Build-Time" to buildTime.toString(), + "Git-Branch" to gitBranch, diff --git a/patches/server/0003-Threaded-Regions.patch b/folia-server/minecraft-patches/features/0001-Threaded-Regions.patch similarity index 65% rename from patches/server/0003-Threaded-Regions.patch rename to folia-server/minecraft-patches/features/0001-Threaded-Regions.patch index 1d33b2e..59a8c0a 100644 --- a/patches/server/0003-Threaded-Regions.patch +++ b/folia-server/minecraft-patches/features/0001-Threaded-Regions.patch @@ -6,26 +6,27 @@ Subject: [PATCH] Threaded Regions See https://docs.papermc.io/folia/reference/overview and https://docs.papermc.io/folia/reference/region-logic -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java b/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java -index 1d288e73fd8605676c0da676e068afb5b4b8abea..30eb7fd0b83ad1626d337cb770fac3dda5202344 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/ChunkSystem.java -@@ -78,17 +78,22 @@ public final class ChunkSystem { - } +diff --git a/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java b/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java +index ece1261b67033e946dfc20a96872708755bffe0a..58986c62c485cae379180ba95ba0ea60145ef73f 100644 +--- a/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java ++++ b/ca/spottedleaf/moonrise/paper/util/BaseChunkSystemHooks.java +@@ -80,18 +80,23 @@ public abstract class BaseChunkSystemHooks implements ca.spottedleaf.moonrise.co - public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { + @Override + public void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) { - + // Folia start - threaded regions + level.regioniser.addChunk(holder.getPos().x, holder.getPos().z); + // Folia end - threaded regions } - public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { + @Override + public void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { // Update progress listener for LevelLoadingScreen -- final ChunkProgressListener progressListener = level.getChunkSource().chunkMap.progressListener; -+ final ChunkProgressListener progressListener = null; // Folia - threaded regions - cannot schedule chunk task here; as it would create a chunkholder +- final net.minecraft.server.level.progress.ChunkProgressListener progressListener = level.getChunkSource().chunkMap.progressListener; ++ final net.minecraft.server.level.progress.ChunkProgressListener progressListener = null; // Folia - threaded regions - cannot schedule chunk task here; as it would create a chunkholder if (progressListener != null) { - ChunkSystem.scheduleChunkTask(level, holder.getPos().x, holder.getPos().z, () -> { + this.scheduleChunkTask(level, holder.getPos().x, holder.getPos().z, () -> { progressListener.onStatusChange(holder.getPos(), null); }); } @@ -34,244 +35,70 @@ index 1d288e73fd8605676c0da676e068afb5b4b8abea..30eb7fd0b83ad1626d337cb770fac3dd + // Folia end - threaded regions } - public static void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) { -@@ -97,16 +102,12 @@ public final class ChunkSystem { - } + @Override +@@ -102,17 +107,13 @@ public abstract class BaseChunkSystemHooks implements ca.spottedleaf.moonrise.co - public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { -- ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add( -- ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() + @Override + public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() - ); + chunk.getLevel().getCurrentWorldData().addChunk(chunk.moonrise$getChunkAndHolder()); // Folia - region threading chunk.loadCallback(); } - public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { -- ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove( -- ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() + @Override + public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() - ); + chunk.getLevel().getCurrentWorldData().removeChunk(chunk.moonrise$getChunkAndHolder()); // Folia - region threading chunk.unloadCallback(); } -@@ -116,9 +117,7 @@ public final class ChunkSystem { - } +@@ -124,9 +125,7 @@ public abstract class BaseChunkSystemHooks implements ca.spottedleaf.moonrise.co - public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { -- ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add( -- ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() + @Override + public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() - ); + chunk.getLevel().getCurrentWorldData().addTickingChunk(chunk.moonrise$getChunkAndHolder()); // Folia - region threading - if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) { + if (!((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) { chunk.postProcessGeneration((ServerLevel)chunk.getLevel()); } -@@ -128,22 +127,16 @@ public final class ChunkSystem { - } +@@ -137,24 +136,18 @@ public abstract class BaseChunkSystemHooks implements ca.spottedleaf.moonrise.co - public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { -- ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove( -- ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() + @Override + public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() - ); + chunk.getLevel().getCurrentWorldData().removeTickingChunk(chunk.moonrise$getChunkAndHolder()); // Folia - region threading - ((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration + ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration } - public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -- ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add( -- ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() + @Override + public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() - ); + chunk.getLevel().getCurrentWorldData().addEntityTickingChunk(chunk.moonrise$getChunkAndHolder()); // Folia - region threading } - public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { -- ((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove( -- ((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() + @Override + public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) { +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder() - ); + chunk.getLevel().getCurrentWorldData().removeEntityTickingChunk(chunk.moonrise$getChunkAndHolder()); // Folia - region threading } - public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) { -diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java -index 217d1f908a36a5177ba3cbb80a33f73d4dab0fa0..301cc1c0d91f5e755f74ace60dbe5551240b496d 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java -+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java -@@ -1,5 +1,11 @@ - package ca.spottedleaf.moonrise.common.util; - -+import io.papermc.paper.threadedregions.RegionShutdownThread; -+import io.papermc.paper.threadedregions.RegionizedServer; -+import io.papermc.paper.threadedregions.RegionizedWorldData; -+import io.papermc.paper.threadedregions.ThreadedRegionizer; -+import io.papermc.paper.threadedregions.TickRegionScheduler; -+import io.papermc.paper.threadedregions.TickRegions; - import net.minecraft.core.BlockPos; - import net.minecraft.world.entity.Entity; - import net.minecraft.world.level.ChunkPos; -@@ -98,46 +104,149 @@ public class TickThread extends Thread { - } - - public static boolean isShutdownThread() { -- return false; -+ return Thread.currentThread().getClass() == RegionShutdownThread.class; - } - - public static boolean isTickThreadFor(final Level world, final BlockPos pos) { -- return isTickThread(); -+ return isTickThreadFor(world, pos.getX() >> 4, pos.getZ() >> 4); - } - - public static boolean isTickThreadFor(final Level world, final ChunkPos pos) { -- return isTickThread(); -+ return isTickThreadFor(world, pos.x, pos.z); - } - - public static boolean isTickThreadFor(final Level world, final Vec3 pos) { -- return isTickThread(); -+ return isTickThreadFor(world, net.minecraft.util.Mth.floor(pos.x) >> 4, net.minecraft.util.Mth.floor(pos.z) >> 4); - } - - public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ) { -- return isTickThread(); -+ final ThreadedRegionizer.ThreadedRegion region = -+ TickRegionScheduler.getCurrentRegion(); -+ if (region == null) { -+ return isShutdownThread(); -+ } -+ return ((net.minecraft.server.level.ServerLevel)world).regioniser.getRegionAtUnsynchronised(chunkX, chunkZ) == region; - } - - public static boolean isTickThreadFor(final Level world, final AABB aabb) { -- return isTickThread(); -+ return isTickThreadFor( -+ world, -+ CoordinateUtils.getChunkCoordinate(aabb.minX), CoordinateUtils.getChunkCoordinate(aabb.minZ), -+ CoordinateUtils.getChunkCoordinate(aabb.maxX), CoordinateUtils.getChunkCoordinate(aabb.maxZ) -+ ); - } - - public static boolean isTickThreadFor(final Level world, final double blockX, final double blockZ) { -- return isTickThread(); -+ return isTickThreadFor(world, CoordinateUtils.getChunkCoordinate(blockX), CoordinateUtils.getChunkCoordinate(blockZ)); - } - - public static boolean isTickThreadFor(final Level world, final Vec3 position, final Vec3 deltaMovement, final int buffer) { -- return isTickThread(); -+ final int fromChunkX = CoordinateUtils.getChunkX(position); -+ final int fromChunkZ = CoordinateUtils.getChunkZ(position); -+ -+ final int toChunkX = CoordinateUtils.getChunkCoordinate(position.x + deltaMovement.x); -+ final int toChunkZ = CoordinateUtils.getChunkCoordinate(position.z + deltaMovement.z); -+ -+ // expect from < to, but that may not be the case -+ return isTickThreadFor( -+ world, -+ Math.min(fromChunkX, toChunkX) - buffer, -+ Math.min(fromChunkZ, toChunkZ) - buffer, -+ Math.max(fromChunkX, toChunkX) + buffer, -+ Math.max(fromChunkZ, toChunkZ) + buffer -+ ); - } - - public static boolean isTickThreadFor(final Level world, final int fromChunkX, final int fromChunkZ, final int toChunkX, final int toChunkZ) { -- return isTickThread(); -+ final ThreadedRegionizer.ThreadedRegion region = -+ TickRegionScheduler.getCurrentRegion(); -+ if (region == null) { -+ return isShutdownThread(); -+ } -+ -+ final int shift = ((net.minecraft.server.level.ServerLevel)world).regioniser.sectionChunkShift; -+ -+ final int minSectionX = fromChunkX >> shift; -+ final int maxSectionX = toChunkX >> shift; -+ final int minSectionZ = fromChunkZ >> shift; -+ final int maxSectionZ = toChunkZ >> shift; -+ -+ for (int secZ = minSectionZ; secZ <= maxSectionZ; ++secZ) { -+ for (int secX = minSectionX; secX <= maxSectionX; ++secX) { -+ final int lowerLeftCX = secX << shift; -+ final int lowerLeftCZ = secZ << shift; -+ if (((net.minecraft.server.level.ServerLevel)world).regioniser.getRegionAtUnsynchronised(lowerLeftCX, lowerLeftCZ) != region) { -+ return false; -+ } -+ } -+ } -+ -+ return true; - } - - public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ, final int radius) { -- return isTickThread(); -+ return isTickThreadFor(world, chunkX - radius, chunkZ - radius, chunkX + radius, chunkZ + radius); - } - - public static boolean isTickThreadFor(final Entity entity) { -- return isTickThread(); -+ if (entity == null) { -+ return true; -+ } -+ final ThreadedRegionizer.ThreadedRegion region = -+ TickRegionScheduler.getCurrentRegion(); -+ if (region == null) { -+ if (RegionizedServer.isGlobalTickThread()) { -+ if (entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { -+ final net.minecraft.server.network.ServerGamePacketListenerImpl possibleBad = serverPlayer.connection; -+ if (possibleBad == null) { -+ return true; -+ } -+ -+ final net.minecraft.network.PacketListener packetListener = possibleBad.connection.getPacketListener(); -+ if (packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { -+ return gamePacketListener.waitingForSwitchToConfig; -+ } -+ if (packetListener instanceof net.minecraft.server.network.ServerConfigurationPacketListenerImpl configurationPacketListener) { -+ return !configurationPacketListener.switchToMain; -+ } -+ return true; -+ } else { -+ return false; -+ } -+ } -+ if (isShutdownThread()) { -+ return true; -+ } -+ if (entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { -+ // off-main access to server player is never ok, server player is owned by one of global context or region context always -+ return false; -+ } -+ // only own entities that have not yet been added to the world -+ -+ // if the entity is removed, then it was in the world previously - which means that a region containing its location -+ // owns it -+ // if the entity has a callback, then it is contained in a world -+ return entity.hasNullCallback() && !entity.isRemoved(); -+ } -+ -+ final Level world = entity.level(); -+ if (world != region.regioniser.world) { -+ // world mismatch -+ return false; -+ } -+ -+ final RegionizedWorldData worldData = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); -+ -+ // pass through the check if the entity is removed and we own its chunk -+ if (worldData.hasEntity(entity)) { -+ return true; -+ } -+ -+ if (entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { -+ net.minecraft.server.network.ServerGamePacketListenerImpl conn = serverPlayer.connection; -+ return conn != null && worldData.connections.contains(conn.connection); -+ } else { -+ return ((entity.hasNullCallback() || entity.isRemoved())) && isTickThreadFor((net.minecraft.server.level.ServerLevel)world, entity.chunkPosition()); -+ } - } - } -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java + @Override +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java index 7554c109c35397bc1a43dd80e87764fd78645bbf..db16fe8d664f9b04710200d63439564cb97c0066 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java +--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java @@ -460,6 +460,19 @@ public abstract class EntityLookup implements LevelEntityGetter { return slices == null || !slices.isPreventingStatusUpdates(); } @@ -302,11 +129,11 @@ index 7554c109c35397bc1a43dd80e87764fd78645bbf..db16fe8d664f9b04710200d63439564c } } -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java -index 58d9187adc188b693b6becc400f766e069bf1bf5..2b44515cede7dfa6d8dbfd469e53632b41dc1c21 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java -@@ -18,7 +18,7 @@ public final class ServerEntityLookup extends EntityLookup { +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java +index 26207443b1223119c03db478d7e816d9cdf8e618..a89ee24c6aed46af23c5de7ae2234c7902f1c0f4 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/server/ServerEntityLookup.java +@@ -17,7 +17,7 @@ public final class ServerEntityLookup extends EntityLookup { private static final Entity[] EMPTY_ENTITY_ARRAY = new Entity[0]; private final ServerLevel serverWorld; @@ -315,7 +142,7 @@ index 58d9187adc188b693b6becc400f766e069bf1bf5..2b44515cede7dfa6d8dbfd469e53632b public ServerEntityLookup(final ServerLevel world, final LevelCallback worldCallback) { super(world, worldCallback); -@@ -76,6 +76,7 @@ public final class ServerEntityLookup extends EntityLookup { +@@ -75,6 +75,7 @@ public final class ServerEntityLookup extends EntityLookup { if (entity instanceof ServerPlayer player) { ((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player); } @@ -323,7 +150,7 @@ index 58d9187adc188b693b6becc400f766e069bf1bf5..2b44515cede7dfa6d8dbfd469e53632b } @Override -@@ -88,14 +89,14 @@ public final class ServerEntityLookup extends EntityLookup { +@@ -87,14 +88,14 @@ public final class ServerEntityLookup extends EntityLookup { @Override protected void entityStartLoaded(final Entity entity) { // Moonrise start - entity tracker @@ -340,10 +167,10 @@ index 58d9187adc188b693b6becc400f766e069bf1bf5..2b44515cede7dfa6d8dbfd469e53632b // Moonrise end - entity tracker } -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java index dd2509996bfd08e8c3f9f2be042229eac6d7692d..f77dcf5a42ff34a1624ddf16bcce2abee81194bb 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java @@ -216,7 +216,7 @@ public final class RegionizedPlayerChunkLoader { final PlayerChunkLoaderData loader = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader(); @@ -362,10 +189,10 @@ index dd2509996bfd08e8c3f9f2be042229eac6d7692d..f77dcf5a42ff34a1624ddf16bcce2abe final PlayerChunkLoaderData loader = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader(); if (loader == null || loader.removed || loader.world != this.world) { // not our problem anymore -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java b/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java index 7eafc5b7cba23d8dec92ecc1050afe3fd8c9e309..4bfcae47ed76346e6200514ebce5b04f907c5026 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java +--- a/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/queue/ChunkUnloadQueue.java @@ -29,6 +29,39 @@ public final class ChunkUnloadQueue { public static record SectionToUnload(int sectionX, int sectionZ, long order, int count) {} @@ -413,11 +240,11 @@ index 7eafc5b7cba23d8dec92ecc1050afe3fd8c9e309..4bfcae47ed76346e6200514ebce5b04f -} \ No newline at end of file +} -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee721b95d506 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -@@ -57,6 +57,14 @@ import java.util.concurrent.atomic.AtomicReference; +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java +index b5817aa8f537593f6d9fc6b612c82ccccb250ac7..aae97116a22a87cffd4756d566da3acd96ce2ae0 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java +@@ -56,6 +56,14 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.LockSupport; import java.util.function.Predicate; @@ -432,7 +259,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 public final class ChunkHolderManager { private static final Logger LOGGER = LogUtils.getClassLogger(); -@@ -79,29 +87,83 @@ public final class ChunkHolderManager { +@@ -78,29 +86,83 @@ public final class ChunkHolderManager { private final ConcurrentLong2ReferenceChainedHashTable chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f); private final ServerLevel world; private final ChunkTaskScheduler taskScheduler; @@ -530,7 +357,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 public ChunkHolderManager(final ServerLevel world, final ChunkTaskScheduler taskScheduler) { this.world = world; -@@ -186,8 +248,13 @@ public final class ChunkHolderManager { +@@ -185,8 +247,13 @@ public final class ChunkHolderManager { } public void close(final boolean save, final boolean halt) { @@ -545,7 +372,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 LOGGER.info("Waiting 60s for chunk system to halt for world '" + WorldUtil.getWorldName(this.world) + "'"); if (!this.taskScheduler.halt(true, TimeUnit.SECONDS.toNanos(60L))) { LOGGER.warn("Failed to halt generation/loading tasks for world '" + WorldUtil.getWorldName(this.world) + "'"); -@@ -197,9 +264,10 @@ public final class ChunkHolderManager { +@@ -196,9 +263,10 @@ public final class ChunkHolderManager { } if (save) { @@ -557,7 +384,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 MoonriseRegionFileIO.flush(this.world); if (halt) { -@@ -221,28 +289,35 @@ public final class ChunkHolderManager { +@@ -220,28 +288,35 @@ public final class ChunkHolderManager { } this.taskScheduler.setShutdown(true); @@ -600,7 +427,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 holder.lastAutoSave = currentTick; if (holder.save(false) != null) { -@@ -256,15 +331,38 @@ public final class ChunkHolderManager { +@@ -255,15 +330,38 @@ public final class ChunkHolderManager { for (final NewChunkHolder holder : reschedule) { if (holder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)) { @@ -642,7 +469,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 LOGGER.info("Saving all chunkholders for world '" + WorldUtil.getWorldName(this.world) + "'"); } -@@ -293,6 +391,12 @@ public final class ChunkHolderManager { +@@ -292,6 +390,12 @@ public final class ChunkHolderManager { } for (int i = 0, len = holders.size(); i < len; ++i) { final NewChunkHolder holder = holders.get(i); @@ -655,7 +482,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 try { final NewChunkHolder.SaveStat saveStat = holder.save(shutdown); if (saveStat != null) { -@@ -328,7 +432,7 @@ public final class ChunkHolderManager { +@@ -327,7 +431,7 @@ public final class ChunkHolderManager { } } } @@ -664,7 +491,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 MoonriseRegionFileIO.flush(this.world); try { MoonriseRegionFileIO.flushRegionStorages(this.world); -@@ -733,7 +837,13 @@ public final class ChunkHolderManager { +@@ -732,7 +836,13 @@ public final class ChunkHolderManager { } public void tick() { @@ -679,7 +506,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 final int sectionShift = ((ChunkSystemServerLevel)this.world).moonrise$getRegionChunkShift(); -@@ -747,7 +857,7 @@ public final class ChunkHolderManager { +@@ -746,7 +856,7 @@ public final class ChunkHolderManager { return removeDelay <= 0L; }; @@ -688,7 +515,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 final long sectionKey = iterator.nextLong(); if (!this.sectionToChunkToExpireCount.containsKey(sectionKey)) { -@@ -1032,26 +1142,56 @@ public final class ChunkHolderManager { +@@ -1031,26 +1141,56 @@ public final class ChunkHolderManager { if (changedFullStatus.isEmpty()) { return; } @@ -755,10 +582,10 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 holder.onUnload(); - this.autoSaveQueue.remove(holder); + this.getCurrentRegionData().autoSaveQueue.remove(holder); // Folia - region threading - ChunkSystem.onChunkHolderDelete(this.world, holder.vanillaChunkHolder); + PlatformHooks.get().onChunkHolderDelete(this.world, holder.vanillaChunkHolder); this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ)); } -@@ -1064,7 +1204,7 @@ public final class ChunkHolderManager { +@@ -1063,7 +1203,7 @@ public final class ChunkHolderManager { throw new IllegalStateException("Cannot unload chunks recursively"); } final int sectionShift = this.unloadQueue.coordinateShift; // sectionShift <= lock shift @@ -767,7 +594,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 int unloadCountTentative = 0; for (final ChunkUnloadQueue.SectionToUnload sectionRef : unloadSectionsForRegion) { final ChunkUnloadQueue.UnloadSection section -@@ -1382,7 +1522,13 @@ public final class ChunkHolderManager { +@@ -1381,7 +1521,13 @@ public final class ChunkHolderManager { // only call on tick thread private boolean processPendingFullUpdate() { @@ -782,7 +609,7 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 boolean ret = false; -@@ -1393,9 +1539,7 @@ public final class ChunkHolderManager { +@@ -1392,9 +1538,7 @@ public final class ChunkHolderManager { ret |= holder.handleFullStatusChange(changedFullStatus); if (!changedFullStatus.isEmpty()) { @@ -793,10 +620,10 @@ index 3990834a41116682d6ae779a3bf24b0fd989d97d..dbb5b6ee36a54d6682b2a6d9389aee72 changedFullStatus.clear(); } } -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java index 67532b85073b7978254a0b04caadfe822679e61f..cba2d16c0cb5adc92952990ef95b1c979eafd40f 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java +--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkTaskScheduler.java @@ -122,7 +122,7 @@ public final class ChunkTaskScheduler { public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor compressionExecutor; public final PrioritisedThreadPool.ExecutorGroup.ThreadPoolExecutor saveExecutor; @@ -870,11 +697,11 @@ index 67532b85073b7978254a0b04caadfe822679e61f..cba2d16c0cb5adc92952990ef95b1c97 public boolean halt(final boolean sync, final long maxWaitNS) { this.radiusAwareGenExecutor.halt(); this.parallelGenExecutor.halt(); -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -index eafa4e6d55cd0f9314ac0f2b96a7f48fbb5e1a4c..9e7e10fe46dbbd03d690a65af6ae719d1665bc6a 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -@@ -1360,10 +1360,10 @@ public final class NewChunkHolder { +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java +index e4a5fa25ed368fc4662c30934da2963ef446d782..601ed36413bbbf9c17e530b42906986e441237fd 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java +@@ -1359,10 +1359,10 @@ public final class NewChunkHolder { private void completeStatusConsumers(ChunkStatus status, final ChunkAccess chunk) { // Update progress listener for LevelLoadingScreen if (chunk != null) { @@ -887,7 +714,7 @@ index eafa4e6d55cd0f9314ac0f2b96a7f48fbb5e1a4c..9e7e10fe46dbbd03d690a65af6ae719d progressListener.onStatusChange(this.vanillaChunkHolder.getPos(), finalStatus); }); } -@@ -1384,7 +1384,7 @@ public final class NewChunkHolder { +@@ -1383,7 +1383,7 @@ public final class NewChunkHolder { } // must be scheduled to main, we do not trust the callback to not do anything stupid @@ -896,7 +723,7 @@ index eafa4e6d55cd0f9314ac0f2b96a7f48fbb5e1a4c..9e7e10fe46dbbd03d690a65af6ae719d for (final Consumer consumer : consumers) { try { consumer.accept(chunk); -@@ -1412,7 +1412,7 @@ public final class NewChunkHolder { +@@ -1411,7 +1411,7 @@ public final class NewChunkHolder { } // must be scheduled to main, we do not trust the callback to not do anything stupid @@ -905,10 +732,10 @@ index eafa4e6d55cd0f9314ac0f2b96a7f48fbb5e1a4c..9e7e10fe46dbbd03d690a65af6ae719d for (final Consumer consumer : consumers) { try { consumer.accept(chunk); -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +diff --git a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java index e04bd54744335fb5398c6e4f7ce8b981f35bfb7d..c7ce32b31fc4247e72baa5f2dedac7378fa708c3 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java +--- a/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java ++++ b/ca/spottedleaf/moonrise/patches/collisions/CollisionUtil.java @@ -1940,7 +1940,7 @@ public final class CollisionUtil { for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) { @@ -918,11 +745,187 @@ index e04bd54744335fb5398c6e4f7ce8b981f35bfb7d..c7ce32b31fc4247e72baa5f2dedac737 if (chunk == null) { if ((collisionFlags & COLLISION_FLAG_COLLIDE_WITH_UNLOADED_CHUNKS) != 0) { -diff --git a/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java -index e7d510af3e415064fd483f0220d5f6a4cd0b9f63..8bc53743698df06cc31365e82c211257cfff6a82 100644 ---- a/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java -+++ b/src/main/java/com/destroystokyo/paper/util/RedstoneWireTurbo.java -@@ -836,14 +836,14 @@ public class RedstoneWireTurbo { +diff --git a/io/papermc/paper/entity/activation/ActivationRange.java b/io/papermc/paper/entity/activation/ActivationRange.java +index bd888ef719b9bfc93bace0b1d0fb771ac659f515..ba8b5a0ebe652bfaf5c1498c19d12a91a192bf8e 100644 +--- a/io/papermc/paper/entity/activation/ActivationRange.java ++++ b/io/papermc/paper/entity/activation/ActivationRange.java +@@ -48,33 +48,34 @@ public final class ActivationRange { + + private static int checkInactiveWakeup(final Entity entity) { + final Level world = entity.level(); ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - threaded regions + final SpigotWorldConfig config = world.spigotConfig; +- final long inactiveFor = MinecraftServer.currentTick - entity.activatedTick; ++ final long inactiveFor = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() - entity.activatedTick; // Folia - threaded regions + if (entity.activationType == ActivationType.VILLAGER) { +- if (inactiveFor > config.wakeUpInactiveVillagersEvery && world.wakeupInactiveRemainingVillagers > 0) { +- world.wakeupInactiveRemainingVillagers--; ++ if (inactiveFor > config.wakeUpInactiveVillagersEvery && worldData.wakeupInactiveRemainingVillagers > 0) { // Folia - threaded regions ++ worldData.wakeupInactiveRemainingVillagers--; // Folia - threaded regions + return config.wakeUpInactiveVillagersFor; + } + } else if (entity.activationType == ActivationType.ANIMAL) { +- if (inactiveFor > config.wakeUpInactiveAnimalsEvery && world.wakeupInactiveRemainingAnimals > 0) { +- world.wakeupInactiveRemainingAnimals--; ++ if (inactiveFor > config.wakeUpInactiveAnimalsEvery && worldData.wakeupInactiveRemainingAnimals > 0) { // Folia - threaded regions ++ worldData.wakeupInactiveRemainingAnimals--; // Folia - threaded regions + return config.wakeUpInactiveAnimalsFor; + } + } else if (entity.activationType == ActivationType.FLYING_MONSTER) { +- if (inactiveFor > config.wakeUpInactiveFlyingEvery && world.wakeupInactiveRemainingFlying > 0) { +- world.wakeupInactiveRemainingFlying--; ++ if (inactiveFor > config.wakeUpInactiveFlyingEvery && worldData.wakeupInactiveRemainingFlying > 0) { // Folia - threaded regions ++ worldData.wakeupInactiveRemainingFlying--; // Folia - threaded regions + return config.wakeUpInactiveFlyingFor; + } + } else if (entity.activationType == ActivationType.MONSTER || entity.activationType == ActivationType.RAIDER) { +- if (inactiveFor > config.wakeUpInactiveMonstersEvery && world.wakeupInactiveRemainingMonsters > 0) { +- world.wakeupInactiveRemainingMonsters--; ++ if (inactiveFor > config.wakeUpInactiveMonstersEvery && worldData.wakeupInactiveRemainingMonsters > 0) { // Folia - threaded regions ++ worldData.wakeupInactiveRemainingMonsters--; // Folia - threaded regions + return config.wakeUpInactiveMonstersFor; + } + } + return -1; + } + +- static AABB maxBB = new AABB(0, 0, 0, 0, 0, 0); ++ //static AABB maxBB = new AABB(0, 0, 0, 0, 0, 0); // Folia - threaded regions - replaced by local variable + + /** + * These entities are excluded from Activation range checks. +@@ -122,10 +123,11 @@ public final class ActivationRange { + final int waterActivationRange = world.spigotConfig.waterActivationRange; + final int flyingActivationRange = world.spigotConfig.flyingMonsterActivationRange; + final int villagerActivationRange = world.spigotConfig.villagerActivationRange; +- world.wakeupInactiveRemainingAnimals = Math.min(world.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals); +- world.wakeupInactiveRemainingVillagers = Math.min(world.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers); +- world.wakeupInactiveRemainingMonsters = Math.min(world.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters); +- world.wakeupInactiveRemainingFlying = Math.min(world.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying); ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - threaded regions ++ worldData.wakeupInactiveRemainingAnimals = Math.min(worldData.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals); // Folia - threaded regions ++ worldData.wakeupInactiveRemainingVillagers = Math.min(worldData.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers); // Folia - threaded regions ++ worldData.wakeupInactiveRemainingMonsters = Math.min(worldData.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters); // Folia - threaded regions ++ worldData.wakeupInactiveRemainingFlying = Math.min(worldData.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying); // Folia - threaded regions + + int maxRange = Math.max(monsterActivationRange, animalActivationRange); + maxRange = Math.max(maxRange, raiderActivationRange); +@@ -135,30 +137,37 @@ public final class ActivationRange { + maxRange = Math.max(maxRange, villagerActivationRange); + maxRange = Math.min((world.spigotConfig.simulationDistance << 4) - 8, maxRange); + +- for (final Player player : world.players()) { +- player.activatedTick = MinecraftServer.currentTick; ++ for (final Player player : world.getLocalPlayers()) { // Folia - region threading ++ player.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - region threading + if (world.spigotConfig.ignoreSpectatorActivation && player.isSpectator()) { + continue; + } + + final int worldHeight = world.getHeight(); +- ActivationRange.maxBB = player.getBoundingBox().inflate(maxRange, worldHeight, maxRange); +- ActivationType.MISC.boundingBox = player.getBoundingBox().inflate(miscActivationRange, worldHeight, miscActivationRange); +- ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate(raiderActivationRange, worldHeight, raiderActivationRange); +- ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate(animalActivationRange, worldHeight, animalActivationRange); +- ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate(monsterActivationRange, worldHeight, monsterActivationRange); +- ActivationType.WATER.boundingBox = player.getBoundingBox().inflate(waterActivationRange, worldHeight, waterActivationRange); +- ActivationType.FLYING_MONSTER.boundingBox = player.getBoundingBox().inflate(flyingActivationRange, worldHeight, flyingActivationRange); +- ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate(villagerActivationRange, worldHeight, villagerActivationRange); ++ final AABB maxBB = player.getBoundingBox().inflate(maxRange, worldHeight, maxRange); // Folia - threaded regions ++ final AABB[] bbByType = new AABB[ActivationType.values().length]; // Folia - threaded regions ++ bbByType[ActivationType.MISC.ordinal()] = player.getBoundingBox().inflate(miscActivationRange, worldHeight, miscActivationRange); // Folia - threaded regions ++ bbByType[ActivationType.RAIDER.ordinal()] = player.getBoundingBox().inflate(raiderActivationRange, worldHeight, raiderActivationRange); // Folia - threaded regions ++ bbByType[ActivationType.ANIMAL.ordinal()] = player.getBoundingBox().inflate(animalActivationRange, worldHeight, animalActivationRange); // Folia - threaded regions ++ bbByType[ActivationType.MONSTER.ordinal()] = player.getBoundingBox().inflate(monsterActivationRange, worldHeight, monsterActivationRange); // Folia - threaded regions ++ bbByType[ActivationType.WATER.ordinal()] = player.getBoundingBox().inflate(waterActivationRange, worldHeight, waterActivationRange); // Folia - threaded regions ++ bbByType[ActivationType.FLYING_MONSTER.ordinal()] = player.getBoundingBox().inflate(flyingActivationRange, worldHeight, flyingActivationRange); // Folia - threaded regions ++ bbByType[ActivationType.VILLAGER.ordinal()] = player.getBoundingBox().inflate(villagerActivationRange, worldHeight, villagerActivationRange); // Folia - threaded regions + +- final java.util.List entities = world.getEntities((Entity) null, ActivationRange.maxBB, e -> true); ++ final java.util.List entities = new java.util.ArrayList<>(); // Folia - region ticking - bypass getEntities thread check, we perform a check on the entities later ++ ((net.minecraft.server.level.ServerLevel)world).moonrise$getEntityLookup().getEntities((Entity)null, maxBB, entities, null); // Folia - region ticking - bypass getEntities thread check, we perform a check on the entities later + final boolean tickMarkers = world.paperConfig().entities.markers.tick; + for (final Entity entity : entities) { ++ // Folia start - region ticking ++ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) { ++ continue; ++ } ++ // Folia end - region ticking + if (!tickMarkers && entity instanceof net.minecraft.world.entity.Marker) { + continue; + } + +- ActivationRange.activateEntity(entity); ++ ActivationRange.activateEntity(entity, bbByType); // Folia - threaded regions + } + } + } +@@ -168,14 +177,14 @@ public final class ActivationRange { + * + * @param entity + */ +- private static void activateEntity(final Entity entity) { +- if (MinecraftServer.currentTick > entity.activatedTick) { ++ private static void activateEntity(final Entity entity, final AABB[] bbByType) { // Folia - threaded regions ++ if (io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() > entity.activatedTick) { // Folia - threaded regions + if (entity.defaultActivationState) { +- entity.activatedTick = MinecraftServer.currentTick; ++ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions + return; + } +- if (entity.activationType.boundingBox.intersects(entity.getBoundingBox())) { +- entity.activatedTick = MinecraftServer.currentTick; ++ if (bbByType[entity.activationType.ordinal()].intersects(entity.getBoundingBox())) { // Folia - threaded regions ++ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions + } + } + } +@@ -189,6 +198,7 @@ public final class ActivationRange { + */ + public static int checkEntityImmunities(final Entity entity) { // return # of ticks to get immunity + final SpigotWorldConfig config = entity.level().spigotConfig; ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = entity.level().getCurrentWorldData(); // Folia - threaded regions + final int inactiveWakeUpImmunity = checkInactiveWakeup(entity); + if (inactiveWakeUpImmunity > -1) { + return inactiveWakeUpImmunity; +@@ -196,10 +206,10 @@ public final class ActivationRange { + if (entity.getRemainingFireTicks() > 0) { + return 2; + } +- if (entity.activatedImmunityTick >= MinecraftServer.currentTick) { ++ if (entity.activatedImmunityTick >= io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick()) { // Folia - threaded regions + return 1; + } +- final long inactiveFor = MinecraftServer.currentTick - entity.activatedTick; ++ final long inactiveFor = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() - entity.activatedTick; // Folia - threaded regions + if ((entity.activationType != ActivationType.WATER && entity.isInWater() && entity.isPushedByFluid())) { + return 100; + } +@@ -296,16 +306,16 @@ public final class ActivationRange { + return true; + } + +- boolean isActive = entity.activatedTick >= MinecraftServer.currentTick; ++ boolean isActive = entity.activatedTick >= io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions + entity.isTemporarilyActive = false; + + // Should this entity tick? + if (!isActive) { +- if ((MinecraftServer.currentTick - entity.activatedTick - 1) % 20 == 0) { ++ if ((io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() - entity.activatedTick - 1) % 20 == 0) { // Folia - threaded regions + // Check immunities every 20 ticks. + final int immunity = checkEntityImmunities(entity); + if (immunity >= 0) { +- entity.activatedTick = MinecraftServer.currentTick + immunity; ++ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + immunity; // Folia - threaded regions + } else { + entity.isTemporarilyActive = true; + } +diff --git a/io/papermc/paper/redstone/RedstoneWireTurbo.java b/io/papermc/paper/redstone/RedstoneWireTurbo.java +index ff747a1ecdf3c888bca0d69de4f85dcd810b6139..5a76c93eada8db35b1ddbb562ccfbd2f0d35f0ca 100644 +--- a/io/papermc/paper/redstone/RedstoneWireTurbo.java ++++ b/io/papermc/paper/redstone/RedstoneWireTurbo.java +@@ -829,14 +829,14 @@ public final class RedstoneWireTurbo { j = getMaxCurrentStrength(upd, j); int l = 0; @@ -939,265 +942,11 @@ index e7d510af3e415064fd483f0220d5f6a4cd0b9f63..8bc53743698df06cc31365e82c211257 // The variable 'k' holds the maximum redstone power value of any adjacent blocks. // If 'k' has the highest level of all neighbors, then the power level of this -diff --git a/src/main/java/io/papermc/paper/SparksFly.java b/src/main/java/io/papermc/paper/SparksFly.java -index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..2ad5b9b0b7e18780ee73310451d9fa73f44c4bdb 100644 ---- a/src/main/java/io/papermc/paper/SparksFly.java -+++ b/src/main/java/io/papermc/paper/SparksFly.java -@@ -33,13 +33,13 @@ public final class SparksFly { - - private final Logger logger; - private final PaperSparkModule spark; -- private final ConcurrentLinkedQueue mainThreadTaskQueue; -+ // Folia - region threading - - private boolean enabled; - private boolean disabledInConfigurationWarningLogged; - - public SparksFly(final Server server) { -- this.mainThreadTaskQueue = new ConcurrentLinkedQueue<>(); -+ // Folia - region threading - this.logger = Logger.getLogger(ID); - this.logger.log(Level.INFO, "This server bundles the spark profiler. For more information please visit https://docs.papermc.io/paper/profiling"); - this.spark = PaperSparkModule.create(Compatibility.VERSION_1_0, server, this.logger, new PaperScheduler() { -@@ -50,7 +50,7 @@ public final class SparksFly { - - @Override - public void executeSync(final Runnable runnable) { -- SparksFly.this.mainThreadTaskQueue.offer(this.catching(runnable, "synchronous")); -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(this.catching(runnable, "synchronous")); // Folia - region threading - } - - private Runnable catching(final Runnable runnable, final String type) { -@@ -88,10 +88,7 @@ public final class SparksFly { - } - - public void executeMainThreadTasks() { -- Runnable task; -- while ((task = this.mainThreadTaskQueue.poll()) != null) { -- task.run(); -- } -+ throw new UnsupportedOperationException(); // Folia - region threading - } - - public void enableEarlyIfRequested() { -diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java -index 14e412ebf75b0e06ab53a1c8f9dd1be6ad1e2680..3f733319482fedcf7461f4b7466e84afeae1fc2b 100644 ---- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java -+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java -@@ -83,7 +83,7 @@ public final class ChatProcessor { - final CraftPlayer player = this.player.getBukkitEntity(); - final AsyncPlayerChatEvent ae = new AsyncPlayerChatEvent(this.async, player, this.craftbukkit$originalMessage, new LazyPlayerSet(this.server)); - this.post(ae); -- if (listenersOnSyncEvent) { -+ if (false && listenersOnSyncEvent) { // Folia - region threading - final PlayerChatEvent se = new PlayerChatEvent(player, ae.getMessage(), ae.getFormat(), ae.getRecipients()); - se.setCancelled(ae.isCancelled()); // propagate cancelled state - this.queueIfAsyncOrRunImmediately(new Waitable() { -@@ -150,7 +150,7 @@ public final class ChatProcessor { - ae.setCancelled(cancelled); // propagate cancelled state - this.post(ae); - final boolean listenersOnSyncEvent = canYouHearMe(ChatEvent.getHandlerList()); -- if (listenersOnSyncEvent) { -+ if (false && listenersOnSyncEvent) { // Folia - region threading - this.queueIfAsyncOrRunImmediately(new Waitable() { - @Override - protected Void evaluate() { -diff --git a/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java b/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java -index 23432eea862c6df716d7726a32da3a0612a3fb77..f59e8bb72c5233f26a8a0d506ac64bb37fef97a5 100644 ---- a/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java -+++ b/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java -@@ -23,35 +23,42 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider { - - public static final class CallbackManager { - -- private final Map callbacks = new HashMap<>(); -- private final Queue queue = new ConcurrentLinkedQueue<>(); -+ private final java.util.concurrent.ConcurrentHashMap callbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Folia - region threading -+ // Folia - region threading - - private CallbackManager() { - } - - public UUID addCallback(final @NotNull ClickCallback callback, final ClickCallback.@NotNull Options options) { - final UUID id = UUID.randomUUID(); -- this.queue.add(new StoredCallback(callback, options, id)); -+ final StoredCallback scb = new StoredCallback(callback, options, id); // Folia - region threading -+ this.callbacks.put(scb.id(), scb); // Folia - region threading - return id; - } - - public void handleQueue(final int currentTick) { - // Evict expired entries - if (currentTick % 100 == 0) { -- this.callbacks.values().removeIf(callback -> !callback.valid()); -+ this.callbacks.values().removeIf(StoredCallback::expired); // Folia - region threading - don't read uses field - } - -- // Add entries from queue -- StoredCallback callback; -- while ((callback = this.queue.poll()) != null) { -- this.callbacks.put(callback.id(), callback); -- } -+ // Folia - region threading - } - - public void runCallback(final @NotNull Audience audience, final UUID id) { -- final StoredCallback callback = this.callbacks.get(id); -- if (callback != null && callback.valid()) { //TODO Message if expired/invalid? -- callback.takeUse(); -+ // Folia start - region threading -+ final StoredCallback[] use = new StoredCallback[1]; -+ this.callbacks.computeIfPresent(id, (final UUID keyInMap, final StoredCallback value) -> { -+ if (!value.valid()) { -+ return null; -+ } -+ use[0] = value; -+ value.takeUse(); -+ return value.valid() ? value : null; -+ }); -+ final StoredCallback callback = use[0]; -+ if (callback != null) { //TODO Message if expired/invalid? -+ // Folia end - region threading - callback.callback.accept(audience); - } - } -diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java -index 7b58b2d6297800c2dcdbf7539e5ab8e7703f39f1..a587d83b78af4efc484f939529acf70834f60d7e 100644 ---- a/src/main/java/io/papermc/paper/command/PaperCommands.java -+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java -@@ -19,6 +19,7 @@ public final class PaperCommands { - COMMANDS.put("paper", new PaperCommand("paper")); - COMMANDS.put("callback", new CallbackCommand("callback")); - COMMANDS.put("mspt", new MSPTCommand("mspt")); -+ COMMANDS.put("tps", new io.papermc.paper.threadedregions.commands.CommandServerHealth()); // Folia - region threading - } - - public static void registerCommands(final MinecraftServer server) { -diff --git a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -index f671b74e4179fc29bc600b52e456ba9f78d8bbd6..fa3367c7f2b3d509886b152d892fe2168d83c6ae 100644 ---- a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -+++ b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java -@@ -129,7 +129,7 @@ public final class EntityCommand implements PaperSubcommand { - final int z = (e.getKey().z << 4) + 8; - final Component message = text(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")) - .hoverEvent(HoverEvent.showText(text("Click to teleport to chunk", GREEN))) -- .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (world.getWorld().getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING) + 1) + " " + z)); -+ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (128) + " " + z)); // Folia - region threading - avoid sync load here - sender.sendMessage(message); - }); - } else { -diff --git a/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java -index cd2e4d792e972b8bf1e07b8961594a670ae949cf..3ab8dbf2768a4ef8fb53af6f5431f7f6afe6d168 100644 ---- a/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java -+++ b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java -@@ -18,7 +18,9 @@ import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; - public final class HeapDumpCommand implements PaperSubcommand { - @Override - public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - this.dumpHeap(sender); -+ }); // Folia - region threading - return true; - } - -diff --git a/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java -index bd68139ae635f2ad7ec8e7a21e0056a139c4c62e..48a43341b17247355a531164019d5cc9c5555f26 100644 ---- a/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java -+++ b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java -@@ -16,7 +16,9 @@ import static net.kyori.adventure.text.format.NamedTextColor.RED; - public final class ReloadCommand implements PaperSubcommand { - @Override - public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - this.doReload(sender); -+ }); // Folia - region threading - return true; - } - -diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -index 088b8fe5d144807f4da1e85b2fa34dfd21286f8c..4ed27c10b432ceebf4447ab8007bc3a1be09a06e 100644 ---- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java -@@ -354,4 +354,18 @@ public class GlobalConfiguration extends ConfigurationPart { - public boolean disableChorusPlantUpdates = false; - public boolean disableMushroomBlockUpdates = false; - } -+ -+ // Folia start - threaded regions -+ public ThreadedRegions threadedRegions; -+ public class ThreadedRegions extends ConfigurationPart { -+ -+ public int threads = -1; -+ public int gridExponent = 2; -+ -+ @PostProcess -+ public void postProcess() { -+ io.papermc.paper.threadedregions.TickRegions.init(this); -+ } -+ } -+ // Folia end - threaded regions - } -diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java -index b1c917d65076a3805e5b78cb946753f0c101e214..ad3d9251e88ce9a35b0f46e9f0f54e62559bd9f9 100644 ---- a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java -+++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java -@@ -505,6 +505,14 @@ public class WorldConfiguration extends ConfigurationPart { - public Chunks chunks; - - public class Chunks extends ConfigurationPart { -+ -+ // Folia start - region threading - force prevent moving into unloaded chunks -+ @PostProcess -+ public void postProcess() { -+ this.preventMovingIntoUnloadedChunks = true; -+ } -+ // Folia end - region threading - force prevent moving into unloaded chunks -+ - public AutosavePeriod autoSaveInterval = AutosavePeriod.def(); - public int maxAutoSaveChunksPerTick = 24; - public int fixedChunkInhabitedTime = -1; -diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -index 3e82ea07ca4194844c5528446e2c4a46ff4acee5..adfd4c16809f6ddd9cc73e4bd845d7aed4925068 100644 ---- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java -@@ -256,12 +256,7 @@ class PaperPluginInstanceManager { - + pluginName + " (Is it up to date?)", ex, plugin); // Paper - } - -- try { -- this.server.getScheduler().cancelTasks(plugin); -- } catch (Throwable ex) { -- this.handlePluginException("Error occurred (in the plugin loader) while cancelling tasks for " -- + pluginName + " (Is it up to date?)", ex, plugin); // Paper -- } -+ // Folia - region threading - - // Paper start - Folia schedulers - try { -diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java -index c03608fec96b51e1867f43d8f42e5aefb1520e46..127d96280cad2d4e5db574a089d67ad68977b34e 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java -+++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java -@@ -50,6 +50,14 @@ public final class EntityScheduler { - this.entity = Validate.notNull(entity); - } - -+ // Folia start - region threading -+ public boolean isRetired() { -+ synchronized (this.stateLock) { -+ return this.tickCount == RETIRED_TICK_COUNT; -+ } -+ } -+ // Folia end - region threading -+ - /** - * Retires the scheduler, preventing new tasks from being scheduled and invoking the retired callback - * on all currently scheduled tasks. -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java b/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java +diff --git a/io/papermc/paper/threadedregions/RegionShutdownThread.java b/io/papermc/paper/threadedregions/RegionShutdownThread.java new file mode 100644 index 0000000000000000000000000000000000000000..261b3019878c31a9e44e56b6611899de6c00ebee --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java ++++ b/io/papermc/paper/threadedregions/RegionShutdownThread.java @@ -0,0 +1,226 @@ +package io.papermc.paper.threadedregions; + @@ -1425,11 +1174,11 @@ index 0000000000000000000000000000000000000000..261b3019878c31a9e44e56b6611899de + // done, part 2 should call exit() + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedData.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedData.java +diff --git a/io/papermc/paper/threadedregions/RegionizedData.java b/io/papermc/paper/threadedregions/RegionizedData.java new file mode 100644 index 0000000000000000000000000000000000000000..1f48ada99d6d24880f9bda1cd05d41a4562e42f5 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedData.java ++++ b/io/papermc/paper/threadedregions/RegionizedData.java @@ -0,0 +1,235 @@ +package io.papermc.paper.threadedregions; + @@ -1666,11 +1415,11 @@ index 0000000000000000000000000000000000000000..1f48ada99d6d24880f9bda1cd05d41a4 + ); + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java +diff --git a/io/papermc/paper/threadedregions/RegionizedServer.java b/io/papermc/paper/threadedregions/RegionizedServer.java new file mode 100644 index 0000000000000000000000000000000000000000..fc053ded0c14b76a1c6c82b59d3fd320372a3293 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedServer.java ++++ b/io/papermc/paper/threadedregions/RegionizedServer.java @@ -0,0 +1,455 @@ +package io.papermc.paper.threadedregions; + @@ -2127,11 +1876,11 @@ index 0000000000000000000000000000000000000000..fc053ded0c14b76a1c6c82b59d3fd320 + + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedTaskQueue.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedTaskQueue.java +diff --git a/io/papermc/paper/threadedregions/RegionizedTaskQueue.java b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java new file mode 100644 index 0000000000000000000000000000000000000000..a2313b5b4c37e8536973a8ea0b371557ea912473 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedTaskQueue.java ++++ b/io/papermc/paper/threadedregions/RegionizedTaskQueue.java @@ -0,0 +1,807 @@ +package io.papermc.paper.threadedregions; + @@ -2940,11 +2689,11 @@ index 0000000000000000000000000000000000000000..a2313b5b4c37e8536973a8ea0b371557 + } + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java b/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java +diff --git a/io/papermc/paper/threadedregions/RegionizedWorldData.java b/io/papermc/paper/threadedregions/RegionizedWorldData.java new file mode 100644 -index 0000000000000000000000000000000000000000..1b741d4bccfd45beeec43300f44770516c0d850e +index 0000000000000000000000000000000000000000..b49ca79c31e30e90c82349aecf2cc22df3b61ee6 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionizedWorldData.java ++++ b/io/papermc/paper/threadedregions/RegionizedWorldData.java @@ -0,0 +1,770 @@ +package io.papermc.paper.threadedregions; + @@ -3392,7 +3141,7 @@ index 0000000000000000000000000000000000000000..1b741d4bccfd45beeec43300f4477051 + } + // Redstone + public final alternate.current.wire.WireHandler wireHandler; -+ public final com.destroystokyo.paper.util.RedstoneWireTurbo turbo; ++ public final io.papermc.paper.redstone.RedstoneWireTurbo turbo; + + public RegionizedWorldData(final ServerLevel world) { + this.world = world; @@ -3401,7 +3150,7 @@ index 0000000000000000000000000000000000000000..1b741d4bccfd45beeec43300f4477051 + this.neighborUpdater = new CollectingNeighborUpdater(world, world.neighbourUpdateMax); + this.nearbyPlayers = new NearbyPlayers(world); + this.wireHandler = new alternate.current.wire.WireHandler(world); -+ this.turbo = new com.destroystokyo.paper.util.RedstoneWireTurbo((RedStoneWireBlock)Blocks.REDSTONE_WIRE); ++ this.turbo = new io.papermc.paper.redstone.RedstoneWireTurbo((RedStoneWireBlock)Blocks.REDSTONE_WIRE); + + // tasks may be drained before the region ticks, so we must set up the tick data early just in case + this.updateTickData(); @@ -3425,9 +3174,9 @@ index 0000000000000000000000000000000000000000..1b741d4bccfd45beeec43300f4477051 + + public void updateTickData() { + this.tickData = this.world.tickData; -+ this.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper -+ this.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper -+ this.skipHopperEvents = this.world.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper ++ this.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent ++ this.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent ++ this.skipHopperEvents = this.world.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers + // always subtract from server init so that the tick starts at zero, allowing us to cast to int without much worry + this.lagCompensationTick = (System.nanoTime() - MinecraftServer.SERVER_INIT) / TickRegionScheduler.TIME_BETWEEN_TICKS; + } @@ -3716,11 +3465,11 @@ index 0000000000000000000000000000000000000000..1b741d4bccfd45beeec43300f4477051 + return this.chunks.size(); + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/Schedule.java b/src/main/java/io/papermc/paper/threadedregions/Schedule.java +diff --git a/io/papermc/paper/threadedregions/Schedule.java b/io/papermc/paper/threadedregions/Schedule.java new file mode 100644 index 0000000000000000000000000000000000000000..112d24a93bddf3d81c9176c05340c94ecd1a40a3 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/Schedule.java ++++ b/io/papermc/paper/threadedregions/Schedule.java @@ -0,0 +1,91 @@ +package io.papermc.paper.threadedregions; + @@ -3813,11 +3562,11 @@ index 0000000000000000000000000000000000000000..112d24a93bddf3d81c9176c05340c94e + this.lastPeriod -= (long)periodsToAdd * periodLength; + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/TeleportUtils.java b/src/main/java/io/papermc/paper/threadedregions/TeleportUtils.java +diff --git a/io/papermc/paper/threadedregions/TeleportUtils.java b/io/papermc/paper/threadedregions/TeleportUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..74ac328bf8d5f762f7060a6c5d49089dee1ddaea --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/TeleportUtils.java ++++ b/io/papermc/paper/threadedregions/TeleportUtils.java @@ -0,0 +1,70 @@ +package io.papermc.paper.threadedregions; + @@ -3889,11 +3638,11 @@ index 0000000000000000000000000000000000000000..74ac328bf8d5f762f7060a6c5d49089d + + private TeleportUtils() {} +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/ThreadedRegionizer.java b/src/main/java/io/papermc/paper/threadedregions/ThreadedRegionizer.java +diff --git a/io/papermc/paper/threadedregions/ThreadedRegionizer.java b/io/papermc/paper/threadedregions/ThreadedRegionizer.java new file mode 100644 index 0000000000000000000000000000000000000000..8e1b1df1c889d9235b10b86fc4cedbc06b7885c2 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/ThreadedRegionizer.java ++++ b/io/papermc/paper/threadedregions/ThreadedRegionizer.java @@ -0,0 +1,1405 @@ +package io.papermc.paper.threadedregions; + @@ -5300,11 +5049,11 @@ index 0000000000000000000000000000000000000000..8e1b1df1c889d9235b10b86fc4cedbc0 + public void preSplit(final ThreadedRegion from, final List> into); + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/TickData.java b/src/main/java/io/papermc/paper/threadedregions/TickData.java +diff --git a/io/papermc/paper/threadedregions/TickData.java b/io/papermc/paper/threadedregions/TickData.java new file mode 100644 index 0000000000000000000000000000000000000000..29f9fed5f02530b3256e6b993e607d4647daa7b6 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/TickData.java ++++ b/io/papermc/paper/threadedregions/TickData.java @@ -0,0 +1,333 @@ +package io.papermc.paper.threadedregions; + @@ -5639,11 +5388,11 @@ index 0000000000000000000000000000000000000000..29f9fed5f02530b3256e6b993e607d46 + double greatest + ) {} +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java +diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java new file mode 100644 index 0000000000000000000000000000000000000000..4471285a4358e51da9912ed791a824527f1a2e8e --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java ++++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java @@ -0,0 +1,564 @@ +package io.papermc.paper.threadedregions; + @@ -6209,10 +5958,10 @@ index 0000000000000000000000000000000000000000..4471285a4358e51da9912ed791a82452 + */ + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java +diff --git a/io/papermc/paper/threadedregions/TickRegions.java b/io/papermc/paper/threadedregions/TickRegions.java index 8424cf9d4617b4732d44cc460d25b04481068989..df15b1139e71dfe10b8f24ec6d235b99f6d5006a 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java -+++ b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java +--- a/io/papermc/paper/threadedregions/TickRegions.java ++++ b/io/papermc/paper/threadedregions/TickRegions.java @@ -1,10 +1,410 @@ package io.papermc.paper.threadedregions; @@ -6627,11 +6376,11 @@ index 8424cf9d4617b4732d44cc460d25b04481068989..df15b1139e71dfe10b8f24ec6d235b99 } } -diff --git a/src/main/java/io/papermc/paper/threadedregions/commands/CommandServerHealth.java b/src/main/java/io/papermc/paper/threadedregions/commands/CommandServerHealth.java +diff --git a/io/papermc/paper/threadedregions/commands/CommandServerHealth.java b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java new file mode 100644 index 0000000000000000000000000000000000000000..3bcb1dc98c61e025874cc9e008faa722581a530c --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/commands/CommandServerHealth.java ++++ b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java @@ -0,0 +1,355 @@ +package io.papermc.paper.threadedregions.commands; + @@ -6988,11 +6737,11 @@ index 0000000000000000000000000000000000000000..3bcb1dc98c61e025874cc9e008faa722 + return new ArrayList<>(); + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/commands/CommandUtil.java b/src/main/java/io/papermc/paper/threadedregions/commands/CommandUtil.java +diff --git a/io/papermc/paper/threadedregions/commands/CommandUtil.java b/io/papermc/paper/threadedregions/commands/CommandUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..d016294fc7eafbddf6d2a758e5803498dfa207b8 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/commands/CommandUtil.java ++++ b/io/papermc/paper/threadedregions/commands/CommandUtil.java @@ -0,0 +1,121 @@ +package io.papermc.paper.threadedregions.commands; + @@ -7115,11 +6864,11 @@ index 0000000000000000000000000000000000000000..d016294fc7eafbddf6d2a758e5803498 + + private CommandUtil() {} +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaRegionScheduler.java +diff --git a/io/papermc/paper/threadedregions/scheduler/FoliaRegionScheduler.java b/io/papermc/paper/threadedregions/scheduler/FoliaRegionScheduler.java new file mode 100644 index 0000000000000000000000000000000000000000..85d3965a67cfb59790c664baa7840b50436a5e28 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/scheduler/FoliaRegionScheduler.java ++++ b/io/papermc/paper/threadedregions/scheduler/FoliaRegionScheduler.java @@ -0,0 +1,424 @@ +package io.papermc.paper.threadedregions.scheduler; + @@ -7545,11 +7294,11 @@ index 0000000000000000000000000000000000000000..85d3965a67cfb59790c664baa7840b50 + } + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/util/SimpleThreadLocalRandomSource.java b/src/main/java/io/papermc/paper/threadedregions/util/SimpleThreadLocalRandomSource.java +diff --git a/io/papermc/paper/threadedregions/util/SimpleThreadLocalRandomSource.java b/io/papermc/paper/threadedregions/util/SimpleThreadLocalRandomSource.java new file mode 100644 index 0000000000000000000000000000000000000000..97cd0e767ed36eeb211ecdf125e8d2bfff19a15e --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/util/SimpleThreadLocalRandomSource.java ++++ b/io/papermc/paper/threadedregions/util/SimpleThreadLocalRandomSource.java @@ -0,0 +1,79 @@ +package io.papermc.paper.threadedregions.util; + @@ -7630,11 +7379,11 @@ index 0000000000000000000000000000000000000000..97cd0e767ed36eeb211ecdf125e8d2bf + } + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/util/ThreadLocalRandomSource.java b/src/main/java/io/papermc/paper/threadedregions/util/ThreadLocalRandomSource.java +diff --git a/io/papermc/paper/threadedregions/util/ThreadLocalRandomSource.java b/io/papermc/paper/threadedregions/util/ThreadLocalRandomSource.java new file mode 100644 index 0000000000000000000000000000000000000000..eda02661b1c09e5303d3912c2562bb1c4ccc04fe --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/util/ThreadLocalRandomSource.java ++++ b/io/papermc/paper/threadedregions/util/ThreadLocalRandomSource.java @@ -0,0 +1,73 @@ +package io.papermc.paper.threadedregions.util; + @@ -7709,76 +7458,33 @@ index 0000000000000000000000000000000000000000..eda02661b1c09e5303d3912c2562bb1c + } + } +} -diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index a4ac34ebb58a404f4fca7e763e61d4ab05ee3af4..4dcec640f5870d713bd3b98389a45dbef8a4ea8a 100644 ---- a/src/main/java/io/papermc/paper/util/MCUtil.java -+++ b/src/main/java/io/papermc/paper/util/MCUtil.java -@@ -94,6 +94,7 @@ public final class MCUtil { - */ - public static void ensureMain(String reason, Runnable run) { - if (!isMainThread()) { -+ if (true) throw new UnsupportedOperationException(); // Folia - region threading - if (reason != null) { - MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException()); - } -@@ -148,6 +149,30 @@ public final class MCUtil { - return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()); +diff --git a/net/minecraft/commands/CommandSourceStack.java b/net/minecraft/commands/CommandSourceStack.java +index 75262c8c9eaecb4a88a94f4076d67119c67a97da..f5d20a831f931b344d37d1fb885556c65671323a 100644 +--- a/net/minecraft/commands/CommandSourceStack.java ++++ b/net/minecraft/commands/CommandSourceStack.java +@@ -91,7 +91,7 @@ public class CommandSourceStack implements ExecutionCommandSource { io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(run);}) // Folia - region threading + ); } -+ // Folia start - TODO MERGE INTO MCUTIL -+ /** -+ * Converts a NMS World/Vector to Bukkit Location -+ * @param world -+ * @param pos -+ * @return -+ */ -+ public static Location toLocation(Level world, Vec3 pos) { -+ return new Location(world.getWorld(), pos.x(), pos.y(), pos.z()); -+ } -+ -+ /** -+ * Converts a NMS World/Vector to Bukkit Location -+ * @param world -+ * @param pos -+ * @param yaw -+ * @param pitch -+ * @return -+ */ -+ public static Location toLocation(Level world, Vec3 pos, float yaw, float pitch) { -+ return new Location(world.getWorld(), pos.x(), pos.y(), pos.z(), yaw, pitch); -+ } -+ // Folia end - TODO MERGE INTO MCUTIL -+ - public static BlockPos toBlockPosition(Location loc) { - return new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); - } -diff --git a/src/main/java/net/minecraft/commands/CommandSourceStack.java b/src/main/java/net/minecraft/commands/CommandSourceStack.java -index 13bd145b1e8006a53c22f5dc0c78f29b540c7663..6d87797523337725141f271087f80065ed67347e 100644 ---- a/src/main/java/net/minecraft/commands/CommandSourceStack.java -+++ b/src/main/java/net/minecraft/commands/CommandSourceStack.java -@@ -69,7 +69,7 @@ public class CommandSourceStack implements ExecutionCommandSource { io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(run);})); // Folia - region threading - } - - protected CommandSourceStack(CommandSource output, Vec3 pos, Vec2 rot, ServerLevel world, int level, String name, Component displayName, MinecraftServer server, @Nullable Entity entity, boolean silent, CommandResultCallback resultStorer, EntityAnchorArgument.Anchor entityAnchor, CommandSigningContext signedArguments, TaskChainer messageChainTaskQueue) { -diff --git a/src/main/java/net/minecraft/commands/Commands.java b/src/main/java/net/minecraft/commands/Commands.java -index 517cb238ec280aadd1fc54bcb675ed386e798eaf..7f16e3040f4686ffe6338290db33d2733bd6659f 100644 ---- a/src/main/java/net/minecraft/commands/Commands.java -+++ b/src/main/java/net/minecraft/commands/Commands.java -@@ -163,13 +163,13 @@ public class Commands { +diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java +index 19ccf3abf14c67f72a1ca065e4a304f50e645ef4..7fc9a62b59a21b2ec96e5a661af75f4c7bf20cd0 100644 +--- a/net/minecraft/commands/Commands.java ++++ b/net/minecraft/commands/Commands.java +@@ -153,13 +153,13 @@ public class Commands { AdvancementCommands.register(this.dispatcher); - AttributeCommand.register(this.dispatcher, commandRegistryAccess); - ExecuteCommand.register(this.dispatcher, commandRegistryAccess); -- BossBarCommands.register(this.dispatcher, commandRegistryAccess); -+ //BossBarCommands.register(this.dispatcher, commandRegistryAccess); // Folia - region threading - TODO - ClearInventoryCommands.register(this.dispatcher, commandRegistryAccess); -- CloneCommands.register(this.dispatcher, commandRegistryAccess); -+ //CloneCommands.register(this.dispatcher, commandRegistryAccess); // Folia - region threading - TODO - DamageCommand.register(this.dispatcher, commandRegistryAccess); + AttributeCommand.register(this.dispatcher, context); + ExecuteCommand.register(this.dispatcher, context); +- BossBarCommands.register(this.dispatcher, context); ++ //BossBarCommands.register(this.dispatcher, context); // Folia - region threading - TODO + ClearInventoryCommands.register(this.dispatcher, context); +- CloneCommands.register(this.dispatcher, context); ++ //CloneCommands.register(this.dispatcher, context); // Folia - region threading - TODO + DamageCommand.register(this.dispatcher, context); - DataCommands.register(this.dispatcher); - DataPackCommand.register(this.dispatcher); - DebugCommand.register(this.dispatcher); @@ -7787,27 +7493,27 @@ index 517cb238ec280aadd1fc54bcb675ed386e798eaf..7f16e3040f4686ffe6338290db33d273 + //DebugCommand.register(this.dispatcher); // Folia - region threading - TODO DefaultGameModeCommands.register(this.dispatcher); DifficultyCommand.register(this.dispatcher); - EffectCommands.register(this.dispatcher, commandRegistryAccess); -@@ -179,47 +179,47 @@ public class Commands { - FillCommand.register(this.dispatcher, commandRegistryAccess); - FillBiomeCommand.register(this.dispatcher, commandRegistryAccess); + EffectCommands.register(this.dispatcher, context); +@@ -169,47 +169,47 @@ public class Commands { + FillCommand.register(this.dispatcher, context); + FillBiomeCommand.register(this.dispatcher, context); ForceLoadCommand.register(this.dispatcher); - FunctionCommand.register(this.dispatcher); + //FunctionCommand.register(this.dispatcher); // Folia - region threading - TODO GameModeCommand.register(this.dispatcher); - GameRuleCommand.register(this.dispatcher, commandRegistryAccess); - GiveCommand.register(this.dispatcher, commandRegistryAccess); + GameRuleCommand.register(this.dispatcher, context); + GiveCommand.register(this.dispatcher, context); HelpCommand.register(this.dispatcher); -- ItemCommands.register(this.dispatcher, commandRegistryAccess); -+ //ItemCommands.register(this.dispatcher, commandRegistryAccess); // Folia - region threading - TODO later +- ItemCommands.register(this.dispatcher, context); ++ //ItemCommands.register(this.dispatcher, context); // Folia - region threading - TODO later KickCommand.register(this.dispatcher); KillCommand.register(this.dispatcher); ListPlayersCommand.register(this.dispatcher); - LocateCommand.register(this.dispatcher, commandRegistryAccess); -- LootCommand.register(this.dispatcher, commandRegistryAccess); -+ //LootCommand.register(this.dispatcher, commandRegistryAccess); // Folia - region threading - TODO later + LocateCommand.register(this.dispatcher, context); +- LootCommand.register(this.dispatcher, context); ++ //LootCommand.register(this.dispatcher, context); // Folia - region threading - TODO later MsgCommand.register(this.dispatcher); - ParticleCommand.register(this.dispatcher, commandRegistryAccess); + ParticleCommand.register(this.dispatcher, context); PlaceCommand.register(this.dispatcher); PlaySoundCommand.register(this.dispatcher); RandomCommand.register(this.dispatcher); @@ -7822,11 +7528,11 @@ index 517cb238ec280aadd1fc54bcb675ed386e798eaf..7f16e3040f4686ffe6338290db33d273 + //RotateCommand.register(this.dispatcher); // Folia - region threading - TODO later SayCommand.register(this.dispatcher); - ScheduleCommand.register(this.dispatcher); -- ScoreboardCommand.register(this.dispatcher, commandRegistryAccess); +- ScoreboardCommand.register(this.dispatcher, context); + //ScheduleCommand.register(this.dispatcher); // Folia - region threading -+ //ScoreboardCommand.register(this.dispatcher, commandRegistryAccess); // Folia - region threading - TODO later - SeedCommand.register(this.dispatcher, environment != Commands.CommandSelection.INTEGRATED); - SetBlockCommand.register(this.dispatcher, commandRegistryAccess); ++ //ScoreboardCommand.register(this.dispatcher, context); // Folia - region threading + SeedCommand.register(this.dispatcher, selection != Commands.CommandSelection.INTEGRATED); + SetBlockCommand.register(this.dispatcher, context); SetSpawnCommand.register(this.dispatcher); SetWorldSpawnCommand.register(this.dispatcher); - SpectateCommand.register(this.dispatcher); @@ -7834,25 +7540,25 @@ index 517cb238ec280aadd1fc54bcb675ed386e798eaf..7f16e3040f4686ffe6338290db33d273 + //SpectateCommand.register(this.dispatcher); // Folia - region threading - TODO later + //SpreadPlayersCommand.register(this.dispatcher); // Folia - region threading - TODO later StopSoundCommand.register(this.dispatcher); - SummonCommand.register(this.dispatcher, commandRegistryAccess); + SummonCommand.register(this.dispatcher, context); - TagCommand.register(this.dispatcher); -- TeamCommand.register(this.dispatcher, commandRegistryAccess); +- TeamCommand.register(this.dispatcher, context); - TeamMsgCommand.register(this.dispatcher); + //TagCommand.register(this.dispatcher); // Folia - region threading - TODO later -+ //TeamCommand.register(this.dispatcher, commandRegistryAccess); // Folia - region threading - TODO later ++ //TeamCommand.register(this.dispatcher, context); // Folia - region threading - TODO later + //TeamMsgCommand.register(this.dispatcher); // Folia - region threading - TODO later TeleportCommand.register(this.dispatcher); - TellRawCommand.register(this.dispatcher, commandRegistryAccess); + TellRawCommand.register(this.dispatcher, context); - TickCommand.register(this.dispatcher); + //TickCommand.register(this.dispatcher); // Folia - region threading - TODO later TimeCommand.register(this.dispatcher); - TitleCommand.register(this.dispatcher, commandRegistryAccess); + TitleCommand.register(this.dispatcher, context); - TriggerCommand.register(this.dispatcher); + //TriggerCommand.register(this.dispatcher); // Folia - region threading - TODO later WeatherCommand.register(this.dispatcher); WorldBorderCommand.register(this.dispatcher); if (JvmProfiler.INSTANCE.isAvailable()) { -@@ -247,8 +247,8 @@ public class Commands { +@@ -237,8 +237,8 @@ public class Commands { OpCommand.register(this.dispatcher); PardonCommand.register(this.dispatcher); PardonIpCommand.register(this.dispatcher); @@ -7863,278 +7569,310 @@ index 517cb238ec280aadd1fc54bcb675ed386e798eaf..7f16e3040f4686ffe6338290db33d273 SaveOffCommand.register(this.dispatcher); SaveOnCommand.register(this.dispatcher); SetPlayerIdleTimeoutCommand.register(this.dispatcher); -@@ -507,9 +507,12 @@ public class Commands { +@@ -480,9 +480,12 @@ public class Commands { } // Paper start - Perf: Async command map building - new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootcommandnode, false).callEvent(); // Paper - Brigadier API + new com.destroystokyo.paper.event.brigadier.AsyncPlayerSendCommandsEvent(player.getBukkitEntity(), (RootCommandNode) rootCommandNode, false).callEvent(); // Paper - Brigadier API - net.minecraft.server.MinecraftServer.getServer().execute(() -> { -- runSync(player, bukkit, rootcommandnode); +- runSync(player, bukkit, rootCommandNode); - }); + // Folia start - region threading + // ignore if retired -+ player.getBukkitEntity().taskScheduler.schedule((updatedPlayer) -> { -+ runSync((ServerPlayer)updatedPlayer, bukkit, rootcommandnode); ++ player.getBukkitEntity().taskScheduler.schedule((ServerPlayer updatedPlayer) -> { ++ runSync((ServerPlayer)updatedPlayer, bukkit, rootCommandNode); + }, null, 1L); + // Folia end - region threading } - private void runSync(ServerPlayer player, Collection bukkit, RootCommandNode rootcommandnode) { -diff --git a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -index ddb264443f2e38b6348226016f9139727c588898..b8c3d6aa9356beeb4bfb431e8d2dd7367969dd8d 100644 ---- a/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java -@@ -54,7 +54,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); + private void runSync(ServerPlayer player, java.util.Collection bukkit, RootCommandNode rootCommandNode) { +diff --git a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java +index 4a881636ba21fae9e50950bbba2b4321b71d35ab..af35d667f7dc752df34c49fe675cd0a6cf8ffe4b 100644 +--- a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java +@@ -46,7 +46,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3)); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3)); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); + serverLevel.getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -index 8aae1d113e84dfad9f2b6f0bcd203ca6c68bc5ce..ca98699f4225192bb3364397402b07001b1402af 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java -@@ -87,7 +87,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack); +diff --git a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +index bd5bbc7e55c6bea77991fe5a3c0c2580313d16c5..907d3a5385b8b9098051f4ec0887d778fb85cf8d 100644 +--- a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java +@@ -78,7 +78,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack); - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), CraftVector.toBukkit(entityitem.getDeltaMovement())); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(itemEntity.getDeltaMovement())); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - world.getCraftServer().getPluginManager().callEvent(event); + level.getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -index c9d7ac819ce26f5301df7df56edce59b7ef377e0..fd5f2864c670c1580e07d67c47bc61d8b354a687 100644 ---- a/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/DispenseItemBehavior.java -@@ -111,7 +111,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); +diff --git a/net/minecraft/core/dispenser/DispenseItemBehavior.java b/net/minecraft/core/dispenser/DispenseItemBehavior.java +index 717c84165d5e25cd384f56b7cb976abf6669b6f0..ebcd1949266f29ca0c99ee26252c366c3f887546 100644 +--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java +@@ -89,7 +89,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); + serverLevel.getCraftServer().getPluginManager().callEvent(event); } -@@ -170,7 +170,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); +@@ -147,7 +147,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -225,7 +225,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - - BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) list.get(0).getBukkitEntity()); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - world.getCraftServer().getPluginManager().callEvent(event); + serverLevel.getCraftServer().getPluginManager().callEvent(event); } -@@ -280,7 +280,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); +@@ -201,7 +201,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); - BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityhorsechestedabstract.getBukkitEntity()); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - world.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -354,7 +354,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event - - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z)); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -419,7 +419,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event - - BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); + org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity()); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); + world.getCraftServer().getPluginManager().callEvent(event); } -@@ -457,7 +457,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); // Paper - ignore stack size on damageable items +@@ -251,7 +251,7 @@ public interface DispenseItemBehavior { + org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, blockSource.pos()); + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleCopy); + org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), abstractChestedHorse.getBukkitLivingEntity()); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + world.getCraftServer().getPluginManager().callEvent(event); + } - BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } +@@ -329,7 +329,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event -@@ -519,7 +519,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event - - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -537,7 +537,8 @@ public interface DispenseItemBehavior { - } - } - -- worldserver.captureTreeGeneration = true; -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = worldserver.getCurrentWorldData(); // Folia - region threading -+ worldData.captureTreeGeneration = true; // Folia - region threading - // CraftBukkit end - - if (!BoneMealItem.growCrop(stack, worldserver, blockposition) && !BoneMealItem.growWaterPlant(stack, worldserver, blockposition, (Direction) null)) { -@@ -546,13 +547,13 @@ public interface DispenseItemBehavior { - worldserver.levelEvent(1505, blockposition, 15); - } - // CraftBukkit start -- worldserver.captureTreeGeneration = false; -- if (worldserver.capturedBlockStates.size() > 0) { -- TreeType treeType = SaplingBlock.treeType; -- SaplingBlock.treeType = null; -+ worldData.captureTreeGeneration = false; // Folia - region threading -+ if (worldData.capturedBlockStates.size() > 0) { // Folia - region threading -+ TreeType treeType = SaplingBlock.treeTypeRT.get(); // Folia - region threading -+ SaplingBlock.treeTypeRT.set(null); // Folia - region threading - Location location = CraftLocation.toBukkit(blockposition, worldserver.getWorld()); -- List blocks = new java.util.ArrayList<>(worldserver.capturedBlockStates.values()); -- worldserver.capturedBlockStates.clear(); -+ List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading -+ worldData.capturedBlockStates.clear(); // Folia - region threading - StructureGrowEvent structureEvent = null; - if (treeType != null) { - structureEvent = new StructureGrowEvent(location, treeType, false, null, blocks); -@@ -588,7 +589,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); - - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockposition.getX() + 0.5D, (double) blockposition.getY(), (double) blockposition.getZ() + 0.5D)); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -631,7 +632,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event - - BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -680,7 +681,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event - - BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -742,7 +743,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - only single item in event - - BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); -- if (!DispenserBlock.eventFired) { -+ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); - } - -@@ -824,7 +825,7 @@ public interface DispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); // Paper - ignore stack size on damageable items - - BlockDispenseEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) list.get(0).getBukkitEntity()); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z)); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - world.getCraftServer().getPluginManager().callEvent(event); + level.getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java -index bf8c511739265c6a9cd277752e844481598f8966..c369c0cad19ade00a1e62e834568f1049fb021cd 100644 ---- a/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java -@@ -50,7 +50,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); +@@ -389,7 +389,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event - BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityliving.getBukkitEntity()); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos)); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + levelAccessor.getMinecraftWorld().getCraftServer().getPluginManager().callEvent(event); + } + +@@ -425,7 +425,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + serverLevel.getCraftServer().getPluginManager().callEvent(event); + } + +@@ -482,7 +482,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + level.getCraftServer().getPluginManager().callEvent(event); + } + +@@ -500,7 +500,8 @@ public interface DispenseItemBehavior { + } + } + +- level.captureTreeGeneration = true; ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading ++ worldData.captureTreeGeneration = true; // Folia - region threading + // CraftBukkit end + if (!BoneMealItem.growCrop(item, level, blockPos) && !BoneMealItem.growWaterPlant(item, level, blockPos, null)) { + this.setSuccess(false); +@@ -508,13 +509,13 @@ public interface DispenseItemBehavior { + level.levelEvent(1505, blockPos, 15); + } + // CraftBukkit start +- level.captureTreeGeneration = false; +- if (level.capturedBlockStates.size() > 0) { +- org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType; +- net.minecraft.world.level.block.SaplingBlock.treeType = null; ++ worldData.captureTreeGeneration = false; // Folia - region threading ++ if (worldData.capturedBlockStates.size() > 0) { // Folia - region threading ++ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get(); // Folia - region threading ++ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null); // Folia - region threading + org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, level.getWorld()); +- List blocks = new java.util.ArrayList<>(level.capturedBlockStates.values()); +- level.capturedBlockStates.clear(); ++ List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading ++ worldData.capturedBlockStates.clear(); // Folia - region threading + org.bukkit.event.world.StructureGrowEvent structureEvent = null; + if (treeType != null) { + structureEvent = new org.bukkit.event.world.StructureGrowEvent(location, treeType, false, null, blocks); +@@ -548,7 +549,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack); + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockPos.getX() + 0.5D, (double) blockPos.getY(), (double) blockPos.getZ() + 0.5D)); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + level.getCraftServer().getPluginManager().callEvent(event); + } + +@@ -591,7 +592,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos)); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + level.getCraftServer().getPluginManager().callEvent(event); + } + +@@ -644,7 +645,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos)); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + level.getCraftServer().getPluginManager().callEvent(event); + } + +@@ -702,7 +703,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - only single item in event + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos)); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + serverLevel.getCraftServer().getPluginManager().callEvent(event); + } + +@@ -783,7 +784,7 @@ public interface DispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity()); +- if (!DispenserBlock.eventFired) { ++ if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + serverLevel.getCraftServer().getPluginManager().callEvent(event); + } + +diff --git a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java +index 3595bbd05fb3e8fe57e38d4e2df5c6237046b726..9bcb803b761aef0bf29a76bd4bea22f22cbeda5d 100644 +--- a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java +@@ -39,7 +39,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack); + + org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) livingEntity.getBukkitEntity()); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading world.getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java -index 3588896b7413be73ade6b3f8fd111d02c48ec550..add1e68b3be50ad5f2894fa40182f5448dcf2537 100644 ---- a/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java -@@ -74,7 +74,7 @@ public class MinecartDispenseItemBehavior extends DefaultDispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); +diff --git a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java +index 116395b6c00a0814922516707544a9ff26d68835..26c326080ee6fc80f0cc6af3e9fcbc1a508ba01a 100644 +--- a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java +@@ -62,7 +62,7 @@ public class MinecartDispenseItemBehavior extends DefaultDispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1); - BlockDispenseEvent event = new BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(vec3d1.x, vec3d1.y, vec3d1.z)); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(vec31.x, vec31.y, vec31.z)); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); + serverLevel.getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -index 54c72cf472e06e214eb61bd8615a0bb27690c807..f8cb78e6347eb4cb0c5942ae8c75728ed1389970 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java -@@ -43,7 +43,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1); +diff --git a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +index 449d9b72ff4650961daa9d1bd25940f3914a6b12..b4f2dbe3dcdeac2a297b7909cedd54a8079938d8 100644 +--- a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java ++++ b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java +@@ -32,7 +32,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1); - BlockDispenseEvent event = new BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) enumdirection.getStepX(), (double) enumdirection.getStepY(), (double) enumdirection.getStepZ())); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) direction.getStepX(), (double) direction.getStepY(), (double) direction.getStepZ())); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); + serverLevel.getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -index 65ed3d77a51b8299517e0c165403b0c5ac413475..bb1180f8739bb211c220950d4612eb8e59ee4afe 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java -@@ -41,7 +41,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack); // Paper - ignore stack size on damageable items - - BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); +diff --git a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +index 626e9feb6a6e7a2cbc7c63e30ba4fb6b923e85c7..eb63e114b666128df924dca46235ea8a7edbae54 100644 +--- a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java ++++ b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java +@@ -25,7 +25,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior { + org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos()); + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0)); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - worldserver.getCraftServer().getPluginManager().callEvent(event); + serverLevel.getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -index 8f9fde5489c0e1d0a91203536caddec5a9c96f6c..d43489fa1f69f025d44b881205afba39bdebba1c 100644 ---- a/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -+++ b/src/main/java/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java -@@ -37,7 +37,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(stack.copyWithCount(1)); // Paper - single item in event +diff --git a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +index 5ab2c8333178335515e619b87ae420f948c83bd1..172f41f15e3f165b8faca85e7bc581082d330041 100644 +--- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java ++++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java +@@ -27,7 +27,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior { + org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event - BlockDispenseEvent event = new BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockposition.getX(), blockposition.getY(), blockposition.getZ())); + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockPos.getX(), blockPos.getY(), blockPos.getZ())); - if (!DispenserBlock.eventFired) { + if (!DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - pointer.level().getCraftServer().getPluginManager().callEvent(event); + blockSource.level().getCraftServer().getPluginManager().callEvent(event); } -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94c65c4690 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -93,7 +93,7 @@ public class Connection extends SimpleChannelInboundHandler> { +diff --git a/net/minecraft/gametest/framework/GameTestHelper.java b/net/minecraft/gametest/framework/GameTestHelper.java +index fe4ae6bcdcbb55c47e9f9a4d63ead4c39e6d63cf..36a5ca39214233f37ef7bfeb47331a7deb566e5c 100644 +--- a/net/minecraft/gametest/framework/GameTestHelper.java ++++ b/net/minecraft/gametest/framework/GameTestHelper.java +@@ -306,7 +306,7 @@ public class GameTestHelper { + }; + Connection connection = new Connection(PacketFlow.SERVERBOUND); + new EmbeddedChannel(connection); +- this.getLevel().getServer().getPlayerList().placeNewPlayer(connection, serverPlayer, commonListenerCookie); ++ if (true) throw new UnsupportedOperationException(); // Folia - region threading + return serverPlayer; + } + +diff --git a/net/minecraft/gametest/framework/GameTestServer.java b/net/minecraft/gametest/framework/GameTestServer.java +index 54ca624a8194e7d1c0f3b1c0ddba81165523382c..a8cc20bfad1790f254c4793f09fc4dd3ddd4f25b 100644 +--- a/net/minecraft/gametest/framework/GameTestServer.java ++++ b/net/minecraft/gametest/framework/GameTestServer.java +@@ -175,8 +175,12 @@ public class GameTestServer extends MinecraftServer { + } + + @Override +- public void tickServer(BooleanSupplier hasTimeLeft) { +- super.tickServer(hasTimeLeft); ++ // Folia start - region threading ++ public void tickServer(long startTime, long scheduledEnd, long targetBuffer, ++ io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { ++ if (true) throw new UnsupportedOperationException(); ++ super.tickServer(startTime, scheduledEnd, targetBuffer, region); ++ // Folia end - region threading + ServerLevel serverLevel = this.overworld(); + if (!this.haveTestsStarted()) { + this.startTests(serverLevel); +diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java +index 208efae06c7c44f220d4192219a86ec55c98a2fe..0a219143a9cd593be68fa23661b653b6c1f6a9fe 100644 +--- a/net/minecraft/network/Connection.java ++++ b/net/minecraft/network/Connection.java +@@ -85,7 +85,7 @@ public class Connection extends SimpleChannelInboundHandler> { private static final ProtocolInfo INITIAL_PROTOCOL = HandshakeProtocols.SERVERBOUND; private final PacketFlow receiving; private volatile boolean sendLoginDisconnect = true; -- private final Queue pendingActions = Queues.newConcurrentLinkedQueue(); // Paper -+ private final Queue pendingActions = new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>(); // Paper // Folia - region threading - connection fixes +- private final Queue pendingActions = Queues.newConcurrentLinkedQueue(); // Paper - Optimize network ++ private final Queue pendingActions = new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>(); // Paper - Optimize network // Folia - region threading - connection fixes public Channel channel; public SocketAddress address; - // Spigot Start -@@ -108,7 +108,7 @@ public class Connection extends SimpleChannelInboundHandler> { + // Spigot start +@@ -100,7 +100,7 @@ public class Connection extends SimpleChannelInboundHandler> { @Nullable private DisconnectionDetails disconnectionDetails; private boolean encrypted; @@ -8143,8 +7881,8 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 private int receivedPackets; private int sentPackets; private float averageReceivedPackets; -@@ -163,6 +163,32 @@ public class Connection extends SimpleChannelInboundHandler> { - this.receiving = side; +@@ -154,6 +154,41 @@ public class Connection extends SimpleChannelInboundHandler> { + this.receiving = receiving; } + // Folia start - region threading @@ -8154,17 +7892,26 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 + return this.becomeActive; + } + -+ private static record DisconnectReq(Component disconnectReason, org.bukkit.event.player.PlayerKickEvent.Cause cause) {} ++ private static record DisconnectReq(DisconnectionDetails disconnectReason, org.bukkit.event.player.PlayerKickEvent.Cause cause) {} + + private final ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue disconnectReqs = -+ new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>(); ++ new ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue<>(); ++ ++ /** ++ * Safely disconnects the connection while possibly on another thread. Note: This call will not block, even if on the ++ * same thread that could disconnect. ++ */ ++ public final void disconnectSafely(DisconnectionDetails disconnectReason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { ++ this.disconnectReqs.add(new DisconnectReq(disconnectReason, cause)); ++ // We can't halt packet processing here because a plugin could cancel a kick request. ++ } + + /** + * Safely disconnects the connection while possibly on another thread. Note: This call will not block, even if on the + * same thread that could disconnect. + */ + public final void disconnectSafely(Component disconnectReason, org.bukkit.event.player.PlayerKickEvent.Cause cause) { -+ this.disconnectReqs.add(new DisconnectReq(disconnectReason, cause)); ++ this.disconnectReqs.add(new DisconnectReq(new DisconnectionDetails(disconnectReason), cause)); + // We can't halt packet processing here because a plugin could cancel a kick request. + } + @@ -8173,19 +7920,18 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 + } + // Folia end - region threading + - public void channelActive(ChannelHandlerContext channelhandlercontext) throws Exception { - super.channelActive(channelhandlercontext); - this.channel = channelhandlercontext.channel(); -@@ -173,7 +199,7 @@ public class Connection extends SimpleChannelInboundHandler> { + @Override + public void channelActive(ChannelHandlerContext context) throws Exception { + super.channelActive(context); +@@ -163,6 +198,7 @@ public class Connection extends SimpleChannelInboundHandler> { if (this.delayedDisconnect != null) { this.disconnect(this.delayedDisconnect); } -- + this.becomeActive = true; // Folia - region threading } - public void channelInactive(ChannelHandlerContext channelhandlercontext) { -@@ -451,7 +477,7 @@ public class Connection extends SimpleChannelInboundHandler> { + @Override +@@ -434,7 +470,7 @@ public class Connection extends SimpleChannelInboundHandler> { } packet.onPacketDispatch(this.getPlayer()); @@ -8193,22 +7939,22 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 + if (false && connected && (InnerUtil.canSendImmediate(this, packet) // Folia - region threading - connection fixes || (io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.pendingActions.isEmpty() && (packet.getExtraPackets() == null || packet.getExtraPackets().isEmpty())))) { - this.sendPacket(packet, callbacks, flush); -@@ -480,11 +506,12 @@ public class Connection extends SimpleChannelInboundHandler> { + this.sendPacket(packet, listener, flush); +@@ -463,11 +499,12 @@ public class Connection extends SimpleChannelInboundHandler> { } - public void runOnceConnected(Consumer task) { + public void runOnceConnected(Consumer action) { - if (this.isConnected()) { + if (false && this.isConnected()) { // Folia - region threading - connection fixes this.flushQueue(); - task.accept(this); + action.accept(this); } else { - this.pendingActions.add(new WrappedConsumer(task)); // Paper - Optimize network + this.pendingActions.add(new WrappedConsumer(action)); // Paper - Optimize network + this.flushQueue(); // Folia - region threading - connection fixes } - } -@@ -543,10 +570,11 @@ public class Connection extends SimpleChannelInboundHandler> { + +@@ -518,10 +555,11 @@ public class Connection extends SimpleChannelInboundHandler> { } public void flushChannel() { @@ -8219,9 +7965,9 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 this.pendingActions.add(new WrappedConsumer(Connection::flush)); // Paper - Optimize network + this.flushQueue(); // Folia - region threading - connection fixes } - } -@@ -564,53 +592,61 @@ public class Connection extends SimpleChannelInboundHandler> { + +@@ -535,53 +573,61 @@ public class Connection extends SimpleChannelInboundHandler> { // Paper start - Optimize network: Rewrite this to be safer if ran off main thread private boolean flushQueue() { @@ -8238,8 +7984,8 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 - } - return false; + return this.processQueue(); // Folia - region threading - connection fixes - } - ++ } ++ + // Folia start - region threading - connection fixes + // allow only one thread to be flushing the queue at once to ensure packets are written in the order they are sent + // into the queue @@ -8247,8 +7993,8 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 + + private static boolean canWrite(WrappedConsumer queued) { + return queued != null && (!(queued instanceof PacketSendAction packet) || packet.packet.isReady()); -+ } -+ + } + + private boolean canWritePackets() { + return canWrite(this.pendingActions.peek()); + } @@ -8317,7 +8063,7 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 } // Paper end - Optimize network -@@ -619,19 +655,39 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -590,17 +636,37 @@ public class Connection extends SimpleChannelInboundHandler> { private static int currTick; // Paper - Buffer joins to world public void tick() { this.flushQueue(); @@ -8333,7 +8079,7 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 + PacketListener packetlistener = this.packetListener; + + if (packetlistener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) { -+ loginPacketListener.disconnect(disconnectReq.disconnectReason); ++ loginPacketListener.disconnect(disconnectReq.disconnectReason.reason()); + // this doesn't fail, so abort any further attempts + return; + } else if (packetlistener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { @@ -8354,9 +8100,7 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 + return; + } + // Folia end - region threading - PacketListener packetlistener = this.packetListener; - - if (packetlistener instanceof TickablePacketListener tickablepacketlistener) { + if (this.packetListener instanceof TickablePacketListener tickablePacketListener) { // Paper start - Buffer joins to world - if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) - || loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING @@ -8365,7 +8109,7 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 // Paper start - detailed watchdog information net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener); try { -@@ -642,7 +698,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -611,7 +677,7 @@ public class Connection extends SimpleChannelInboundHandler> { } // Paper end - Buffer joins to world } @@ -8374,51 +8118,50 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 this.handleDisconnection(); } -@@ -692,6 +748,7 @@ public class Connection extends SimpleChannelInboundHandler> { +@@ -662,6 +728,7 @@ public class Connection extends SimpleChannelInboundHandler> { this.channel.close(); // We can't wait as this may be called from an event loop. - this.disconnectionDetails = disconnectionInfo; + this.disconnectionDetails = disconnectionDetails; } + this.becomeActive = true; // Folia - region threading - } -@@ -895,10 +952,10 @@ public class Connection extends SimpleChannelInboundHandler> { + public boolean isMemoryConnection() { +@@ -853,10 +920,10 @@ public class Connection extends SimpleChannelInboundHandler> { public void handleDisconnection() { if (this.channel != null && !this.channel.isOpen()) { - if (this.disconnectionHandled) { -+ if (this.disconnectionHandled.getAndSet(true)) { // Folia - region threading - may be called concurrently during configuration stage - // Connection.LOGGER.warn("handleDisconnection() called twice"); // Paper - Don't log useless message ++ if (!this.disconnectionHandled.compareAndSet(false, true)) { // Folia - region threading - may be called concurrently during configuration stage + // LOGGER.warn("handleDisconnection() called twice"); // Paper - Don't log useless message } else { - this.disconnectionHandled = true; -+ // Folia - region threading - may be called concurrently during configuration stage - set above - PacketListener packetlistener = this.getPacketListener(); - PacketListener packetlistener1 = packetlistener != null ? packetlistener : this.disconnectListener; - -@@ -930,6 +987,22 @@ public class Connection extends SimpleChannelInboundHandler> { ++ //this.disconnectionHandled = true; // Folia - region threading - may be called concurrently during configuration stage - set above + PacketListener packetListener = this.getPacketListener(); + PacketListener packetListener1 = packetListener != null ? packetListener : this.disconnectListener; + if (packetListener1 != null) { +@@ -885,6 +952,21 @@ public class Connection extends SimpleChannelInboundHandler> { } } // Paper end - Add PlayerConnectionCloseEvent + // Folia start - region threading -+ if (packetlistener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { ++ if (packetListener instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl commonPacketListener) { + net.minecraft.server.MinecraftServer.getServer().getPlayerList().removeConnection( -+ commonPacketListener.getOwner().getName(), -+ commonPacketListener.getOwner().getId(), this ++ commonPacketListener.getOwner().getName(), ++ commonPacketListener.getOwner().getId(), this + ); -+ } else if (packetlistener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) { ++ } else if (packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) { + if (loginPacketListener.state.ordinal() >= net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING.ordinal()) { + net.minecraft.server.MinecraftServer.getServer().getPlayerList().removeConnection( -+ loginPacketListener.authenticatedProfile.getName(), -+ loginPacketListener.authenticatedProfile.getId(), this ++ loginPacketListener.authenticatedProfile.getName(), ++ loginPacketListener.authenticatedProfile.getId(), this + ); + } + } + // Folia end - region threading -+ // Paper end - } } -@@ -950,15 +1023,25 @@ public class Connection extends SimpleChannelInboundHandler> { + } +@@ -904,15 +986,25 @@ public class Connection extends SimpleChannelInboundHandler> { // Paper start - Optimize network public void clearPacketQueue() { final net.minecraft.server.level.ServerPlayer player = getPlayer(); @@ -8450,49 +8193,50 @@ index 3c866432c8a938c677a315612f3e159bda67a2a2..30e3d0d7b0ca8cfa30efb60eefa73d94 } private static class InnerUtil { // Attempt to hide these methods from ProtocolLib, so it doesn't accidently pick them up. -diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -index 1f7f68aad97ee73763c042837f239bdc7167db55..d6eb8f495688a1b65a4c419aa3ee655cd8eb322a 100644 ---- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java -+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -@@ -46,7 +46,7 @@ public class PacketUtils { +diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java +index 4535858701b2bb232b9d2feb2af6551526232ddc..b28ff2f18ab7e0e3a61e37ee46048ab5cb7ab45d 100644 +--- a/net/minecraft/network/protocol/PacketUtils.java ++++ b/net/minecraft/network/protocol/PacketUtils.java +@@ -20,7 +20,7 @@ public class PacketUtils { - public static void ensureRunningOnSameThread(Packet packet, T listener, BlockableEventLoop engine) throws RunningOnDifferentThreadException { - if (!engine.isSameThread()) { -- engine.executeIfPossible(() -> { + public static void ensureRunningOnSameThread(Packet packet, T processor, BlockableEventLoop executor) throws RunningOnDifferentThreadException { + if (!executor.isSameThread()) { +- executor.executeIfPossible(() -> { + Runnable run = () -> { // Folia - region threading - packetProcessing.push(listener); // Paper - detailed watchdog information + packetProcessing.push(processor); // Paper - detailed watchdog information try { // Paper - detailed watchdog information - if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players -@@ -74,7 +74,23 @@ public class PacketUtils { + if (processor instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // Paper - Don't handle sync packets for kicked players +@@ -43,7 +43,24 @@ public class PacketUtils { + packetProcessing.pop(); } // Paper end - detailed watchdog information - - }); -+ }; // Folia start - region threading ++ // Folia start - region threading ++ }; + // ignore retired state, if removed then we don't want the packet to be handled -+ if (listener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { ++ if (processor instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { + gamePacketListener.player.getBukkitEntity().taskScheduler.schedule( -+ (net.minecraft.server.level.ServerPlayer player) -> { -+ run.run(); -+ }, -+ null, 1L ++ (net.minecraft.server.level.ServerPlayer player) -> { ++ run.run(); ++ }, ++ null, 1L + ); -+ } else if (listener instanceof net.minecraft.server.network.ServerConfigurationPacketListenerImpl configurationPacketListener) { ++ } else if (processor instanceof net.minecraft.server.network.ServerConfigurationPacketListenerImpl configurationPacketListener) { + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(run); -+ } else if (listener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) { ++ } else if (processor instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener) { + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(run); + } else { -+ throw new UnsupportedOperationException("Unknown listener: " + listener); ++ throw new UnsupportedOperationException("Unknown listener: " + processor); + } + // Folia end - region threading throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD; } } -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ae4ebf509837e8d44255781c61d02873f8b74be8..25b4b0d531f0698338ffeac686013a4631d60c00 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -216,7 +216,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop processQueue = new java.util.concurrent.ConcurrentLinkedQueue(); public int autosavePeriod; // Paper - don't store the vanilla dispatcher -@@ -334,6 +333,50 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation + // Folia start - regionised ticking @@ -8568,10 +8312,10 @@ index ae4ebf509837e8d44255781c61d02873f8b74be8..25b4b0d531f0698338ffeac686013a46 + } + // Folia end - regionised ticking + - public static S spin(Function serverFactory) { + public static S spin(Function threadFunction) { ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system - AtomicReference atomicreference = new AtomicReference(); -@@ -368,46 +411,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop atomicReference = new AtomicReference<>(); +@@ -332,46 +375,30 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> 4; -+ world.randomSpawnSelection = new ChunkPos(world.getChunkSource().randomState().sampler().findSpawnPosition()); ++ serverLevel.randomSpawnSelection = new ChunkPos(serverLevel.getChunkSource().randomState().sampler().findSpawnPosition()); + for (int currX = -loadRegionRadius; currX <= loadRegionRadius; ++currX) { + for (int currZ = -loadRegionRadius; currZ <= loadRegionRadius; ++currZ) { + ChunkPos pos = new ChunkPos(currX, currZ); -+ world.chunkSource.addTicketAtLevel( -+ net.minecraft.server.level.TicketType.UNKNOWN, pos, ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.MAX_TICKET_LEVEL, pos ++ serverLevel.chunkSource.addTicketAtLevel( ++ net.minecraft.server.level.TicketType.UNKNOWN, pos, ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.MAX_TICKET_LEVEL, pos + ); + } + } + // Folia end - region threading // Paper - Put world into worldlist before initing the world; move up - this.getPlayerList().addWorldborderListener(world); -@@ -749,6 +790,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 ? Mth.square(ChunkProgressListener.calculateDiameter(i)) : 0; +@@ -869,14 +912,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 ? Mth.square(ChunkProgressListener.calculateDiameter(_int)) : 0; -- while (chunkproviderserver.getTickingGenerated() < j) { +- while (chunkSource.getTickingGenerated() < i) { - // CraftBukkit start -- // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS; +- // this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; - this.executeModerately(); - } + // Folia - region threading - // this.nextTickTimeNanos = SystemUtils.getNanos() + MinecraftServer.PREPARE_LEVELS_DEFAULT_DELAY_NANOS; + // this.nextTickTimeNanos = Util.getNanos() + PREPARE_LEVELS_DEFAULT_DELAY_NANOS; - this.executeModerately(); + //this.executeModerately(); // Folia - region threading - // Iterator iterator = this.levels.values().iterator(); if (true) { -@@ -938,7 +977,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -- return false; -- } : this::haveTime); -+ if (true) throw new UnsupportedOperationException(); // Folia - region threading - // Paper start - rewrite chunk system - final Throwable crash = this.chunkSystemCrash; - if (crash != null) { -@@ -1531,21 +1623,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop false : this::haveTime); ++ if (true) throw new UnsupportedOperationException(); // Folia - region threading + // Paper start - rewrite chunk system + final Throwable crash = this.chunkSystemCrash; + if (crash != null) { +@@ -1403,28 +1497,24 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { -+ if (false && j > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy +- if (i > 0) { ++ if (false && i > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping - ++this.emptyTicks; + this.emptyTicks++; } else { -@@ -1652,24 +1744,59 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop true, false); } // Paper end - avoid issues with certain tasks not processing during sleep - this.server.spark.executeMainThreadTasks(); // Paper - spark -+ // Folia - region threading ++ //this.server.spark.executeMainThreadTasks(); // Paper - spark // Folia - region threading this.tickConnection(); this.server.spark.tickEnd(((double)(System.nanoTime() - lastTick) / 1000000D)); // Paper - spark return; @@ -8922,38 +8647,36 @@ index ae4ebf509837e8d44255781c61d02873f8b74be8..25b4b0d531f0698338ffeac686013a46 } + // Folia start - region threading -+ if (region != null) { -+ region.world.getCurrentWorldData().updateTickData(); -+ if (region.world.checkInitialised.get() != ServerLevel.WORLD_INIT_CHECKED) { -+ synchronized (region.world.checkInitialised) { -+ if (region.world.checkInitialised.compareAndSet(ServerLevel.WORLD_INIT_NOT_CHECKED, ServerLevel.WORLD_INIT_CHECKING)) { -+ LOGGER.info("Initialising world '" + region.world.getWorld().getName() + "' before it can be ticked..."); -+ this.initWorld(region.world, region.world.serverLevelData, worldData, region.world.serverLevelData.worldGenOptions()); // Folia - delayed until first tick of world -+ region.world.checkInitialised.set(ServerLevel.WORLD_INIT_CHECKED); -+ LOGGER.info("Initialised world '" + region.world.getWorld().getName() + "'"); -+ } // else: must be checked -+ } ++ region.world.getCurrentWorldData().updateTickData(); ++ if (region.world.checkInitialised.get() != ServerLevel.WORLD_INIT_CHECKED) { ++ synchronized (region.world.checkInitialised) { ++ if (region.world.checkInitialised.compareAndSet(ServerLevel.WORLD_INIT_NOT_CHECKED, ServerLevel.WORLD_INIT_CHECKING)) { ++ LOGGER.info("Initialising world '" + region.world.getWorld().getName() + "' before it can be ticked..."); ++ this.initWorld(region.world, region.world.serverLevelData, worldData, region.world.serverLevelData.worldGenOptions()); // Folia - delayed until first tick of world ++ region.world.checkInitialised.set(ServerLevel.WORLD_INIT_CHECKED); ++ LOGGER.info("Initialised world '" + region.world.getWorld().getName() + "'"); ++ } // else: must be checked + } + } -+ BooleanSupplier shouldKeepTicking = () -> { ++ BooleanSupplier hasTimeLeft = () -> { + return scheduledEnd - System.nanoTime() > targetBuffer; + }; + // Folia end - region threading + this.server.spark.tickStart(); // Paper - spark - new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper - Server Tick Events -- ++this.tickCount; +- this.tickCount++; - this.tickRateManager.tick(); -- this.tickChildren(shouldKeepTicking); -- if (i - this.lastServerStatus >= MinecraftServer.STATUS_EXPIRE_TIME_NANOS) { +- this.tickChildren(hasTimeLeft); +- if (nanos - this.lastServerStatus >= STATUS_EXPIRE_TIME_NANOS) { + new com.destroystokyo.paper.event.server.ServerTickStartEvent((int)region.getCurrentTick()).callEvent(); // Paper - Server Tick Events // Folia - region threading + // Folia start - region threading + if (region != null) { + region.getTaskQueueData().drainTasks(); -+ ((io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler)Bukkit.getRegionScheduler()).tick(); ++ ((io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler)org.bukkit.Bukkit.getRegionScheduler()).tick(); + // now run all the entity schedulers + // TODO there has got to be a more efficient variant of this crap -+ for (Entity entity : region.world.getCurrentWorldData().getLocalEntitiesCopy()) { ++ for (net.minecraft.world.entity.Entity entity : region.world.getCurrentWorldData().getLocalEntitiesCopy()) { + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity) || entity.isRemoved()) { + continue; + } @@ -8964,19 +8687,20 @@ index ae4ebf509837e8d44255781c61d02873f8b74be8..25b4b0d531f0698338ffeac686013a46 + } + } + // Folia end - region threading -+ if (region == null) this.tickRateManager.tick(); // Folia - region threading -+ this.tickChildren(shouldKeepTicking, region); // Folia - region threading -+ if (region == null && i - this.lastServerStatus >= MinecraftServer.STATUS_EXPIRE_TIME_NANOS) { // Folia - region threading - this.lastServerStatus = i; ++ //this.tickCount++; // Folia - region threading ++ //this.tickRateManager.tick(); // Folia - region threading ++ this.tickChildren(hasTimeLeft, region); // Folia - region threading ++ if (false && nanos - this.lastServerStatus >= STATUS_EXPIRE_TIME_NANOS) { // Folia - region threading + this.lastServerStatus = nanos; this.status = this.buildServerStatus(); } -- --this.ticksUntilAutosave; -+ // Folia - region threading +- this.ticksUntilAutosave--; ++ //this.ticksUntilAutosave--; // Folia - region threading // Paper start - Incremental chunk and player saving final ProfilerFiller profiler = Profiler.get(); int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate; -@@ -1677,15 +1804,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop list = this.playerList.getPlayers(); -+ List list = new java.util.ArrayList<>(this.playerList.getPlayers()); // Folia - region threading - int i = this.getMaxPlayers(); - +- List players = this.playerList.getPlayers(); ++ List players = new java.util.ArrayList<>(this.playerList.getPlayers()); // Folia - region threading + int maxPlayers = this.getMaxPlayers(); if (this.hidesOnlinePlayers()) { -@@ -1796,48 +1899,38 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -+ if (region == null) this.getPlayerList().getPlayers().forEach((entityplayer) -> { // Folia - region threading - entityplayer.connection.suspendFlushing(); - }); + ProfilerFiller profilerFiller = Profiler.get(); +- this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing()); - this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit -+ // Folia - region threading ++ //this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing()); // Folia - region threading ++ //this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit // Folia - region threading // Paper start - Folia scheduler API -- ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) Bukkit.getGlobalRegionScheduler()).tick(); +- ((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick(); - getAllLevels().forEach(level -> { -- for (final Entity entity : level.getEntities().getAll()) { +- for (final net.minecraft.world.entity.Entity entity : level.getEntities().getAll()) { - if (entity.isRemoved()) { - continue; - } @@ -9120,24 +8835,23 @@ index ae4ebf509837e8d44255781c61d02873f8b74be8..25b4b0d531f0698338ffeac686013a46 + // Folia - region threading - moved to global tick - and moved entity scheduler to tickRegion // Paper end - Folia scheduler API - io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper -+ // Folia - region threading - moved to global tick - gameprofilerfiller.push("commandFunctions"); ++ //io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper // Folia - region threading - moved to global tick + profilerFiller.push("commandFunctions"); - this.getFunctions().tick(); -+ if (region == null) this.getFunctions().tick(); // Folia - region threading - TODO Purge functions - gameprofilerfiller.popPush("levels"); - //Iterator iterator = this.getAllLevels().iterator(); // Paper - Throw exception on world create while being ticked; moved down ++ //this.getFunctions().tick(); // Folia - region threading - TODO Purge functions + profilerFiller.popPush("levels"); // CraftBukkit start // Run tasks that are waiting on processing - while (!this.processQueue.isEmpty()) { -+ if (region == null) while (!this.processQueue.isEmpty()) { // Folia - region threading ++ if (false) while (!this.processQueue.isEmpty()) { // Folia - region threading this.processQueue.remove().run(); } // Send time updates to everyone, it will get the right time from the world the player is in. // Paper start - Perf: Optimize time updates - for (final ServerLevel level : this.getAllLevels()) { -+ for (final ServerLevel level : (region == null ? this.getAllLevels() : Arrays.asList(region.world))) { // Folia - region threading ++ for (final ServerLevel level : Arrays.asList(region.world)) { // Folia - region threading final boolean doDaylight = level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT); final long dayTime = level.getDayTime(); long worldTime = level.getGameTime(); @@ -9149,70 +8863,66 @@ index ae4ebf509837e8d44255781c61d02873f8b74be8..25b4b0d531f0698338ffeac686013a46 continue; } ServerPlayer entityplayer = (ServerPlayer) entityhuman; -@@ -1849,14 +1942,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper - BlockPhysicsEvent -- worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent -- net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers -- worldserver.updateLagCompensationTick(); // Paper - lag compensation +- for (ServerLevel serverLevel : this.getAllLevels()) { +- serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent +- serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent +- serverLevel.updateLagCompensationTick(); // Paper - lag compensation +- net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers ++ //this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked // Folia - region threading ++ for (ServerLevel serverLevel : Arrays.asList(region.world)) { // Folia - region threading + // Folia - region threading - - gameprofilerfiller.push(() -> { - String s = String.valueOf(worldserver); -@@ -1874,7 +1964,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop serverLevel + " " + serverLevel.dimension().location()); + /* Drop global time updates + if (this.tickCount % 20 == 0) { +@@ -1721,7 +1815,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { -+ operation.perform(player, selection); ++ action.perform(player, advancements); + }, null, 1L); + // Folia end - region threading } if (i == 0) { -@@ -320,9 +325,12 @@ public class AdvancementCommands { - throw ERROR_CRITERION_NOT_FOUND.create(Advancement.name(advancement), criterion); +@@ -310,9 +315,12 @@ public class AdvancementCommands { + throw ERROR_CRITERION_NOT_FOUND.create(Advancement.name(advancement), criterionName); } else { for (ServerPlayer serverPlayer : targets) { -- if (operation.performCriterion(serverPlayer, advancement, criterion)) { +- if (action.performCriterion(serverPlayer, advancement, criterionName)) { - i++; - } + // Folia start - region threading + ++i; + serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { -+ operation.performCriterion(player, advancement, criterion); ++ action.performCriterion(player, advancement, criterionName); + }, null, 1L); + // Folia end - region threading } if (i == 0) { -diff --git a/src/main/java/net/minecraft/server/commands/AttributeCommand.java b/src/main/java/net/minecraft/server/commands/AttributeCommand.java -index 3ca51820d0fcf3f5c9f86b0d2fd8b2469bfb9795..af7a7fcd6377db1e61613977c7bb0ba1faa98d9c 100644 ---- a/src/main/java/net/minecraft/server/commands/AttributeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/AttributeCommand.java -@@ -262,37 +262,76 @@ public class AttributeCommand { +diff --git a/net/minecraft/server/commands/AttributeCommand.java b/net/minecraft/server/commands/AttributeCommand.java +index 2f0e8b2b1dda17cf861f80f8c1e655a345b76d10..505f0ce1f7b453d7e30e07c13a6b7678e12b0fda 100644 +--- a/net/minecraft/server/commands/AttributeCommand.java ++++ b/net/minecraft/server/commands/AttributeCommand.java +@@ -266,30 +266,62 @@ public class AttributeCommand { } } @@ -9351,40 +9060,19 @@ index 3ca51820d0fcf3f5c9f86b0d2fd8b2469bfb9795..af7a7fcd6377db1e61613977c7bb0ba1 + } + // Folia end - region threading + - private static int getAttributeValue(CommandSourceStack source, Entity target, Holder attribute, double multiplier) throws CommandSyntaxException { -- LivingEntity livingEntity = getEntityWithAttribute(target, attribute); + private static int getAttributeValue(CommandSourceStack source, Entity entity, Holder attribute, double scale) throws CommandSyntaxException { +- LivingEntity entityWithAttribute = getEntityWithAttribute(entity, attribute); + // Folia start - region threading -+ target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { ++ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { + try { + // Folia end - region threading -+ LivingEntity livingEntity = getEntityWithAttribute(nmsEntity, attribute); // Folia - region threading - double d = livingEntity.getAttributeValue(attribute); -- source.sendSuccess(() -> Component.translatable("commands.attribute.value.get.success", getAttributeDescription(attribute), target.getName(), d), false); -- return (int)(d * multiplier); -+ source.sendSuccess(() -> Component.translatable("commands.attribute.value.get.success", getAttributeDescription(attribute), nmsEntity.getName(), d), false); // Folia - region threading -+ return; // Folia - region threading -+ // Folia start - region threading -+ } catch (CommandSyntaxException ex) { -+ sendMessage(source, ex); -+ } -+ }, null, 1L); -+ return 0; -+ // Folia end - region threading - } - - private static int getAttributeBase(CommandSourceStack source, Entity target, Holder attribute, double multiplier) throws CommandSyntaxException { -- LivingEntity livingEntity = getEntityWithAttribute(target, attribute); -+ // Folia start - region threading -+ target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { -+ try { -+ // Folia end - region threading -+ LivingEntity livingEntity = getEntityWithAttribute(nmsEntity, attribute); // Folia - region threading - double d = livingEntity.getAttributeBaseValue(attribute); ++ LivingEntity entityWithAttribute = getEntityWithAttribute(nmsEntity, attribute); // Folia - region threading + double attributeValue = entityWithAttribute.getAttributeValue(attribute); source.sendSuccess( -- () -> Component.translatable("commands.attribute.base_value.get.success", getAttributeDescription(attribute), target.getName(), d), false -+ () -> Component.translatable("commands.attribute.base_value.get.success", getAttributeDescription(attribute), nmsEntity.getName(), d), false // Folia - region threading +- () -> Component.translatable("commands.attribute.value.get.success", getAttributeDescription(attribute), entity.getName(), attributeValue), false ++ () -> Component.translatable("commands.attribute.value.get.success", getAttributeDescription(attribute), nmsEntity.getName(), attributeValue), false // Folia - region threading ); -- return (int)(d * multiplier); +- return (int)(attributeValue * scale); + return; // Folia - region threading + // Folia start - region threading + } catch (CommandSyntaxException ex) { @@ -9395,27 +9083,55 @@ index 3ca51820d0fcf3f5c9f86b0d2fd8b2469bfb9795..af7a7fcd6377db1e61613977c7bb0ba1 + // Folia end - region threading } - private static int getAttributeModifier(CommandSourceStack source, Entity target, Holder attribute, ResourceLocation id, double multiplier) throws CommandSyntaxException { -- LivingEntity livingEntity = getEntityWithAttribute(target, attribute); + private static int getAttributeBase(CommandSourceStack source, Entity entity, Holder attribute, double scale) throws CommandSyntaxException { +- LivingEntity entityWithAttribute = getEntityWithAttribute(entity, attribute); + // Folia start - region threading -+ target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { ++ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { + try { + // Folia end - region threading -+ LivingEntity livingEntity = getEntityWithAttribute(nmsEntity, attribute); // Folia - region threading - AttributeMap attributeMap = livingEntity.getAttributes(); - if (!attributeMap.hasModifier(attribute, id)) { -- throw ERROR_NO_SUCH_MODIFIER.create(target.getName(), getAttributeDescription(attribute), id); ++ LivingEntity entityWithAttribute = getEntityWithAttribute(nmsEntity, attribute); // Folia - region threading + double attributeBaseValue = entityWithAttribute.getAttributeBaseValue(attribute); + source.sendSuccess( +- () -> Component.translatable("commands.attribute.base_value.get.success", getAttributeDescription(attribute), entity.getName(), attributeBaseValue), ++ () -> Component.translatable("commands.attribute.base_value.get.success", getAttributeDescription(attribute), nmsEntity.getName(), attributeBaseValue), // Folia - region threading + false + ); +- return (int)(attributeBaseValue * scale); ++ return; // Folia - region threading ++ // Folia start - region threading ++ } catch (CommandSyntaxException ex) { ++ sendMessage(source, ex); ++ } ++ }, null, 1L); ++ return 0; ++ // Folia end - region threading + } + + private static int getAttributeModifier(CommandSourceStack source, Entity entity, Holder attribute, ResourceLocation id, double scale) throws CommandSyntaxException { +- LivingEntity entityWithAttribute = getEntityWithAttribute(entity, attribute); ++ // Folia start - region threading ++ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { ++ try { ++ // Folia end - region threading ++ LivingEntity entityWithAttribute = getEntityWithAttribute(nmsEntity, attribute); // Folia - region threading + AttributeMap attributes = entityWithAttribute.getAttributes(); + if (!attributes.hasModifier(attribute, id)) { +- throw ERROR_NO_SUCH_MODIFIER.create(entity.getName(), getAttributeDescription(attribute), id); + throw ERROR_NO_SUCH_MODIFIER.create(nmsEntity.getName(), getAttributeDescription(attribute), id); // Folia - region threading } else { - double d = attributeMap.getModifierValue(attribute, id); + double modifierValue = attributes.getModifierValue(attribute, id); source.sendSuccess( - () -> Component.translatable( -- "commands.attribute.modifier.value.get.success", Component.translationArg(id), getAttributeDescription(attribute), target.getName(), d -+ "commands.attribute.modifier.value.get.success", Component.translationArg(id), getAttributeDescription(attribute), nmsEntity.getName(), d // Folia - region threading - ), +@@ -297,13 +329,20 @@ public class AttributeCommand { + "commands.attribute.modifier.value.get.success", + Component.translationArg(id), + getAttributeDescription(attribute), +- entity.getName(), ++ nmsEntity.getName(), // Folia - region threading + modifierValue + ), false ); -- return (int)(d * multiplier); +- return (int)(modifierValue * scale); + return; // Folia - region threading } + // Folia start - region threading @@ -9427,19 +9143,19 @@ index 3ca51820d0fcf3f5c9f86b0d2fd8b2469bfb9795..af7a7fcd6377db1e61613977c7bb0ba1 + // Folia end - region threading } - private static Stream getAttributeModifiers(Entity target, Holder attribute) throws CommandSyntaxException { -@@ -301,11 +340,22 @@ public class AttributeCommand { + private static Stream getAttributeModifiers(Entity entity, Holder attribute) throws CommandSyntaxException { +@@ -312,11 +351,22 @@ public class AttributeCommand { } - private static int setAttributeBase(CommandSourceStack source, Entity target, Holder attribute, double value) throws CommandSyntaxException { -- getAttributeInstance(target, attribute).setBaseValue(value); + private static int setAttributeBase(CommandSourceStack source, Entity entity, Holder attribute, double value) throws CommandSyntaxException { +- getAttributeInstance(entity, attribute).setBaseValue(value); + // Folia start - region threading -+ target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { ++ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { + try { + // Folia end - region threading + getAttributeInstance(nmsEntity, attribute).setBaseValue(value); // Folia - region threading source.sendSuccess( -- () -> Component.translatable("commands.attribute.base_value.set.success", getAttributeDescription(attribute), target.getName(), value), false +- () -> Component.translatable("commands.attribute.base_value.set.success", getAttributeDescription(attribute), entity.getName(), value), false + () -> Component.translatable("commands.attribute.base_value.set.success", getAttributeDescription(attribute), nmsEntity.getName(), value), false // Folia - region threading ); - return 1; @@ -9453,28 +9169,28 @@ index 3ca51820d0fcf3f5c9f86b0d2fd8b2469bfb9795..af7a7fcd6377db1e61613977c7bb0ba1 + // Folia end - region threading } - private static int resetAttributeBase(CommandSourceStack source, Entity target, Holder attribute) throws CommandSyntaxException { -@@ -324,35 +374,57 @@ public class AttributeCommand { + private static int resetAttributeBase(CommandSourceStack source, Entity entity, Holder attribute) throws CommandSyntaxException { +@@ -338,35 +388,57 @@ public class AttributeCommand { private static int addModifier( - CommandSourceStack source, Entity target, Holder attribute, ResourceLocation id, double value, AttributeModifier.Operation operation + CommandSourceStack source, Entity entity, Holder attribute, ResourceLocation id, double amount, AttributeModifier.Operation operation ) throws CommandSyntaxException { -- AttributeInstance attributeInstance = getAttributeInstance(target, attribute); +- AttributeInstance attributeInstance = getAttributeInstance(entity, attribute); + // Folia start - region threading -+ target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { ++ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { + try { + // Folia end - region threading + AttributeInstance attributeInstance = getAttributeInstance(nmsEntity, attribute); // Folia - region threading - AttributeModifier attributeModifier = new AttributeModifier(id, value, operation); + AttributeModifier attributeModifier = new AttributeModifier(id, amount, operation); if (attributeInstance.hasModifier(id)) { -- throw ERROR_MODIFIER_ALREADY_PRESENT.create(target.getName(), getAttributeDescription(attribute), id); +- throw ERROR_MODIFIER_ALREADY_PRESENT.create(entity.getName(), getAttributeDescription(attribute), id); + throw ERROR_MODIFIER_ALREADY_PRESENT.create(nmsEntity.getName(), getAttributeDescription(attribute), id); // Folia - region threading } else { attributeInstance.addPermanentModifier(attributeModifier); source.sendSuccess( () -> Component.translatable( -- "commands.attribute.modifier.add.success", Component.translationArg(id), getAttributeDescription(attribute), target.getName() -+ "commands.attribute.modifier.add.success", Component.translationArg(id), getAttributeDescription(attribute), nmsEntity.getName() // Folia - region threading - ), +- "commands.attribute.modifier.add.success", Component.translationArg(id), getAttributeDescription(attribute), entity.getName() ++ "commands.attribute.modifier.add.success", Component.translationArg(id), getAttributeDescription(attribute), nmsEntity.getName() // Folia - region threading + ), false ); - return 1; @@ -9489,25 +9205,25 @@ index 3ca51820d0fcf3f5c9f86b0d2fd8b2469bfb9795..af7a7fcd6377db1e61613977c7bb0ba1 + // Folia end - region threading } - private static int removeModifier(CommandSourceStack source, Entity target, Holder attribute, ResourceLocation id) throws CommandSyntaxException { -- AttributeInstance attributeInstance = getAttributeInstance(target, attribute); + private static int removeModifier(CommandSourceStack source, Entity entity, Holder attribute, ResourceLocation id) throws CommandSyntaxException { +- AttributeInstance attributeInstance = getAttributeInstance(entity, attribute); + // Folia start - region threading -+ target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { ++ entity.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { + try { + // Folia end - region threading + AttributeInstance attributeInstance = getAttributeInstance(nmsEntity, attribute); // Folia - region threading if (attributeInstance.removeModifier(id)) { source.sendSuccess( () -> Component.translatable( -- "commands.attribute.modifier.remove.success", Component.translationArg(id), getAttributeDescription(attribute), target.getName() -+ "commands.attribute.modifier.remove.success", Component.translationArg(id), getAttributeDescription(attribute), nmsEntity.getName() // Folia - region threading - ), +- "commands.attribute.modifier.remove.success", Component.translationArg(id), getAttributeDescription(attribute), entity.getName() ++ "commands.attribute.modifier.remove.success", Component.translationArg(id), getAttributeDescription(attribute), nmsEntity.getName() // Folia - region threading + ), false ); - return 1; + return; // Folia - region threading } else { -- throw ERROR_NO_SUCH_MODIFIER.create(target.getName(), getAttributeDescription(attribute), id); +- throw ERROR_NO_SUCH_MODIFIER.create(entity.getName(), getAttributeDescription(attribute), id); + throw ERROR_NO_SUCH_MODIFIER.create(nmsEntity.getName(), getAttributeDescription(attribute), id); // Folia - region threading } + // Folia start - region threading @@ -9520,21 +9236,21 @@ index 3ca51820d0fcf3f5c9f86b0d2fd8b2469bfb9795..af7a7fcd6377db1e61613977c7bb0ba1 } private static Component getAttributeDescription(Holder attribute) { -diff --git a/src/main/java/net/minecraft/server/commands/ClearInventoryCommands.java b/src/main/java/net/minecraft/server/commands/ClearInventoryCommands.java -index 4e6171ca870649114d4c7460baad2982173da09e..f8f0d33c663e6b9adac9f7e3eb21b5a6ff860c5d 100644 ---- a/src/main/java/net/minecraft/server/commands/ClearInventoryCommands.java -+++ b/src/main/java/net/minecraft/server/commands/ClearInventoryCommands.java +diff --git a/net/minecraft/server/commands/ClearInventoryCommands.java b/net/minecraft/server/commands/ClearInventoryCommands.java +index 73650c835ae3a8709d21462bc91a466167cd115f..3cbeaf2046bb0a41085a00134e69162df46d2081 100644 +--- a/net/minecraft/server/commands/ClearInventoryCommands.java ++++ b/net/minecraft/server/commands/ClearInventoryCommands.java @@ -65,9 +65,14 @@ public class ClearInventoryCommands { int i = 0; - for (ServerPlayer serverPlayer : targets) { -- i += serverPlayer.getInventory().clearOrCountMatchingItems(item, maxCount, serverPlayer.inventoryMenu.getCraftSlots()); + for (ServerPlayer serverPlayer : targetPlayers) { +- i += serverPlayer.getInventory().clearOrCountMatchingItems(itemPredicate, maxCount, serverPlayer.inventoryMenu.getCraftSlots()); - serverPlayer.containerMenu.broadcastChanges(); - serverPlayer.inventoryMenu.slotsChanged(serverPlayer.getInventory()); + // Folia start - region threading + ++i; + serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { -+ player.getInventory().clearOrCountMatchingItems(item, maxCount, player.inventoryMenu.getCraftSlots()); ++ player.getInventory().clearOrCountMatchingItems(itemPredicate, maxCount, player.inventoryMenu.getCraftSlots()); + player.containerMenu.broadcastChanges(); + player.inventoryMenu.slotsChanged(player.getInventory()); + }, null, 1L); @@ -9542,11 +9258,11 @@ index 4e6171ca870649114d4c7460baad2982173da09e..f8f0d33c663e6b9adac9f7e3eb21b5a6 } if (i == 0) { -diff --git a/src/main/java/net/minecraft/server/commands/DamageCommand.java b/src/main/java/net/minecraft/server/commands/DamageCommand.java -index 4184f5e8785b54694108cbbb231cab503803109d..d8a64ca978545c0ff9957fa828b07912ed03f377 100644 ---- a/src/main/java/net/minecraft/server/commands/DamageCommand.java -+++ b/src/main/java/net/minecraft/server/commands/DamageCommand.java -@@ -104,12 +104,29 @@ public class DamageCommand { +diff --git a/net/minecraft/server/commands/DamageCommand.java b/net/minecraft/server/commands/DamageCommand.java +index d99602f2c7e5463243dfaf83ada12c1d8e7d1192..5f3c886e2bc8a23e902cf8037ac8c871a601883f 100644 +--- a/net/minecraft/server/commands/DamageCommand.java ++++ b/net/minecraft/server/commands/DamageCommand.java +@@ -102,12 +102,29 @@ public class DamageCommand { ); } @@ -9556,15 +9272,15 @@ index 4184f5e8785b54694108cbbb231cab503803109d..d8a64ca978545c0ff9957fa828b07912 + } + // Folia end - region threading + - private static int damage(CommandSourceStack source, Entity target, float amount, DamageSource damageSource) throws CommandSyntaxException { -- if (target.hurtServer(source.getLevel(), damageSource, amount)) { + private static int damage(CommandSourceStack source, Entity target, float amount, DamageSource damageType) throws CommandSyntaxException { +- if (target.hurtServer(source.getLevel(), damageType, amount)) { - source.sendSuccess(() -> Component.translatable("commands.damage.success", amount, target.getDisplayName()), true); - return 1; + // Folia start - region threading + target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { + try { + // Folia end - region threading -+ if (nmsEntity.hurtServer(source.getLevel(), damageSource, amount)) { // Folia - region threading ++ if (nmsEntity.hurtServer(source.getLevel(), damageType, amount)) { // Folia - region threading + source.sendSuccess(() -> Component.translatable("commands.damage.success", amount, nmsEntity.getDisplayName()), true); // Folia - region threading + return; // Folia - region threading } else { @@ -9579,88 +9295,77 @@ index 4184f5e8785b54694108cbbb231cab503803109d..d8a64ca978545c0ff9957fa828b07912 + // Folia end - region threading } } -diff --git a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java -index a046a0b1519806ff3d987e6402f152b60a3a6f4c..60649ced046fa126ef59b7a2dc3e6b5eeaf42bc4 100644 ---- a/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java -+++ b/src/main/java/net/minecraft/server/commands/DefaultGameModeCommands.java +diff --git a/net/minecraft/server/commands/DefaultGameModeCommands.java b/net/minecraft/server/commands/DefaultGameModeCommands.java +index fd42373ccfedf28ffc0fcf9b3153e5a308c561c5..8a8e51c6a63858df2eae4176df75a66636d3f458 100644 +--- a/net/minecraft/server/commands/DefaultGameModeCommands.java ++++ b/net/minecraft/server/commands/DefaultGameModeCommands.java @@ -28,12 +28,14 @@ public class DefaultGameModeCommands { - GameType gameType = minecraftServer.getForcedGameType(); - if (gameType != null) { - for (ServerPlayer serverPlayer : minecraftServer.getPlayerList().getPlayers()) { + GameType forcedGameType = server.getForcedGameType(); + if (forcedGameType != null) { + for (ServerPlayer serverPlayer : server.getPlayerList().getPlayers()) { + serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { // Folia - region threading // Paper start - Expand PlayerGameModeChangeEvent -- org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.empty()); -+ org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.empty()); // Folia - region threading +- org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gamemode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.empty()); ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(gamemode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, net.kyori.adventure.text.Component.empty()); // Folia - region threading if (event != null && event.isCancelled()) { - source.sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false); + commandSource.sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), false); } // Paper end - Expand PlayerGameModeChangeEvent + }, null, 1L); // Folia - region threading i++; } } -diff --git a/src/main/java/net/minecraft/server/commands/EffectCommands.java b/src/main/java/net/minecraft/server/commands/EffectCommands.java -index ed6336065a0061af095d3395b927b8976443cb68..5a6f53cfaded2df14a82ee7639cdd0bb4728012e 100644 ---- a/src/main/java/net/minecraft/server/commands/EffectCommands.java -+++ b/src/main/java/net/minecraft/server/commands/EffectCommands.java -@@ -84,7 +84,15 @@ public class EffectCommands { +diff --git a/net/minecraft/server/commands/EffectCommands.java b/net/minecraft/server/commands/EffectCommands.java +index 0089ff5ca207278b829ec7530f50ec14681ab574..8d6e1dab63a6ef79d038fc6c3e9f7bf184b1d8c7 100644 +--- a/net/minecraft/server/commands/EffectCommands.java ++++ b/net/minecraft/server/commands/EffectCommands.java +@@ -180,7 +180,12 @@ public class EffectCommands { + for (Entity entity : targets) { if (entity instanceof LivingEntity) { - MobEffectInstance mobeffect = new MobEffectInstance(statusEffect, k, amplifier, false, showParticles); - -- if (((LivingEntity) entity).addEffect(mobeffect, source.getEntity(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit + MobEffectInstance mobEffectInstance = new MobEffectInstance(effect, i1, amplifier, false, showParticles); +- if (((LivingEntity)entity).addEffect(mobEffectInstance, source.getEntity(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit + // Folia start - region threading -+ entity.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { -+ if (!(nmsEntity instanceof LivingEntity)) { -+ return; -+ } -+ ((LivingEntity) nmsEntity).addEffect(mobeffect, null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND); ++ entity.getBukkitEntity().taskScheduler.schedule((LivingEntity nmsEntity) -> { ++ ((LivingEntity)nmsEntity).addEffect(mobEffectInstance, source.getEntity(), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND); + }, null, 1L); + // Folia end - region threading + if (true) { // CraftBukkit // Folia - region threading - ++j; + i++; } } -@@ -114,8 +122,16 @@ public class EffectCommands { - while (iterator.hasNext()) { - Entity entity = (Entity) iterator.next(); +@@ -210,7 +215,12 @@ public class EffectCommands { + int i = 0; -- if (entity instanceof LivingEntity && ((LivingEntity) entity).removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit -+ if (entity instanceof LivingEntity) { // CraftBukkit // Folia - region threading - ++i; + for (Entity entity : targets) { +- if (entity instanceof LivingEntity && ((LivingEntity)entity).removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit ++ if (entity instanceof LivingEntity && true) { // CraftBukkit // Folia - region threading + // Folia start - region threading -+ entity.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { -+ if (!(nmsEntity instanceof LivingEntity)) { -+ return; -+ } -+ ((LivingEntity) nmsEntity).removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND); ++ entity.getBukkitEntity().taskScheduler.schedule((LivingEntity nmsEntity) -> { ++ ((LivingEntity)nmsEntity).removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND); + }, null, 1L); + // Folia end - region threading + i++; } } +@@ -235,7 +245,12 @@ public class EffectCommands { + int i = 0; -@@ -144,8 +160,16 @@ public class EffectCommands { - while (iterator.hasNext()) { - Entity entity = (Entity) iterator.next(); - -- if (entity instanceof LivingEntity && ((LivingEntity) entity).removeEffect(statusEffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit -+ if (entity instanceof LivingEntity) { // CraftBukkit // Folia - region threading - ++i; + for (Entity entity : targets) { +- if (entity instanceof LivingEntity && ((LivingEntity)entity).removeEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND)) { // CraftBukkit ++ if (entity instanceof LivingEntity && true) { // CraftBukkit // Folia - region threading + // Folia start - region threading -+ entity.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { -+ if (!(nmsEntity instanceof LivingEntity)) { -+ return; -+ } -+ ((LivingEntity) nmsEntity).removeEffect(statusEffect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND); ++ entity.getBukkitEntity().taskScheduler.schedule((LivingEntity nmsEntity) -> { ++ ((LivingEntity)nmsEntity).removeEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.COMMAND); + }, null, 1L); + // Folia end - region threading + i++; } } - -diff --git a/src/main/java/net/minecraft/server/commands/EnchantCommand.java b/src/main/java/net/minecraft/server/commands/EnchantCommand.java -index cf0a5943f457c532958f40b4989fa18f967abae6..10422cbac32c7dfbd65cda3157f30b4d4c5ce9a2 100644 ---- a/src/main/java/net/minecraft/server/commands/EnchantCommand.java -+++ b/src/main/java/net/minecraft/server/commands/EnchantCommand.java -@@ -68,51 +68,79 @@ public class EnchantCommand { +diff --git a/net/minecraft/server/commands/EnchantCommand.java b/net/minecraft/server/commands/EnchantCommand.java +index fe86823f1a02d66df143756f00ee56fb9f634475..b62ed9d5456ae2c050c4d502b10c5e50c7265b96 100644 +--- a/net/minecraft/server/commands/EnchantCommand.java ++++ b/net/minecraft/server/commands/EnchantCommand.java +@@ -68,51 +68,78 @@ public class EnchantCommand { ); } @@ -9671,9 +9376,9 @@ index cf0a5943f457c532958f40b4989fa18f967abae6..10422cbac32c7dfbd65cda3157f30b4d + // Folia end - region threading + private static int enchant(CommandSourceStack source, Collection targets, Holder enchantment, int level) throws CommandSyntaxException { - Enchantment enchantment2 = enchantment.value(); - if (level > enchantment2.getMaxLevel()) { - throw ERROR_LEVEL_TOO_HIGH.create(level, enchantment2.getMaxLevel()); + Enchantment enchantment1 = enchantment.value(); + if (level > enchantment1.getMaxLevel()) { + throw ERROR_LEVEL_TOO_HIGH.create(level, enchantment1.getMaxLevel()); } else { - int i = 0; + final java.util.concurrent.atomic.AtomicInteger changed = new java.util.concurrent.atomic.AtomicInteger(0); // Folia - region threading @@ -9683,28 +9388,27 @@ index cf0a5943f457c532958f40b4989fa18f967abae6..10422cbac32c7dfbd65cda3157f30b4d for (Entity entity : targets) { if (entity instanceof LivingEntity) { - LivingEntity livingEntity = (LivingEntity)entity; -- ItemStack itemStack = livingEntity.getMainHandItem(); -- if (!itemStack.isEmpty()) { -- if (enchantment2.canEnchant(itemStack) -- && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment)) { -- itemStack.enchant(enchantment, level); +- ItemStack mainHandItem = livingEntity.getMainHandItem(); +- if (!mainHandItem.isEmpty()) { +- if (enchantment1.canEnchant(mainHandItem) +- && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(mainHandItem).keySet(), enchantment)) { +- mainHandItem.enchant(enchantment, level); - i++; - } else if (targets.size() == 1) { -- throw ERROR_INCOMPATIBLE.create(itemStack.getHoverName().getString()); -+ +- throw ERROR_INCOMPATIBLE.create(mainHandItem.getHoverName().getString()); + // Folia start - region threading + entity.getBukkitEntity().taskScheduler.schedule((LivingEntity nmsEntity) -> { + try { + LivingEntity livingEntity = (LivingEntity)nmsEntity; -+ ItemStack itemStack = livingEntity.getMainHandItem(); -+ if (!itemStack.isEmpty()) { -+ if (enchantment2.canEnchant(itemStack) -+ && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(itemStack).keySet(), enchantment)) { -+ itemStack.enchant(enchantment, level); ++ ItemStack mainHandItem = livingEntity.getMainHandItem(); ++ if (!mainHandItem.isEmpty()) { ++ if (enchantment1.canEnchant(mainHandItem) ++ && EnchantmentHelper.isEnchantmentCompatible(EnchantmentHelper.getEnchantmentsForCrafting(mainHandItem).keySet(), enchantment)) { ++ mainHandItem.enchant(enchantment, level); + possibleSingleDisplayName.set(livingEntity.getDisplayName()); + changed.incrementAndGet(); + } else if (targets.size() == 1) { -+ throw ERROR_INCOMPATIBLE.create(itemStack.getHoverName().getString()); ++ throw ERROR_INCOMPATIBLE.create(mainHandItem.getHoverName().getString()); + } + } else if (targets.size() == 1) { + throw ERROR_NO_ITEM.create(livingEntity.getName().getString()); @@ -9741,9 +9445,9 @@ index cf0a5943f457c532958f40b4989fa18f967abae6..10422cbac32c7dfbd65cda3157f30b4d + if (i == 1) { source.sendSuccess( () -> Component.translatable( -- "commands.enchant.success.single", Enchantment.getFullname(enchantment, level), targets.iterator().next().getDisplayName() -+ "commands.enchant.success.single", Enchantment.getFullname(enchantment, level), possibleSingleDisplayName.get() - ), +- "commands.enchant.success.single", Enchantment.getFullname(enchantment, level), targets.iterator().next().getDisplayName() ++ "commands.enchant.success.single", Enchantment.getFullname(enchantment, level), possibleSingleDisplayName.get() + ), true ); } else { @@ -9759,53 +9463,53 @@ index cf0a5943f457c532958f40b4989fa18f967abae6..10422cbac32c7dfbd65cda3157f30b4d } + // Folia end - region threading } -diff --git a/src/main/java/net/minecraft/server/commands/ExperienceCommand.java b/src/main/java/net/minecraft/server/commands/ExperienceCommand.java -index b4578e25286a245bba84543fac50c415dc20ba36..89cc58ba70930822f7a678577b8b7c7077a35791 100644 ---- a/src/main/java/net/minecraft/server/commands/ExperienceCommand.java -+++ b/src/main/java/net/minecraft/server/commands/ExperienceCommand.java +diff --git a/net/minecraft/server/commands/ExperienceCommand.java b/net/minecraft/server/commands/ExperienceCommand.java +index cb59af8018d3009876a47fae249885c00b6c7b57..e0d95f61e8a2841979bc9b5381dfaf7d3239beb7 100644 +--- a/net/minecraft/server/commands/ExperienceCommand.java ++++ b/net/minecraft/server/commands/ExperienceCommand.java @@ -131,14 +131,18 @@ public class ExperienceCommand { } - private static int queryExperience(CommandSourceStack source, ServerPlayer player, ExperienceCommand.Type component) { -- int i = component.query.applyAsInt(player); -- source.sendSuccess(() -> Component.translatable("commands.experience.query." + component.name, player.getDisplayName(), i), false); + private static int queryExperience(CommandSourceStack source, ServerPlayer player, ExperienceCommand.Type type) { +- int i = type.query.applyAsInt(player); +- source.sendSuccess(() -> Component.translatable("commands.experience.query." + type.name, player.getDisplayName(), i), false); - return i; + player.getBukkitEntity().taskScheduler.schedule((ServerPlayer serverPlayer) -> { // Folia - region threading -+ int i = component.query.applyAsInt(serverPlayer); // Folia - region threading -+ source.sendSuccess(() -> Component.translatable("commands.experience.query." + component.name, serverPlayer.getDisplayName(), i), false); // Folia - region threading ++ int i = type.query.applyAsInt(serverPlayer); // Folia - region threading ++ source.sendSuccess(() -> Component.translatable("commands.experience.query." + type.name, serverPlayer.getDisplayName(), i), false); // Folia - region threading + }, null, 1L); // Folia - region threading + return 0; // Folia - region threading } - private static int addExperience(CommandSourceStack source, Collection targets, int amount, ExperienceCommand.Type component) { + private static int addExperience(CommandSourceStack source, Collection targets, int amount, ExperienceCommand.Type type) { for (ServerPlayer serverPlayer : targets) { -- component.add.accept(serverPlayer, amount); +- type.add.accept(serverPlayer, amount); + serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { // Folia - region threading -+ component.add.accept(player, amount); // Folia - region threading ++ type.add.accept(player, amount); + }, null, 1L); // Folia - region threading } if (targets.size() == 1) { -@@ -159,9 +163,11 @@ public class ExperienceCommand { +@@ -157,9 +161,11 @@ public class ExperienceCommand { int i = 0; for (ServerPlayer serverPlayer : targets) { -- if (component.set.test(serverPlayer, amount)) { +- if (type.set.test(serverPlayer, amount)) { - i++; -+ ++i; serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { // Folia - region threading -+ if (component.set.test(player, amount)) { // Folia - region threading -+ // Folia - region threading ++ i++; serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { // Folia - region threading ++ if (type.set.test(player, amount)) { // Folia - region threading ++ //i++; // Folia - region threading } + }, null, 1L); // Folia - region threading } if (i == 0) { -diff --git a/src/main/java/net/minecraft/server/commands/FillBiomeCommand.java b/src/main/java/net/minecraft/server/commands/FillBiomeCommand.java -index 4034f52c4fcedf30b6c79b73f47afe1a97888202..d6f98bbfcb57dade34834fca87b4209c5f5d002f 100644 ---- a/src/main/java/net/minecraft/server/commands/FillBiomeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/FillBiomeCommand.java -@@ -106,6 +106,16 @@ public class FillBiomeCommand { - }); +diff --git a/net/minecraft/server/commands/FillBiomeCommand.java b/net/minecraft/server/commands/FillBiomeCommand.java +index bb2c8612b27bb04758c467ec6245de1236fc4de1..d5ae0eeb504b9306015de37abc59bf1a76a23837 100644 +--- a/net/minecraft/server/commands/FillBiomeCommand.java ++++ b/net/minecraft/server/commands/FillBiomeCommand.java +@@ -107,6 +107,16 @@ public class FillBiomeCommand { + return fill(level, from, to, biome, biome1 -> true, message -> {}); } + // Folia start - region threading @@ -9819,15 +9523,15 @@ index 4034f52c4fcedf30b6c79b73f47afe1a97888202..d6f98bbfcb57dade34834fca87b4209c + // Folia end - region threading + public static Either fill( - ServerLevel world, BlockPos from, BlockPos to, Holder biome, Predicate> filter, Consumer> feedbackConsumer + ServerLevel level, BlockPos from, BlockPos to, Holder biome, Predicate> filter, Consumer> messageOutput ) { -@@ -117,6 +127,17 @@ public class FillBiomeCommand { - if (i > j) { - return Either.right(ERROR_VOLUME_TOO_LARGE.create(j, i)); +@@ -118,6 +128,17 @@ public class FillBiomeCommand { + if (i > _int) { + return Either.right(ERROR_VOLUME_TOO_LARGE.create(_int, i)); } else { + // Folia start - region threading + int buffer = 0; // no buffer, we do not touch neighbours -+ world.moonrise$loadChunksAsync( ++ level.moonrise$loadChunksAsync( + (boundingBox.minX() - buffer) >> 4, + (boundingBox.maxX() + buffer) >> 4, + (boundingBox.minZ() - buffer) >> 4, @@ -9835,12 +9539,12 @@ index 4034f52c4fcedf30b6c79b73f47afe1a97888202..d6f98bbfcb57dade34834fca87b4209c + net.minecraft.world.level.chunk.status.ChunkStatus.FULL, + ca.spottedleaf.concurrentutil.util.Priority.NORMAL, + (chunks) -> { -+ sendMessage(feedbackConsumer, () -> { ++ sendMessage(messageOutput, () -> { List list = new ArrayList<>(); - for (int k = SectionPos.blockToSectionCoord(boundingBox.minZ()); k <= SectionPos.blockToSectionCoord(boundingBox.maxZ()); k++) { -@@ -153,6 +174,11 @@ public class FillBiomeCommand { - ) + for (int sectionPosMinZ = SectionPos.blockToSectionCoord(boundingBox.minZ()); +@@ -158,6 +179,11 @@ public class FillBiomeCommand { + ) ); return Either.left(mutableInt.getValue()); + // Folia start - region threading @@ -9851,10 +9555,10 @@ index 4034f52c4fcedf30b6c79b73f47afe1a97888202..d6f98bbfcb57dade34834fca87b4209c } } -diff --git a/src/main/java/net/minecraft/server/commands/FillCommand.java b/src/main/java/net/minecraft/server/commands/FillCommand.java -index 0509e28f79d13615b5baefc34799b0ad2df071be..d52a31656f2ade6d860cee6bc2f7d92a0588d643 100644 ---- a/src/main/java/net/minecraft/server/commands/FillCommand.java -+++ b/src/main/java/net/minecraft/server/commands/FillCommand.java +diff --git a/net/minecraft/server/commands/FillCommand.java b/net/minecraft/server/commands/FillCommand.java +index a224f8cc122fc6d79b4abd08815f58f0e6aa340b..89154adfc659afa188cd771e70087e3b1a9c98b9 100644 +--- a/net/minecraft/server/commands/FillCommand.java ++++ b/net/minecraft/server/commands/FillCommand.java @@ -151,6 +151,12 @@ public class FillCommand { ); } @@ -9866,32 +9570,32 @@ index 0509e28f79d13615b5baefc34799b0ad2df071be..d52a31656f2ade6d860cee6bc2f7d92a + // Folia end - region threading + private static int fillBlocks( - CommandSourceStack source, BoundingBox range, BlockInput block, FillCommand.Mode mode, @Nullable Predicate filter + CommandSourceStack source, BoundingBox area, BlockInput newBlock, FillCommand.Mode mode, @Nullable Predicate replacingPredicate ) throws CommandSyntaxException { @@ -161,6 +167,18 @@ public class FillCommand { } else { List list = Lists.newArrayList(); - ServerLevel serverLevel = source.getLevel(); + ServerLevel level = source.getLevel(); + // Folia start - region threading + int buffer = 32; + // physics may spill into neighbour chunks, so use a buffer -+ serverLevel.moonrise$loadChunksAsync( -+ (range.minX() - buffer) >> 4, -+ (range.maxX() + buffer) >> 4, -+ (range.minZ() - buffer) >> 4, -+ (range.maxZ() + buffer) >> 4, -+ net.minecraft.world.level.chunk.status.ChunkStatus.FULL, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (chunks) -> { -+ try { // Folia end - region threading - int k = 0; ++ level.moonrise$loadChunksAsync( ++ (area.minX() - buffer) >> 4, ++ (area.maxX() + buffer) >> 4, ++ (area.minZ() - buffer) >> 4, ++ (area.maxZ() + buffer) >> 4, ++ net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (chunks) -> { ++ try { // Folia end - region threading + int i1 = 0; - for (BlockPos blockPos : BlockPos.betweenClosed(range.minX(), range.minY(), range.minZ(), range.maxX(), range.maxY(), range.maxZ())) { + for (BlockPos blockPos : BlockPos.betweenClosed(area.minX(), area.minY(), area.minZ(), area.maxX(), area.maxY(), area.maxZ())) { @@ -187,8 +205,13 @@ public class FillCommand { } else { - int l = k; - source.sendSuccess(() -> Component.translatable("commands.fill.success", l), true); -- return k; + int i2 = i1; + source.sendSuccess(() -> Component.translatable("commands.fill.success", i2), true); +- return i1; + return; // Folia - region threading } + // Folia start - region threading @@ -9902,10 +9606,10 @@ index 0509e28f79d13615b5baefc34799b0ad2df071be..d52a31656f2ade6d860cee6bc2f7d92a } } -diff --git a/src/main/java/net/minecraft/server/commands/ForceLoadCommand.java b/src/main/java/net/minecraft/server/commands/ForceLoadCommand.java -index 255211f47a1678f714b1e04b31298976ada8a781..87275b46c4411fd51d6572ec7b3f924e347d4ed7 100644 ---- a/src/main/java/net/minecraft/server/commands/ForceLoadCommand.java -+++ b/src/main/java/net/minecraft/server/commands/ForceLoadCommand.java +diff --git a/net/minecraft/server/commands/ForceLoadCommand.java b/net/minecraft/server/commands/ForceLoadCommand.java +index 619ffb7846047d3e033378c750dc4ceaf9ac6239..6e174d54a3bf6a7a23a0aa6e7802b407e3969a47 100644 +--- a/net/minecraft/server/commands/ForceLoadCommand.java ++++ b/net/minecraft/server/commands/ForceLoadCommand.java @@ -97,7 +97,17 @@ public class ForceLoadCommand { ); } @@ -9922,10 +9626,10 @@ index 255211f47a1678f714b1e04b31298976ada8a781..87275b46c4411fd51d6572ec7b3f924e + try { + // Folia end - region threading ChunkPos chunkPos = pos.toChunkPos(); - ServerLevel serverLevel = source.getLevel(); - ResourceKey resourceKey = serverLevel.dimension(); + ServerLevel level = source.getLevel(); + ResourceKey resourceKey = level.dimension(); @@ -109,14 +119,22 @@ public class ForceLoadCommand { - ), + ), false ); - return 1; @@ -9943,45 +9647,45 @@ index 255211f47a1678f714b1e04b31298976ada8a781..87275b46c4411fd51d6572ec7b3f924e } private static int listForceLoad(CommandSourceStack source) { - ServerLevel serverLevel = source.getLevel(); + ServerLevel level = source.getLevel(); + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - ResourceKey resourceKey = serverLevel.dimension(); - LongSet longSet = serverLevel.getForcedChunks(); - int i = longSet.size(); + ResourceKey resourceKey = level.dimension(); + LongSet forcedChunks = level.getForcedChunks(); + int size = forcedChunks.size(); @@ -134,20 +152,27 @@ public class ForceLoadCommand { } else { source.sendFailure(Component.translatable("commands.forceload.added.none", Component.translationArg(resourceKey.location()))); } + }); // Folia - region threading -- return i; +- return size; + return 1; // Folia - region threading } private static int removeAll(CommandSourceStack source) { - ServerLevel serverLevel = source.getLevel(); - ResourceKey resourceKey = serverLevel.dimension(); + ServerLevel level = source.getLevel(); + ResourceKey resourceKey = level.dimension(); + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - LongSet longSet = serverLevel.getForcedChunks(); - longSet.forEach(chunkPos -> serverLevel.setChunkForced(ChunkPos.getX(chunkPos), ChunkPos.getZ(chunkPos), false)); + LongSet forcedChunks = level.getForcedChunks(); + forcedChunks.forEach(packedChunkPos -> level.setChunkForced(ChunkPos.getX(packedChunkPos), ChunkPos.getZ(packedChunkPos), false)); source.sendSuccess(() -> Component.translatable("commands.forceload.removed.all", Component.translationArg(resourceKey.location())), true); + }); // Folia - region threading return 0; } - private static int changeForceLoad(CommandSourceStack source, ColumnPos from, ColumnPos to, boolean forceLoaded) throws CommandSyntaxException { + private static int changeForceLoad(CommandSourceStack source, ColumnPos from, ColumnPos to, boolean add) throws CommandSyntaxException { + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + // Folia end - region threading - int i = Math.min(from.x(), to.x()); - int j = Math.min(from.z(), to.z()); - int k = Math.max(from.x(), to.x()); + int min = Math.min(from.x(), to.x()); + int min1 = Math.min(from.z(), to.z()); + int max = Math.max(from.x(), to.x()); @@ -207,11 +232,18 @@ public class ForceLoadCommand { ); } -- return u; +- return i2x; + return; // Folia - region threading } } @@ -9997,23 +9701,25 @@ index 255211f47a1678f714b1e04b31298976ada8a781..87275b46c4411fd51d6572ec7b3f924e + // Folia end - region threading } } -diff --git a/src/main/java/net/minecraft/server/commands/GameModeCommand.java b/src/main/java/net/minecraft/server/commands/GameModeCommand.java -index d1da3600dc07107309b20ebe6e7c0c4da0e8de76..a2075133b0e8ea6299dec0fa5125e4296eb3276a 100644 ---- a/src/main/java/net/minecraft/server/commands/GameModeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/GameModeCommand.java -@@ -60,15 +60,18 @@ public class GameModeCommand { +diff --git a/net/minecraft/server/commands/GameModeCommand.java b/net/minecraft/server/commands/GameModeCommand.java +index c44cdbbdc06b25bd20a208386545a10af9b96df8..f6204e765afda2668ab394c570444fbb7f152b8b 100644 +--- a/net/minecraft/server/commands/GameModeCommand.java ++++ b/net/minecraft/server/commands/GameModeCommand.java +@@ -54,15 +54,18 @@ public class GameModeCommand { int i = 0; - for (ServerPlayer serverPlayer : targets) { -+ serverPlayer.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { // Folia - region threading + for (ServerPlayer serverPlayer : players) { ++ serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer nmsEntity) -> { // Folia - region threading // Paper start - Expand PlayerGameModeChangeEvent - org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND, net.kyori.adventure.text.Component.empty()); +- org.bukkit.event.player.PlayerGameModeChangeEvent event = serverPlayer.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND, net.kyori.adventure.text.Component.empty()); ++ org.bukkit.event.player.PlayerGameModeChangeEvent event = nmsEntity.setGameMode(gameType, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.COMMAND, net.kyori.adventure.text.Component.empty()); // Folia - region threading if (event != null && !event.isCancelled()) { - logGamemodeChange(context.getSource(), serverPlayer, gameMode); +- logGamemodeChange(source.getSource(), serverPlayer, gameType); - i++; -+ // Folia - region threading ++ logGamemodeChange(source.getSource(), nmsEntity, gameType); // Folia - region threading ++ //i++; // Folia - region threading } else if (event != null && event.cancelMessage() != null) { - context.getSource().sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), true); + source.getSource().sendSuccess(() -> io.papermc.paper.adventure.PaperAdventure.asVanilla(event.cancelMessage()), true); // Paper end - Expand PlayerGameModeChangeEvent } + }, null, 1L); // Folia - region threading @@ -10021,30 +9727,59 @@ index d1da3600dc07107309b20ebe6e7c0c4da0e8de76..a2075133b0e8ea6299dec0fa5125e429 } return i; -diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java -index 0d9de4c61c7b26a6ff37c12fde629161fd0c3d5a..fca164cd59f1f0bf396e82a4c824c8d779b6c640 100644 ---- a/src/main/java/net/minecraft/server/commands/GiveCommand.java -+++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java -@@ -57,6 +57,7 @@ public class GiveCommand { +diff --git a/net/minecraft/server/commands/GiveCommand.java b/net/minecraft/server/commands/GiveCommand.java +index 8b7af734ca4ed3cafa810460b2cea6c1e6342a69..6f5d88d83ad724fa2b7549075b687aebd4b24eed 100644 +--- a/net/minecraft/server/commands/GiveCommand.java ++++ b/net/minecraft/server/commands/GiveCommand.java +@@ -65,32 +65,34 @@ public class GiveCommand { + int min = Math.min(maxStackSize, i1); + i1 -= min; + ItemStack itemStack1 = item.createItemStack(min, false); +- boolean flag = serverPlayer.getInventory().add(itemStack1); ++ serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer nmsEntity) -> { // Folia - region threading ++ boolean flag = nmsEntity.getInventory().add(itemStack1); // Folia - region threading + if (flag && itemStack1.isEmpty()) { +- ItemEntity itemEntity = serverPlayer.drop(itemStack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event ++ ItemEntity itemEntity = nmsEntity.drop(itemStack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event // Folia - region threading + if (itemEntity != null) { + itemEntity.makeFakeItem(); + } - l -= i1; - ItemStack itemstack1 = item.createItemStack(i1, false); -+ entityplayer.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { // Folia - region threading - boolean flag = entityplayer.getInventory().add(itemstack1); - ItemEntity entityitem; - -@@ -75,6 +76,7 @@ public class GiveCommand { - entityitem.setTarget(entityplayer.getUUID()); +- serverPlayer.level() ++ nmsEntity.level() // Folia - region threading + .playSound( + null, +- serverPlayer.getX(), +- serverPlayer.getY(), +- serverPlayer.getZ(), ++ nmsEntity.getX(), // Folia - region threading ++ nmsEntity.getY(), // Folia - region threading ++ nmsEntity.getZ(), // Folia - region threading + SoundEvents.ITEM_PICKUP, + SoundSource.PLAYERS, + 0.2F, +- ((serverPlayer.getRandom().nextFloat() - serverPlayer.getRandom().nextFloat()) * 0.7F + 1.0F) * 2.0F ++ ((nmsEntity.getRandom().nextFloat() - nmsEntity.getRandom().nextFloat()) * 0.7F + 1.0F) * 2.0F // Folia - region threading + ); +- serverPlayer.containerMenu.broadcastChanges(); ++ nmsEntity.containerMenu.broadcastChanges(); // Folia - region threading + } else { +- ItemEntity itemEntity = serverPlayer.drop(itemStack1, false); ++ ItemEntity itemEntity = nmsEntity.drop(itemStack1, false); // Folia - region threading + if (itemEntity != null) { + itemEntity.setNoPickUpDelay(); +- itemEntity.setTarget(serverPlayer.getUUID()); ++ itemEntity.setTarget(nmsEntity.getUUID()); // Folia - region threading } } + }, null, 1L); // Folia - region threading } } -diff --git a/src/main/java/net/minecraft/server/commands/KillCommand.java b/src/main/java/net/minecraft/server/commands/KillCommand.java +diff --git a/net/minecraft/server/commands/KillCommand.java b/net/minecraft/server/commands/KillCommand.java index e8ab673921c8089a35a2e678d7a6efed1f728cd7..287681a351f49eabd4f480396314a882bee73645 100644 ---- a/src/main/java/net/minecraft/server/commands/KillCommand.java -+++ b/src/main/java/net/minecraft/server/commands/KillCommand.java +--- a/net/minecraft/server/commands/KillCommand.java ++++ b/net/minecraft/server/commands/KillCommand.java @@ -24,7 +24,9 @@ public class KillCommand { private static int kill(CommandSourceStack source, Collection targets) { @@ -10056,12 +9791,12 @@ index e8ab673921c8089a35a2e678d7a6efed1f728cd7..287681a351f49eabd4f480396314a882 } if (targets.size() == 1) { -diff --git a/src/main/java/net/minecraft/server/commands/PlaceCommand.java b/src/main/java/net/minecraft/server/commands/PlaceCommand.java -index 89f89c0d223961a5aabfe60150893984f5894ff9..7f55ea913e557d99cf575ae4604523ca6d0c1f17 100644 ---- a/src/main/java/net/minecraft/server/commands/PlaceCommand.java -+++ b/src/main/java/net/minecraft/server/commands/PlaceCommand.java -@@ -88,12 +88,25 @@ public class PlaceCommand { - }))))))))); +diff --git a/net/minecraft/server/commands/PlaceCommand.java b/net/minecraft/server/commands/PlaceCommand.java +index f019285714cf6e7ac08d6b3b96fe705b8a564c28..4decfa02f0fa11a14abd48944e9cb2dd86bb96a2 100644 +--- a/net/minecraft/server/commands/PlaceCommand.java ++++ b/net/minecraft/server/commands/PlaceCommand.java +@@ -233,36 +233,79 @@ public class PlaceCommand { + ); } + // Folia start - region threading @@ -10071,25 +9806,22 @@ index 89f89c0d223961a5aabfe60150893984f5894ff9..7f55ea913e557d99cf575ae4604523ca + // Folia end - region threading + public static int placeFeature(CommandSourceStack source, Holder.Reference> feature, BlockPos pos) throws CommandSyntaxException { - ServerLevel worldserver = source.getLevel(); - ConfiguredFeature worldgenfeatureconfigured = (ConfiguredFeature) feature.value(); - ChunkPos chunkcoordintpair = new ChunkPos(pos); - - PlaceCommand.checkLoaded(worldserver, new ChunkPos(chunkcoordintpair.x - 1, chunkcoordintpair.z - 1), new ChunkPos(chunkcoordintpair.x + 1, chunkcoordintpair.z + 1)); + ServerLevel level = source.getLevel(); + ConfiguredFeature configuredFeature = feature.value(); + ChunkPos chunkPos = new ChunkPos(pos); + checkLoaded(level, new ChunkPos(chunkPos.x - 1, chunkPos.z - 1), new ChunkPos(chunkPos.x + 1, chunkPos.z + 1)); + // Folia start - region threading -+ worldserver.moonrise$loadChunksAsync( -+ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (chunks) -> { -+ try { -+ // Folia end - region threading - if (!worldgenfeatureconfigured.place(worldserver, worldserver.getChunkSource().getGenerator(), worldserver.getRandom(), pos)) { - throw PlaceCommand.ERROR_FEATURE_FAILED.create(); ++ level.moonrise$loadChunksAsync( ++ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (chunks) -> { ++ try { ++ // Folia end - region threading + if (!configuredFeature.place(level, level.getChunkSource().getGenerator(), level.getRandom(), pos)) { + throw ERROR_FEATURE_FAILED.create(); } else { -@@ -102,8 +115,16 @@ public class PlaceCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.place.feature.success", s, pos.getX(), pos.getY(), pos.getZ()); - }, true); + String string = feature.key().location().toString(); + source.sendSuccess(() -> Component.translatable("commands.place.feature.success", string, pos.getX(), pos.getY(), pos.getZ()), true); - return 1; + return; // Folia - region threading } @@ -10103,26 +9835,23 @@ index 89f89c0d223961a5aabfe60150893984f5894ff9..7f55ea913e557d99cf575ae4604523ca + // Folia end - region threading } - public static int placeJigsaw(CommandSourceStack source, Holder structurePool, ResourceLocation id, int maxDepth, BlockPos pos) throws CommandSyntaxException { -@@ -111,20 +132,42 @@ public class PlaceCommand { - ChunkPos chunkcoordintpair = new ChunkPos(pos); - - PlaceCommand.checkLoaded(worldserver, chunkcoordintpair, chunkcoordintpair); + public static int placeJigsaw(CommandSourceStack source, Holder templatePool, ResourceLocation target, int maxDepth, BlockPos pos) throws CommandSyntaxException { + ServerLevel level = source.getLevel(); + ChunkPos chunkPos = new ChunkPos(pos); + checkLoaded(level, chunkPos, chunkPos); + // Folia start - region threading -+ worldserver.moonrise$loadChunksAsync( -+ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (chunks) -> { -+ try { -+ // Folia end - region threading - if (!JigsawPlacement.generateJigsaw(worldserver, structurePool, id, maxDepth, pos, false)) { - throw PlaceCommand.ERROR_JIGSAW_FAILED.create(); ++ level.moonrise$loadChunksAsync( ++ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (chunks) -> { ++ try { ++ // Folia end - region threading + if (!JigsawPlacement.generateJigsaw(level, templatePool, target, maxDepth, pos, false)) { + throw ERROR_JIGSAW_FAILED.create(); } else { - source.sendSuccess(() -> { - return Component.translatable("commands.place.jigsaw.success", pos.getX(), pos.getY(), pos.getZ()); - }, true); + source.sendSuccess(() -> Component.translatable("commands.place.jigsaw.success", pos.getX(), pos.getY(), pos.getZ()), true); - return 1; -+ return; // Folia start - region threading ++ return; // Folia - region threading } + // Folia start - region threading + } catch (CommandSyntaxException ex) { @@ -10135,23 +9864,23 @@ index 89f89c0d223961a5aabfe60150893984f5894ff9..7f55ea913e557d99cf575ae4604523ca } public static int placeStructure(CommandSourceStack source, Holder.Reference structure, BlockPos pos) throws CommandSyntaxException { - ServerLevel worldserver = source.getLevel(); - Structure structure1 = (Structure) structure.value(); - ChunkGenerator chunkgenerator = worldserver.getChunkSource().getGenerator(); + ServerLevel level = source.getLevel(); + Structure structure1 = structure.value(); + ChunkGenerator generator = level.getChunkSource().getGenerator(); + // Folia start - region threading -+ worldserver.moonrise$loadChunksAsync( -+ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (chunks) -> { -+ try { -+ // Folia end - region threading - StructureStart structurestart = structure1.generate(structure, worldserver.dimension(), source.registryAccess(), chunkgenerator, chunkgenerator.getBiomeSource(), worldserver.getChunkSource().randomState(), worldserver.getStructureManager(), worldserver.getSeed(), new ChunkPos(pos), 0, worldserver, (holder) -> { - return true; - }); -@@ -146,12 +189,27 @@ public class PlaceCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.place.structure.success", s, pos.getX(), pos.getY(), pos.getZ()); - }, true); ++ level.moonrise$loadChunksAsync( ++ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (chunks) -> { ++ try { ++ // Folia end - region threading + StructureStart structureStart = structure1.generate( + structure, + level.dimension(), +@@ -305,14 +348,29 @@ public class PlaceCommand { + ); + String string = structure.key().location().toString(); + source.sendSuccess(() -> Component.translatable("commands.place.structure.success", string, pos.getX(), pos.getY(), pos.getZ()), true); - return 1; + return; // Folia - region threading } @@ -10165,22 +9894,24 @@ index 89f89c0d223961a5aabfe60150893984f5894ff9..7f55ea913e557d99cf575ae4604523ca + // Folia end - region threading } - public static int placeTemplate(CommandSourceStack source, ResourceLocation id, BlockPos pos, Rotation rotation, Mirror mirror, float integrity, int seed) throws CommandSyntaxException { - ServerLevel worldserver = source.getLevel(); + public static int placeTemplate( + CommandSourceStack source, ResourceLocation template, BlockPos pos, Rotation rotation, Mirror mirror, float integrity, int seed + ) throws CommandSyntaxException { + ServerLevel level = source.getLevel(); + // Folia start - region threading -+ worldserver.moonrise$loadChunksAsync( -+ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (chunks) -> { -+ try { -+ // Folia end - region threading - StructureTemplateManager structuretemplatemanager = worldserver.getStructureManager(); ++ level.moonrise$loadChunksAsync( ++ pos, 16, net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (chunks) -> { ++ try { ++ // Folia end - region threading + StructureTemplateManager structureManager = level.getStructureManager(); - Optional optional; -@@ -182,9 +240,17 @@ public class PlaceCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.place.template.success", Component.translationArg(id), pos.getX(), pos.getY(), pos.getZ()); - }, true); + Optional optional; +@@ -340,9 +398,17 @@ public class PlaceCommand { + () -> Component.translatable("commands.place.template.success", Component.translationArg(template), pos.getX(), pos.getY(), pos.getZ()), + true + ); - return 1; + return; // Folia - region threading } @@ -10195,11 +9926,11 @@ index 89f89c0d223961a5aabfe60150893984f5894ff9..7f55ea913e557d99cf575ae4604523ca + // Folia end - region threading } - private static void checkLoaded(ServerLevel world, ChunkPos pos1, ChunkPos pos2) throws CommandSyntaxException { -diff --git a/src/main/java/net/minecraft/server/commands/RecipeCommand.java b/src/main/java/net/minecraft/server/commands/RecipeCommand.java -index dabb43ffe0e9e8aef0aa275c48ab7fdba03762cc..eb55ca5730588d2f7f1d6e80f8cb43a1955c44cb 100644 ---- a/src/main/java/net/minecraft/server/commands/RecipeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/RecipeCommand.java + private static void checkLoaded(ServerLevel level, ChunkPos start, ChunkPos end) throws CommandSyntaxException { +diff --git a/net/minecraft/server/commands/RecipeCommand.java b/net/minecraft/server/commands/RecipeCommand.java +index d171a5b8c1969f6a482f029afa5fb0228aefb04d..c8ab7f56c5e5af99b5410784a3ae33dedd7bf2f3 100644 +--- a/net/minecraft/server/commands/RecipeCommand.java ++++ b/net/minecraft/server/commands/RecipeCommand.java @@ -81,7 +81,12 @@ public class RecipeCommand { int i = 0; @@ -10228,10 +9959,10 @@ index dabb43ffe0e9e8aef0aa275c48ab7fdba03762cc..eb55ca5730588d2f7f1d6e80f8cb43a1 } if (i == 0) { -diff --git a/src/main/java/net/minecraft/server/commands/SetBlockCommand.java b/src/main/java/net/minecraft/server/commands/SetBlockCommand.java -index 977f3b1f0b6822d37254452c681717d31d3e1011..ea13a3b409b8a4a6a77071c700b4dd0a33b02716 100644 ---- a/src/main/java/net/minecraft/server/commands/SetBlockCommand.java -+++ b/src/main/java/net/minecraft/server/commands/SetBlockCommand.java +diff --git a/net/minecraft/server/commands/SetBlockCommand.java b/net/minecraft/server/commands/SetBlockCommand.java +index 8b72116b80da0497e255ce5a3f3c7bccb6321aec..05b824409546ba8bacf7efdaeac106af89ff0715 100644 +--- a/net/minecraft/server/commands/SetBlockCommand.java ++++ b/net/minecraft/server/commands/SetBlockCommand.java @@ -80,10 +80,21 @@ public class SetBlockCommand { ); } @@ -10243,20 +9974,20 @@ index 977f3b1f0b6822d37254452c681717d31d3e1011..ea13a3b409b8a4a6a77071c700b4dd0a + // Folia end - region threading + private static int setBlock( - CommandSourceStack source, BlockPos pos, BlockInput block, SetBlockCommand.Mode mode, @Nullable Predicate condition + CommandSourceStack source, BlockPos pos, BlockInput state, SetBlockCommand.Mode mode, @Nullable Predicate predicate ) throws CommandSyntaxException { - ServerLevel serverLevel = source.getLevel(); + ServerLevel level = source.getLevel(); + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( -+ serverLevel, pos.getX() >> 4, pos.getZ() >> 4, () -> { -+ try { -+ // Folia end - region threading - if (condition != null && !condition.test(new BlockInWorld(serverLevel, pos, true))) { ++ level, pos.getX() >> 4, pos.getZ() >> 4, () -> { ++ try { ++ // Folia end - region threading + if (predicate != null && !predicate.test(new BlockInWorld(level, pos, true))) { throw ERROR_FAILED.create(); } else { @@ -102,9 +113,16 @@ public class SetBlockCommand { } else { - serverLevel.blockUpdated(pos, block.getState().getBlock()); + level.blockUpdated(pos, state.getState().getBlock()); source.sendSuccess(() -> Component.translatable("commands.setblock.success", pos.getX(), pos.getY(), pos.getZ()), true); - return 1; + return; // Folia - region threading @@ -10272,80 +10003,92 @@ index 977f3b1f0b6822d37254452c681717d31d3e1011..ea13a3b409b8a4a6a77071c700b4dd0a } public interface Filter { -diff --git a/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java b/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java -index 15db9368227dbc29d07d74e85bd126b345b526b6..161ae9c5f9ff0e8cdf3bb3c6bb1d068607f9c2ad 100644 ---- a/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java -+++ b/src/main/java/net/minecraft/server/commands/SetSpawnCommand.java -@@ -43,7 +43,11 @@ public class SetSpawnCommand { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); - +diff --git a/net/minecraft/server/commands/SetSpawnCommand.java b/net/minecraft/server/commands/SetSpawnCommand.java +index e38c7f012098e46337561b2225b31a7097495647..6fc6a748a8096524440d32d692088a8176875786 100644 +--- a/net/minecraft/server/commands/SetSpawnCommand.java ++++ b/net/minecraft/server/commands/SetSpawnCommand.java +@@ -69,7 +69,11 @@ public class SetSpawnCommand { + final Collection actualTargets = new java.util.ArrayList<>(); // Paper - Add PlayerSetSpawnEvent + for (ServerPlayer serverPlayer : targets) { // Paper start - Add PlayerSetSpawnEvent -- if (entityplayer.setRespawnPosition(resourcekey, pos, angle, true, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND)) { +- if (serverPlayer.setRespawnPosition(resourceKey, pos, angle, true, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND)) { + // Folia start - region threading -+ entityplayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { -+ player.setRespawnPosition(resourcekey, pos, angle, true, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND); ++ serverPlayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { ++ player.setRespawnPosition(resourceKey, pos, angle, true, false, com.destroystokyo.paper.event.player.PlayerSetSpawnEvent.Cause.COMMAND); + }, null, 1L); + if (true) { // Folia end - region threading - actualTargets.add(entityplayer); + actualTargets.add(serverPlayer); } // Paper end - Add PlayerSetSpawnEvent -diff --git a/src/main/java/net/minecraft/server/commands/SummonCommand.java b/src/main/java/net/minecraft/server/commands/SummonCommand.java -index f635da34335cd2901adf975fcd74c5c6f9785836..fb80b635d279a18758c6b0ce99858326bcade38e 100644 ---- a/src/main/java/net/minecraft/server/commands/SummonCommand.java -+++ b/src/main/java/net/minecraft/server/commands/SummonCommand.java -@@ -64,11 +64,18 @@ public class SummonCommand { +diff --git a/net/minecraft/server/commands/SummonCommand.java b/net/minecraft/server/commands/SummonCommand.java +index b68c0e617d3593cc9ba999ed25ea2c1b7c762597..2d4bf39f3f35811a7f48f361c91ee3d5722ba839 100644 +--- a/net/minecraft/server/commands/SummonCommand.java ++++ b/net/minecraft/server/commands/SummonCommand.java +@@ -88,12 +88,18 @@ public class SummonCommand { if (entity == null) { - throw SummonCommand.ERROR_FAILED.create(); + throw ERROR_FAILED.create(); } else { -- if (initialize && entity instanceof Mob) { -- ((Mob) entity).finalizeSpawn(source.getLevel(), source.getLevel().getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.COMMAND, (SpawnGroupData) null); +- if (randomizeProperties && entity instanceof Mob) { +- ((Mob)entity) +- .finalizeSpawn(source.getLevel(), source.getLevel().getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.COMMAND, null); - } + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( -+ worldserver, entity.chunkPosition().x, entity.chunkPosition().z, () -> { -+ if (initialize && entity instanceof Mob) { -+ ((Mob) entity).finalizeSpawn(source.getLevel(), source.getLevel().getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.COMMAND, (SpawnGroupData) null); -+ } -+ worldserver.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND); -+ } -+ ); ++ level, entity.chunkPosition().x, entity.chunkPosition().z, () -> { ++ if (randomizeProperties && entity instanceof Mob) { ++ ((Mob)entity) ++ .finalizeSpawn(source.getLevel(), source.getLevel().getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.COMMAND, null); ++ } ++ level.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND); ++ }); + // Folia end - region threading -- if (!worldserver.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND)) { // CraftBukkit - pass a spawn reason of "COMMAND" +- if (!level.tryAddFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND)) { // CraftBukkit - pass a spawn reason of "COMMAND" + if (false) { // CraftBukkit - pass a spawn reason of "COMMAND" // Folia - region threading - throw SummonCommand.ERROR_DUPLICATE_UUID.create(); + throw ERROR_DUPLICATE_UUID.create(); } else { return entity; -diff --git a/src/main/java/net/minecraft/server/commands/TeleportCommand.java b/src/main/java/net/minecraft/server/commands/TeleportCommand.java -index c13b6f14c3061710c2b27034db240cc94ec0fcb5..854897f5fcc8109a69cabc7d4fef1a23289d2733 100644 ---- a/src/main/java/net/minecraft/server/commands/TeleportCommand.java -+++ b/src/main/java/net/minecraft/server/commands/TeleportCommand.java -@@ -75,7 +75,7 @@ public class TeleportCommand { - while (iterator.hasNext()) { - Entity entity1 = (Entity) iterator.next(); +diff --git a/net/minecraft/server/commands/TeleportCommand.java b/net/minecraft/server/commands/TeleportCommand.java +index 01f8e2fec232210c9311565197860cf0257081fd..174122905addbc88e818cd4946e831aec051b91a 100644 +--- a/net/minecraft/server/commands/TeleportCommand.java ++++ b/net/minecraft/server/commands/TeleportCommand.java +@@ -154,18 +154,7 @@ public class TeleportCommand { -- TeleportCommand.performTeleport(source, entity1, (ServerLevel) destination.level(), destination.getX(), destination.getY(), destination.getZ(), EnumSet.noneOf(Relative.class), destination.getYRot(), destination.getXRot(), (LookAt) null); -+ io.papermc.paper.threadedregions.TeleportUtils.teleport(entity1, false, destination, Float.valueOf(destination.getYRot()), Float.valueOf(destination.getXRot()), Entity.TELEPORT_FLAG_LOAD_CHUNK, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND, null); // Folia - region threading + private static int teleportToEntity(CommandSourceStack source, Collection targets, Entity destination) throws CommandSyntaxException { + for (Entity entity : targets) { +- performTeleport( +- source, +- entity, +- (ServerLevel)destination.level(), +- destination.getX(), +- destination.getY(), +- destination.getZ(), +- EnumSet.noneOf(Relative.class), +- destination.getYRot(), +- destination.getXRot(), +- null +- ); ++ io.papermc.paper.threadedregions.TeleportUtils.teleport(entity, false, destination, Float.valueOf(destination.getYRot()), Float.valueOf(destination.getXRot()), Entity.TELEPORT_FLAG_LOAD_CHUNK, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND, null); // Folia - region threading } if (targets.size() == 1) { -@@ -173,6 +173,24 @@ public class TeleportCommand { - float f4 = Mth.wrapDegrees(f2); - float f5 = Mth.wrapDegrees(f3); - +@@ -290,6 +279,24 @@ public class TeleportCommand { + float f1 = relatives.contains(Relative.X_ROT) ? xRot - target.getXRot() : xRot; + float f2 = Mth.wrapDegrees(f); + float f3 = Mth.wrapDegrees(f1); + // Folia start - region threading + if (true) { -+ ServerLevel worldFinal = world; ++ ServerLevel worldFinal = level; + Vec3 posFinal = new Vec3(x, y, z); -+ Float yawFinal = Float.valueOf(f2); -+ Float pitchFinal = Float.valueOf(f3); -+ target.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { ++ Float yawFinal = Float.valueOf(f); ++ Float pitchFinal = Float.valueOf(f1); ++ target.getBukkitEntity().taskScheduler.schedule((Entity nmsEntity) -> { + nmsEntity.unRide(); + nmsEntity.teleportAsync( -+ worldFinal, posFinal, yawFinal, pitchFinal, Vec3.ZERO, -+ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND, -+ Entity.TELEPORT_FLAG_LOAD_CHUNK, -+ null ++ worldFinal, posFinal, yawFinal, pitchFinal, Vec3.ZERO, ++ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.COMMAND, ++ Entity.TELEPORT_FLAG_LOAD_CHUNK, ++ null + ); + }, null, 1L); + return; @@ -10353,87 +10096,79 @@ index c13b6f14c3061710c2b27034db240cc94ec0fcb5..854897f5fcc8109a69cabc7d4fef1a23 + // Folia end - region threading // CraftBukkit start - Teleport event boolean result; - if (target instanceof ServerPlayer player) { -diff --git a/src/main/java/net/minecraft/server/commands/TimeCommand.java b/src/main/java/net/minecraft/server/commands/TimeCommand.java -index 8b83d747de831878ff45dc74b4ae7cd9efb21d8c..92214e96d4b174dfac8a1d6bb3a195571aa91bc6 100644 ---- a/src/main/java/net/minecraft/server/commands/TimeCommand.java -+++ b/src/main/java/net/minecraft/server/commands/TimeCommand.java -@@ -55,6 +55,7 @@ public class TimeCommand { + if (target instanceof final net.minecraft.server.level.ServerPlayer player) { +diff --git a/net/minecraft/server/commands/TimeCommand.java b/net/minecraft/server/commands/TimeCommand.java +index e952ca088a2f36fc7f1eef4d9b217351569becc1..5d1fc3bb00abd177325a292f55d2cf1cddd3158b 100644 +--- a/net/minecraft/server/commands/TimeCommand.java ++++ b/net/minecraft/server/commands/TimeCommand.java +@@ -56,6 +56,7 @@ public class TimeCommand { + } + public static int setTime(CommandSourceStack source, int time) { - Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change - + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - while (iterator.hasNext()) { - ServerLevel worldserver = (ServerLevel) iterator.next(); + for (ServerLevel serverLevel : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) { // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change + // serverLevel.setDayTime(time); + // CraftBukkit start +@@ -69,10 +70,12 @@ public class TimeCommand { -@@ -71,12 +72,14 @@ public class TimeCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.time.set", time); - }, true); -- return TimeCommand.getDayTime(source.getLevel()); + source.getServer().forceTimeSynchronization(); + source.sendSuccess(() -> Component.translatable("commands.time.set", time), true); +- return getDayTime(source.getLevel()); + }); // Folia - region threading + return 0; // Folia - region threading } - public static int addTime(CommandSourceStack source, int time) { - Iterator iterator = io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels().iterator() : com.google.common.collect.Iterators.singletonIterator(source.getLevel()); // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change - + public static int addTime(CommandSourceStack source, int amount) { + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - while (iterator.hasNext()) { - ServerLevel worldserver = (ServerLevel) iterator.next(); - -@@ -95,6 +98,7 @@ public class TimeCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.time.set", j); - }, true); -- return j; + for (ServerLevel serverLevel : io.papermc.paper.configuration.GlobalConfiguration.get().commands.timeCommandAffectsAllWorlds ? source.getServer().getAllLevels() : java.util.List.of(source.getLevel())) { // CraftBukkit - SPIGOT-6496: Only set the time for the world the command originates in // Paper - add config option for spigot's change + // CraftBukkit start + org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent(serverLevel.getWorld(), org.bukkit.event.world.TimeSkipEvent.SkipReason.COMMAND, amount); +@@ -86,6 +89,7 @@ public class TimeCommand { + source.getServer().forceTimeSynchronization(); + int dayTime = getDayTime(source.getLevel()); + source.sendSuccess(() -> Component.translatable("commands.time.set", dayTime), true); +- return dayTime; + }); // Folia - region threading + return 0; // Folia - region threading } } -diff --git a/src/main/java/net/minecraft/server/commands/WeatherCommand.java b/src/main/java/net/minecraft/server/commands/WeatherCommand.java -index 4f5463bc299a43c32fefad6c57aa6a74fe73245b..72ce93dbb8ed9c3063c20fcf1b3cf0b59de8c4cb 100644 ---- a/src/main/java/net/minecraft/server/commands/WeatherCommand.java -+++ b/src/main/java/net/minecraft/server/commands/WeatherCommand.java -@@ -38,26 +38,32 @@ public class WeatherCommand { +diff --git a/net/minecraft/server/commands/WeatherCommand.java b/net/minecraft/server/commands/WeatherCommand.java +index 9b14b6218b2673e9b13b749b566e3b8a6a8d9c7d..dade5adec00c081cb4def7464f0f04d2f5a6ae26 100644 +--- a/net/minecraft/server/commands/WeatherCommand.java ++++ b/net/minecraft/server/commands/WeatherCommand.java +@@ -48,20 +48,26 @@ public class WeatherCommand { } - private static int setClear(CommandSourceStack source, int duration) { + private static int setClear(CommandSourceStack source, int time) { + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - source.getLevel().setWeatherParameters(WeatherCommand.getDuration(source, duration, ServerLevel.RAIN_DELAY), 0, false, false); // CraftBukkit - SPIGOT-7680: per-world - source.sendSuccess(() -> { - return Component.translatable("commands.weather.set.clear"); - }, true); + source.getLevel().setWeatherParameters(getDuration(source, time, ServerLevel.RAIN_DELAY), 0, false, false); // CraftBukkit - SPIGOT-7680: per-world + source.sendSuccess(() -> Component.translatable("commands.weather.set.clear"), true); + }); // Folia - region threading - return duration; + return time; } - private static int setRain(CommandSourceStack source, int duration) { + private static int setRain(CommandSourceStack source, int time) { + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - source.getLevel().setWeatherParameters(0, WeatherCommand.getDuration(source, duration, ServerLevel.RAIN_DURATION), true, false); // CraftBukkit - SPIGOT-7680: per-world - source.sendSuccess(() -> { - return Component.translatable("commands.weather.set.rain"); - }, true); + source.getLevel().setWeatherParameters(0, getDuration(source, time, ServerLevel.RAIN_DURATION), true, false); // CraftBukkit - SPIGOT-7680: per-world + source.sendSuccess(() -> Component.translatable("commands.weather.set.rain"), true); + }); // Folia - region threading - return duration; + return time; } - private static int setThunder(CommandSourceStack source, int duration) { + private static int setThunder(CommandSourceStack source, int time) { + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - source.getLevel().setWeatherParameters(0, WeatherCommand.getDuration(source, duration, ServerLevel.THUNDER_DURATION), true, true); // CraftBukkit - SPIGOT-7680: per-world - source.sendSuccess(() -> { - return Component.translatable("commands.weather.set.thunder"); - }, true); + source.getLevel().setWeatherParameters(0, getDuration(source, time, ServerLevel.THUNDER_DURATION), true, true); // CraftBukkit - SPIGOT-7680: per-world + source.sendSuccess(() -> Component.translatable("commands.weather.set.thunder"), true); + }); // Folia - region threading - return duration; + return time; } } -diff --git a/src/main/java/net/minecraft/server/commands/WorldBorderCommand.java b/src/main/java/net/minecraft/server/commands/WorldBorderCommand.java -index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e0204986b244 100644 ---- a/src/main/java/net/minecraft/server/commands/WorldBorderCommand.java -+++ b/src/main/java/net/minecraft/server/commands/WorldBorderCommand.java -@@ -56,7 +56,17 @@ public class WorldBorderCommand { - }))))); +diff --git a/net/minecraft/server/commands/WorldBorderCommand.java b/net/minecraft/server/commands/WorldBorderCommand.java +index e2697b03a0d204eea537e3aaec2dd8fb9f426722..f6af541a7076c3fefb237b865038d08919de35ed 100644 +--- a/net/minecraft/server/commands/WorldBorderCommand.java ++++ b/net/minecraft/server/commands/WorldBorderCommand.java +@@ -134,18 +134,39 @@ public class WorldBorderCommand { + ); } + // Folia start - region threading @@ -10447,14 +10182,13 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + // Folia end - region threading - WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit - - if (worldborder.getDamageSafeZone() == (double) distance) { -@@ -66,11 +76,22 @@ public class WorldBorderCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.worldborder.damage.buffer.success", String.format(Locale.ROOT, "%.2f", distance)); - }, true); -- return (int) distance; + WorldBorder worldBorder = source.getLevel().getWorldBorder(); // CraftBukkit + if (worldBorder.getDamageSafeZone() == distance) { + throw ERROR_SAME_DAMAGE_BUFFER.create(); + } else { + worldBorder.setDamageSafeZone(distance); + source.sendSuccess(() -> Component.translatable("commands.worldborder.damage.buffer.success", String.format(Locale.ROOT, "%.2f", distance)), true); +- return (int)distance; + return; // Folia - region threading } + // Folia start - region threading @@ -10471,14 +10205,14 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + // Folia end - region threading - WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit - - if (worldborder.getDamagePerBlock() == (double) damagePerBlock) { -@@ -80,11 +101,22 @@ public class WorldBorderCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.worldborder.damage.amount.success", String.format(Locale.ROOT, "%.2f", damagePerBlock)); - }, true); -- return (int) damagePerBlock; + WorldBorder worldBorder = source.getLevel().getWorldBorder(); // CraftBukkit + if (worldBorder.getDamagePerBlock() == damagePerBlock) { + throw ERROR_SAME_DAMAGE_AMOUNT.create(); +@@ -154,39 +175,79 @@ public class WorldBorderCommand { + source.sendSuccess( + () -> Component.translatable("commands.worldborder.damage.amount.success", String.format(Locale.ROOT, "%.2f", damagePerBlock)), true + ); +- return (int)damagePerBlock; + return; // Folia - region threading } + // Folia start - region threading @@ -10495,13 +10229,12 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + // Folia end - region threading - WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit - - if (worldborder.getWarningTime() == time) { -@@ -94,11 +126,22 @@ public class WorldBorderCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.worldborder.warning.time.success", time); - }, true); + WorldBorder worldBorder = source.getLevel().getWorldBorder(); // CraftBukkit + if (worldBorder.getWarningTime() == time) { + throw ERROR_SAME_WARNING_TIME.create(); + } else { + worldBorder.setWarningTime(time); + source.sendSuccess(() -> Component.translatable("commands.worldborder.warning.time.success", time), true); - return time; + return; // Folia - region threading } @@ -10519,13 +10252,12 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + // Folia end - region threading - WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit - - if (worldborder.getWarningBlocks() == distance) { -@@ -108,20 +151,38 @@ public class WorldBorderCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.worldborder.warning.distance.success", distance); - }, true); + WorldBorder worldBorder = source.getLevel().getWorldBorder(); // CraftBukkit + if (worldBorder.getWarningBlocks() == distance) { + throw ERROR_SAME_WARNING_DISTANCE.create(); + } else { + worldBorder.setWarningBlocks(distance); + source.sendSuccess(() -> Component.translatable("commands.worldborder.warning.distance.success", distance), true); - return distance; + return; // Folia - region threading } @@ -10541,13 +10273,10 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 private static int getSize(CommandSourceStack source) { + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { -+ // Folia end - region threading - double d0 = source.getLevel().getWorldBorder().getSize(); // CraftBukkit - - source.sendSuccess(() -> { - return Component.translatable("commands.worldborder.get", String.format(Locale.ROOT, "%.0f", d0)); - }, false); -- return Mth.floor(d0 + 0.5D); ++ // Folia end - region threading + double size = source.getLevel().getWorldBorder().getSize(); // CraftBukkit + source.sendSuccess(() -> Component.translatable("commands.worldborder.get", String.format(Locale.ROOT, "%.0f", size)), false); +- return Mth.floor(size + 0.5); + return; // Folia - region threading + // Folia start - region threading + }); @@ -10560,17 +10289,17 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + // Folia end - region threading - WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit - - if (worldborder.getCenterX() == (double) pos.x && worldborder.getCenterZ() == (double) pos.y) { -@@ -131,13 +192,24 @@ public class WorldBorderCommand { - source.sendSuccess(() -> { - return Component.translatable("commands.worldborder.center.success", String.format(Locale.ROOT, "%.2f", pos.x), String.format(Locale.ROOT, "%.2f", pos.y)); - }, true); + WorldBorder worldBorder = source.getLevel().getWorldBorder(); // CraftBukkit + if (worldBorder.getCenterX() == pos.x && worldBorder.getCenterZ() == pos.y) { + throw ERROR_SAME_CENTER.create(); +@@ -198,13 +259,24 @@ public class WorldBorderCommand { + ), + true + ); - return 0; + return; // Folia - region threading } else { - throw WorldBorderCommand.ERROR_TOO_FAR_OUT.create(); + throw ERROR_TOO_FAR_OUT.create(); } + // Folia start - region threading + } catch (CommandSyntaxException ex) { @@ -10581,19 +10310,19 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 + // Folia end - region threading } - private static int setSize(CommandSourceStack source, double distance, long time) throws CommandSyntaxException { + private static int setSize(CommandSourceStack source, double newSize, long time) throws CommandSyntaxException { + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { + try { + // Folia end - region threading - WorldBorder worldborder = source.getLevel().getWorldBorder(); // CraftBukkit - double d1 = worldborder.getSize(); - -@@ -166,7 +238,14 @@ public class WorldBorderCommand { - }, true); + WorldBorder worldBorder = source.getLevel().getWorldBorder(); // CraftBukkit + double size = worldBorder.getSize(); + if (size == newSize) { +@@ -234,7 +306,14 @@ public class WorldBorderCommand { + source.sendSuccess(() -> Component.translatable("commands.worldborder.set.immediate", String.format(Locale.ROOT, "%.1f", newSize)), true); } -- return (int) (distance - d1); +- return (int)(newSize - size); + return; // Folia - region threading } + // Folia start - region threading @@ -10605,11 +10334,11 @@ index 812f2adc6fc20aa126e629284fe594a923b24540..0a5e6961fb37e9a53cd39b1bd233e020 + // Folia end - region threading } } -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..78f33298e809a7f6d079d9f2c64e2caa47a1b25a 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -451,7 +451,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java +index 97a294d2f5c1ddf0af7ffec3e1425eb329c5751b..341e400f789e0eda29827e2c45c483a470d2e982 100644 +--- a/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/net/minecraft/server/dedicated/DedicatedServer.java +@@ -425,7 +425,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @Override public void tickConnection() { super.tickConnection(); @@ -10618,7 +10347,7 @@ index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..78f33298e809a7f6d079d9f2c64e2caa } @Override -@@ -768,7 +768,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -732,7 +732,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface public String runCommand(RconConsoleSource rconConsoleSource, String s) { rconConsoleSource.prepareForCommand(); @@ -10626,9 +10355,9 @@ index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..78f33298e809a7f6d079d9f2c64e2caa + final java.util.concurrent.atomic.AtomicReference command = new java.util.concurrent.atomic.AtomicReference<>(s); // Folia start - region threading + Runnable sync = () -> { // Folia - region threading CommandSourceStack wrapper = rconConsoleSource.createCommandSourceStack(); - RemoteServerCommandEvent event = new RemoteServerCommandEvent(rconConsoleSource.getBukkitSender(wrapper), s); + org.bukkit.event.server.RemoteServerCommandEvent event = new org.bukkit.event.server.RemoteServerCommandEvent(rconConsoleSource.getBukkitSender(wrapper), s); this.server.getPluginManager().callEvent(event); -@@ -777,7 +778,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -741,7 +742,16 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface } ConsoleInput serverCommand = new ConsoleInput(event.getCommand(), wrapper); this.server.dispatchServerCommand(event.getSender(), serverCommand); @@ -10646,82 +10375,69 @@ index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..78f33298e809a7f6d079d9f2c64e2caa return rconConsoleSource.getCommandResponse(); // CraftBukkit end } -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index cfeeddf2cb4ff50dbc29c6913e78ca1dee076790..1668011de11a5ed513815fa1b547ff3a7636cc13 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -139,8 +139,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - public final ChunkMap.ChunkDistanceManager distanceManager; - public final AtomicInteger tickingGenerated; // Paper - public +diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java +index b3f498558614243cf633dcd71e3c49c2c55e6e0f..06cc9d69220b09667db30a5c1e161333d2563b23 100644 +--- a/net/minecraft/server/level/ChunkMap.java ++++ b/net/minecraft/server/level/ChunkMap.java +@@ -128,8 +128,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + public final ChunkMap.DistanceManager distanceManager; + public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public private final String storageName; -- private final PlayerMap playerMap; -- public final Int2ObjectMap entityMap; -+ //private final PlayerMap playerMap; // Folia - region threading -+ //public final Int2ObjectMap entityMap; // Folia - region threading - private final Long2ByteMap chunkTypeCache; +- private final PlayerMap playerMap = new PlayerMap(); +- public final Int2ObjectMap entityMap = new Int2ObjectOpenHashMap<>(); ++ //private final PlayerMap playerMap = new PlayerMap(); // Folia - region threading ++ //public final Int2ObjectMap entityMap = new Int2ObjectOpenHashMap<>(); // Folia - region threading + private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap(); // Paper - rewrite chunk system public int serverViewDistance; -@@ -185,8 +185,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper - rewrite chunk system - this.toDrop = new LongOpenHashSet(); - this.tickingGenerated = new AtomicInteger(); -- this.playerMap = new PlayerMap(); -- this.entityMap = new Int2ObjectOpenHashMap(); -+ //this.playerMap = new PlayerMap(); // Folia - region threading -+ //this.entityMap = new Int2ObjectOpenHashMap(); // Folia - region threading - this.chunkTypeCache = new Long2ByteOpenHashMap(); - // Paper - rewrite chunk system - Path path = session.getDimensionPath(world.dimension()); -@@ -796,13 +796,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -797,12 +797,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - void updatePlayerStatus(ServerPlayer player, boolean added) { - boolean flag1 = this.skipPlayer(player); -- boolean flag2 = this.playerMap.ignoredOrUnknown(player); -+ // Folia - region threading - - if (added) { -- this.playerMap.addPlayer(player, flag1); -+ // Folia - region threading + void updatePlayerStatus(ServerPlayer player, boolean track) { + boolean flag = this.skipPlayer(player); +- boolean flag1 = this.playerMap.ignoredOrUnknown(player); ++ //boolean flag1 = this.playerMap.ignoredOrUnknown(player); // Folia - region threading + if (track) { +- this.playerMap.addPlayer(player, flag); ++ //this.playerMap.addPlayer(player, flag); // Folia - region threading this.updatePlayerPos(player); - if (!flag1) { -- this.distanceManager.addPlayer(SectionPos.of((EntityAccess) player), player); -+ // Folia - region threading + if (!flag) { +- this.distanceManager.addPlayer(SectionPos.of(player), player); ++ //this.distanceManager.addPlayer(SectionPos.of(player), player); // Folia - region threading ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$addPlayer(player, SectionPos.of(player)); // Paper - chunk tick iteration optimisation } -@@ -811,9 +811,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -810,9 +810,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + ca.spottedleaf.moonrise.common.PlatformHooks.get().addPlayerToDistanceMaps(this.level, player); // Paper - rewrite chunk system } else { - SectionPos sectionposition = player.getLastSectionPos(); - + SectionPos lastSectionPos = player.getLastSectionPos(); - this.playerMap.removePlayer(player); -- if (!flag2) { -- this.distanceManager.removePlayer(sectionposition, player); -+ // Folia - region threading +- if (!flag1) { +- this.distanceManager.removePlayer(lastSectionPos, player); ++ //this.playerMap.removePlayer(player); // Folia - region threading + if (true) { // Folia - region threading -+ // Folia - region threading ++ //this.distanceManager.removePlayer(lastSectionPos, player); // Folia - region threading ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$removePlayer(player, SectionPos.of(player)); // Paper - chunk tick iteration optimisation } -@@ -833,28 +833,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -830,27 +830,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - SectionPos sectionposition = player.getLastSectionPos(); - SectionPos sectionposition1 = SectionPos.of((EntityAccess) player); + SectionPos lastSectionPos = player.getLastSectionPos(); + SectionPos sectionPos = SectionPos.of(player); - boolean flag = this.playerMap.ignored(player); -+ // Folia - region threading ++ //boolean flag = this.playerMap.ignored(player); // Folia - region threading boolean flag1 = this.skipPlayer(player); -- boolean flag2 = sectionposition.asLong() != sectionposition1.asLong(); -+ // Folia - region threading - +- boolean flag2 = lastSectionPos.asLong() != sectionPos.asLong(); - if (flag2 || flag != flag1) { ++ //boolean flag2 = lastSectionPos.asLong() != sectionPos.asLong(); // Folia - region threading + if (true) { // Folia - region threading this.updatePlayerPos(player); -- ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$updatePlayer(player, sectionposition, sectionposition1, flag, flag1); // Paper - chunk tick iteration optimisation +- ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$updatePlayer(player, lastSectionPos, sectionPos, flag, flag1); // Paper - chunk tick iteration optimisation - if (!flag) { -- this.distanceManager.removePlayer(sectionposition, player); +- this.distanceManager.removePlayer(lastSectionPos, player); - } - - if (!flag1) { -- this.distanceManager.addPlayer(sectionposition1, player); +- this.distanceManager.addPlayer(sectionPos, player); - } - - if (!flag && flag1) { @@ -10731,12 +10447,12 @@ index cfeeddf2cb4ff50dbc29c6913e78ca1dee076790..1668011de11a5ed513815fa1b547ff3a - if (flag && !flag1) { - this.playerMap.unIgnorePlayer(player); - } -+ ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$updatePlayer(player, sectionposition, sectionposition1, false, flag1); // Paper - chunk tick iteration optimisation // Folia - region threading ++ ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager)this.distanceManager).moonrise$updatePlayer(player, lastSectionPos, sectionPos, false, flag1); // Paper - chunk tick iteration optimisation // Folia - region threading + // Folia - region threading // Paper - rewrite chunk system } -@@ -885,9 +871,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -880,9 +866,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider public void addEntity(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity track"); // Spigot // Paper start - ignore and warn about illegal addEntity calls instead of crashing server @@ -10748,72 +10464,62 @@ index cfeeddf2cb4ff50dbc29c6913e78ca1dee076790..1668011de11a5ed513815fa1b547ff3a return; } // Paper end - ignore and warn about illegal addEntity calls instead of crashing server -@@ -900,32 +886,30 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -893,22 +879,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + i = org.spigotmc.TrackingRange.getEntityTrackingRange(entity, i); // Spigot if (i != 0) { - int j = entitytypes.updateInterval(); - + int updateInterval = type.updateInterval(); - if (this.entityMap.containsKey(entity.getId())) { + if (entity.moonrise$getTrackedEntity() != null) { // Folia - region threading - throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Entity is already tracked!")); + throw (IllegalStateException)Util.pauseInIde(new IllegalStateException("Entity is already tracked!")); } else { - ChunkMap.TrackedEntity playerchunkmap_entitytracker = new ChunkMap.TrackedEntity(entity, i, j, entitytypes.trackDeltas()); - -- this.entityMap.put(entity.getId(), playerchunkmap_entitytracker); -+ // Folia - region threading + ChunkMap.TrackedEntity trackedEntity = new ChunkMap.TrackedEntity(entity, i, updateInterval, type.trackDeltas()); +- this.entityMap.put(entity.getId(), trackedEntity); ++ //this.entityMap.put(entity.getId(), trackedEntity); // Folia - region threading // Paper start - optimise entity tracker if (((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$getTrackedEntity() != null) { throw new IllegalStateException("Entity is already tracked"); } - ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$setTrackedEntity(playerchunkmap_entitytracker); + ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$setTrackedEntity(trackedEntity); // Paper end - optimise entity tracker -- playerchunkmap_entitytracker.updatePlayers(this.level.players()); -+ playerchunkmap_entitytracker.updatePlayers(this.level.getLocalPlayers()); // Folia - region threading - if (entity instanceof ServerPlayer) { - ServerPlayer entityplayer = (ServerPlayer) entity; +- trackedEntity.updatePlayers(this.level.players()); ++ trackedEntity.updatePlayers(this.level.getLocalPlayers()); // Folia - region threading + if (entity instanceof ServerPlayer serverPlayer) { + this.updatePlayerStatus(serverPlayer, true); - this.updatePlayerStatus(entityplayer, true); -- ObjectIterator objectiterator = this.entityMap.values().iterator(); -- -- while (objectiterator.hasNext()) { -- ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) objectiterator.next(); -- -- if (playerchunkmap_entitytracker1.entity != entityplayer) { -- playerchunkmap_entitytracker1.updatePlayer(entityplayer); +- for (ChunkMap.TrackedEntity trackedEntity1 : this.entityMap.values()) { + // Folia start - region threading + for (Entity possible : this.level.getCurrentWorldData().trackerEntities) { -+ if (possible.moonrise$getTrackedEntity() != null) { -+ possible.moonrise$getTrackedEntity().updatePlayer(entityplayer); ++ ChunkMap.TrackedEntity trackedEntity1 = possible.moonrise$getTrackedEntity(); ++ if (trackedEntity == null) { ++ continue; ++ } ++ // Folia end - region threading + if (trackedEntity1.entity != serverPlayer) { + trackedEntity1.updatePlayer(serverPlayer); } - } -+ // Folia end - region threading - } +@@ -924,12 +916,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + if (entity instanceof ServerPlayer serverPlayer) { + this.updatePlayerStatus(serverPlayer, false); - } -@@ -937,16 +921,16 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - org.spigotmc.AsyncCatcher.catchOp("entity untrack"); // Spigot - if (entity instanceof ServerPlayer entityplayer) { - this.updatePlayerStatus(entityplayer, false); -- ObjectIterator objectiterator = this.entityMap.values().iterator(); -- -- while (objectiterator.hasNext()) { -- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); -- -- playerchunkmap_entitytracker.removePlayer(entityplayer); +- for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) { + // Folia start - region threading + for (Entity possible : this.level.getCurrentWorldData().getLocalEntities()) { -+ if (possible.moonrise$getTrackedEntity() != null) { -+ possible.moonrise$getTrackedEntity().removePlayer(entityplayer); ++ ChunkMap.TrackedEntity trackedEntity = possible.moonrise$getTrackedEntity(); ++ if (trackedEntity == null) { ++ continue; + } ++ // Folia end - region threading + trackedEntity.removePlayer(serverPlayer); } + // Folia end - region threading } -- ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = (ChunkMap.TrackedEntity) this.entityMap.remove(entity.getId()); -+ ChunkMap.TrackedEntity playerchunkmap_entitytracker1 = entity.moonrise$getTrackedEntity(); // Folia - region threading - - if (playerchunkmap_entitytracker1 != null) { - playerchunkmap_entitytracker1.broadcastRemoved(); -@@ -957,9 +941,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +- ChunkMap.TrackedEntity trackedEntity1 = this.entityMap.remove(entity.getId()); ++ ChunkMap.TrackedEntity trackedEntity1 = entity.moonrise$getTrackedEntity(); // Folia - region threading + if (trackedEntity1 != null) { + trackedEntity1.broadcastRemoved(); + } +@@ -938,9 +937,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper start - optimise entity tracker private void newTrackerTick() { @@ -10825,66 +10531,55 @@ index cfeeddf2cb4ff50dbc29c6913e78ca1dee076790..1668011de11a5ed513815fa1b547ff3a final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked(); for (int i = 0, len = trackerEntities.size(); i < len; ++i) { final Entity entity = trackerEntitiesRaw[i]; -@@ -985,47 +970,12 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -966,44 +966,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider // Paper end - optimise entity tracker // Paper - rewrite chunk system - List list = Lists.newArrayList(); - List list1 = this.level.players(); -- ObjectIterator objectiterator = this.entityMap.values().iterator(); -- -- ChunkMap.TrackedEntity playerchunkmap_entitytracker; -- -- while (objectiterator.hasNext()) { -- playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); -- SectionPos sectionposition = playerchunkmap_entitytracker.lastSectionPos; -- SectionPos sectionposition1 = SectionPos.of((EntityAccess) playerchunkmap_entitytracker.entity); -- boolean flag = !Objects.equals(sectionposition, sectionposition1); - +- for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) { +- SectionPos sectionPos = trackedEntity.lastSectionPos; +- SectionPos sectionPos1 = SectionPos.of(trackedEntity.entity); +- boolean flag = !Objects.equals(sectionPos, sectionPos1); - if (flag) { -- playerchunkmap_entitytracker.updatePlayers(list1); -- Entity entity = playerchunkmap_entitytracker.entity; -- +- trackedEntity.updatePlayers(list1); +- Entity entity = trackedEntity.entity; - if (entity instanceof ServerPlayer) { -- list.add((ServerPlayer) entity); +- list.add((ServerPlayer)entity); - } - -- playerchunkmap_entitytracker.lastSectionPos = sectionposition1; +- trackedEntity.lastSectionPos = sectionPos1; - } - -- if (flag || this.distanceManager.inEntityTickingRange(sectionposition1.chunk().toLong())) { -- playerchunkmap_entitytracker.serverEntity.sendChanges(); +- if (flag || this.distanceManager.inEntityTickingRange(sectionPos1.chunk().toLong())) { +- trackedEntity.serverEntity.sendChanges(); - } - } - - if (!list.isEmpty()) { -- objectiterator = this.entityMap.values().iterator(); -- -- while (objectiterator.hasNext()) { -- playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) objectiterator.next(); -- playerchunkmap_entitytracker.updatePlayers(list); +- for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) { +- trackedEntity.updatePlayers(list); - } - } + // Folia - region threading - } public void broadcast(Entity entity, Packet packet) { -- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId()); -+ ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) entity.moonrise$getTrackedEntity(); // Folia - region threading - - if (playerchunkmap_entitytracker != null) { - playerchunkmap_entitytracker.broadcast(packet); -@@ -1034,7 +984,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +- ChunkMap.TrackedEntity trackedEntity = this.entityMap.get(entity.getId()); ++ ChunkMap.TrackedEntity trackedEntity = entity.moonrise$getTrackedEntity(); // Folia - region threading + if (trackedEntity != null) { + trackedEntity.broadcast(packet); + } } protected void broadcastAndSend(Entity entity, Packet packet) { -- ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) this.entityMap.get(entity.getId()); -+ ChunkMap.TrackedEntity playerchunkmap_entitytracker = (ChunkMap.TrackedEntity) entity.moonrise$getTrackedEntity(); // Folia - region threading - - if (playerchunkmap_entitytracker != null) { - playerchunkmap_entitytracker.broadcastAndSend(packet); -@@ -1287,9 +1237,14 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +- ChunkMap.TrackedEntity trackedEntity = this.entityMap.get(entity.getId()); ++ ChunkMap.TrackedEntity trackedEntity = entity.moonrise$getTrackedEntity(); // Folia - region threading + if (trackedEntity != null) { + trackedEntity.broadcastAndSend(packet); + } +@@ -1231,8 +1205,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); // Paper end - Configurable entity tracking range by Y @@ -10893,18 +10588,17 @@ index cfeeddf2cb4ff50dbc29c6913e78ca1dee076790..1668011de11a5ed513815fa1b547ff3a + flag = false; + } + // Folia end - region threading - // CraftBukkit start - respect vanish API - if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits + if (flag && (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player) || !player.getBukkitEntity().canSee(this.entity.getBukkitEntity()))) { // Paper - only consider hits // Folia - region threading flag = false; } // CraftBukkit end -diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java -index 746f61661e22d22f2acbbe54a5933e57fbca45b2..f6015f2ac77aeddbd900226d183bf24c93112b21 100644 ---- a/src/main/java/net/minecraft/server/level/DistanceManager.java -+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java -@@ -59,16 +59,16 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches +diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java +index 5eab6179ce3913cb4e4d424f910ba423faf21c85..338f9d047101619605cedab172358b4fd737af97 100644 +--- a/net/minecraft/server/level/DistanceManager.java ++++ b/net/minecraft/server/level/DistanceManager.java +@@ -57,16 +57,16 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches } // Paper end - rewrite chunk system // Paper start - chunk tick iteration optimisation @@ -10924,7 +10618,7 @@ index 746f61661e22d22f2acbbe54a5933e57fbca45b2..f6015f2ac77aeddbd900226d183bf24c } @Override -@@ -76,9 +76,9 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches +@@ -74,9 +74,9 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches final SectionPos oldPos, final SectionPos newPos, final boolean oldIgnore, final boolean newIgnore) { if (newIgnore) { @@ -10936,7 +10630,7 @@ index 746f61661e22d22f2acbbe54a5933e57fbca45b2..f6015f2ac77aeddbd900226d183bf24c } } // Paper end - chunk tick iteration optimisation -@@ -217,15 +217,15 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches +@@ -208,15 +208,15 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches } public int getNaturalSpawnChunkCount() { @@ -10955,11 +10649,11 @@ index 746f61661e22d22f2acbbe54a5933e57fbca45b2..f6015f2ac77aeddbd900226d183bf24c } public String getDebugStatus() { -diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc254282da35 100644 ---- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java -+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java -@@ -62,18 +62,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java +index 6540b2d6a1062d883811ce240c49d30d1925b291..c340d537749c49d83f50f6cec84ac75e1ace2bbd 100644 +--- a/net/minecraft/server/level/ServerChunkCache.java ++++ b/net/minecraft/server/level/ServerChunkCache.java +@@ -61,18 +61,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon public final ServerChunkCache.MainThreadExecutor mainThreadProcessor; public final ChunkMap chunkMap; private final DimensionDataStorage dataStorage; @@ -10971,8 +10665,8 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 private final long[] lastChunkPos = new long[4]; private final ChunkStatus[] lastChunkStatus = new ChunkStatus[4]; private final ChunkAccess[] lastChunk = new ChunkAccess[4]; -- private final List tickingChunks = new ArrayList(); -- private final Set chunkHoldersToBroadcast = new ReferenceOpenHashSet(); +- private final List tickingChunks = new ArrayList<>(); +- private final Set chunkHoldersToBroadcast = new ReferenceOpenHashSet<>(); - @Nullable - @VisibleForDebug - private NaturalSpawner.SpawnState lastSpawnState; @@ -10980,7 +10674,7 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 // Paper start private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); public int getFullChunksCount() { -@@ -99,6 +95,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -98,6 +94,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } private ChunkAccess syncLoad(final int chunkX, final int chunkZ, final ChunkStatus toStatus) { @@ -10992,48 +10686,46 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler chunkTaskScheduler = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler(); final CompletableFuture completable = new CompletableFuture<>(); chunkTaskScheduler.scheduleChunkLoad( -@@ -329,6 +330,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -355,6 +356,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } - public CompletableFuture> getChunkFuture(int chunkX, int chunkZ, ChunkStatus leastStatus, boolean create) { + public CompletableFuture> getChunkFuture(int x, int z, ChunkStatus chunkStatus, boolean requireChunk) { + if (true) throw new UnsupportedOperationException(); // Folia - region threading - boolean flag1 = Thread.currentThread() == this.mainThread; - CompletableFuture completablefuture; - -@@ -482,16 +484,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + boolean flag = Thread.currentThread() == this.mainThread; + CompletableFuture> chunkFutureMainThread; + if (flag) { +@@ -502,14 +504,15 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } private void tickChunks() { -- long i = this.level.getGameTime(); -- long j = i - this.lastInhabitedUpdate; +- long gameTime = this.level.getGameTime(); +- long l = gameTime - this.lastInhabitedUpdate; +- this.lastInhabitedUpdate = gameTime; + io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData(); // Folia - region threading -+ //long i = this.level.getGameTime(); // Folia - region threading -+ long j = 1L; // Folia - region threading - -- this.lastInhabitedUpdate = i; -+ //this.lastInhabitedUpdate = i; // Folia - region threading ++ //long gameTime = this.level.getGameTime(); // Folia - region threading ++ long l = 1L; // Folia - region threading ++ //this.lastInhabitedUpdate = gameTime; // Folia - region threading if (!this.level.isDebug()) { - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push("pollingChunks"); + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("pollingChunks"); if (this.level.tickRateManager().runsNormally()) { - List list = this.tickingChunks; + List list = regionizedWorldData.temporaryChunkTickList; // Folia - region threading try { - gameprofilerfiller.push("filteringTickingChunks"); -@@ -514,8 +517,9 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + profilerFiller.push("filteringTickingChunks"); +@@ -532,23 +535,24 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } private void broadcastChangedChunks(ProfilerFiller profiler) { + io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData(); // Folia - region threading profiler.push("broadcast"); -- Iterator iterator = this.chunkHoldersToBroadcast.iterator(); -+ Iterator iterator = regionizedWorldData.chunkHoldersToBroadcast.iterator(); // Folia - region threading - note: do not need to thread check, as getChunkToSend is only non-null when the chunkholder is loaded - while (iterator.hasNext()) { - ChunkHolder playerchunk = (ChunkHolder) iterator.next(); -@@ -526,14 +530,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +- for (ChunkHolder chunkHolder : this.chunkHoldersToBroadcast) { ++ for (ChunkHolder chunkHolder : regionizedWorldData.chunkHoldersToBroadcast) { // Folia - region threading - note: do not need to thread check, as getChunkToSend is only non-null when the chunkholder is loaded + LevelChunk tickingChunk = chunkHolder.getChunkToSend(); // Paper - rewrite chunk system + if (tickingChunk != null) { + chunkHolder.broadcastChanges(tickingChunk); } } @@ -11042,7 +10734,7 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 profiler.pop(); } - private void collectTickingChunks(List chunks) { + private void collectTickingChunks(List output) { // Paper start - chunk tick iteration optimisation final ca.spottedleaf.moonrise.common.list.ReferenceList tickingChunks = - ((ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks(); @@ -11050,16 +10742,15 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked(); final int size = tickingChunks.size(); -@@ -554,6 +558,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -569,13 +573,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } - private void tickChunks(ProfilerFiller profiler, long timeDelta, List chunks) { + private void tickChunks(ProfilerFiller profiler, long timeInhabited, List chunks) { + io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData(); // Folia - region threading profiler.popPush("naturalSpawnCount"); - int j = this.distanceManager.getNaturalSpawnChunkCount(); + int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount(); // Paper start - Optional per player mob spawns -@@ -561,7 +566,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - NaturalSpawner.SpawnState spawnercreature_d; // moved down + NaturalSpawner.SpawnState spawnState; if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled // re-set mob counts - for (ServerPlayer player : this.level.players) { @@ -11067,27 +10758,25 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 // Paper start - per player mob spawning backoff for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { player.mobCounts[ii] = 0; -@@ -574,28 +579,28 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -588,26 +593,26 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } // Paper end - per player mob spawning backoff } -- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); -+ spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, null, true); // Folia - region threading - note: function only cares about loaded entities, doesn't need all +- spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); ++ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, null, true); // Folia - region threading - note: function only cares about loaded entities, doesn't need all } else { -- spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); -+ spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all +- spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); ++ spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all } // Paper end - Optional per player mob spawns - -- this.lastSpawnState = spawnercreature_d; -+ regionizedWorldData.lastSpawnState = spawnercreature_d; // Folia - region threading +- this.lastSpawnState = spawnState; ++ regionizedWorldData.lastSpawnState = spawnState; // Folia - region threading profiler.popPush("spawnAndTick"); -- boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit -+ boolean flag = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.getLocalPlayers().isEmpty(); // CraftBukkit // Folia - region threading - int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); - List list1; - - if (flag && (this.spawnEnemies || this.spawnFriendlies)) { +- boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit ++ boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.getLocalPlayers().isEmpty(); // CraftBukkit // Folia - region threading + int _int = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); + List filteredSpawningCategories; + if (_boolean && (this.spawnEnemies || this.spawnFriendlies)) { // Paper start - PlayerNaturallySpawnCreaturesEvent - for (ServerPlayer entityPlayer : this.level.players()) { + for (ServerPlayer entityPlayer : this.level.getLocalPlayers()) { // Folia - region threading @@ -11097,43 +10786,40 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 entityPlayer.playerNaturallySpawnedEvent.callEvent(); } // Paper end - PlayerNaturallySpawnCreaturesEvent -- boolean flag1 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit -+ boolean flag1 = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getRedstoneGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit // Folia - region threading - - list1 = NaturalSpawner.getFilteredSpawningCategories(spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1, this.level); // CraftBukkit +- boolean flag = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit ++ boolean flag = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getRedstoneGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit // Folia - region threading + filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit } else { -@@ -669,21 +674,26 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(ChunkPos.asLong(i, j)); - - if (playerchunk != null && playerchunk.blockChanged(pos)) { -- this.chunkHoldersToBroadcast.add(playerchunk); -+ this.level.getCurrentWorldData().chunkHoldersToBroadcast.add(playerchunk); // Folia - region threading + filteredSpawningCategories = List.of(); +@@ -673,18 +678,23 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + int sectionPosZ = SectionPos.blockToSectionCoord(pos.getZ()); + ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(ChunkPos.asLong(sectionPosX, sectionPosZ)); + if (visibleChunkIfPresent != null && visibleChunkIfPresent.blockChanged(pos)) { +- this.chunkHoldersToBroadcast.add(visibleChunkIfPresent); ++ this.level.getCurrentWorldData().chunkHoldersToBroadcast.add(visibleChunkIfPresent); // Folia - region threading } - } @Override public void onLightUpdate(LightLayer type, SectionPos pos) { - this.mainThreadProcessor.execute(() -> { + Runnable run = () -> { // Folia - region threading - ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos.chunk().toLong()); - - if (playerchunk != null && playerchunk.sectionLightChanged(type, pos.y())) { -- this.chunkHoldersToBroadcast.add(playerchunk); -+ this.level.getCurrentWorldData().chunkHoldersToBroadcast.add(playerchunk); // Folia - region threading + ChunkHolder visibleChunkIfPresent = this.getVisibleChunkIfPresent(pos.chunk().toLong()); + if (visibleChunkIfPresent != null && visibleChunkIfPresent.sectionLightChanged(type, pos.y())) { +- this.chunkHoldersToBroadcast.add(visibleChunkIfPresent); ++ this.level.getCurrentWorldData().chunkHoldersToBroadcast.add(visibleChunkIfPresent); // Folia - region threading } - - }); + }; // Folia - region threading + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueChunkTask( -+ this.level, pos.getX(), pos.getZ(), run ++ this.level, pos.getX(), pos.getZ(), run + ); + // Folia end - region threading } - public void addRegionTicket(TicketType ticketType, ChunkPos pos, int radius, T argument) { -@@ -767,7 +777,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + public void addRegionTicket(TicketType type, ChunkPos pos, int distance, T value) { +@@ -766,7 +776,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @Nullable @VisibleForDebug public NaturalSpawner.SpawnState getLastSpawnState() { @@ -11143,16 +10829,16 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 } public void removeTicketsOnClosing() { -@@ -776,7 +787,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -775,7 +786,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon public void onChunkReadyToSend(ChunkHolder chunkHolder) { if (chunkHolder.hasChangesToBroadcast()) { - this.chunkHoldersToBroadcast.add(chunkHolder); + throw new UnsupportedOperationException(); // Folia - region threading } - } -@@ -814,8 +825,59 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + +@@ -812,20 +823,76 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon return ServerChunkCache.this.mainThread; } @@ -11212,9 +10898,8 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 Profiler.get().incrementCounter("runTask"); super.doRunTask(task); } -@@ -823,12 +885,17 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + @Override - // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task public boolean pollTask() { + // Folia start - region threading + if (ServerChunkCache.this.level != io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().world) { @@ -11230,46 +10915,46 @@ index 1c87904bb99cc40bafc9357fb2fc1703b759c3df..1a43c6fba5eea514dd6cf406f600dc25 + return io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegion().getData().getTaskQueueData().executeChunkTask(); // Folia - region threading } // Paper end - rewrite chunk system - // CraftBukkit end -diff --git a/src/main/java/net/minecraft/server/level/ServerEntityGetter.java b/src/main/java/net/minecraft/server/level/ServerEntityGetter.java -index 296059746fe9f5c35fedd8ca1dea488da519ac05..7df954d6375abb83cb0b140a16336b478d13e9d8 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntityGetter.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntityGetter.java + } +diff --git a/net/minecraft/server/level/ServerEntityGetter.java b/net/minecraft/server/level/ServerEntityGetter.java +index 794770985c261fd56806188237921b5ec5e548e6..b715d1fbde9db81a2515249bb9a0fc7a5fee40f0 100644 +--- a/net/minecraft/server/level/ServerEntityGetter.java ++++ b/net/minecraft/server/level/ServerEntityGetter.java @@ -14,17 +14,17 @@ public interface ServerEntityGetter extends EntityGetter { @Nullable - default Player getNearestPlayer(TargetingConditions targetPredicate, LivingEntity entity) { -- return this.getNearestEntity(this.players(), targetPredicate, entity, entity.getX(), entity.getY(), entity.getZ()); -+ return this.getNearestEntity(this.getLocalPlayers(), targetPredicate, entity, entity.getX(), entity.getY(), entity.getZ()); // Folia - region threading + default Player getNearestPlayer(TargetingConditions targetingConditions, LivingEntity source) { +- return this.getNearestEntity(this.players(), targetingConditions, source, source.getX(), source.getY(), source.getZ()); ++ return this.getNearestEntity(this.getLocalPlayers(), targetingConditions, source, source.getX(), source.getY(), source.getZ()); // Folia - region threading } @Nullable - default Player getNearestPlayer(TargetingConditions targetPredicate, LivingEntity entity, double x, double y, double z) { -- return this.getNearestEntity(this.players(), targetPredicate, entity, x, y, z); -+ return this.getNearestEntity(this.getLocalPlayers(), targetPredicate, entity, x, y, z); // Folia - region threading + default Player getNearestPlayer(TargetingConditions targetingConditions, LivingEntity source, double x, double y, double z) { +- return this.getNearestEntity(this.players(), targetingConditions, source, x, y, z); ++ return this.getNearestEntity(this.getLocalPlayers(), targetingConditions, source, x, y, z); // Folia - region threading } @Nullable - default Player getNearestPlayer(TargetingConditions targetPredicate, double x, double y, double z) { -- return this.getNearestEntity(this.players(), targetPredicate, null, x, y, z); -+ return this.getNearestEntity(this.getLocalPlayers(), targetPredicate, null, x, y, z); // Folia - region threading + default Player getNearestPlayer(TargetingConditions targetingConditions, double x, double y, double z) { +- return this.getNearestEntity(this.players(), targetingConditions, null, x, y, z); ++ return this.getNearestEntity(this.getLocalPlayers(), targetingConditions, null, x, y, z); // Folia - region threading } @Nullable @@ -57,7 +57,7 @@ public interface ServerEntityGetter extends EntityGetter { - default List getNearbyPlayers(TargetingConditions targetPredicate, LivingEntity entity, AABB box) { + default List getNearbyPlayers(TargetingConditions targetingConditions, LivingEntity source, AABB area) { List list = new ArrayList<>(); - for (Player player : this.players()) { + for (Player player : this.getLocalPlayers()) { // Folia - region threading - if (box.contains(player.getX(), player.getY(), player.getZ()) && targetPredicate.test(this.getLevel(), entity, player)) { + if (area.contains(player.getX(), player.getY(), player.getZ()) && targetingConditions.test(this.getLevel(), source, player)) { list.add(player); } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2a0a99dff 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -196,42 +196,40 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index ebeeb63c3dca505a3ce8b88feaa5d2ca20ec24a2..c09099070117483054f438b2bb77ff48a81610f0 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -179,42 +179,40 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe private static final Logger LOGGER = LogUtils.getLogger(); private static final int EMPTY_TIME_NO_TICK = 300; private static final int MAX_SCHEDULED_TICKS_PER_TICK = 65536; @@ -11277,7 +10962,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 + final List players = new java.util.concurrent.CopyOnWriteArrayList<>(); // Folia - region threading public final ServerChunkCache chunkSource; private final MinecraftServer server; - public final PrimaryLevelData serverLevelData; // CraftBukkit - type + public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type private int lastSpawnChunkRadius; - final EntityTickList entityTickList = new EntityTickList(); + //final EntityTickList entityTickList = new EntityTickList(); // Folia - region threading @@ -11290,23 +10975,23 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 - private final LevelTicks blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded); - private final LevelTicks fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded); - private final PathTypeCache pathTypesByPosCache = new PathTypeCache(); -- final Set navigatingMobs = new ObjectOpenHashSet(); +- final Set navigatingMobs = new ObjectOpenHashSet<>(); + //private final LevelTicks blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded); // Folia - region threading + //private final LevelTicks fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded); // Folia - region threading + //private final PathTypeCache pathTypesByPosCache = new PathTypeCache(); // Folia - region threading -+ //final Set navigatingMobs = new ObjectOpenHashSet(); // Folia - region threading ++ //final Set navigatingMobs = new ObjectOpenHashSet<>(); // Folia - region threading volatile boolean isUpdatingNavigations; protected final Raids raids; -- private final ObjectLinkedOpenHashSet blockEvents = new ObjectLinkedOpenHashSet(); -- private final List blockEventsToReschedule = new ArrayList(64); +- private final ObjectLinkedOpenHashSet blockEvents = new ObjectLinkedOpenHashSet<>(); +- private final List blockEventsToReschedule = new ArrayList<>(64); - private boolean handlingTick; -+ //private final ObjectLinkedOpenHashSet blockEvents = new ObjectLinkedOpenHashSet(); // Folia - region threading -+ //private final List blockEventsToReschedule = new ArrayList(64); // Folia - region threading ++ //private final ObjectLinkedOpenHashSet blockEvents = new ObjectLinkedOpenHashSet<>(); // Folia - region threading ++ //private final List blockEventsToReschedule = new ArrayList<>(64); // Folia - region threading + //private boolean handlingTick; // Folia - region threading private final List customSpawners; @Nullable private EndDragonFight dragonFight; - final Int2ObjectMap dragonParts = new Int2ObjectOpenHashMap(); + final Int2ObjectMap dragonParts = new Int2ObjectOpenHashMap<>(); private final StructureManager structureManager; private final StructureCheck structureCheck; - private final boolean tickTime; @@ -11314,7 +10999,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 private final RandomSequences randomSequences; // CraftBukkit start - public final LevelStorageSource.LevelStorageAccess convertable; + public final LevelStorageSource.LevelStorageAccess levelStorageAccess; public final UUID uuid; - public boolean hasPhysicsEvent = true; // Paper - BlockPhysicsEvent - public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent @@ -11323,7 +11008,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 public LevelChunk getChunkIfLoaded(int x, int z) { return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately -@@ -259,6 +257,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -242,6 +240,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe int minChunkZ = minBlockZ >> 4; int maxChunkZ = maxBlockZ >> 4; @@ -11337,7 +11022,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 ServerChunkCache chunkProvider = this.getChunkSource(); for (int cx = minChunkX; cx <= maxChunkX; ++cx) { -@@ -314,11 +319,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -297,11 +302,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe private final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler chunkTaskScheduler; private long lastMidTickFailure; private long tickedBlocksOrFluids; @@ -11350,7 +11035,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 @Override public final LevelChunk moonrise$getFullChunkIfLoaded(final int chunkX, final int chunkZ) { -@@ -376,7 +377,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -359,7 +360,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public final int moonrise$getRegionChunkShift() { @@ -11359,7 +11044,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } @Override -@@ -475,22 +476,22 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -460,22 +461,22 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public final ca.spottedleaf.moonrise.common.misc.NearbyPlayers moonrise$getNearbyPlayers() { @@ -11386,7 +11071,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } @Override -@@ -510,91 +511,96 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -495,80 +496,85 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper end - rewrite chunk system // Paper start - chunk tick iteration private static final ServerChunkCache.ChunkAndHolder[] EMPTY_PLAYER_CHUNK_HOLDERS = new ServerChunkCache.ChunkAndHolder[0]; @@ -11444,57 +11129,21 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 @Override public final void moonrise$removePlayerTickingRequest(final int chunkX, final int chunkZ) { - ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)(Object)this, chunkX, chunkZ, "Cannot remove ticking request async"); -- -- final long chunkKey = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ); -- final int val = this.playerTickingRequests.addTo(chunkKey, -1); -- -- if (val <= 0) { -- throw new IllegalStateException("Negative counter"); -- } -- -- if (val != 1) { -- // still has at least one request -- return; -- } -- -- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)(ServerLevel)(Object)this).moonrise$getChunkTaskScheduler() -- .chunkHolderManager.getChunkHolder(chunkKey); -- -- if (chunkHolder == null || !chunkHolder.isTickingReady()) { -- return; -- } -- -- this.playerTickingChunks.remove( -- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder() -- ); + // Folia - region threading - } - // Paper end - chunk tick iteration - // Paper start - lag compensation - private long lagCompensationTick = net.minecraft.server.MinecraftServer.SERVER_INIT; - - public long getLagCompensationTick() { -- return this.lagCompensationTick; -+ return this.getCurrentWorldData().getLagCompensationTick(); // Folia - region threading - } - - public void updateLagCompensationTick() { -- this.lagCompensationTick = (System.nanoTime() - net.minecraft.server.MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L)); -+ throw new UnsupportedOperationException(); // Folia - region threading - } - // Paper end - lag compensation ++ } ++ // Paper end - chunk tick iteration + // Folia start - region threading + public final io.papermc.paper.threadedregions.TickRegions tickRegions = new io.papermc.paper.threadedregions.TickRegions(); + public final io.papermc.paper.threadedregions.ThreadedRegionizer regioniser; + { + this.regioniser = new io.papermc.paper.threadedregions.ThreadedRegionizer<>( -+ (int)Math.max(1L, (8L * 16L * 16L) / (1L << (2 * (io.papermc.paper.threadedregions.TickRegions.getRegionChunkShift())))), -+ (1.0 / 6.0), -+ Math.max(1, 8 / (1 << io.papermc.paper.threadedregions.TickRegions.getRegionChunkShift())), -+ 1, -+ io.papermc.paper.threadedregions.TickRegions.getRegionChunkShift(), -+ this, -+ this.tickRegions ++ (int)Math.max(1L, (8L * 16L * 16L) / (1L << (2 * (io.papermc.paper.threadedregions.TickRegions.getRegionChunkShift())))), ++ (1.0 / 6.0), ++ Math.max(1, 8 / (1 << io.papermc.paper.threadedregions.TickRegions.getRegionChunkShift())), ++ 1, ++ io.papermc.paper.threadedregions.TickRegions.getRegionChunkShift(), ++ this, ++ this.tickRegions + ); + } + public final io.papermc.paper.threadedregions.RegionizedTaskQueue.WorldRegionTaskData taskQueueRegionData = new io.papermc.paper.threadedregions.RegionizedTaskQueue.WorldRegionTaskData(this); @@ -11503,51 +11152,66 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 + public static final int WORLD_INIT_CHECKED = 2; + public final java.util.concurrent.atomic.AtomicInteger checkInitialised = new java.util.concurrent.atomic.AtomicInteger(WORLD_INIT_NOT_CHECKED); + public ChunkPos randomSpawnSelection; -+ + +- final long chunkKey = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkX, chunkZ); +- final int val = this.playerTickingRequests.addTo(chunkKey, -1); + public static final record PendingTeleport(Entity.EntityTreeNode rootVehicle, Vec3 to) {} + private final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet pendingTeleports = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); -+ + +- if (val <= 0) { +- throw new IllegalStateException("Negative counter"); + public void pushPendingTeleport(final PendingTeleport teleport) { + synchronized (this.pendingTeleports) { + this.pendingTeleports.add(teleport); -+ } + } + } -+ + +- if (val != 1) { +- // still has at least one request +- return; + public boolean removePendingTeleport(final PendingTeleport teleport) { + synchronized (this.pendingTeleports) { + return this.pendingTeleports.remove(teleport); -+ } + } + } -+ + +- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)(ServerLevel)(Object)this).moonrise$getChunkTaskScheduler() +- .chunkHolderManager.getChunkHolder(chunkKey); + public List removeAllRegionTeleports() { + final List ret = new ArrayList<>(); -+ + +- if (chunkHolder == null || !chunkHolder.isTickingReady()) { +- return; + synchronized (this.pendingTeleports) { -+ for (final Iterator iterator = this.pendingTeleports.iterator(); iterator.hasNext(); ) { ++ for (final java.util.Iterator iterator = this.pendingTeleports.iterator(); iterator.hasNext(); ) { + final PendingTeleport pendingTeleport = iterator.next(); + if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this, pendingTeleport.to())) { + ret.add(pendingTeleport); + iterator.remove(); + } + } -+ } -+ + } + +- this.playerTickingChunks.remove( +- ((ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder() +- ); + return ret; -+ } + } +- // Paper end - chunk tick iteration + // Folia end - region threading - // Add env and gen to constructor, IWorldDataServer -> WorldDataServer - public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { -@@ -639,7 +645,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - }); + public ServerLevel( + MinecraftServer server, +@@ -633,7 +639,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ); this.chunkSource.getGeneratorState().ensureStructuresGenerated(); this.portalForcer = new PortalForcer(this); - this.updateSkyBrightness(); + //this.updateSkyBrightness(); // Folia - region threading - delay until first tick this.prepareWeather(); - this.getWorldBorder().setAbsoluteMaxSize(minecraftserver.getAbsoluteMaxWorldSize()); - this.raids = (Raids) this.getDataStorage().computeIfAbsent(Raids.factory(this), Raids.getFileId(this.dimensionTypeRegistration())); -@@ -677,7 +683,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.getWorldBorder().setAbsoluteMaxSize(server.getAbsoluteMaxWorldSize()); + this.raids = this.getDataStorage().computeIfAbsent(Raids.factory(this), Raids.getFileId(this.dimensionTypeRegistration())); +@@ -681,7 +687,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler); // Paper end - rewrite chunk system this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit @@ -11562,8 +11226,8 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 // Paper start @Override -@@ -706,60 +719,44 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - return this.getChunkSource().getGenerator().getBiomeSource().getNoiseBiome(biomeX, biomeY, biomeZ, this.getChunkSource().randomState().sampler()); +@@ -709,61 +722,39 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + return this.getChunkSource().getGenerator().getBiomeSource().getNoiseBiome(x, y, z, this.getChunkSource().randomState().sampler()); } + @Override // Folia - region threading @@ -11571,90 +11235,90 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 return this.structureManager; } -- public void tick(BooleanSupplier shouldKeepTicking) { -+ public void tick(BooleanSupplier shouldKeepTicking, io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking +- public void tick(BooleanSupplier hasTimeLeft) { ++ public void tick(BooleanSupplier hasTimeLeft, io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking + final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking - ProfilerFiller gameprofilerfiller = Profiler.get(); - + ProfilerFiller profilerFiller = Profiler.get(); - this.handlingTick = true; + regionizedWorldData.setHandlingTick(true); // Folia - regionised ticking - TickRateManager tickratemanager = this.tickRateManager(); - boolean flag = tickratemanager.runsNormally(); - - if (flag) { - gameprofilerfiller.push("world border"); + TickRateManager tickRateManager = this.tickRateManager(); + boolean runsNormally = tickRateManager.runsNormally(); + if (runsNormally) { + profilerFiller.push("world border"); - this.getWorldBorder().tick(); -+ if (region == null) this.getWorldBorder().tick(); // Folia - regionised ticking - gameprofilerfiller.popPush("weather"); ++ //this.getWorldBorder().tick(); // Folia - regionised ticking + profilerFiller.popPush("weather"); - this.advanceWeatherCycle(); -+ if (region == null) this.advanceWeatherCycle(); // Folia - regionised ticking - gameprofilerfiller.pop(); ++ //this.advanceWeatherCycle(); // Folia - regionised ticking + profilerFiller.pop(); } -- int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); -+ //int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); // Folia - region threading - move into tickSleep - long j; - -- if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { -- // CraftBukkit start -- j = this.levelData.getDayTime() + 24000L; -- TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime()); +- int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); +- if (this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { +- // Paper start - create time skip event - move up calculations +- final long newDayTime = this.levelData.getDayTime() + 24000L; +- org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent( +- this.getWorld(), +- org.bukkit.event.world.TimeSkipEvent.SkipReason.NIGHT_SKIP, +- (newDayTime - newDayTime % 24000L) - this.getDayTime() +- ); +- // Paper end - create time skip event - move up calculations - if (this.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { -- this.getCraftServer().getPluginManager().callEvent(event); -- if (!event.isCancelled()) { +- // Paper start - call time skip event if gamerule is enabled +- // long l = this.levelData.getDayTime() + 24000L; // Paper - diff on change to above - newDayTime +- // this.setDayTime(l - l % 24000L); // Paper - diff on change to above - event param +- if (event.callEvent()) { - this.setDayTime(this.getDayTime() + event.getSkipAmount()); - } +- // Paper end - call time skip event if gamerule is enabled - } - -- if (!event.isCancelled()) { -- this.wakeUpAllPlayers(); -- } -- // CraftBukkit end +- if (!event.isCancelled()) this.wakeUpAllPlayers(); // Paper - only wake up players if time skip event is not cancelled - if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) { - this.resetWeatherCycle(); - } - } -+ if (region == null) this.tickSleep(); // Folia - region threading ++ this.tickSleep(); // Folia - region threading - move into tickSleep - this.updateSkyBrightness(); -+ if (region == null) this.updateSkyBrightness(); // Folia - region threading - if (flag) { ++ //this.updateSkyBrightness(); // Folia - region threading + if (runsNormally) { this.tickTime(); } - gameprofilerfiller.push("tickPending"); - if (!this.isDebug() && flag) { -- j = this.getGameTime(); -+ j = regionizedWorldData.getRedstoneGameTime(); // Folia - region threading - gameprofilerfiller.push("blockTicks"); -- this.blockTicks.tick(j, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks -+ regionizedWorldData.getBlockLevelTicks().tick(j, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks // Folia - region ticking - gameprofilerfiller.popPush("fluidTicks"); -- this.fluidTicks.tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks -+ regionizedWorldData.getFluidLevelTicks().tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks // Folia - region ticking - gameprofilerfiller.pop(); + profilerFiller.push("tickPending"); + if (!this.isDebug() && runsNormally) { +- long l = this.getGameTime(); ++ long l = regionizedWorldData.getRedstoneGameTime(); // Folia - region threading + profilerFiller.push("blockTicks"); +- this.blockTicks.tick(l, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks ++ regionizedWorldData.getBlockLevelTicks().tick(l, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks // Folia - region ticking + profilerFiller.popPush("fluidTicks"); +- this.fluidTicks.tick(l, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks ++ regionizedWorldData.getFluidLevelTicks().tick(l, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks // Folia - region ticking + profilerFiller.pop(); } -@@ -775,9 +772,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -779,9 +770,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe this.runBlockEvents(); } - this.handlingTick = false; + regionizedWorldData.setHandlingTick(false); // Folia - regionised ticking - gameprofilerfiller.pop(); -- boolean flag1 = !paperConfig().unsupportedSettings.disableWorldTickingWhenEmpty || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this -+ boolean flag1 = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this // Folia - unrestore this, we always need to tick empty worlds - - if (flag1) { + profilerFiller.pop(); +- boolean flag = !paperConfig().unsupportedSettings.disableWorldTickingWhenEmpty || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this ++ boolean flag = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players // Paper - restore this // Folia - unrestore this, we always need to tick empty worlds + if (flag) { this.resetEmptyTime(); -@@ -786,17 +783,27 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (flag1 || this.emptyTime++ < 300) { - gameprofilerfiller.push("entities"); - if (this.dragonFight != null && flag) { + } +@@ -789,19 +780,29 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (flag || this.emptyTime++ < 300) { + profilerFiller.push("entities"); + if (this.dragonFight != null && runsNormally) { + if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this, this.dragonFight.origin)) { // Folia - region threading - gameprofilerfiller.push("dragonFight"); + profilerFiller.push("dragonFight"); this.dragonFight.tick(); - gameprofilerfiller.pop(); + profilerFiller.pop(); + } else { // Folia start - region threading + // try to load dragon fight + ChunkPos fightCenter = new ChunkPos(this.dragonFight.origin); @@ -11665,39 +11329,47 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 + } // Folia end - region threading } - org.spigotmc.ActivationRange.activateEntities(this); // Spigot -- this.entityTickList.forEach((entity) -> { -+ regionizedWorldData.forEachTickingEntity((entity) -> { // Folia - regionised ticking - if (!entity.isRemoved()) { - if (!tickratemanager.isEntityFrozen(entity)) { - gameprofilerfiller.push("checkDespawn"); - entity.checkDespawn(); -+ if (entity.isRemoved()) return; // Folia - region threading - if we despawned, DON'T TICK IT! - gameprofilerfiller.pop(); - if (true) { // Paper - rewrite chunk system - Entity entity1 = entity.getVehicle(); -@@ -825,6 +832,31 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - gameprofilerfiller.pop(); + io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR +- this.entityTickList +- .forEach( ++ regionizedWorldData // Folia - regionised ticking ++ .forEachTickingEntity( // Folia - regionised ticking + entity -> { + if (!entity.isRemoved()) { + if (!tickRateManager.isEntityFrozen(entity)) { + profilerFiller.push("checkDespawn"); + entity.checkDespawn(); ++ if (entity.isRemoved()) return; // Folia - region threading - if we despawned, DON'T TICK IT! + profilerFiller.pop(); + if (true) { // Paper - rewrite chunk system + Entity vehicle = entity.getVehicle(); +@@ -830,6 +831,36 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + profilerFiller.pop(); } + // Folia start - region threading + public void tickSleep() { -+ int i = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); long j; // Folia moved from tick loop -+ if (this.sleepStatus.areEnoughSleeping(i) && this.sleepStatus.areEnoughDeepSleeping(i, this.players)) { -+ // CraftBukkit start -+ j = this.levelData.getDayTime() + 24000L; -+ TimeSkipEvent event = new TimeSkipEvent(this.getWorld(), TimeSkipEvent.SkipReason.NIGHT_SKIP, (j - j % 24000L) - this.getDayTime()); ++ int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE); ++ if (this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { ++ // Paper start - create time skip event - move up calculations ++ final long newDayTime = this.levelData.getDayTime() + 24000L; ++ org.bukkit.event.world.TimeSkipEvent event = new org.bukkit.event.world.TimeSkipEvent( ++ this.getWorld(), ++ org.bukkit.event.world.TimeSkipEvent.SkipReason.NIGHT_SKIP, ++ (newDayTime - newDayTime % 24000L) - this.getDayTime() ++ ); ++ // Paper end - create time skip event - move up calculations + if (this.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { -+ this.getCraftServer().getPluginManager().callEvent(event); -+ if (!event.isCancelled()) { ++ // Paper start - call time skip event if gamerule is enabled ++ // long l = this.levelData.getDayTime() + 24000L; // Paper - diff on change to above - newDayTime ++ // this.setDayTime(l - l % 24000L); // Paper - diff on change to above - event param ++ if (event.callEvent()) { + this.setDayTime(this.getDayTime() + event.getSkipAmount()); + } ++ // Paper end - call time skip event if gamerule is enabled + } + -+ if (!event.isCancelled()) { -+ this.wakeUpAllPlayers(); -+ } -+ // CraftBukkit end ++ if (!event.isCancelled()) this.wakeUpAllPlayers(); // Paper - only wake up players if time skip event is not cancelled + if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE) && this.isRaining()) { + this.resetWeatherCycle(); + } @@ -11708,39 +11380,41 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 @Override public boolean shouldTickBlocksAt(long chunkPos) { // Paper start - rewrite chunk system -@@ -835,13 +867,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -840,12 +871,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe protected void tickTime() { if (this.tickTime) { -- long i = this.levelData.getGameTime() + 1L; +- long l = this.levelData.getGameTime() + 1L; +- this.serverLevelData.setGameTime(l); + io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - region threading -+ long i = regionizedWorldData.getRedstoneGameTime() + 1L; // Folia - region threading - -- this.serverLevelData.setGameTime(i); -+ regionizedWorldData.setRedstoneGameTime(i); // Folia - region threading ++ long l = regionizedWorldData.getRedstoneGameTime() + 1L; // Folia - region threading ++ regionizedWorldData.setRedstoneGameTime(l); // Folia - region threading Profiler.get().push("scheduledFunctions"); -- this.serverLevelData.getScheduledEvents().tick(this.server, i); -+ if (false) this.serverLevelData.getScheduledEvents().tick(this.server, i); // Folia - region threading - TODO any way to bring this in? +- this.serverLevelData.getScheduledEvents().tick(this.server, l); ++ //this.serverLevelData.getScheduledEvents().tick(this.server, l); // Folia - region threading - TODO any way to bring this in? Profiler.get().pop(); - if (this.serverLevelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { + if (false && this.serverLevelData.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)) { // Folia - region threading this.setDayTime(this.levelData.getDayTime() + 1L); } + } +@@ -863,16 +895,27 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe -@@ -866,17 +899,24 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe private void wakeUpAllPlayers() { this.sleepStatus.removeAllSleepers(); - (this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList())).forEach((entityplayer) -> { // CraftBukkit - decompile error -- entityplayer.stopSleepInBed(false, false); -+ // Folia start - region threading -+ entityplayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { -+ if (player.level() != ServerLevel.this || !player.isSleeping()) { -+ return; +- this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList()).forEach(player -> player.stopSleepInBed(false, false)); ++ // Folia start - region threading ++ this.players.stream().filter(LivingEntity::isSleeping).collect(Collectors.toList()).forEach((ServerPlayer entityplayer) -> { ++ // Folia start - region threading ++ entityplayer.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> { ++ if (player.level() != ServerLevel.this || !player.isSleeping()) { ++ return; ++ } ++ player.stopSleepInBed(false, false); ++ }, null, 1L); + } -+ player.stopSleepInBed(false, false); -+ }, null, 1L); -+ // Folia end - region threading - }); ++ ); ++ // Folia end - region threading } // Paper start - optimise random ticking @@ -11755,16 +11429,16 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294(); final ChunkPos cpos = chunk.getPos(); -@@ -923,7 +963,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -919,7 +962,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper end - optimise random ticking public void tickChunk(LevelChunk chunk, int randomTickSpeed) { - final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom simpleRandom = this.simpleRandom; // Paper - optimise random ticking + final io.papermc.paper.threadedregions.util.SimpleThreadLocalRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Folia - region threading - ChunkPos chunkcoordintpair = chunk.getPos(); - boolean flag = this.isRaining(); - int j = chunkcoordintpair.getMinBlockX(); -@@ -1061,7 +1101,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ChunkPos pos = chunk.getPos(); + boolean isRaining = this.isRaining(); + int minBlockX = pos.getMinBlockX(); +@@ -1044,7 +1087,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } public boolean isHandlingTick() { @@ -11773,7 +11447,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } public boolean canSleepThroughNights() { -@@ -1093,6 +1133,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1070,6 +1113,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } public void updateSleepingPlayerList() { @@ -11788,50 +11462,42 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 if (!this.players.isEmpty() && this.sleepStatus.update(this.players)) { this.announceSleepStatus(); } -@@ -1104,7 +1152,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1080,7 +1131,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe return this.server.getScoreboard(); } - private void advanceWeatherCycle() { + public void advanceWeatherCycle() { // Folia - region threading - public - boolean flag = this.isRaining(); - + boolean isRaining = this.isRaining(); if (this.dimensionType().hasSkyLight()) { -@@ -1190,23 +1238,24 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.server.getPlayerList().broadcastAll(new PacketPlayOutGameStateChange(PacketPlayOutGameStateChange.THUNDER_LEVEL_CHANGE, this.thunderLevel)); + if (this.getGameRules().getBoolean(GameRules.RULE_WEATHER_CYCLE)) { +@@ -1166,7 +1217,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.server.getPlayerList().broadcastAll(new ClientboundGameEventPacket(ClientboundGameEventPacket.THUNDER_LEVEL_CHANGE, this.thunderLevel)); } - // */ -- for (int idx = 0; idx < this.players.size(); ++idx) { -- if (((ServerPlayer) this.players.get(idx)).level() == this) { -- ((ServerPlayer) this.players.get(idx)).tickWeather(); + */ +- for (ServerPlayer player : this.players) { + ServerPlayer[] players = this.players.toArray(new ServerPlayer[0]); // Folia - region threading + for (ServerPlayer player : players) { // Folia - region threading -+ if (player.level() == this) { // Folia - region threading -+ player.tickWeather(); // Folia - region threading + if (player.level() == this) { + player.tickWeather(); } - } +@@ -1174,13 +1226,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (flag != this.isRaining()) { + if (isRaining != this.isRaining()) { // Only send weather packets to those affected -- for (int idx = 0; idx < this.players.size(); ++idx) { -- if (((ServerPlayer) this.players.get(idx)).level() == this) { -- ((ServerPlayer) this.players.get(idx)).setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false); +- for (ServerPlayer player : this.players) { + for (ServerPlayer player : players) { // Folia - region threading -+ if (player.level() == this) { // Folia - region threading -+ player.setPlayerWeather((!flag ? WeatherType.DOWNFALL : WeatherType.CLEAR), false); // Folia - region threading + if (player.level() == this) { + player.setPlayerWeather((!isRaining ? org.bukkit.WeatherType.DOWNFALL : org.bukkit.WeatherType.CLEAR), false); } } } -- for (int idx = 0; idx < this.players.size(); ++idx) { -- if (((ServerPlayer) this.players.get(idx)).level() == this) { -- ((ServerPlayer) this.players.get(idx)).updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel); +- for (ServerPlayer player : this.players) { + for (ServerPlayer player : players) { // Folia - region threading -+ if (player.level() == this) { // Folia - region threading -+ player.updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel); // Folia - region threading + if (player.level() == this) { + player.updateWeather(this.oRainLevel, this.rainLevel, this.oThunderLevel, this.thunderLevel); } - } - // CraftBukkit end -@@ -1268,13 +1317,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1241,13 +1293,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper start - log detailed entity tick information // TODO replace with varhandle @@ -11847,7 +11513,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } // Paper end - log detailed entity tick information -@@ -1282,9 +1328,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1255,9 +1304,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper start - log detailed entity tick information ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot tick an entity off-main"); try { @@ -11856,10 +11522,10 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 - } + // Folia - region threading // Paper end - log detailed entity tick information - // Spigot start - /*if (!org.spigotmc.ActivationRange.checkIfActive(entity)) { // Paper - comment out EAR 2 -@@ -1304,7 +1348,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); // Paper - EAR 2 + entity.setOldPosAndRot(); + ProfilerFiller profilerFiller = Profiler.get(); +@@ -1267,7 +1314,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2 if (isActive) { // Paper - EAR 2 entity.tick(); - entity.postTick(); // CraftBukkit @@ -11873,11 +11539,11 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 + return; + } + // Folia end - region threading - } else { entity.inactiveTick(); } // Paper - EAR 2 - gameprofilerfiller.pop(); - Iterator iterator = entity.getPassengers().iterator(); -@@ -1317,16 +1370,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } else {entity.inactiveTick();} // Paper - EAR 2 + profilerFiller.pop(); +@@ -1276,9 +1332,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } // Paper start - log detailed entity tick information } finally { - if (currentlyTickingEntity.get() == entity) { @@ -11887,33 +11553,34 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } // Paper end - log detailed entity tick information } - - private void tickPassenger(Entity vehicle, Entity passenger, boolean isActive) { // Paper - EAR 2 - if (!passenger.isRemoved() && passenger.getVehicle() == vehicle) { -- if (passenger instanceof Player || this.entityTickList.contains(passenger)) { -+ if (passenger instanceof Player || this.getCurrentWorldData().hasEntityTickingEntity(passenger)) { // Folia - region threading - passenger.setOldPosAndRot(); - ++passenger.tickCount; - ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -1338,7 +1389,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Paper start - EAR 2 - if (isActive) { - passenger.rideTick(); -- passenger.postTick(); // CraftBukkit -+ // Folia start - region threading -+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(passenger)) { -+ // removed from region while ticking -+ return; -+ } -+ if (passenger.handlePortal()) { -+ // portalled -+ return; -+ } -+ // Folia end - region threading - } else { - passenger.setDeltaMovement(Vec3.ZERO); - passenger.inactiveTick(); -@@ -1423,19 +1483,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1286,7 +1340,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2 + if (passengerEntity.isRemoved() || passengerEntity.getVehicle() != ridingEntity) { + passengerEntity.stopRiding(); +- } else if (passengerEntity instanceof Player || this.entityTickList.contains(passengerEntity)) { ++ } else if (passengerEntity instanceof Player || this.getCurrentWorldData().hasEntityTickingEntity(passengerEntity)) { // Folia - region threading + passengerEntity.setOldPosAndRot(); + passengerEntity.tickCount++; + ProfilerFiller profilerFiller = Profiler.get(); +@@ -1295,7 +1349,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // Paper start - EAR 2 + if (isActive) { + passengerEntity.rideTick(); +- passengerEntity.postTick(); // CraftBukkit ++ // Folia start - region threading ++ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(passengerEntity)) { ++ // removed from region while ticking ++ return; ++ } ++ if (passengerEntity.handlePortal()) { ++ // portalled ++ return; ++ } ++ // Folia end - region threading + } else { + passengerEntity.setDeltaMovement(Vec3.ZERO); + passengerEntity.inactiveTick(); +@@ -1369,19 +1432,20 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } // Paper end - add close param @@ -11922,13 +11589,13 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 - - this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings()); - this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess())); -- this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); +- this.levelStorageAccess.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); - // CraftBukkit end + // Folia - move into saveLevelData } -- private void saveLevelData(boolean flush) { -+ public void saveLevelData(boolean flush) { // Folia - public +- private void saveLevelData(boolean join) { ++ public void saveLevelData(boolean join) { // Folia - public if (this.dragonFight != null) { this.serverLevelData.setEndDragonFightData(this.dragonFight.saveData()); // CraftBukkit } @@ -11937,12 +11604,12 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 + + this.serverLevelData.setWorldBorder(worldserver1.getWorldBorder().createSettings()); + this.serverLevelData.setCustomBossEvents(this.server.getCustomBossEvents().save(this.registryAccess())); -+ this.convertable.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); ++ this.levelStorageAccess.saveDataTag(this.server.registryAccess(), this.serverLevelData, this.server.getPlayerList().getSingleplayerData()); + // Folia end - moved into saveLevelData - DimensionDataStorage worldpersistentdata = this.getChunkSource().getDataStorage(); - -@@ -1497,6 +1558,19 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + DimensionDataStorage dataStorage = this.getChunkSource().getDataStorage(); + if (join) { +@@ -1437,6 +1501,19 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe return list; } @@ -11961,8 +11628,8 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 + @Nullable public ServerPlayer getRandomPlayer() { - List list = this.getPlayers(LivingEntity::isAlive); -@@ -1581,8 +1655,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + List players = this.getPlayers(LivingEntity::isAlive); +@@ -1518,8 +1595,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } else { if (entity instanceof net.minecraft.world.entity.item.ItemEntity itemEntity && itemEntity.getItem().isEmpty()) return false; // Paper - Prevent empty items from being added // Paper start - capture all item additions to the world @@ -11973,101 +11640,100 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 return true; } // Paper end - capture all item additions to the world -@@ -1751,21 +1825,22 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1694,13 +1771,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) { - if (this.isUpdatingNavigations) { ++ final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - region threading + if (false && this.isUpdatingNavigations) { // Folia - region threading - String s = "recursive call to sendBlockUpdated"; - + String string = "recursive call to sendBlockUpdated"; Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated")); } this.getChunkSource().blockChanged(pos); - this.pathTypesByPosCache.invalidate(pos); -+ final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - region threading + regionizedWorldData.pathTypesByPosCache.invalidate(pos); // Folia - region threading if (this.paperConfig().misc.updatePathfindingOnBlockUpdate) { // Paper - option to disable pathfinding updates - VoxelShape voxelshape = oldState.getCollisionShape(this, pos); - VoxelShape voxelshape1 = newState.getCollisionShape(this, pos); + VoxelShape collisionShape = oldState.getCollisionShape(this, pos); + VoxelShape collisionShape1 = newState.getCollisionShape(this, pos); +@@ -1708,7 +1786,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + List list = new ObjectArrayList<>(); - if (Shapes.joinIsNotEmpty(voxelshape, voxelshape1, BooleanOp.NOT_SAME)) { - List list = new ObjectArrayList(); -- Iterator iterator = this.navigatingMobs.iterator(); -+ Iterator iterator = regionizedWorldData.getNavigatingMobs(); // Folia - region threading - - while (iterator.hasNext()) { - // CraftBukkit start - fix SPIGOT-6362 -@@ -1788,7 +1863,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } + try { // Paper - catch CME see below why +- for (Mob mob : this.navigatingMobs) { ++ for (java.util.Iterator iterator = regionizedWorldData.getNavigatingMobs(); iterator.hasNext();) { // Folia - region threading ++ Mob mob = iterator.next(); // Folia - region threading + PathNavigation navigation = mob.getNavigation(); + if (navigation.shouldRecomputePath(pos)) { + list.add(navigation); +@@ -1725,13 +1804,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // Paper end - catch CME see below why try { - this.isUpdatingNavigations = true; + //this.isUpdatingNavigations = true; // Folia - region threading - iterator = list.iterator(); - while (iterator.hasNext()) { -@@ -1797,7 +1872,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - navigationabstract1.recomputePath(); + for (PathNavigation pathNavigation : list) { + pathNavigation.recomputePath(); } } finally { - this.isUpdatingNavigations = false; + //this.isUpdatingNavigations = false; // Folia - region threading } - } -@@ -1806,29 +1881,29 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } // Paper - option to disable pathfinding updates +@@ -1739,29 +1818,29 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public void updateNeighborsAt(BlockPos pos, Block block) { - if (captureBlockStates) { return; } // Paper - Cancel all physics during placement + if (this.getCurrentWorldData().captureBlockStates) { return; } // Paper - Cancel all physics during placement // Folia - region threading - this.updateNeighborsAt(pos, block, ExperimentalRedstoneUtils.initialOrientation(this, (Direction) null, (Direction) null)); + this.updateNeighborsAt(pos, block, ExperimentalRedstoneUtils.initialOrientation(this, null, null)); } @Override - public void updateNeighborsAt(BlockPos pos, Block sourceBlock, @Nullable Orientation orientation) { + public void updateNeighborsAt(BlockPos pos, Block block, @Nullable Orientation orientation) { - if (captureBlockStates) { return; } // Paper - Cancel all physics during placement -- this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null, orientation); +- this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, block, null, orientation); + if (this.getCurrentWorldData().captureBlockStates) { return; } // Paper - Cancel all physics during placement // Folia - region threading -+ this.getCurrentWorldData().neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, (Direction) null, orientation); // Folia - region threading ++ this.getCurrentWorldData().neighborUpdater.updateNeighborsAtExceptFromFacing(pos, block, null, orientation); // Folia - region threading } @Override - public void updateNeighborsAtExceptFromFacing(BlockPos pos, Block sourceBlock, Direction direction, @Nullable Orientation orientation) { -- this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, direction, orientation); -+ this.getCurrentWorldData().neighborUpdater.updateNeighborsAtExceptFromFacing(pos, sourceBlock, direction, orientation); // Folia - region threading + public void updateNeighborsAtExceptFromFacing(BlockPos pos, Block block, Direction facing, @Nullable Orientation orientation) { +- this.neighborUpdater.updateNeighborsAtExceptFromFacing(pos, block, facing, orientation); ++ this.getCurrentWorldData().neighborUpdater.updateNeighborsAtExceptFromFacing(pos, block, facing, orientation); // Folia - region threading } @Override - public void neighborChanged(BlockPos pos, Block sourceBlock, @Nullable Orientation orientation) { -- this.neighborUpdater.neighborChanged(pos, sourceBlock, orientation); -+ this.getCurrentWorldData().neighborUpdater.neighborChanged(pos, sourceBlock, orientation); // Folia - region threading + public void neighborChanged(BlockPos pos, Block block, @Nullable Orientation orientation) { +- this.neighborUpdater.neighborChanged(pos, block, orientation); ++ this.getCurrentWorldData().neighborUpdater.neighborChanged(pos, block, orientation); // Folia - region threading } @Override - public void neighborChanged(BlockState state, BlockPos pos, Block sourceBlock, @Nullable Orientation orientation, boolean notify) { -- this.neighborUpdater.neighborChanged(state, pos, sourceBlock, orientation, notify); -+ this.getCurrentWorldData().neighborUpdater.neighborChanged(state, pos, sourceBlock, orientation, notify); // Folia - region threading + public void neighborChanged(BlockState state, BlockPos pos, Block block, @Nullable Orientation orientation, boolean movedByPiston) { +- this.neighborUpdater.neighborChanged(state, pos, block, orientation, movedByPiston); ++ this.getCurrentWorldData().neighborUpdater.neighborChanged(state, pos, block, orientation, movedByPiston); // Folia - region threading } @Override -@@ -1898,7 +1973,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - } +@@ -1851,7 +1930,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // CraftBukkit end - ParticleOptions particleparam2 = serverexplosion.isSmall() ? particleparam : particleparam1; -- Iterator iterator = this.players.iterator(); -+ Iterator iterator = this.getLocalPlayers().iterator(); // Folia - region thraeding + ParticleOptions particleOptions = serverExplosion.isSmall() ? smallExplosionParticles : largeExplosionParticles; - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -@@ -1919,25 +1994,28 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +- for (ServerPlayer serverPlayer : this.players) { ++ for (ServerPlayer serverPlayer : this.getLocalPlayers()) { // Folia - region thraeding + if (serverPlayer.distanceToSqr(vec3) < 4096.0) { + Optional optional = Optional.ofNullable(serverExplosion.getHitPlayers().get(serverPlayer)); + serverPlayer.connection.send(new ClientboundExplodePacket(vec3, optional, particleOptions, explosionSound)); +@@ -1867,14 +1946,17 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override - public void blockEvent(BlockPos pos, Block block, int type, int data) { -- this.blockEvents.add(new BlockEventData(pos, block, type, data)); -+ this.getCurrentWorldData().pushBlockEvent(new BlockEventData(pos, block, type, data)); // Folia - regionised ticking + public void blockEvent(BlockPos pos, Block block, int eventID, int eventParam) { +- this.blockEvents.add(new BlockEventData(pos, block, eventID, eventParam)); ++ this.getCurrentWorldData().pushBlockEvent(new BlockEventData(pos, block, eventID, eventParam)); // Folia - regionised ticking } private void runBlockEvents() { @@ -12075,20 +11741,21 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 + List blockEventsToReschedule = new ArrayList<>(64); // Folia - regionised ticking - while (!this.blockEvents.isEmpty()) { -- BlockEventData blockactiondata = (BlockEventData) this.blockEvents.removeFirst(); +- BlockEventData blockEventData = this.blockEvents.removeFirst(); + // Folia start - regionised ticking + io.papermc.paper.threadedregions.RegionizedWorldData worldRegionData = this.getCurrentWorldData(); -+ BlockEventData blockactiondata; -+ while ((blockactiondata = worldRegionData.removeFirstBlockEvent()) != null) { ++ BlockEventData blockEventData; ++ while ((blockEventData = worldRegionData.removeFirstBlockEvent()) != null) { + // Folia end - regionised ticking - - if (this.shouldTickBlocksAt(blockactiondata.pos())) { - if (this.doBlockEvent(blockactiondata)) { - this.server.getPlayerList().broadcast((Player) null, (double) blockactiondata.pos().getX(), (double) blockactiondata.pos().getY(), (double) blockactiondata.pos().getZ(), 64.0D, this.dimension(), new ClientboundBlockEventPacket(blockactiondata.pos(), blockactiondata.block(), blockactiondata.paramA(), blockactiondata.paramB())); + if (this.shouldTickBlocksAt(blockEventData.pos())) { + if (this.doBlockEvent(blockEventData)) { + this.server +@@ -1890,11 +1972,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ); } } else { -- this.blockEventsToReschedule.add(blockactiondata); -+ blockEventsToReschedule.add(blockactiondata); // Folia - regionised ticking +- this.blockEventsToReschedule.add(blockEventData); ++ blockEventsToReschedule.add(blockEventData); // Folia - regionised ticking } } @@ -12097,7 +11764,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } private boolean doBlockEvent(BlockEventData event) { -@@ -1948,12 +2026,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1904,12 +1986,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @Override public LevelTicks getBlockTicks() { @@ -12112,20 +11779,20 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } @Nonnull -@@ -1981,7 +2059,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // CraftBukkit start - visibility api support - public int sendParticlesSource(ServerPlayer sender, T t0, boolean flag, boolean flag1, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) { - // Paper start - Particle API -- return this.sendParticlesSource(this.players, sender, t0, flag, flag1, d0, d1, d2, i, d3, d4, d5, d6); -+ return this.sendParticlesSource(this.getLocalPlayers(), sender, t0, flag, flag1, d0, d1, d2, i, d3, d4, d5, d6); // Folia - region threading +@@ -1962,7 +2044,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + double zOffset, + double speed + ) { +- return sendParticlesSource(this.players, sender, type, overrideLimiter, alwaysShow, posX, posY, posZ, particleCount, xOffset, yOffset, zOffset, speed); ++ return sendParticlesSource(this.getLocalPlayers(), sender, type, overrideLimiter, alwaysShow, posX, posY, posZ, particleCount, xOffset, yOffset, zOffset, speed); // Folia - region threading } - public int sendParticlesSource(List receivers, @Nullable ServerPlayer sender, T t0, boolean flag, boolean flag1, double d0, double d1, double d2, int i, double d3, double d4, double d5, double d6) { - // Paper end - Particle API -@@ -2039,7 +2117,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + public int sendParticlesSource( + List receivers, +@@ -2045,7 +2127,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + @Nullable public Entity getEntityOrPart(int id) { - Entity entity = (Entity) this.getEntities().get(id); - -- return entity != null ? entity : (Entity) this.dragonParts.get(id); + Entity entity = this.getEntities().get(id); +- return entity != null ? entity : this.dragonParts.get(id); + // Folia start - region threading + if (entity != null) { + return entity; @@ -12137,15 +11804,15 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } @Override -@@ -2094,6 +2179,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2105,6 +2194,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper start - Call missing map initialize event and set id final DimensionDataStorage storage = this.getServer().overworld().getDataStorage(); + synchronized (storage.cache) { // Folia - region threading - final Optional cacheEntry = storage.cache.get(id.key()); + final Optional cacheEntry = storage.cache.get(mapId.key()); if (cacheEntry == null) { // Cache did not contain, try to load and may init - final MapItemSavedData worldmap = storage.get(MapItemSavedData.factory(), id.key()); // get populates the cache -@@ -2113,6 +2199,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + final MapItemSavedData mapData = storage.get(MapItemSavedData.factory(), mapId.key()); // get populates the cache +@@ -2124,6 +2214,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } return null; @@ -12153,96 +11820,95 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 // Paper end - Call missing map initialize event and set id } -@@ -2170,6 +2257,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2178,6 +2269,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } - public boolean setChunkForced(int x, int z, boolean forced) { + public boolean setChunkForced(int chunkX, int chunkZ, boolean add) { + io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify force loaded chunks off of the global region"); // Folia - region threading - ForcedChunksSavedData forcedchunk = (ForcedChunksSavedData) this.getDataStorage().computeIfAbsent(ForcedChunksSavedData.factory(), "chunks"); - ChunkPos chunkcoordintpair = new ChunkPos(x, z); - long k = chunkcoordintpair.toLong(); -@@ -2178,7 +2266,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (forced) { - flag1 = forcedchunk.getChunks().add(k); - if (flag1) { -- this.getChunk(x, z); -+ //this.getChunk(x, z); // Folia - region threading - we must let the chunk load asynchronously + ForcedChunksSavedData forcedChunksSavedData = this.getDataStorage().computeIfAbsent(ForcedChunksSavedData.factory(), "chunks"); + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + long packedChunkPos = chunkPos.toLong(); +@@ -2185,7 +2277,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (add) { + flag = forcedChunksSavedData.getChunks().add(packedChunkPos); + if (flag) { +- this.getChunk(chunkX, chunkZ); ++ //this.getChunk(chunkX, chunkZ); // Folia - region threading - we must let the chunk load asynchronously } } else { - flag1 = forcedchunk.getChunks().remove(k); -@@ -2206,13 +2294,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - BlockPos blockposition1 = pos.immutable(); - - optional.ifPresent((holder) -> { -- this.getServer().execute(() -> { -+ Runnable run = () -> { // Folia - region threading - this.getPoiManager().remove(blockposition1); - DebugPackets.sendPoiRemovedPacket(this, blockposition1); -- }); -+ }; // Folia - region threading + flag = forcedChunksSavedData.getChunks().remove(packedChunkPos); +@@ -2210,11 +2302,24 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + Optional> optional1 = PoiTypes.forState(newState); + if (!Objects.equals(optional, optional1)) { + BlockPos blockPos = pos.immutable(); +- optional.ifPresent(poiType -> this.getServer().execute(() -> { ++ // Folia start - region threading ++ optional.ifPresent(poiType -> { ++ Runnable run = () -> { ++ // Folia end - region threading + this.getPoiManager().remove(blockPos); + DebugPackets.sendPoiRemovedPacket(this, blockPos); +- })); +- optional1.ifPresent(poiType -> this.getServer().execute(() -> { ++ // Folia start - region threading ++ }; + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueChunkTask( -+ this, blockposition1.getX() >> 4, blockposition1.getZ() >> 4, run ++ this, blockPos.getX() >> 4, blockPos.getZ() >> 4, run + ); -+ // Folia end - region threading - }); - optional1.ifPresent((holder) -> { -- this.getServer().execute(() -> { -+ Runnable run = () -> { // Folia - region threading - // Paper start - Remove stale POIs - if (optional.isEmpty() && this.getPoiManager().exists(blockposition1, poiType -> true)) { - this.getPoiManager().remove(blockposition1); -@@ -2220,7 +2313,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - // Paper end - Remove stale POIs - this.getPoiManager().add(blockposition1, holder); - DebugPackets.sendPoiAddedPacket(this, blockposition1); -- }); -+ }; // Folia - region threading ++ }); ++ // Folia end - region threading ++ // Folia start - region threading ++ optional1.ifPresent(poiType -> { ++ Runnable run = () -> { ++ // Folia end - region threading + // Paper start - Remove stale POIs + if (optional.isEmpty() && this.getPoiManager().exists(blockPos, ignored -> true)) { + this.getPoiManager().remove(blockPos); +@@ -2222,7 +2327,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + // Paper end - Remove stale POIs + this.getPoiManager().add(blockPos, (Holder)poiType); + DebugPackets.sendPoiAddedPacket(this, blockPos); +- })); ++ // Folia start - region threading ++ }; + // Folia start - region threading + io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueChunkTask( -+ this, blockposition1.getX() >> 4, blockposition1.getZ() >> 4, run ++ this, blockPos.getX() >> 4, blockPos.getZ() >> 4, run + ); + // Folia end - region threading - }); ++ }); ++ // Folia end - region threading } } -@@ -2267,7 +2365,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - BufferedWriter bufferedwriter = Files.newBufferedWriter(path.resolve("stats.txt")); - try { -- bufferedwriter.write(String.format(Locale.ROOT, "spawning_chunks: %d\n", playerchunkmap.getDistanceManager().getNaturalSpawnChunkCount())); -+ //bufferedwriter.write(String.format(Locale.ROOT, "spawning_chunks: %d\n", playerchunkmap.getDistanceManager().getNaturalSpawnChunkCount())); // Folia - region threading - NaturalSpawner.SpawnState spawnercreature_d = this.getChunkSource().getLastSpawnState(); - - if (spawnercreature_d != null) { -@@ -2281,7 +2379,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2276,7 +2389,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } - bufferedwriter.write(String.format(Locale.ROOT, "entities: %s\n", this.moonrise$getEntityLookup().getDebugInfo())); // Paper - rewrite chunk system -- bufferedwriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size())); -+ //bufferedwriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size())); // Folia - region threading - bufferedwriter.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count())); - bufferedwriter.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count())); - bufferedwriter.write("distance_manager: " + playerchunkmap.getDistanceManager().getDebugStatus() + "\n"); -@@ -2427,7 +2525,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + bufferedWriter.write(String.format(Locale.ROOT, "entities: %s\n", this.moonrise$getEntityLookup().getDebugInfo())); // Paper - rewrite chunk system +- bufferedWriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size())); ++ //bufferedWriter.write(String.format(Locale.ROOT, "block_entity_tickers: %d\n", this.blockEntityTickers.size())); // Folia - region threading + bufferedWriter.write(String.format(Locale.ROOT, "block_ticks: %d\n", this.getBlockTicks().count())); + bufferedWriter.write(String.format(Locale.ROOT, "fluid_ticks: %d\n", this.getFluidTicks().count())); + bufferedWriter.write("distance_manager: " + chunkMap.getDistanceManager().getDebugStatus() + "\n"); +@@ -2346,7 +2459,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + private void dumpBlockEntityTickers(Writer output) throws IOException { + CsvOutput csvOutput = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("type").build(output); - private void dumpBlockEntityTickers(Writer writer) throws IOException { - CsvOutput csvwriter = CsvOutput.builder().addColumn("x").addColumn("y").addColumn("z").addColumn("type").build(writer); -- Iterator iterator = this.blockEntityTickers.iterator(); -+ Iterator iterator = null; // Folia - region threading - - while (iterator.hasNext()) { - TickingBlockEntity tickingblockentity = (TickingBlockEntity) iterator.next(); -@@ -2440,7 +2538,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +- for (TickingBlockEntity tickingBlockEntity : this.blockEntityTickers) { ++ for (TickingBlockEntity tickingBlockEntity : (Iterable)null) { // Folia - region threading + BlockPos pos = tickingBlockEntity.getPos(); + csvOutput.writeRow(pos.getX(), pos.getY(), pos.getZ(), tickingBlockEntity.getType()); + } +@@ -2354,14 +2467,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @VisibleForTesting - public void clearBlockEvents(BoundingBox box) { -- this.blockEvents.removeIf((blockactiondata) -> { -+ this.getCurrentWorldData().removeIfBlockEvents((blockactiondata) -> { // Folia - regionised ticking - return box.isInside(blockactiondata.pos()); - }); + public void clearBlockEvents(BoundingBox boundingBox) { +- this.blockEvents.removeIf(blockEventData -> boundingBox.isInside(blockEventData.pos())); ++ this.getCurrentWorldData().removeIfBlockEvents(blockEventData -> boundingBox.isInside(blockEventData.pos())); // Folia - regionised ticking } -@@ -2449,7 +2547,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + @Override public void blockUpdated(BlockPos pos, Block block) { if (!this.isDebug()) { // CraftBukkit start @@ -12251,18 +11917,18 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 return; } // CraftBukkit end -@@ -2492,9 +2590,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - - @VisibleForTesting - public String getWatchdogStats() { -- return String.format(Locale.ROOT, "players: %s, entities: %s [%s], block_entities: %d [%s], block_ticks: %d, fluid_ticks: %d, chunk_source: %s", this.players.size(), this.moonrise$getEntityLookup().getDebugInfo(), ServerLevel.getTypeCount(this.moonrise$getEntityLookup().getAll(), (entity) -> { // Paper - rewrite chunk system -- return BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString(); -- }), this.blockEntityTickers.size(), ServerLevel.getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType), this.getBlockTicks().count(), this.getFluidTicks().count(), this.gatherChunkSourceStats()); -+ return "region threading"; // Folia - region threading - } - - private static String getTypeCount(Iterable items, Function classifier) { -@@ -2544,17 +2640,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2410,8 +2523,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + this.players.size(), + this.moonrise$getEntityLookup().getDebugInfo(), // Paper - rewrite chunk system + getTypeCount(this.moonrise$getEntityLookup().getAll(), entity -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()), // Paper - rewrite chunk system +- this.blockEntityTickers.size(), +- getTypeCount(this.blockEntityTickers, TickingBlockEntity::getType), ++ 0, // Folia - region threading ++ "null", // Folia - region threading + this.getBlockTicks().count(), + this.getFluidTicks().count(), + this.gatherChunkSourceStats() +@@ -2463,15 +2576,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } public void startTickingChunk(LevelChunk chunk) { @@ -12271,13 +11937,8 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } public void onStructureStartsAvailable(ChunkAccess chunk) { -- this.server.execute(() -> { -- this.structureCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts()); -- }); -+ // Folia start - region threading -+ // no longer needs to be on main -+ this.structureCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts()); -+ // Folia end - region threading +- this.server.execute(() -> this.structureCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts())); ++ this.structureCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts()); // Folia - region threading } public PathTypeCache getPathTypeCache() { @@ -12286,7 +11947,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } @Override -@@ -2574,7 +2671,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2489,7 +2602,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe return this.moonrise$getAnyChunkIfLoaded(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(chunkPos), ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(chunkPos)) != null; // Paper - rewrite chunk system } @@ -12295,7 +11956,7 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 // Paper start - rewrite chunk system final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos); // isTicking implies the chunk is loaded, and the chunk is loaded now implies the entities are loaded -@@ -2669,7 +2766,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -2581,7 +2694,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Paper start - optimize redstone (Alternate Current) @Override public alternate.current.wire.WireHandler getWireHandler() { @@ -12304,102 +11965,93 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 } // Paper end - optimize redstone (Alternate Current) -@@ -2680,16 +2777,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - public void onCreated(Entity entity) {} +@@ -2592,18 +2705,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + @Override public void onDestroyed(Entity entity) { - ServerLevel.this.getScoreboard().entityRemoved(entity); + // ServerLevel.this.getScoreboard().entityRemoved(entity); // Folia - region threading } + @Override public void onTickingStart(Entity entity) { if (entity instanceof net.minecraft.world.entity.Marker && !paperConfig().entities.markers.tick) return; // Paper - Configurable marker ticking - ServerLevel.this.entityTickList.add(entity); + ServerLevel.this.getCurrentWorldData().addEntityTickingEntity(entity); // Folia - region threading } + @Override public void onTickingEnd(Entity entity) { - ServerLevel.this.entityTickList.remove(entity); + ServerLevel.this.getCurrentWorldData().removeEntityTickingEntity(entity); // Folia - region threading // Paper start - Reset pearls when they stop being ticked if (ServerLevel.this.paperConfig().fixes.disableUnloadedChunkEnderpearlExploit && ServerLevel.this.paperConfig().misc.legacyEnderPearlBehavior && entity instanceof net.minecraft.world.entity.projectile.ThrownEnderpearl pearl) { pearl.cachedOwner = null; -@@ -2700,6 +2797,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - +@@ -2615,6 +2728,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + @Override public void onTrackingStart(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity register"); // Spigot + ServerLevel.this.getCurrentWorldData().addLoadedEntity(entity); // Folia - region threading // ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true - if (entity instanceof ServerPlayer entityplayer) { - ServerLevel.this.players.add(entityplayer); -@@ -2713,7 +2811,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); + if (entity instanceof ServerPlayer serverPlayer) { + ServerLevel.this.players.add(serverPlayer); +@@ -2629,12 +2743,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ); } -- ServerLevel.this.navigatingMobs.add(entityinsentient); -+ ServerLevel.this.getCurrentWorldData().addNavigatingMob(entityinsentient); // Folia - region threading +- ServerLevel.this.navigatingMobs.add(mob); ++ ServerLevel.this.getCurrentWorldData().addNavigatingMob(mob); // Folia - region threading } - if (entity instanceof EnderDragon entityenderdragon) { -@@ -2723,7 +2821,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - for (int j = 0; j < i; ++j) { - EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; - + if (entity instanceof EnderDragon enderDragon) { + for (EnderDragonPart enderDragonPart : enderDragon.getSubEntities()) { + synchronized (ServerLevel.this.dragonParts) { // Folia - region threading - ServerLevel.this.dragonParts.put(entitycomplexpart.getId(), entitycomplexpart); + ServerLevel.this.dragonParts.put(enderDragonPart.getId(), enderDragonPart); + } // Folia - region threading } } -@@ -2745,16 +2845,24 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - +@@ -2657,18 +2773,27 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + @Override public void onTrackingEnd(Entity entity) { org.spigotmc.AsyncCatcher.catchOp("entity unregister"); // Spigot -+ ServerLevel.this.getCurrentWorldData().removeLoadedEntity(entity); - // Spigot start - if ( entity instanceof Player ) - { - com.google.common.collect.Streams.stream( ServerLevel.this.getServer().getAllLevels() ).map( ServerLevel::getDataStorage ).forEach( (worldData) -> - { -- for (Object o : worldData.cache.values() ) ++ ServerLevel.this.getCurrentWorldData().removeLoadedEntity(entity); // Folia - region threading + // Spigot start // TODO I don't think this is needed anymore + if (entity instanceof Player player) { + for (final ServerLevel level : ServerLevel.this.getServer().getAllLevels()) { +- for (final Optional savedData : level.getDataStorage().cache.values()) { + // Folia start - make map data thread-safe -+ List worldDataCache; -+ synchronized (worldData.cache) { -+ worldDataCache = new java.util.ArrayList<>(worldData.cache.values()); ++ List> worldDataCache; ++ synchronized (level.getDataStorage().cache) { ++ worldDataCache = new java.util.ArrayList<>(level.getDataStorage().cache.values()); + } -+ for (Object o : worldDataCache ) -+ // Folia end - make map data thread-safe - { - if ( o instanceof MapItemSavedData ) - { - MapItemSavedData map = (MapItemSavedData) o; -+ synchronized (map) { // Folia - make map data thread-safe - map.carriedByPlayers.remove( (Player) entity ); - for ( Iterator iter = (Iterator) map.carriedBy.iterator(); iter.hasNext(); ) - { -@@ -2764,6 +2872,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - iter.remove(); - } - } -+ } // Folia - make map data thread-safe ++ for (final Optional savedData : worldDataCache) { ++ // Folia end - make map data thread-safe + if (savedData.isEmpty() || !(savedData.get() instanceof MapItemSavedData map)) { + continue; } + ++ synchronized (map) { // Folia - make map data thread-safe + map.carriedByPlayers.remove(player); + if (map.carriedBy.removeIf(holdingPlayer -> holdingPlayer.player == player)) { + map.decorations.remove(player.getName().getString()); + } ++ } // Folia - make map data thread-safe } - } ); -@@ -2794,7 +2903,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - Util.logAndPauseIfInIde("onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")); + } + } +@@ -2699,18 +2824,21 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + ); } -- ServerLevel.this.navigatingMobs.remove(entityinsentient); -+ ServerLevel.this.getCurrentWorldData().removeNavigatingMob(entityinsentient); // Folia - region threading +- ServerLevel.this.navigatingMobs.remove(mob); ++ ServerLevel.this.getCurrentWorldData().removeNavigatingMob(mob); // Folia - region threading } - if (entity instanceof EnderDragon entityenderdragon) { -@@ -2804,13 +2913,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - for (int j = 0; j < i; ++j) { - EnderDragonPart entitycomplexpart = aentitycomplexpart[j]; - + if (entity instanceof EnderDragon enderDragon) { + for (EnderDragonPart enderDragonPart : enderDragon.getSubEntities()) { + synchronized (ServerLevel.this.dragonParts) { // Folia - region threading - ServerLevel.this.dragonParts.remove(entitycomplexpart.getId()); + ServerLevel.this.dragonParts.remove(enderDragonPart.getId()); + } // Folia - region threading } } @@ -12411,22 +12063,36 @@ index 1f898500d0e9b18a880645ceb0a8ff0fe75f4e48..e0ad5a7715949c281a94f000e2df5cb2 if (!(entity instanceof ServerPlayer)) { for (ServerPlayer player : ServerLevel.this.server.getPlayerList().players) { // Paper - call onEntityRemove for all online players player.getBukkitEntity().onEntityRemove(entity); -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b922dac538 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -220,7 +220,7 @@ import org.bukkit.inventory.MainHand; - public class ServerPlayer extends net.minecraft.world.entity.player.Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system +@@ -2738,11 +2866,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + private long lagCompensationTick = MinecraftServer.SERVER_INIT; + public long getLagCompensationTick() { +- return this.lagCompensationTick; ++ return this.getCurrentWorldData().getLagCompensationTick(); // Folia - region threading + } + + public void updateLagCompensationTick() { +- this.lagCompensationTick = (System.nanoTime() - MinecraftServer.SERVER_INIT) / (java.util.concurrent.TimeUnit.MILLISECONDS.toNanos(50L)); ++ throw new UnsupportedOperationException(); // Folia - region threading + } + // Paper end - lag compensation + } +diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java +index f347ff8d863f4bcef46604c757de112cb3fe445c..ab85c5acc63abc07a55ff7c5e207527bb18d50b2 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -180,7 +180,7 @@ import org.slf4j.Logger; + + public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer { // Paper - rewrite chunk system private static final Logger LOGGER = LogUtils.getLogger(); - public long lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving + public static final long LAST_SAVE_ABSENT = Long.MIN_VALUE; public long lastSave = LAST_SAVE_ABSENT; // Paper // Folia - threaded regions - changed to nanoTime private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; private static final int FLY_STAT_RECORDING_SPEED = 25; -@@ -541,8 +541,149 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple +@@ -443,8 +443,149 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + this.maxHealthCache = this.getMaxHealth(); } - // CraftBukkit end + // Folia start - region threading + private static final int SPAWN_RADIUS_SELECTION_SEARCH = 5; @@ -12455,7 +12121,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + } + + private static void completeSpawn(ServerLevel world, BlockPos selected, -+ ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { ++ ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { + toComplete.complete(io.papermc.paper.util.MCUtil.toLocation(world, Vec3.atBottomCenterOf(selected), world.levelData.getSpawnAngle(), 0.0f)); + } + @@ -12483,7 +12149,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + + // rets false when another attempt is required + private static boolean trySpawnOrSchedule(ServerLevel world, ServerPlayer player, RandomSource random, int[] attemptCount, int maxAttempts, -+ ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { ++ ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { + ++attemptCount[0]; + + BlockPos rough = getRandomSpawn(world, random); @@ -12497,17 +12163,17 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + // we could short circuit this check, but it would possibly recurse. Then, it could end up causing a stack overflow + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(world, minX, minZ, maxX, maxZ) || !world.moonrise$areChunksLoaded(minX, minZ, maxX, maxZ)) { + world.moonrise$loadChunksAsync(minX, maxX, minZ, maxZ, ca.spottedleaf.concurrentutil.util.Priority.HIGHER, -+ (unused) -> { -+ BlockPos selected = findSpawnAround(world, player, rough); -+ if (selected == null) { -+ // run more spawn attempts -+ selectSpawn(world, player, random, attemptCount, maxAttempts, toComplete); ++ (unused) -> { ++ BlockPos selected = findSpawnAround(world, player, rough); ++ if (selected == null) { ++ // run more spawn attempts ++ selectSpawn(world, player, random, attemptCount, maxAttempts, toComplete); ++ return; ++ } ++ ++ completeSpawn(world, selected, toComplete); + return; + } -+ -+ completeSpawn(world, selected, toComplete); -+ return; -+ } + ); + return true; + } @@ -12522,7 +12188,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + } + + private static void selectSpawn(ServerLevel world, ServerPlayer player, RandomSource random, int[] attemptCount, int maxAttempts, -+ ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { ++ ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { + do { + if (attemptCount[0] >= maxAttempts) { + BlockPos sharedSpawn = world.getSharedSpawnPos(); @@ -12536,23 +12202,23 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + } + + -+ private static void selectSpawnWithoutRadius(ServerLevel world, ServerPlayer player, BlockPos spawn, ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { ++ private static void selectSpawnWithoutRadius(ServerLevel world, ServerPlayer player, BlockPos spawn, ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { + world.loadChunksForMoveAsync(player.getBoundingBoxAt(spawn.getX() + 0.5, spawn.getY(), spawn.getZ() + 0.5), -+ ca.spottedleaf.concurrentutil.util.Priority.HIGHER, -+ (c) -> { -+ BlockPos ret = spawn; -+ while (!player.noCollisionNoLiquid(world, player.getBoundingBoxAt(ret.getX() + 0.5, ret.getY(), ret.getZ() + 0.5)) && ret.getY() < (double)world.getMaxY()) { -+ ret = ret.above(); ++ ca.spottedleaf.concurrentutil.util.Priority.HIGHER, ++ (c) -> { ++ BlockPos ret = spawn; ++ while (!player.noCollisionNoLiquid(world, player.getBoundingBoxAt(ret.getX() + 0.5, ret.getY(), ret.getZ() + 0.5)) && ret.getY() < (double)world.getMaxY()) { ++ ret = ret.above(); ++ } ++ while (player.noCollisionNoLiquid(world, player.getBoundingBoxAt(ret.getX() + 0.5, ret.getY() - 1, ret.getZ() + 0.5)) && ret.getY() > (double)(world.getMinY() + 1)) { ++ ret = ret.below(); ++ } ++ toComplete.complete(io.papermc.paper.util.MCUtil.toLocation(world, Vec3.atBottomCenterOf(ret), world.levelData.getSpawnAngle(), 0.0f)); + } -+ while (player.noCollisionNoLiquid(world, player.getBoundingBoxAt(ret.getX() + 0.5, ret.getY() - 1, ret.getZ() + 0.5)) && ret.getY() > (double)(world.getMinY() + 1)) { -+ ret = ret.below(); -+ } -+ toComplete.complete(io.papermc.paper.util.MCUtil.toLocation(world, Vec3.atBottomCenterOf(ret), world.levelData.getSpawnAngle(), 0.0f)); -+ } + ); + } + -+ public static void fudgeSpawnLocation(ServerLevel world, ServerPlayer player, ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { // Folia - region threading ++ public static void fudgeSpawnLocation(ServerLevel world, ServerPlayer player, ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { // Folia - region threading + BlockPos blockposition = world.getSharedSpawnPos(); + + if (world.dimensionType().hasSkyLight() && world.serverLevelData.getGameType() != GameType.ADVENTURE) { // CraftBukkit @@ -12565,38 +12231,37 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + // Folia end - region threading + @Override - public BlockPos adjustSpawnLocation(ServerLevel world, BlockPos basePos) { + public BlockPos adjustSpawnLocation(ServerLevel level, BlockPos pos) { + // Folia start - region threading + if (true) { + throw new UnsupportedOperationException(); + } + // Folia end - region threading - AABB axisalignedbb = this.getDimensions(Pose.STANDING).makeBoundingBox(Vec3.ZERO); - BlockPos blockposition1 = basePos; - -@@ -883,11 +1024,18 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple - - if (worldserver != null) { - Entity entity = EntityType.loadEntityRecursive(nbttagcompound, worldserver, EntitySpawnReason.LOAD, (entity1) -> { -- return !worldserver.addWithUUID(entity1) ? null : entity1; -+ return entity1; // Folia - region threading - delay world add - }); - - if (entity != null) { -- ServerPlayer.placeEnderPearlTicket(worldserver, entity.chunkPosition()); -+ // Folia start - region threading -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( -+ worldserver, entity.chunkPosition().x, entity.chunkPosition().z, () -> { -+ worldserver.addFreshEntityWithPassengers(entity); -+ ServerPlayer.placeEnderPearlTicket(worldserver, entity.chunkPosition()); + AABB aabb = this.getDimensions(Pose.STANDING).makeBoundingBox(Vec3.ZERO); + BlockPos blockPos = pos; + if (level.dimensionType().hasSkyLight() && level.serverLevelData.getGameType() != GameType.ADVENTURE) { // CraftBukkit +@@ -709,10 +850,17 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + ServerLevel level = this.level().getServer().getLevel(optional.get()); + if (level != null) { + Entity entity = EntityType.loadEntityRecursive( +- compoundTag, level, EntitySpawnReason.LOAD, entity1 -> !level.addWithUUID(entity1) ? null : entity1 ++ compoundTag, level, EntitySpawnReason.LOAD, entity1 -> entity1 // Folia - region threading - delay world add + ); + if (entity != null) { +- placeEnderPearlTicket(level, entity.chunkPosition()); ++ // Folia start - region threading ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( ++ level, entity.chunkPosition().x, entity.chunkPosition().z, () -> { ++ level.addFreshEntityWithPassengers(entity); ++ ServerPlayer.placeEnderPearlTicket(level, entity.chunkPosition()); + } -+ ); -+ // Folia end - region threading - } else { - ServerPlayer.LOGGER.warn("Failed to spawn player ender pearl in level ({}), skipping", optional1.get()); - } -@@ -1572,6 +1720,324 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple - ++ ); ++ // Folia end - region threading + } else { + LOGGER.warn("Failed to spawn player ender pearl in level ({}), skipping", optional.get()); + } +@@ -1357,6 +1505,324 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + } } + // Folia start - region threading @@ -12618,11 +12283,11 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + }, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.END_PORTAL, true); + } + -+ public void respawn(java.util.function.Consumer respawnComplete, PlayerRespawnEvent.RespawnReason reason) { ++ public void respawn(java.util.function.Consumer respawnComplete, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason reason) { + this.respawn(respawnComplete, reason, false); + } + -+ private void respawn(java.util.function.Consumer respawnComplete, PlayerRespawnEvent.RespawnReason reason, boolean alive) { ++ private void respawn(java.util.function.Consumer respawnComplete, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason reason, boolean alive) { + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot respawn entity async"); + + this.getBukkitEntity(); // force bukkit entity to be created before TPing @@ -12659,7 +12324,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + float respawnAngle = this.getRespawnAngle(); + boolean isRespawnForced = this.isRespawnForced(); + -+ ca.spottedleaf.concurrentutil.completable.CallbackCompletable spawnPosComplete = ++ ca.spottedleaf.concurrentutil.completable.CallbackCompletable spawnPosComplete = + new ca.spottedleaf.concurrentutil.completable.CallbackCompletable<>(); + boolean[] usedRespawnAnchor = new boolean[1]; + @@ -12677,7 +12342,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + origin, + // use the load chunk flag just in case the spawn loc isn't loaded, and to ensure the chunks + // stay loaded for a bit with the teleport ticket -+ ((CraftWorld)spawnLoc.getWorld()).getHandle(), ++ ((org.bukkit.craftbukkit.CraftWorld)spawnLoc.getWorld()).getHandle(), + TELEPORT_FLAG_LOAD_CHUNK | TELEPORT_FLAGS_PLAYER_RESPAWN, + passengerTree, // note: we expect this to just be the player, no passengers + (entity) -> { @@ -12891,7 +12556,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + public boolean endPortalLogicAsync(BlockPos portalPos) { + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot portal entity async"); + -+ if (this.level().getTypeKey() == LevelStem.END) { ++ if (this.level().getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END) { + if (!this.canPortalAsync(null, false)) { + return false; + } @@ -12911,7 +12576,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + @Override + protected void prePortalLogic(ServerLevel origin, ServerLevel destination, PortalType type) { + super.prePortalLogic(origin, destination, type); -+ if (origin.getTypeKey() == LevelStem.OVERWORLD && destination.getTypeKey() == LevelStem.NETHER) { ++ if (origin.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.OVERWORLD && destination.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.NETHER) { + this.enteredNetherPosition = this.position(); + } + } @@ -12919,21 +12584,20 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 + @Nullable @Override - public ServerPlayer teleport(TeleportTransition teleportTarget) { -@@ -2605,6 +3071,12 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple - public void setCamera(@Nullable Entity entity) { - Entity entity1 = this.getCamera(); + public ServerPlayer teleport(TeleportTransition teleportTransition) { +@@ -2398,6 +2864,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + } + public void setCamera(@Nullable Entity entityToSpectate) { + // Folia start - region threading -+ if (entity != null && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) { ++ if (entityToSpectate != null && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entityToSpectate)) { + return; + } + // Folia end - region threading -+ - this.camera = (Entity) (entity == null ? this : entity); - if (entity1 != this.camera) { - // Paper start - Add PlayerStartSpectatingEntityEvent and PlayerStopSpectatingEntity -@@ -3098,11 +3570,11 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple + Entity camera = this.getCamera(); + this.camera = (Entity)(entityToSpectate == null ? this : entityToSpectate); + if (camera != this.camera) { +@@ -2896,11 +3367,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc } public void registerEnderPearl(ThrownEnderpearl enderPearl) { @@ -12947,7 +12611,7 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 } public Set getEnderPearls() { -@@ -3261,7 +3733,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple +@@ -3054,7 +3525,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc this.experienceLevel = this.newLevel; this.totalExperience = this.newTotalExp; this.experienceProgress = 0; @@ -12956,38 +12620,38 @@ index fc7f7a34babd095a51b5321f600aef65a2a9d123..130643b97fdab3bf89fc87afd6d4e0b9 this.setArrowCount(0, true); // CraftBukkit - ArrowBodyCountChangeEvent this.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.DEATH); this.effectsDirty = true; -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -index a96f859a5d0c6ec692d4627a69f3c9ee49199dbc..ad8da6726b4113068b200426ab1ac1e24a061942 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayerGameMode.java -@@ -131,7 +131,7 @@ public class ServerPlayerGameMode { - BlockState iblockdata; - +diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java +index 623c069f1fe079e020c6391a3db1a3d95cd3dbf5..61804cdb6be06b1b3316e563df57f0b38268958a 100644 +--- a/net/minecraft/server/level/ServerPlayerGameMode.java ++++ b/net/minecraft/server/level/ServerPlayerGameMode.java +@@ -114,7 +114,7 @@ public class ServerPlayerGameMode { + // this.gameTicks = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit + this.gameTicks = (int) this.level.getLagCompensationTick(); // Paper - lag compensate eating if (this.hasDelayedDestroy) { -- iblockdata = this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks -+ iblockdata = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.delayedDestroyPos) ? null : this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks // Folia - region threading - don't destroy blocks not owned - if (iblockdata == null || iblockdata.isAir()) { // Paper - Don't allow digging into unloaded chunks +- BlockState blockState = this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks ++ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.delayedDestroyPos) ? null : this.level.getBlockStateIfLoaded(this.delayedDestroyPos); // Paper - Don't allow digging into unloaded chunks // Folia - region threading - don't destroy blocks not owned + if (blockState == null || blockState.isAir()) { // Paper - Don't allow digging into unloaded chunks this.hasDelayedDestroy = false; } else { -@@ -144,7 +144,7 @@ public class ServerPlayerGameMode { +@@ -126,7 +126,7 @@ public class ServerPlayerGameMode { } } else if (this.isDestroyingBlock) { // Paper start - Don't allow digging into unloaded chunks; don't want to do same logic as above, return instead -- iblockdata = this.level.getBlockStateIfLoaded(this.destroyPos); -+ iblockdata = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.destroyPos) ? null : this.level.getBlockStateIfLoaded(this.destroyPos); - if (iblockdata == null) { +- BlockState blockState = this.level.getBlockStateIfLoaded(this.destroyPos); ++ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.destroyPos) ? null : this.level.getBlockStateIfLoaded(this.destroyPos); // Folia - region threading - don't destroy blocks not owned + if (blockState == null) { this.isDestroyingBlock = false; return; -@@ -422,7 +422,7 @@ public class ServerPlayerGameMode { +@@ -369,7 +369,7 @@ public class ServerPlayerGameMode { } else { // CraftBukkit start org.bukkit.block.BlockState state = bblock.getState(); -- this.level.captureDrops = new ArrayList<>(); -+ this.level.getCurrentWorldData().captureDrops = new ArrayList<>(); // Folia - region threading +- this.level.captureDrops = new java.util.ArrayList<>(); ++ this.level.getCurrentWorldData().captureDrops = new java.util.ArrayList<>(); // Folia - region threading // CraftBukkit end - BlockState iblockdata1 = block.playerWillDestroy(this.level, pos, iblockdata, this.player); + BlockState blockState1 = block.playerWillDestroy(this.level, pos, blockState, this.player); boolean flag = this.level.removeBlock(pos, false); -@@ -450,8 +450,8 @@ public class ServerPlayerGameMode { +@@ -395,8 +395,8 @@ public class ServerPlayerGameMode { // return true; // CraftBukkit } // CraftBukkit start @@ -12998,11 +12662,16 @@ index a96f859a5d0c6ec692d4627a69f3c9ee49199dbc..ad8da6726b4113068b200426ab1ac1e2 if (event.isDropItems()) { org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockDropItemEvent(bblock, state, this.player, itemsToDrop); // Paper - capture all item additions to the world } -diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java -index 4d3f7d4a8e05a8d84aa5202134eda1ce9621712e..02e97634932f4aea6ea36a8e6479ec90cbba0a54 100644 ---- a/src/main/java/net/minecraft/server/level/TicketType.java -+++ b/src/main/java/net/minecraft/server/level/TicketType.java -@@ -26,6 +26,14 @@ public class TicketType { +diff --git a/net/minecraft/server/level/TicketType.java b/net/minecraft/server/level/TicketType.java +index 8f12a4df5d63ecd11e6e615d910b6e3f6dde5f3c..f8b74eaf534c6264ce018a6826c3d035089e7d30 100644 +--- a/net/minecraft/server/level/TicketType.java ++++ b/net/minecraft/server/level/TicketType.java +@@ -17,10 +17,18 @@ public class TicketType { + public static final TicketType FORCED = create("forced", Comparator.comparingLong(ChunkPos::toLong)); + public static final TicketType PORTAL = create("portal", Vec3i::compareTo, 300); + public static final TicketType ENDER_PEARL = create("ender_pearl", Comparator.comparingLong(ChunkPos::toLong), 40); +- public static final TicketType UNKNOWN = create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1); ++ public static final TicketType UNKNOWN = create("unknown", Comparator.comparingLong(ChunkPos::toLong), 5); // Folia - region threading public static final TicketType PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit public static final TicketType PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit public static final TicketType POST_TELEPORT = TicketType.create("post_teleport", Integer::compare, 5); // Paper - post teleport ticket type @@ -13015,16 +12684,16 @@ index 4d3f7d4a8e05a8d84aa5202134eda1ce9621712e..02e97634932f4aea6ea36a8e6479ec90 + public static final TicketType REGION_SCHEDULER_API_HOLD = create("folia:region_scheduler_api_hold", (a, b) -> 0); + // Folia end - region threading - public static TicketType create(String name, Comparator argumentComparator) { - return new TicketType<>(name, argumentComparator, 0L); -diff --git a/src/main/java/net/minecraft/server/level/WorldGenRegion.java b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -index e4b0dc3121101d54394a0c3a413dabf8103b2ea6..0026ec8a393d4348d36242d745e4eccf6327744c 100644 ---- a/src/main/java/net/minecraft/server/level/WorldGenRegion.java -+++ b/src/main/java/net/minecraft/server/level/WorldGenRegion.java -@@ -115,6 +115,14 @@ public class WorldGenRegion implements WorldGenLevel { + public static TicketType create(String name, Comparator comparator) { + return new TicketType<>(name, comparator, 0L); +diff --git a/net/minecraft/server/level/WorldGenRegion.java b/net/minecraft/server/level/WorldGenRegion.java +index 7fa41dea184b01891f45d8e404bc1cba19cf1bcf..43de96cc3c2b1259b1edb5feae3f202dea65dcdf 100644 +--- a/net/minecraft/server/level/WorldGenRegion.java ++++ b/net/minecraft/server/level/WorldGenRegion.java +@@ -107,6 +107,13 @@ public class WorldGenRegion implements WorldGenLevel { + return this.getLightEngine().getRawBrightness(blockPos, subtract); } // Paper end - rewrite chunk system - + // Folia start - region threading + private final net.minecraft.world.level.StructureManager structureManager; + @Override @@ -13032,24 +12701,23 @@ index e4b0dc3121101d54394a0c3a413dabf8103b2ea6..0026ec8a393d4348d36242d745e4eccf + return this.structureManager; + } + // Folia end - region threading -+ - public WorldGenRegion(ServerLevel world, StaticCache2D chunks, ChunkStep generationStep, ChunkAccess centerPos) { - this.generatingStep = generationStep; - this.cache = chunks; -@@ -125,6 +133,7 @@ public class WorldGenRegion implements WorldGenLevel { - this.random = world.getChunkSource().randomState().getOrCreateRandomFactory(WorldGenRegion.WORLDGEN_REGION_RANDOM).at(this.center.getPos().getWorldPosition()); - this.dimensionType = world.dimensionType(); + + public WorldGenRegion(ServerLevel level, StaticCache2D cache, ChunkStep generatingStep, ChunkAccess center) { + this.generatingStep = generatingStep; +@@ -118,6 +125,7 @@ public class WorldGenRegion implements WorldGenLevel { + this.random = level.getChunkSource().randomState().getOrCreateRandomFactory(WORLDGEN_REGION_RANDOM).at(this.center.getPos().getWorldPosition()); + this.dimensionType = level.dimensionType(); this.biomeManager = new BiomeManager(this, BiomeManager.obfuscateSeed(this.seed)); -+ this.structureManager = world.structureManager().forWorldGenRegion(this); // Folia - region threading ++ this.structureManager = level.structureManager().forWorldGenRegion(this); // Folia - region threading } - public boolean isOldChunkAround(ChunkPos chunkPos, int checkRadius) { -diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index b0bc66dc7248aae691dcab68b925b52a1695e63f..d01063b964a67ecff2998a9e02e7f37a9af88c84 100644 ---- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -114,6 +114,10 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - + public boolean isOldChunkAround(ChunkPos pos, int radius) { +diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +index e71c1a564e5d4ac43460f89879ff709ee685706f..6eca15223b92aedac74233db886e2c1248750e2c 100644 +--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +@@ -96,6 +96,10 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + } } + // Folia start - region threading @@ -13057,10 +12725,10 @@ index b0bc66dc7248aae691dcab68b925b52a1695e63f..d01063b964a67ecff2998a9e02e7f37a + // Folia end - region threading + @Override - public void onDisconnect(DisconnectionDetails info) { + public void onDisconnect(DisconnectionDetails details) { // Paper start - Fix kick event leave message not being sent -@@ -121,10 +125,18 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - } +@@ -104,10 +108,18 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + public void onDisconnect(DisconnectionDetails info, @Nullable net.kyori.adventure.text.Component quitMessage) { // Paper end - Fix kick event leave message not being sent + // Folia start - region threading @@ -13071,22 +12739,22 @@ index b0bc66dc7248aae691dcab68b925b52a1695e63f..d01063b964a67ecff2998a9e02e7f37a + this.handledDisconnect = true; + // Folia end - region threading if (this.isSingleplayerOwner()) { - ServerCommonPacketListenerImpl.LOGGER.info("Stopping singleplayer server as player logged out"); + LOGGER.info("Stopping singleplayer server as player logged out"); this.server.halt(false); } + this.player.getBukkitEntity().taskScheduler.retire(); // Folia - region threading - } -@@ -354,24 +366,8 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + @Override +@@ -330,24 +342,8 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack if (this.processedDisconnect) { return; } - if (!this.cserver.isPrimaryThread()) { -- Waitable waitable = new Waitable() { +- org.bukkit.craftbukkit.util.Waitable waitable = new org.bukkit.craftbukkit.util.Waitable() { - @Override - protected Object evaluate() { -- ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo, cause); // Paper - kick event causes +- ServerCommonPacketListenerImpl.this.disconnect(disconnectionDetails, cause); // Paper - kick event causes - return null; - } - }; @@ -13097,31 +12765,32 @@ index b0bc66dc7248aae691dcab68b925b52a1695e63f..d01063b964a67ecff2998a9e02e7f37a - waitable.get(); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); -- } catch (ExecutionException e) { +- } catch (java.util.concurrent.ExecutionException e) { - throw new RuntimeException(e); - } + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.player)) { // Folia - region threading -+ this.connection.disconnectSafely(disconnectionInfo.reason(), cause); // Folia - region threading - it HAS to be delayed/async to avoid deadlock if we try to wait for another region ++ this.connection.disconnectSafely(disconnectionDetails, cause); // Folia - region threading - it HAS to be delayed/async to avoid deadlock if we try to wait for another region return; } -@@ -404,7 +400,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - - Objects.requireNonNull(this.connection); +@@ -378,7 +374,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack + this.onDisconnect(disconnectionDetails, leaveMessage); // CraftBukkit - fire quit instantly // Paper - use kick event leave message + this.connection.setReadOnly(); // CraftBukkit - Don't wait -- minecraftserver.scheduleOnMain(networkmanager::handleDisconnection); // Paper -+ // Folia - region threading +- this.server.scheduleOnMain(this.connection::handleDisconnection); // Paper ++ //this.server.scheduleOnMain(this.connection::handleDisconnection); // Paper // Folia - region threading } // Paper start - add proper async disconnect -@@ -417,18 +413,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack +@@ -391,19 +387,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack } - public void disconnectAsync(DisconnectionDetails disconnectionInfo, PlayerKickEvent.Cause cause) { + public void disconnectAsync(DisconnectionDetails disconnectionInfo, org.bukkit.event.player.PlayerKickEvent.Cause cause) { - if (this.cserver.isPrimaryThread()) { - this.disconnect(disconnectionInfo, cause); - return; - } +- - this.connection.setReadOnly(); - this.server.scheduleOnMain(() -> { - ServerCommonPacketListenerImpl.this.disconnect(disconnectionInfo, cause); @@ -13134,23 +12803,23 @@ index b0bc66dc7248aae691dcab68b925b52a1695e63f..d01063b964a67ecff2998a9e02e7f37a } // Paper end - add proper async disconnect -diff --git a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java -index 880e5c52746e9e3a9a1f42ec6461be54e3ee136c..70665e5bea075ced6db7696efcffe502f81cffdf 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java -@@ -54,6 +54,7 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis +diff --git a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java +index 2e9eb04c7c4342393c05339906c267bca9ff29b1..00fb8a5dda1f305a0e0f947bbb75a3f40b5318cc 100644 +--- a/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerConfigurationPacketListenerImpl.java +@@ -47,6 +47,7 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis private ClientInformation clientInformation; @Nullable private SynchronizeRegistriesTask synchronizeRegistriesTask; + public boolean switchToMain = false; // Folia - region threading - rewrite login process // CraftBukkit start - public ServerConfigurationPacketListenerImpl(MinecraftServer minecraftserver, Connection networkmanager, CommonListenerCookie commonlistenercookie, ServerPlayer player) { -@@ -170,7 +171,58 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis + public ServerConfigurationPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie, ServerPlayer player) { +@@ -160,7 +161,58 @@ public class ServerConfigurationPacketListenerImpl extends ServerCommonPacketLis + } - ServerPlayer entityplayer = playerlist.getPlayerForLogin(this.gameProfile, this.clientInformation, this.player); // CraftBukkit - -- playerlist.placeNewPlayer(this.connection, entityplayer, this.createCookie(this.clientInformation)); + ServerPlayer playerForLogin = playerList.getPlayerForLogin(this.gameProfile, this.clientInformation, this.player); // CraftBukkit +- playerList.placeNewPlayer(this.connection, playerForLogin, this.createCookie(this.clientInformation)); + // Folia start - region threading - rewrite login process + io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot handle player login off global tick thread"); + CommonListenerCookie clientData = this.createCookie(this.clientInformation); @@ -13180,9 +12849,9 @@ index 880e5c52746e9e3a9a1f42ec6461be54e3ee136c..70665e5bea075ced6db7696efcffe502 + () -> { + // once switchToMain is set, the current ticking region now owns the connection and is responsible + // for cleaning it up -+ playerlist.placeNewPlayer( ++ playerList.placeNewPlayer( + ServerConfigurationPacketListenerImpl.this.connection, -+ entityplayer, ++ playerForLogin, + clientData, + java.util.Optional.ofNullable(data.getValue()), + lastKnownName.getValue(), @@ -13195,7 +12864,7 @@ index 880e5c52746e9e3a9a1f42ec6461be54e3ee136c..70665e5bea075ced6db7696efcffe502 + this.switchToMain = true; + try { + // now the connection responsibility is transferred on the region -+ playerlist.loadSpawnForNewPlayer(this.connection, entityplayer, clientData, data, lastKnownName, toComplete); ++ playerList.loadSpawnForNewPlayer(this.connection, playerForLogin, clientData, data, lastKnownName, toComplete); + } catch (final Throwable throwable) { + // assume toComplete will not be invoked + // ensure global tick thread owns the connection again, to properly disconnect it @@ -13203,54 +12872,47 @@ index 880e5c52746e9e3a9a1f42ec6461be54e3ee136c..70665e5bea075ced6db7696efcffe502 + throw new RuntimeException(throwable); + } + // Folia end - region threading - rewrite login process - } catch (Exception exception) { - ServerConfigurationPacketListenerImpl.LOGGER.error("Couldn't place player in world", exception); + } catch (Exception var5) { + LOGGER.error("Couldn't place player in world", (Throwable)var5); // Paper start - Debugging -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index 3a9e25b436f366fffe08c3b0c1fce11ed42ee646..ae88c6e2635b1608383f8c74813d723f7c6ffaf8 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -167,10 +167,13 @@ public class ServerConnectionListener { - }); - } - // Paper end - Add support for proxy protocol -- pending.add(object); // Paper - prevent blocking on adding a new connection while the server is ticking -+ // Folia - connection fixes - move down - ((Connection) object).configurePacketHandler(channelpipeline); - ((Connection) object).setListenerForServerboundHandshake(new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, (Connection) object)); - io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper - Add Channel initialization listeners -+ // Folia start - regionised threading -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addConnection(object); -+ // Folia end - regionised threading - } - }).group(eventloopgroup).localAddress(address)).option(ChannelOption.AUTO_READ, false).bind().syncUninterruptibly()); // CraftBukkit // Paper - Unix domain socket support - } -@@ -232,7 +235,7 @@ public class ServerConnectionListener { - // Spigot Start +diff --git a/net/minecraft/server/network/ServerConnectionListener.java b/net/minecraft/server/network/ServerConnectionListener.java +index bd07e6a5aa1883786d789ea71711a0c0c0a95c26..09469ad131622158fe5579216fc4164251ff2220 100644 +--- a/net/minecraft/server/network/ServerConnectionListener.java ++++ b/net/minecraft/server/network/ServerConnectionListener.java +@@ -167,12 +167,15 @@ public class ServerConnectionListener { + } + // Paper end - Add support for proxy protocol + // ServerConnectionListener.this.connections.add(connection); // Paper - prevent blocking on adding a new connection while the server is ticking +- ServerConnectionListener.this.pending.add(connection); // Paper - prevent blocking on adding a new connection while the server is ticking ++ //ServerConnectionListener.this.pending.add(connection); // Paper - prevent blocking on adding a new connection while the server is ticking // Folia - connection fixes - move down + connection.configurePacketHandler(channelPipeline); + connection.setListenerForServerboundHandshake( + new ServerHandshakePacketListenerImpl(ServerConnectionListener.this.server, connection) + ); + io.papermc.paper.network.ChannelInitializeListenerHolder.callListeners(channel); // Paper - Add Channel initialization listeners ++ // Folia start - regionised threading ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addConnection(connection); ++ // Folia end - regionised threading + } + } + ) +@@ -242,7 +245,7 @@ public class ServerConnectionListener { + // Spigot start this.addPending(); // Paper - prevent blocking on adding a new connection while the server is ticking // This prevents players from 'gaming' the server, and strategically relogging to increase their position in the tick order -- if ( org.spigotmc.SpigotConfig.playerShuffle > 0 && MinecraftServer.currentTick % org.spigotmc.SpigotConfig.playerShuffle == 0 ) -+ if ( org.spigotmc.SpigotConfig.playerShuffle > 0 && 0 % org.spigotmc.SpigotConfig.playerShuffle == 0 ) // Folia - region threading - { - Collections.shuffle( this.connections ); +- if (org.spigotmc.SpigotConfig.playerShuffle > 0 && MinecraftServer.currentTick % org.spigotmc.SpigotConfig.playerShuffle == 0) { ++ if (org.spigotmc.SpigotConfig.playerShuffle > 0 && 0 % org.spigotmc.SpigotConfig.playerShuffle == 0) { // Folia - region threading + Collections.shuffle(this.connections); } -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a82cf69d0 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -312,7 +312,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private final LastSeenMessagesValidator lastSeenMessages = new LastSeenMessagesValidator(20); - private final MessageSignatureCache messageSignatureCache = MessageSignatureCache.createDefault(); - private final FutureChain chatMessageChain; -- private boolean waitingForSwitchToConfig; -+ public volatile boolean waitingForSwitchToConfig; // Folia - rewrite login process - fix bad ordering of this field write + public - private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length - - public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie clientData) { -@@ -329,10 +329,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - } - - // CraftBukkit start - add fields and methods + // Spigot end +diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +index d248671b2e1c6256fc4d74320bdb29ca078bad0b..8154cec88f2222b7f75c695332e942cf4839b4d9 100644 +--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +@@ -292,10 +292,10 @@ public class ServerGamePacketListenerImpl + private int knownMovePacketCount; + private boolean receivedMovementThisTick; + // CraftBukkit start - add fields - private int lastTick = MinecraftServer.currentTick; + private long lastTick = Util.getMillis() / 50L; // Folia - region threading private int allowedPlayerTicks = 1; @@ -13261,9 +12923,13 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a private int dropCount = 0; private boolean hasMoved = false; -@@ -344,8 +344,21 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - private boolean justTeleported = false; - // CraftBukkit end +@@ -313,9 +313,16 @@ public class ServerGamePacketListenerImpl + private final LastSeenMessagesValidator lastSeenMessages = new LastSeenMessagesValidator(20); + private final MessageSignatureCache messageSignatureCache = MessageSignatureCache.createDefault(); + private final FutureChain chatMessageChain; +- private boolean waitingForSwitchToConfig; ++ public volatile boolean waitingForSwitchToConfig; // Folia - rewrite login process - fix bad ordering of this field write + public + private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length + // Folia start - region threading + public net.minecraft.world.level.ChunkPos disconnectPos; @@ -13272,6 +12938,11 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a + public final Long disconnectTicketId = Long.valueOf(DISCONNECT_TICKET_ID_GENERATOR.getAndIncrement()); + // Folia end - region threading + + public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) { + super(server, connection, cookie, player); // CraftBukkit + this.chunkSender = new PlayerChunkSender(connection.isMemoryConnection()); +@@ -328,6 +335,12 @@ public class ServerGamePacketListenerImpl + @Override public void tick() { + // Folia start - region threading @@ -13283,16 +12954,16 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a if (this.ackBlockChangesUpTo > -1) { this.send(new ClientboundBlockChangedAckPacket(this.ackBlockChangesUpTo)); this.ackBlockChangesUpTo = -1; -@@ -394,7 +407,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -376,7 +389,7 @@ public class ServerGamePacketListenerImpl this.aboveGroundVehicleTickCount = 0; } - this.keepConnectionAlive(); + // Folia - region threading - moved to beginning of method this.chatSpamThrottler.tick(); + this.dropSpamThrottler.tick(); this.tabSpamThrottler.tick(); // Paper - configurable tab spam limits - this.recipeSpamPackets.tick(); // Paper - auto recipe limit -@@ -432,6 +445,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -412,6 +425,19 @@ public class ServerGamePacketListenerImpl this.lastGoodX = this.player.getX(); this.lastGoodY = this.player.getY(); this.lastGoodZ = this.player.getZ(); @@ -13312,7 +12983,7 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a } @Override -@@ -538,9 +564,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -519,9 +545,10 @@ public class ServerGamePacketListenerImpl // Paper end - fix large move vectors killing the server // CraftBukkit start - handle custom speeds and skipped ticks @@ -13325,22 +12996,22 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a ++this.receivedMovePacketCount; int i = this.receivedMovePacketCount - this.knownMovePacketCount; -@@ -614,7 +641,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -588,7 +615,7 @@ public class ServerGamePacketListenerImpl } - entity.absMoveTo(d3, d4, d5, f, f1); -- this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit -+ //this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit // Folia - move to repositionAllPassengers - + rootVehicle.absMoveTo(d, d1, d2, f, f1); +- this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit ++ //this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit // Folia - move to repositionAllPassengers // Paper start - optimise out extra getCubes boolean teleportBack = flag2; // violating this is always a fail -@@ -627,11 +654,19 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + if (!teleportBack) { +@@ -600,11 +627,19 @@ public class ServerGamePacketListenerImpl } if (teleportBack) { // Paper end - optimise out extra getCubes - entity.absMoveTo(d0, d1, d2, f, f1); -- this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit -+ //this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit // Folia - not needed, the player is no longer updated - this.send(ClientboundMoveVehiclePacket.fromEntity(entity)); + rootVehicle.absMoveTo(x, y, z, f, f1); +- this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit ++ //this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit // Folia - not needed, the player is no longer updated + this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle)); return; } @@ -13349,13 +13020,13 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a + // tick, which would make any desync here visible + // this will correctly update the passenger positions for all mounted entities + // this prevents desync and ensures that all passengers have the correct rider-adjusted position -+ entity.repositionAllPassengers(false); ++ rootVehicle.repositionAllPassengers(false); + // Folia end - move to positionRider + // CraftBukkit start - fire PlayerMoveEvent - Player player = this.getCraftPlayer(); + org.bukkit.entity.Player player = this.getCraftPlayer(); if (!this.hasMoved) { -@@ -662,7 +697,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -635,7 +670,7 @@ public class ServerGamePacketListenerImpl // If the event is cancelled we move the player back to their old location. if (event.isCancelled()) { @@ -13364,7 +13035,7 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a return; } -@@ -670,7 +705,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -643,7 +678,7 @@ public class ServerGamePacketListenerImpl // there to avoid any 'Moved wrongly' or 'Moved too quickly' errors. // We only do this if the Event was not cancelled. if (!oldTo.equals(event.getTo()) && !event.isCancelled()) { @@ -13373,16 +13044,16 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a return; } -@@ -838,7 +873,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -817,7 +852,7 @@ public class ServerGamePacketListenerImpl } // This needs to be on main -- this.server.scheduleOnMain(() -> this.sendServerSuggestions(packet, stringreader)); -+ this.player.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> this.sendServerSuggestions(packet, stringreader), null, 1L); // Folia - region threading +- this.server.scheduleOnMain(() -> this.sendServerSuggestions(packet, stringReader)); ++ this.player.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> this.sendServerSuggestions(packet, stringReader), null, 1L); // Folia - region threading } else if (!completions.isEmpty()) { - final com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), stringreader.getTotalLength()); + final com.mojang.brigadier.suggestion.SuggestionsBuilder builder0 = new com.mojang.brigadier.suggestion.SuggestionsBuilder(packet.getCommand(), stringReader.getTotalLength()); final com.mojang.brigadier.suggestion.SuggestionsBuilder builder = builder0.createOffset(builder0.getInput().lastIndexOf(' ') + 1); -@@ -1265,11 +1300,11 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1200,11 +1235,11 @@ public class ServerGamePacketListenerImpl } // Paper end - Book size limits // CraftBukkit start @@ -13394,23 +13065,23 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a - this.lastBookTick = MinecraftServer.currentTick; + this.lastBookTick = this.lastTick; // Folia - region threading // CraftBukkit end - int i = packet.slot(); - -@@ -1286,7 +1321,22 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - this.updateBookContents(list1, i); - }; - -- this.filterTextPacket((List) list).thenAcceptAsync(consumer, this.server); + int slot = packet.slot(); + if (Inventory.isHotbarSlot(slot) || slot == 40) { +@@ -1215,7 +1250,22 @@ public class ServerGamePacketListenerImpl + Consumer> consumer = optional.isPresent() + ? texts -> this.signBook(texts.get(0), texts.subList(1, texts.size()), slot) + : texts -> this.updateBookContents(texts, slot); +- this.filterTextPacket(list).thenAcceptAsync(consumer, this.server); + // Folia start - region threading + this.filterTextPacket(list).thenAcceptAsync( -+ consumer, -+ (Runnable run) -> { -+ this.player.getBukkitEntity().taskScheduler.schedule( -+ (player) -> { -+ run.run(); -+ }, -+ null, 1L); -+ } ++ consumer, ++ (Runnable run) -> { ++ this.player.getBukkitEntity().taskScheduler.schedule( ++ (player) -> { ++ run.run(); ++ }, ++ null, 1L); ++ } + ).whenComplete((Object res, Throwable thr) -> { + if (thr != null) { + LOGGER.error("Failed to handle book update packet", thr); @@ -13420,7 +13091,7 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a } } -@@ -1434,9 +1484,10 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1341,9 +1391,10 @@ public class ServerGamePacketListenerImpl int i = this.receivedMovePacketCount - this.knownMovePacketCount; // CraftBukkit start - handle custom speeds and skipped ticks @@ -13432,8 +13103,8 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a + this.lastTick = (int) currTick; // Folia - region threading if (i > Math.max(this.allowedPlayerTicks, 5)) { - ServerGamePacketListenerImpl.LOGGER.debug("{} is sending move packets too frequently ({} packets since last tick)", this.player.getName().getString(), i); -@@ -1628,7 +1679,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + LOGGER.debug("{} is sending move packets too frequently ({} packets since last tick)", this.player.getName().getString(), i); +@@ -1532,7 +1583,7 @@ public class ServerGamePacketListenerImpl // If the event is cancelled we move the player back to their old location. if (event.isCancelled()) { @@ -13442,7 +13113,7 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a return; } -@@ -1636,7 +1687,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1540,7 +1591,7 @@ public class ServerGamePacketListenerImpl // there to avoid any 'Moved wrongly' or 'Moved too quickly' errors. // We only do this if the Event was not cancelled. if (!oldTo.equals(event.getTo()) && !event.isCancelled()) { @@ -13451,7 +13122,7 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a return; } -@@ -1883,9 +1934,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1799,9 +1850,9 @@ public class ServerGamePacketListenerImpl if (!this.player.isSpectator()) { // limit how quickly items can be dropped // If the ticks aren't the same then the count starts from 0 and we update the lastDropTick. @@ -13463,43 +13134,43 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a } else { // Else we increment the drop count and check the amount. this.dropCount++; -@@ -1913,7 +1964,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1829,7 +1880,7 @@ public class ServerGamePacketListenerImpl case ABORT_DESTROY_BLOCK: case STOP_DESTROY_BLOCK: // Paper start - Don't allow digging into unloaded chunks -- if (this.player.level().getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) == null) { -+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.player.serverLevel(), blockposition.getX() >> 4, blockposition.getZ() >> 4, 8) || this.player.level().getChunkIfLoadedImmediately(blockposition.getX() >> 4, blockposition.getZ() >> 4) == null) { // Folia - region threading - don't destroy blocks not owned +- if (this.player.level().getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null) { ++ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.player.serverLevel(), pos.getX() >> 4, pos.getZ() >> 4, 8) || this.player.level().getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null) { // Folia - region threading - don't destroy blocks not owned this.player.connection.ackBlockChangesUpTo(packet.getSequence()); return; } -@@ -1998,7 +2049,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // Paper end - improve distance check - BlockPos blockposition = movingobjectpositionblock.getBlockPos(); - -- if (this.player.canInteractWithBlock(blockposition, 1.0D)) { -+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.player.serverLevel(), blockposition.getX() >> 4, blockposition.getZ() >> 4, 8) && this.player.canInteractWithBlock(blockposition, 1.0D)) { // Folia - do not allow players to interact with blocks outside the current region - Vec3 vec3d1 = vec3d.subtract(Vec3.atCenterOf(blockposition)); - double d0 = 1.0000001D; - -@@ -2132,7 +2183,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - Entity entity = packet.getEntity(worldserver); - +@@ -1911,7 +1962,7 @@ public class ServerGamePacketListenerImpl + } + // Paper end - improve distance check + BlockPos blockPos = hitResult.getBlockPos(); +- if (this.player.canInteractWithBlock(blockPos, 1.0)) { ++ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.player.serverLevel(), blockPos.getX() >> 4, blockPos.getZ() >> 4, 8) && this.player.canInteractWithBlock(blockPos, 1.0)) { // Folia - do not allow players to interact with blocks outside the current region + Vec3 vec3 = location.subtract(Vec3.atCenterOf(blockPos)); + double d = 1.0000001; + if (Math.abs(vec3.x()) < 1.0000001 && Math.abs(vec3.y()) < 1.0000001 && Math.abs(vec3.z()) < 1.0000001) { +@@ -2032,7 +2083,7 @@ public class ServerGamePacketListenerImpl + for (ServerLevel serverLevel : this.server.getAllLevels()) { + Entity entity = packet.getEntity(serverLevel); if (entity != null) { -- this.player.teleportTo(worldserver, entity.getX(), entity.getY(), entity.getZ(), Set.of(), entity.getYRot(), entity.getXRot(), true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit +- this.player.teleportTo(serverLevel, entity.getX(), entity.getY(), entity.getZ(), Set.of(), entity.getYRot(), entity.getXRot(), true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE); // CraftBukkit + io.papermc.paper.threadedregions.TeleportUtils.teleport(this.player, false, entity, null, null, Entity.TELEPORT_FLAG_LOAD_CHUNK, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.SPECTATE, null); // Folia - region threading return; } } -@@ -2167,7 +2218,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2064,7 +2115,7 @@ public class ServerGamePacketListenerImpl } // CraftBukkit end - ServerGamePacketListenerImpl.LOGGER.info("{} lost connection: {}", this.player.getName().getString(), info.reason().getString()); + LOGGER.info("{} lost connection: {}", this.player.getName().getString(), details.reason().getString()); - this.removePlayerFromWorld(quitMessage); // Paper - Fix kick event leave message not being sent + if (!this.waitingForSwitchToConfig) this.removePlayerFromWorld(quitMessage); // Paper - Fix kick event leave message not being sent // Folia - region threading - super.onDisconnect(info, quitMessage); // Paper - Fix kick event leave message not being sent + super.onDisconnect(details, quitMessage); // Paper - Fix kick event leave message not being sent } -@@ -2176,6 +2227,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2073,6 +2124,8 @@ public class ServerGamePacketListenerImpl this.removePlayerFromWorld(null); } @@ -13508,7 +13179,7 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a private void removePlayerFromWorld(@Nullable net.kyori.adventure.text.Component quitMessage) { // Paper end - Fix kick event leave message not being sent this.chatMessageChain.close(); -@@ -2188,6 +2241,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2086,6 +2139,8 @@ public class ServerGamePacketListenerImpl this.player.disconnect(); // Paper start - Adventure quitMessage = quitMessage == null ? this.server.getPlayerList().remove(this.player) : this.server.getPlayerList().remove(this.player, quitMessage); // Paper - pass in quitMessage to fix kick message not being used @@ -13516,17 +13187,17 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a + if (!this.hackSwitchingConfig) this.player.serverLevel().chunkSource.addTicketAtLevel(DISCONNECT_TICKET, this.disconnectPos, ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.MAX_TICKET_LEVEL, this.disconnectTicketId); // Folia - region threading - force chunk to be loaded so that the region is not lost if ((quitMessage != null) && !quitMessage.equals(net.kyori.adventure.text.Component.empty())) { this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(quitMessage), false); - // Paper end -@@ -2444,7 +2499,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl + // Paper end - Adventure +@@ -2324,7 +2379,7 @@ public class ServerGamePacketListenerImpl this.player.resetLastActionTime(); // CraftBukkit start if (sync) { -- this.server.execute(runnable); -+ this.player.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> runnable.run(), null, 1L); // Folia - region threading +- this.server.execute(handler); ++ this.player.getBukkitEntity().taskScheduler.schedule((ServerPlayer player) -> handler.run(), null, 1L); // Folia - region threading } else { - runnable.run(); + handler.run(); } -@@ -2502,7 +2557,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2379,7 +2434,7 @@ public class ServerGamePacketListenerImpl String originalFormat = event.getFormat(), originalMessage = event.getMessage(); this.cserver.getPluginManager().callEvent(event); @@ -13535,16 +13206,16 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a // Evil plugins still listening to deprecated event final PlayerChatEvent queueEvent = new PlayerChatEvent(player, event.getMessage(), event.getFormat(), event.getRecipients()); queueEvent.setCancelled(event.isCancelled()); -@@ -2600,6 +2655,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - if (s.isEmpty()) { - ServerGamePacketListenerImpl.LOGGER.warn(this.player.getScoreboardName() + " tried to send an empty message"); +@@ -2476,6 +2531,7 @@ public class ServerGamePacketListenerImpl + if (rawMessage.isEmpty()) { + LOGGER.warn("{} tried to send an empty message", this.player.getScoreboardName()); } else if (this.getCraftPlayer().isConversing()) { + if (true) throw new UnsupportedOperationException(); // Folia - region threading - final String conversationInput = s; - this.server.processQueue.add(new Runnable() { - @Override -@@ -2838,8 +2894,25 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - // Spigot End + final String conversationInput = rawMessage; + this.server.processQueue.add(() -> ServerGamePacketListenerImpl.this.getCraftPlayer().acceptConversationInput(conversationInput)); + } else if (this.player.getChatVisibility() == ChatVisiblity.SYSTEM) { // Re-add "Command Only" flag check +@@ -2701,8 +2757,25 @@ public class ServerGamePacketListenerImpl + // Spigot end public void switchToConfig() { - this.waitingForSwitchToConfig = true; @@ -13570,17 +13241,17 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a this.send(ClientboundStartConfigurationPacket.INSTANCE); this.connection.setupOutboundProtocol(ConfigurationProtocols.CLIENTBOUND); } -@@ -2866,7 +2939,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - +@@ -2727,7 +2800,7 @@ public class ServerGamePacketListenerImpl + // Spigot end this.player.resetLastActionTime(); this.player.setShiftKeyDown(packet.isUsingSecondaryAction()); -- if (entity != null) { -+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity) && entity != null) { // Folia - region threading - do not allow interaction of entities outside the current region - if (!worldserver.getWorldBorder().isWithinBounds(entity.blockPosition())) { +- if (target != null) { ++ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(target) && target != null) { // Folia - region threading - do not allow interaction of entities outside the current region + if (!serverLevel.getWorldBorder().isWithinBounds(target.blockPosition())) { return; } -@@ -3014,6 +3087,12 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - switch (packetplayinclientcommand_enumclientcommand) { +@@ -2859,6 +2932,12 @@ public class ServerGamePacketListenerImpl + switch (action) { case PERFORM_RESPAWN: if (this.player.wonGame) { + // Folia start - region threading @@ -13592,7 +13263,7 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a this.player.wonGame = false; this.player = this.server.getPlayerList().respawn(this.player, true, Entity.RemovalReason.CHANGED_DIMENSION, RespawnReason.END_PORTAL); // CraftBukkit this.resetPosition(); -@@ -3023,6 +3102,17 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -2868,6 +2947,17 @@ public class ServerGamePacketListenerImpl return; } @@ -13610,12 +13281,15 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a this.player = this.server.getPlayerList().respawn(this.player, false, Entity.RemovalReason.KILLED, RespawnReason.DEATH); // CraftBukkit this.resetPosition(); if (this.server.isHardcore()) { -@@ -3585,7 +3675,18 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - - this.filterTextPacket(list).thenAcceptAsync((list1) -> { - this.updateSignText(packet, list1); -- }, this.server); -+ }, (Runnable run) -> { // Folia start - region threading +@@ -3413,7 +3503,21 @@ public class ServerGamePacketListenerImpl + } + List list = Stream.of(lines).map(ChatFormatting::stripFormatting).collect(Collectors.toList()); + // Paper end - Limit client sign length +- this.filterTextPacket(list).thenAcceptAsync(list1 -> this.updateSignText(packet, (List)list1), this.server); ++ // Folia start - region threading ++ this.filterTextPacket(list).thenAcceptAsync((list1) -> { ++ this.updateSignText(packet, (List)list1); ++ }, (Runnable run) -> { + this.player.getBukkitEntity().taskScheduler.schedule( + (player) -> { + run.run(); @@ -13629,14 +13303,14 @@ index 84fa24880d02dc7ba1ec8bda3575be38447fd4b2..7783e023e84ab84e3903fc0371aad08a + // Folia end - region threading } - private void updateSignText(ServerboundSignUpdatePacket packet, List signText) { -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 033755682c61c889723c3669b5cff4de147f637e..7fdb9304de7cf1979d57e3fac32415d7c674609d 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java + private void updateSignText(ServerboundSignUpdatePacket packet, List filteredText) { +diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index 6689aeacf50d1498e8d23cce696fb4fecbd1cf39..6173f704b0d093813ec67eb231c75be49a462e7d 100644 +--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -111,7 +111,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - } // Paper end - Do not allow logins while the server is shutting down + if (this.state == ServerLoginPacketListenerImpl.State.VERIFYING) { - if (this.connection.isConnected()) { // Paper - prevent logins to be processed even though disconnect was called + // Folia start - region threading - rewrite login process @@ -13644,19 +13318,19 @@ index 033755682c61c889723c3669b5cff4de147f637e..7fdb9304de7cf1979d57e3fac32415d7 + java.util.UUID uniqueId = this.authenticatedProfile.getId(); + if (this.server.getPlayerList().pushPendingJoin(name, uniqueId, this.connection)) { + // Folia end - region threading - rewrite login process - this.verifyLoginAndFinishConnectionSetup((GameProfile) Objects.requireNonNull(this.authenticatedProfile)); + this.verifyLoginAndFinishConnectionSetup(Objects.requireNonNull(this.authenticatedProfile)); } // Paper - prevent logins to be processed even though disconnect was called } -@@ -257,7 +261,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - })); +@@ -250,7 +254,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + ); } -- boolean flag = playerlist.disconnectAllPlayersWithProfile(gameprofile, this.player); // CraftBukkit - add player reference -+ boolean flag = false && playerlist.disconnectAllPlayersWithProfile(gameprofile, this.player); // CraftBukkit - add player reference // Folia - rewrite login process - always false here - +- boolean flag = playerList.disconnectAllPlayersWithProfile(profile, this.player); // CraftBukkit - add player reference ++ boolean flag = false && playerList.disconnectAllPlayersWithProfile(profile, this.player); // CraftBukkit - add player reference // Folia - rewrite login process - always false here if (flag) { this.state = ServerLoginPacketListenerImpl.State.WAITING_FOR_DUPE_DISCONNECT; -@@ -377,7 +381,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + } else { +@@ -362,7 +366,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, uniqueId = gameprofile.getId(); // Paper end - Add more fields to AsyncPlayerPreLoginEvent @@ -13665,50 +13339,50 @@ index 033755682c61c889723c3669b5cff4de147f637e..7fdb9304de7cf1979d57e3fac32415d7 final PlayerPreLoginEvent event = new PlayerPreLoginEvent(playerName, address, uniqueId); if (asyncEvent.getResult() != PlayerPreLoginEvent.Result.ALLOWED) { event.disallow(asyncEvent.getResult(), asyncEvent.kickMessage()); // Paper - Adventure -diff --git a/src/main/java/net/minecraft/server/players/BanListEntry.java b/src/main/java/net/minecraft/server/players/BanListEntry.java -index 8b1da1fb5ca27432a39aff6dbc452b793268dab5..e83f3676d5a194fa8d3d1567edcb4b6f7847a4c1 100644 ---- a/src/main/java/net/minecraft/server/players/BanListEntry.java -+++ b/src/main/java/net/minecraft/server/players/BanListEntry.java -@@ -10,7 +10,7 @@ import net.minecraft.network.chat.Component; +diff --git a/net/minecraft/server/players/BanListEntry.java b/net/minecraft/server/players/BanListEntry.java +index e111adec2116f922fe67ee434635e50c60dad15c..851d3ae5d37541e6455b83b3300d630e8f6d5c83 100644 +--- a/net/minecraft/server/players/BanListEntry.java ++++ b/net/minecraft/server/players/BanListEntry.java +@@ -9,7 +9,7 @@ import javax.annotation.Nullable; + import net.minecraft.network.chat.Component; public abstract class BanListEntry extends StoredUserEntry { - - public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.ROOT); + public static final ThreadLocal DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.ROOT)); // Folia - region threading - SDF is not thread-safe public static final String EXPIRES_NEVER = "forever"; protected final Date created; protected final String source; -@@ -32,7 +32,7 @@ public abstract class BanListEntry extends StoredUserEntry { - Date date; +@@ -30,7 +30,7 @@ public abstract class BanListEntry extends StoredUserEntry { + Date date; try { -- date = json.has("created") ? BanListEntry.DATE_FORMAT.parse(json.get("created").getAsString()) : new Date(); -+ date = json.has("created") ? BanListEntry.DATE_FORMAT.get().parse(json.get("created").getAsString()) : new Date(); // Folia - region threading - SDF is not thread-safe - } catch (ParseException parseexception) { +- date = entryData.has("created") ? DATE_FORMAT.parse(entryData.get("created").getAsString()) : new Date(); ++ date = entryData.has("created") ? DATE_FORMAT.get().parse(entryData.get("created").getAsString()) : new Date(); // Folia - region threading - SDF is not thread-safe + } catch (ParseException var7) { date = new Date(); } -@@ -43,7 +43,7 @@ public abstract class BanListEntry extends StoredUserEntry { - Date date1; +@@ -40,7 +40,7 @@ public abstract class BanListEntry extends StoredUserEntry { + Date date1; try { -- date1 = json.has("expires") ? BanListEntry.DATE_FORMAT.parse(json.get("expires").getAsString()) : null; -+ date1 = json.has("expires") ? BanListEntry.DATE_FORMAT.get().parse(json.get("expires").getAsString()) : null; // Folia - region threading - SDF is not thread-safe - } catch (ParseException parseexception1) { +- date1 = entryData.has("expires") ? DATE_FORMAT.parse(entryData.get("expires").getAsString()) : null; ++ date1 = entryData.has("expires") ? DATE_FORMAT.get().parse(entryData.get("expires").getAsString()) : null; // Folia - region threading - SDF is not thread-safe + } catch (ParseException var6) { date1 = null; } -@@ -78,9 +78,9 @@ public abstract class BanListEntry extends StoredUserEntry { +@@ -75,9 +75,9 @@ public abstract class BanListEntry extends StoredUserEntry { @Override - protected void serialize(JsonObject json) { -- json.addProperty("created", BanListEntry.DATE_FORMAT.format(this.created)); -+ json.addProperty("created", BanListEntry.DATE_FORMAT.get().format(this.created)); // Folia - region threading - SDF is not thread-safe - json.addProperty("source", this.source); -- json.addProperty("expires", this.expires == null ? "forever" : BanListEntry.DATE_FORMAT.format(this.expires)); -+ json.addProperty("expires", this.expires == null ? "forever" : BanListEntry.DATE_FORMAT.get().format(this.expires)); // Folia - region threading - SDF is not thread-safe - json.addProperty("reason", this.reason); + protected void serialize(JsonObject data) { +- data.addProperty("created", DATE_FORMAT.format(this.created)); ++ data.addProperty("created", DATE_FORMAT.get().format(this.created)); // Folia - region threading - SDF is not thread-safe + data.addProperty("source", this.source); +- data.addProperty("expires", this.expires == null ? "forever" : DATE_FORMAT.format(this.expires)); ++ data.addProperty("expires", this.expires == null ? "forever" : DATE_FORMAT.get().format(this.expires)); // Folia - region threading - SDF is not thread-safe + data.addProperty("reason", this.reason); } -@@ -89,7 +89,7 @@ public abstract class BanListEntry extends StoredUserEntry { +@@ -86,7 +86,7 @@ public abstract class BanListEntry extends StoredUserEntry { Date expires = null; try { @@ -13717,24 +13391,24 @@ index 8b1da1fb5ca27432a39aff6dbc452b793268dab5..e83f3676d5a194fa8d3d1567edcb4b6f } catch (ParseException ex) { // Guess we don't have a date } -diff --git a/src/main/java/net/minecraft/server/players/OldUsersConverter.java b/src/main/java/net/minecraft/server/players/OldUsersConverter.java -index 653856d0b8dcf2baf4cc77a276f17c8cc1fa717e..3f5639f26f249ca10e03826231d087ab715b7ce7 100644 ---- a/src/main/java/net/minecraft/server/players/OldUsersConverter.java -+++ b/src/main/java/net/minecraft/server/players/OldUsersConverter.java -@@ -516,7 +516,7 @@ public class OldUsersConverter { - Date date1; - +diff --git a/net/minecraft/server/players/OldUsersConverter.java b/net/minecraft/server/players/OldUsersConverter.java +index 7dbcd9d96f052bb10127ad2b061154c23cc9ffd4..20d895ed04cd2263560f91ef38dda6aa866bc603 100644 +--- a/net/minecraft/server/players/OldUsersConverter.java ++++ b/net/minecraft/server/players/OldUsersConverter.java +@@ -469,7 +469,7 @@ public class OldUsersConverter { + static Date parseDate(String input, Date defaultValue) { + Date date; try { -- date1 = BanListEntry.DATE_FORMAT.parse(dateString); -+ date1 = BanListEntry.DATE_FORMAT.get().parse(dateString); // Folia - region threading - SDF is not thread-safe - } catch (ParseException parseexception) { - date1 = fallback; +- date = BanListEntry.DATE_FORMAT.parse(input); ++ date = BanListEntry.DATE_FORMAT.get().parse(input); // Folia - region threading - SDF is not thread-safe + } catch (ParseException var4) { + date = defaultValue; } -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb5d2ed44e 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -134,10 +134,10 @@ public abstract class PlayerList { +diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java +index 03feaf0adb8ee87e33744a4615dc2507a02f92d7..65835fa09cdcd3bb158025f7d8b3cb29ac8b2549 100644 +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -110,10 +110,10 @@ public abstract class PlayerList { public static final Component DUPLICATE_LOGIN_DISCONNECT_MESSAGE = Component.translatable("multiplayer.disconnect.duplicate_login"); private static final Logger LOGGER = LogUtils.getLogger(); private static final int SEND_PLAYER_INFO_INTERVAL = 600; @@ -13744,15 +13418,11 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb public final List players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety - private final Map playersByUUID = Maps.newHashMap(); + private final Map playersByUUID = new java.util.concurrent.ConcurrentHashMap<>(); // Folia - region threading - change to CHM - Note: we do NOT expect concurrency PER KEY! - private final UserBanList bans; - private final IpBanList ipBans; - private final ServerOpList ops; -@@ -158,9 +158,63 @@ public abstract class PlayerList { - - // CraftBukkit start - private CraftServer cserver; -- private final Map playersByName = new java.util.HashMap<>(); -+ private final Map playersByName = new java.util.concurrent.ConcurrentHashMap<>(); // Folia - region threading - change to CHM - Note: we do NOT expect concurrency PER KEY! + private final UserBanList bans = new UserBanList(USERBANLIST_FILE); + private final IpBanList ipBans = new IpBanList(IPBANLIST_FILE); + private final ServerOpList ops = new ServerOpList(OPLIST_FILE); +@@ -137,6 +137,60 @@ public abstract class PlayerList { + private final Map playersByName = new java.util.HashMap<>(); public @Nullable String collideRuleTeamName; // Paper - Configurable player collision + // Folia start - region threading @@ -13809,37 +13479,37 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb + } + // Folia end - region threading + - public PlayerList(MinecraftServer server, LayeredRegistryAccess registryManager, PlayerDataStorage saveHandler, int maxPlayers) { - this.cserver = server.server = new CraftServer((DedicatedServer) server, this); + public PlayerList(MinecraftServer server, LayeredRegistryAccess registries, PlayerDataStorage playerIo, int maxPlayers) { + this.cserver = server.server = new org.bukkit.craftbukkit.CraftServer((net.minecraft.server.dedicated.DedicatedServer) server, this); server.console = new com.destroystokyo.paper.console.TerminalConsoleCommandSender(); // Paper -@@ -181,7 +235,7 @@ public abstract class PlayerList { - } +@@ -149,7 +203,7 @@ public abstract class PlayerList { + abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor -- public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData) { -+ public void loadSpawnForNewPlayer(final Connection connection, final ServerPlayer player, final CommonListenerCookie clientData, org.apache.commons.lang3.mutable.MutableObject data, org.apache.commons.lang3.mutable.MutableObject lastKnownName, ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { // Folia - region threading - rewrite login process +- public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie cookie) { ++ public void loadSpawnForNewPlayer(final Connection connection, final ServerPlayer player, final CommonListenerCookie cookie, org.apache.commons.lang3.mutable.MutableObject data, org.apache.commons.lang3.mutable.MutableObject lastKnownName, ca.spottedleaf.concurrentutil.completable.CallbackCompletable toComplete) { // Folia - region threading - rewrite login process player.isRealPlayer = true; // Paper player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed - GameProfile gameprofile = player.getGameProfile(); -@@ -258,18 +312,42 @@ public abstract class PlayerList { + GameProfile gameProfile = player.getGameProfile(); +@@ -221,17 +275,41 @@ public abstract class PlayerList { player.spawnReason = org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT; // set Player SpawnReason to DEFAULT on first login // Paper start - reset to main world spawn if first spawn or invalid world } + // Folia start - region threading - rewrite login process + // must write to these before toComplete is invoked + data.setValue(optional.orElse(null)); -+ lastKnownName.setValue(s); ++ lastKnownName.setValue(string); + // Folia end - region threading - rewrite login process if (optional.isEmpty() || invalidPlayerWorld[0]) { // Paper end - reset to main world spawn if first spawn or invalid world -- player.moveTo(player.adjustSpawnLocation(worldserver1, worldserver1.getSharedSpawnPos()).getBottomCenter(), worldserver1.getSharedSpawnAngle(), 0.0F); // Paper - MC-200092 - fix first spawn pos yaw being ignored -+ ServerPlayer.fudgeSpawnLocation(worldserver1, player, toComplete); // Paper - MC-200092 - fix first spawn pos yaw being ignored // Folia - region threading +- player.moveTo(player.adjustSpawnLocation(serverLevel, serverLevel.getSharedSpawnPos()).getBottomCenter(), serverLevel.getSharedSpawnAngle(), 0.0F); // Paper - MC-200092 - fix first spawn pos yaw being ignored ++ ServerPlayer.fudgeSpawnLocation(serverLevel, player, toComplete); // Paper - MC-200092 - fix first spawn pos yaw being ignored // Folia - region threading + } else { -+ worldserver1.loadChunksForMoveAsync( ++ serverLevel.loadChunksForMoveAsync( + player.getBoundingBox(), + ca.spottedleaf.concurrentutil.util.Priority.HIGHER, + (c) -> { -+ toComplete.complete(io.papermc.paper.util.MCUtil.toLocation(worldserver1, player.position())); ++ toComplete.complete(io.papermc.paper.util.MCUtil.toLocation(serverLevel, player.position())); + } + ); } @@ -13850,43 +13520,43 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb + } + // optional -> player data + // s -> last known name -+ public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie clientData, Optional optional, String s, Location selectedSpawn) { -+ ServerLevel worldserver1 = ((CraftWorld)selectedSpawn.getWorld()).getHandle(); ++ public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie cookie, Optional optional, String string, org.bukkit.Location selectedSpawn) { ++ ServerLevel serverLevel = ((org.bukkit.craftbukkit.CraftWorld)selectedSpawn.getWorld()).getHandle(); + player.setPosRaw(selectedSpawn.getX(), selectedSpawn.getY(), selectedSpawn.getZ()); + player.lastSave = System.nanoTime(); // changed to nanoTime + // Folia end - region threading - rewrite login process - player.setServerLevel(worldserver1); - String s1 = connection.getLoggableAddress(this.server.logIPs()); - + player.setServerLevel(serverLevel); + String loggableAddress = connection.getLoggableAddress(this.server.logIPs()); // Spigot start - spawn location event - Player spawnPlayer = player.getBukkitEntity(); + org.bukkit.entity.Player spawnPlayer = player.getBukkitEntity(); org.spigotmc.event.player.PlayerSpawnLocationEvent ev = new org.spigotmc.event.player.PlayerSpawnLocationEvent(spawnPlayer, spawnPlayer.getLocation()); - this.cserver.getPluginManager().callEvent(ev); + //this.cserver.getPluginManager().callEvent(ev); // Folia - region threading - TODO WTF TO DO WITH THIS EVENT? - Location loc = ev.getSpawnLocation(); - worldserver1 = ((CraftWorld) loc.getWorld()).getHandle(); -@@ -288,6 +366,10 @@ public abstract class PlayerList { - - player.loadGameTypes((CompoundTag) optional.orElse(null)); // CraftBukkit - decompile error - ServerGamePacketListenerImpl playerconnection = new ServerGamePacketListenerImpl(this.server, connection, player, clientData); + org.bukkit.Location loc = ev.getSpawnLocation(); + serverLevel = ((org.bukkit.craftbukkit.CraftWorld) loc.getWorld()).getHandle(); +@@ -254,6 +332,11 @@ public abstract class PlayerList { + LevelData levelData = serverLevel.getLevelData(); + player.loadGameTypes(optional.orElse(null)); + ServerGamePacketListenerImpl serverGamePacketListenerImpl = new ServerGamePacketListenerImpl(this.server, connection, player, cookie); + // Folia start - rewrite login process + // only after setting the connection listener to game type, add the connection to this regions list -+ worldserver1.getCurrentWorldData().connections.add(connection); ++ serverLevel.getCurrentWorldData().connections.add(connection); + // Folia end - rewrite login process - - connection.setupInboundProtocol(GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())), playerconnection); - GameRules gamerules = worldserver1.getGameRules(); -@@ -307,7 +389,7 @@ public abstract class PlayerList { ++ + connection.setupInboundProtocol( + GameProtocols.SERVERBOUND_TEMPLATE.bind(RegistryFriendlyByteBuf.decorator(this.server.registryAccess())), serverGamePacketListenerImpl + ); +@@ -287,7 +370,7 @@ public abstract class PlayerList { this.sendPlayerPermissionLevel(player); player.getStats().markAllDirty(); player.getRecipeBook().sendInitialRecipeBook(player); -- this.updateEntireScoreboard(worldserver1.getScoreboard(), player); -+ if (false) this.updateEntireScoreboard(worldserver1.getScoreboard(), player); // Folia - region threading +- this.updateEntireScoreboard(serverLevel.getScoreboard(), player); ++ //this.updateEntireScoreboard(serverLevel.getScoreboard(), player); // Folia - region threading this.server.invalidateStatus(); - MutableComponent ichatmutablecomponent; - -@@ -350,7 +432,7 @@ public abstract class PlayerList { + MutableComponent mutableComponent; + if (player.getGameProfile().getName().equalsIgnoreCase(string)) { +@@ -327,7 +410,7 @@ public abstract class PlayerList { this.cserver.getPluginManager().callEvent(playerJoinEvent); if (!player.connection.isAcceptingMessages()) { @@ -13895,7 +13565,7 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb } final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage(); -@@ -365,8 +447,7 @@ public abstract class PlayerList { +@@ -342,8 +425,7 @@ public abstract class PlayerList { ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); // Paper - Add Listing API for Player final List onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join @@ -13905,7 +13575,7 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb if (entityplayer1.getBukkitEntity().canSee(bukkitPlayer)) { // Paper start - Add Listing API for Player -@@ -415,7 +496,7 @@ public abstract class PlayerList { +@@ -392,7 +474,7 @@ public abstract class PlayerList { // Paper start - Configurable player collision; Add to collideRule team if needed final net.minecraft.world.scores.Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard(); final PlayerTeam collideRuleTeam = scoreboard.getPlayerTeam(this.collideRuleTeamName); @@ -13914,16 +13584,16 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb scoreboard.addPlayerToTeam(player.getScoreboardName(), collideRuleTeam); } // Paper end - Configurable player collision -@@ -518,7 +599,7 @@ public abstract class PlayerList { +@@ -482,7 +564,7 @@ public abstract class PlayerList { protected void save(ServerPlayer player) { if (!player.getBukkitEntity().isPersistent()) return; // CraftBukkit - player.lastSave = MinecraftServer.currentTick; // Paper - Incremental chunk and player saving + player.lastSave = System.nanoTime(); // Folia - region threading - changed to nanoTime tracking this.playerIo.save(player); - ServerStatsCounter serverstatisticmanager = (ServerStatsCounter) player.getStats(); // CraftBukkit - -@@ -558,7 +639,7 @@ public abstract class PlayerList { + ServerStatsCounter serverStatsCounter = player.getStats(); // CraftBukkit + if (serverStatsCounter != null) { +@@ -517,7 +599,7 @@ public abstract class PlayerList { // CraftBukkit end // Paper start - Configurable player collision; Remove from collideRule team if needed @@ -13931,39 +13601,39 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb + if (false && this.collideRuleTeamName != null) { // Folia - region threading final net.minecraft.world.scores.Scoreboard scoreBoard = this.server.getLevel(Level.OVERWORLD).getScoreboard(); final PlayerTeam team = scoreBoard.getPlayersTeam(this.collideRuleTeamName); - if (entityplayer.getTeam() == team && team != null) { -@@ -612,7 +693,7 @@ public abstract class PlayerList { + if (player.getTeam() == team && team != null) { +@@ -566,7 +648,7 @@ public abstract class PlayerList { } - worldserver.removePlayerImmediately(entityplayer, Entity.RemovalReason.UNLOADED_WITH_PLAYER); -- entityplayer.retireScheduler(); // Paper - Folia schedulers -+ // Folia - region threading - move to onDisconnect of common packet listener - entityplayer.getAdvancements().stopListening(); - this.players.remove(entityplayer); - this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot -@@ -631,8 +712,7 @@ public abstract class PlayerList { + serverLevel.removePlayerImmediately(player, Entity.RemovalReason.UNLOADED_WITH_PLAYER); +- player.retireScheduler(); // Paper - Folia schedulers ++ //player.retireScheduler(); // Paper - Folia schedulers // Folia - region threading - move to onDisconnect of common packet listener + player.getAdvancements().stopListening(); + this.players.remove(player); + this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot +@@ -584,8 +666,7 @@ public abstract class PlayerList { // CraftBukkit start - // this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID()))); - ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(entityplayer.getUUID())); + // this.broadcastAll(new ClientboundPlayerInfoRemovePacket(List.of(player.getUUID()))); + ClientboundPlayerInfoRemovePacket packet = new ClientboundPlayerInfoRemovePacket(List.of(player.getUUID())); - for (int i = 0; i < this.players.size(); i++) { -- ServerPlayer entityplayer2 = (ServerPlayer) this.players.get(i); -+ for (ServerPlayer entityplayer2 : this.players) { // Folia - region threading +- ServerPlayer otherPlayer = (ServerPlayer) this.players.get(i); ++ for (ServerPlayer otherPlayer : this.players) { // Folia - region threading - if (entityplayer2.getBukkitEntity().canSee(entityplayer.getBukkitEntity())) { - entityplayer2.connection.send(packet); -@@ -657,19 +737,12 @@ public abstract class PlayerList { + if (otherPlayer.getBukkitEntity().canSee(player.getBukkitEntity())) { + otherPlayer.connection.send(packet); +@@ -609,19 +690,12 @@ public abstract class PlayerList { ServerPlayer entityplayer; - for (int i = 0; i < this.players.size(); ++i) { - entityplayer = (ServerPlayer) this.players.get(i); -- if (entityplayer.getUUID().equals(uuid) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameprofile.getName()))) { // Paper - validate usernames +- if (entityplayer.getUUID().equals(uuid) || (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && entityplayer.getGameProfile().getName().equalsIgnoreCase(gameProfile.getName()))) { // Paper - validate usernames - list.add(entityplayer); - } - } + // Folia - region threading - rewrite login process - moved to pushPendingJoin - Iterator iterator = list.iterator(); + java.util.Iterator iterator = list.iterator(); while (iterator.hasNext()) { - entityplayer = (ServerPlayer) iterator.next(); @@ -13973,59 +13643,60 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb } // Instead of kicking then returning, we need to store the kick reason -@@ -689,7 +762,7 @@ public abstract class PlayerList { - - ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned.reason", gameprofilebanentry.getReason()); - if (gameprofilebanentry.getExpires() != null) { -- ichatmutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned.expiration", PlayerList.BAN_DATE_FORMAT.format(gameprofilebanentry.getExpires()))); -+ ichatmutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned.expiration", PlayerList.BAN_DATE_FORMAT.get().format(gameprofilebanentry.getExpires()))); // Folia - region threading - SDF is not thread-safe +@@ -641,7 +715,7 @@ public abstract class PlayerList { + MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned.reason", userBanListEntry.getReason()); + if (userBanListEntry.getExpires() != null) { + mutableComponent.append( +- Component.translatable("multiplayer.disconnect.banned.expiration", BAN_DATE_FORMAT.format(userBanListEntry.getExpires())) ++ Component.translatable("multiplayer.disconnect.banned.expiration", BAN_DATE_FORMAT.get().format(userBanListEntry.getExpires())) // Folia - region threading - SDF is not thread-safe + ); } - // return chatmessage; -@@ -702,14 +775,14 @@ public abstract class PlayerList { - - ichatmutablecomponent = Component.translatable("multiplayer.disconnect.banned_ip.reason", ipbanentry.getReason()); - if (ipbanentry.getExpires() != null) { -- ichatmutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned_ip.expiration", PlayerList.BAN_DATE_FORMAT.format(ipbanentry.getExpires()))); -+ ichatmutablecomponent.append((Component) Component.translatable("multiplayer.disconnect.banned_ip.expiration", PlayerList.BAN_DATE_FORMAT.get().format(ipbanentry.getExpires()))); // Folia - region threading - SDF is not thread-safe +@@ -655,7 +729,7 @@ public abstract class PlayerList { + MutableComponent mutableComponent = Component.translatable("multiplayer.disconnect.banned_ip.reason", ipBanListEntry.getReason()); + if (ipBanListEntry.getExpires() != null) { + mutableComponent.append( +- Component.translatable("multiplayer.disconnect.banned_ip.expiration", BAN_DATE_FORMAT.format(ipBanListEntry.getExpires())) ++ Component.translatable("multiplayer.disconnect.banned_ip.expiration", BAN_DATE_FORMAT.get().format(ipBanListEntry.getExpires())) // Folia - region threading - SDF is not thread-safe + ); } - // return chatmessage; - event.disallow(PlayerLoginEvent.Result.KICK_BANNED, io.papermc.paper.adventure.PaperAdventure.asAdventure(ichatmutablecomponent)); // Paper - Adventure - } else { - // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile) ? IChatBaseComponent.translatable("multiplayer.disconnect.server_full") : null; -- if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameprofile)) { -+ if (!this.countConnection(loginlistener.connection, this.maxPlayers) && !this.canBypassPlayerLimit(gameprofile)) { // Folia - region threading - we control connection state here now async, not player list size - event.disallow(PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure +@@ -665,7 +739,7 @@ public abstract class PlayerList { + // return this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameProfile) + // ? Component.translatable("multiplayer.disconnect.server_full") + // : null; +- if (this.players.size() >= this.maxPlayers && !this.canBypassPlayerLimit(gameProfile)) { ++ if (!this.countConnection(loginlistener.connection, this.maxPlayers) && !this.canBypassPlayerLimit(gameProfile)) { // Folia - region threading - we control connection state here now async, not player list size + event.disallow(org.bukkit.event.player.PlayerLoginEvent.Result.KICK_FULL, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(org.spigotmc.SpigotConfig.serverFullMessage)); // Spigot // Paper - Adventure } } -@@ -769,6 +842,11 @@ public abstract class PlayerList { +@@ -714,6 +788,11 @@ public abstract class PlayerList { + return this.respawn(player, keepInventory, reason, eventReason, null); } - - public ServerPlayer respawn(ServerPlayer entityplayer, boolean flag, Entity.RemovalReason entity_removalreason, RespawnReason reason, Location location) { + public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason eventReason, org.bukkit.Location location) { + // Folia start - region threading + if (true) { + throw new UnsupportedOperationException("Must use teleportAsync while in region threading"); + } + // Folia end - region threading - entityplayer.stopRiding(); // CraftBukkit - this.players.remove(entityplayer); - this.playersByName.remove(entityplayer.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot -@@ -945,10 +1023,10 @@ public abstract class PlayerList { + player.stopRiding(); // CraftBukkit + this.players.remove(player); + this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot +@@ -884,10 +963,10 @@ public abstract class PlayerList { public void tick() { if (++this.sendAllPlayerInfoIn > 600) { // CraftBukkit start - for (int i = 0; i < this.players.size(); ++i) { -- final ServerPlayer target = (ServerPlayer) this.players.get(i); +- final ServerPlayer target = this.players.get(i); + ServerPlayer[] players = this.players.toArray(new ServerPlayer[0]); // Folia - region threading + for (final ServerPlayer target : players) { // Folia - region threading -- target.connection.send(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), this.players.stream().filter(new Predicate() { -+ target.connection.send(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), java.util.Arrays.stream(players).filter(new Predicate() { // Folia - region threading - @Override - public boolean test(ServerPlayer input) { - return target.getBukkitEntity().canSee(input.getBukkitEntity()); -@@ -974,18 +1052,17 @@ public abstract class PlayerList { +- target.connection.send(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), com.google.common.collect.Collections2.filter(this.players, t -> target.getBukkitEntity().canSee(t.getBukkitEntity())))); ++ target.connection.send(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY), com.google.common.collect.Collections2.filter(java.util.Arrays.asList(players),t -> target.getBukkitEntity().canSee(t.getBukkitEntity())))); // Folia - region threading + } + // CraftBukkit end + this.sendAllPlayerInfoIn = 0; +@@ -896,18 +975,17 @@ public abstract class PlayerList { // CraftBukkit start - add a world/entity limited version public void broadcastAll(Packet packet, net.minecraft.world.entity.player.Player entityhuman) { @@ -14048,74 +13719,73 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb } } -@@ -1029,8 +1106,7 @@ public abstract class PlayerList { - if (scoreboardteam == null) { +@@ -944,8 +1022,7 @@ public abstract class PlayerList { + if (team == null) { this.broadcastSystemMessage(message, false); } else { -- for (int i = 0; i < this.players.size(); ++i) { -- ServerPlayer entityplayer = (ServerPlayer) this.players.get(i); -+ for (ServerPlayer entityplayer : this.players) { // Folia - region threading - - if (entityplayer.getTeam() != scoreboardteam) { - entityplayer.sendSystemMessage(message); -@@ -1041,10 +1117,12 @@ public abstract class PlayerList { +- for (int i = 0; i < this.players.size(); i++) { +- ServerPlayer serverPlayer = this.players.get(i); ++ for (ServerPlayer serverPlayer : this.players) { // Folia - region threading + if (serverPlayer.getTeam() != team) { + serverPlayer.sendSystemMessage(message); + } +@@ -954,10 +1031,11 @@ public abstract class PlayerList { } public String[] getPlayerNamesArray() { -- String[] astring = new String[this.players.size()]; -+ List players = new java.util.ArrayList<>(this.players); // Folia start - region threading -+ String[] astring = new String[players.size()]; ++ List players = new java.util.ArrayList<>(this.players); // Folia - region threading + String[] strings = new String[this.players.size()]; -- for (int i = 0; i < this.players.size(); ++i) { -- astring[i] = ((ServerPlayer) this.players.get(i)).getGameProfile().getName(); -+ for (int i = 0; i < players.size(); ++i) { -+ astring[i] = ((ServerPlayer) players.get(i)).getGameProfile().getName(); -+ // Folia end - region threading +- for (int i = 0; i < this.players.size(); i++) { +- strings[i] = this.players.get(i).getGameProfile().getName(); ++ for (int i = 0; i < players.size(); i++) { // Folia - region threading ++ strings[i] = players.get(i).getGameProfile().getName(); // Folia - region threading } - return astring; -@@ -1063,7 +1141,9 @@ public abstract class PlayerList { - ServerPlayer entityplayer = this.getPlayer(profile.getId()); - - if (entityplayer != null) { -+ entityplayer.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { // Folia - region threading - this.sendPlayerPermissionLevel(entityplayer); + return strings; +@@ -975,7 +1053,9 @@ public abstract class PlayerList { + this.ops.add(new ServerOpListEntry(profile, this.server.getOperatorUserPermissionLevel(), this.ops.canBypassPlayerLimit(profile))); + ServerPlayer player = this.getPlayer(profile.getId()); + if (player != null) { +- this.sendPlayerPermissionLevel(player); ++ player.getBukkitEntity().taskScheduler.schedule((ServerPlayer serverPlayer) -> { // Folia - region threading ++ this.sendPlayerPermissionLevel(serverPlayer); // Folia - region threading + }, null, 1L); // Folia - region threading } - } -@@ -1073,7 +1153,10 @@ public abstract class PlayerList { - ServerPlayer entityplayer = this.getPlayer(profile.getId()); - if (entityplayer != null) { -+ entityplayer.getBukkitEntity().taskScheduler.schedule((nmsEntity) -> { // Folia - region threading - this.sendPlayerPermissionLevel(entityplayer); +@@ -983,7 +1063,9 @@ public abstract class PlayerList { + this.ops.remove(profile); + ServerPlayer player = this.getPlayer(profile.getId()); + if (player != null) { +- this.sendPlayerPermissionLevel(player); ++ player.getBukkitEntity().taskScheduler.schedule((ServerPlayer serverPlayer) -> { // Folia - region threading ++ this.sendPlayerPermissionLevel(serverPlayer); // Folia - region threading + }, null, 1L); // Folia - region threading -+ } - - } -@@ -1136,8 +1219,7 @@ public abstract class PlayerList { } - public void broadcast(@Nullable net.minecraft.world.entity.player.Player player, double x, double y, double z, double distance, ResourceKey worldKey, Packet packet) { -- for (int i = 0; i < this.players.size(); ++i) { -- ServerPlayer entityplayer = (ServerPlayer) this.players.get(i); -+ for (ServerPlayer entityplayer : this.players) { // Folia - region threading +@@ -1046,8 +1128,7 @@ public abstract class PlayerList { + } + public void broadcast(@Nullable Player except, double x, double y, double z, double radius, ResourceKey dimension, Packet packet) { +- for (int i = 0; i < this.players.size(); i++) { +- ServerPlayer serverPlayer = this.players.get(i); ++ for (ServerPlayer serverPlayer : this.players) { // Folia - region threading // CraftBukkit start - Test if player receiving packet can see the source of the packet - if (player != null && !entityplayer.getBukkitEntity().canSee(player.getBukkitEntity())) { -@@ -1166,10 +1248,15 @@ public abstract class PlayerList { - public void saveAll(int interval) { + if (except != null && !serverPlayer.getBukkitEntity().canSee(except.getBukkitEntity())) { + continue; +@@ -1072,10 +1153,15 @@ public abstract class PlayerList { + public void saveAll(final int interval) { io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main int numSaved = 0; -- long now = MinecraftServer.currentTick; -- for (int i = 0; i < this.players.size(); ++i) { +- final long now = MinecraftServer.currentTick; +- for (int i = 0; i < this.players.size(); i++) { - final ServerPlayer player = this.players.get(i); - if (interval == -1 || now - player.lastSave >= interval) { -+ long now = System.nanoTime(); // Folia - region threading ++ final long now = System.nanoTime(); // Folia - region threading + long timeInterval = (long)interval * io.papermc.paper.threadedregions.TickRegionScheduler.TIME_BETWEEN_TICKS; // Folia - region threading -+ for (ServerPlayer player : this.players) { // Folia - region threading ++ for (final ServerPlayer player : this.players) { // Folia - region threading + // Folia start - region threading + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player)) { + continue; @@ -14123,9 +13793,9 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb + // Folia end - region threading + if (interval == -1 || now - player.lastSave >= timeInterval) { // Folia - region threading this.save(player); - if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; } - } -@@ -1290,6 +1377,20 @@ public abstract class PlayerList { + if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { + break; +@@ -1194,6 +1280,20 @@ public abstract class PlayerList { } public void removeAll(boolean isRestarting) { @@ -14146,7 +13816,7 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb // Paper end // CraftBukkit start - disconnect safely for (ServerPlayer player : this.players) { -@@ -1299,7 +1400,7 @@ public abstract class PlayerList { +@@ -1203,7 +1303,7 @@ public abstract class PlayerList { // CraftBukkit end // Paper start - Configurable player collision; Remove collideRule team if it exists @@ -14155,55 +13825,54 @@ index 9b71655a425356132afb786eff623f558e1e3498..b449de44b1911e2ff0701956bfba53fb final net.minecraft.world.scores.Scoreboard scoreboard = this.getServer().getLevel(Level.OVERWORLD).getScoreboard(); final PlayerTeam team = scoreboard.getPlayersTeam(this.collideRuleTeamName); if (team != null) scoreboard.removePlayerTeam(team); -diff --git a/src/main/java/net/minecraft/server/players/StoredUserList.java b/src/main/java/net/minecraft/server/players/StoredUserList.java -index c038da20b76c0b7b1c18471b20be01e849d29f3a..87114cc9ce7489ff8e29e2d88ebb0d47eb68232e 100644 ---- a/src/main/java/net/minecraft/server/players/StoredUserList.java -+++ b/src/main/java/net/minecraft/server/players/StoredUserList.java -@@ -103,6 +103,7 @@ public abstract class StoredUserList> { +diff --git a/net/minecraft/server/players/StoredUserList.java b/net/minecraft/server/players/StoredUserList.java +index d445e8f126f077d8419c52fa5436ea963a1a42a4..cabbc68f7cd5fd326c7ffd3b02b3ec4a4390f5b0 100644 +--- a/net/minecraft/server/players/StoredUserList.java ++++ b/net/minecraft/server/players/StoredUserList.java +@@ -97,6 +97,7 @@ public abstract class StoredUserList> { } public void save() throws IOException { + synchronized (this) { // Folia - region threading this.removeExpired(); // Paper - remove expired values before saving - JsonArray jsonarray = new JsonArray(); - Stream stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error -@@ -133,10 +134,12 @@ public abstract class StoredUserList> { - if (bufferedwriter != null) { - bufferedwriter.close(); + JsonArray jsonArray = new JsonArray(); + this.map.values().stream().map(storedEntry -> Util.make(new JsonObject(), storedEntry::serialize)).forEach(jsonArray::add); +@@ -104,9 +105,11 @@ public abstract class StoredUserList> { + try (BufferedWriter writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) { + GSON.toJson(jsonArray, GSON.newJsonWriter(writer)); } + } // Folia - region threading - } public void load() throws IOException { + synchronized (this) { // Folia - region threading if (this.file.exists()) { - BufferedReader bufferedreader = Files.newReader(this.file, StandardCharsets.UTF_8); - -@@ -193,5 +196,6 @@ public abstract class StoredUserList> { + try (BufferedReader reader = Files.newReader(this.file, StandardCharsets.UTF_8)) { + this.map.clear(); +@@ -131,5 +134,6 @@ public abstract class StoredUserList> { } - + // Spigot end } + } // Folia - region threading } } -diff --git a/src/main/java/net/minecraft/util/SpawnUtil.java b/src/main/java/net/minecraft/util/SpawnUtil.java -index a8903f087c75c851e8111b96e5aa9f271d618392..27fb5cd80b33fdca0ff8785072c469ff9a42aa6a 100644 ---- a/src/main/java/net/minecraft/util/SpawnUtil.java -+++ b/src/main/java/net/minecraft/util/SpawnUtil.java -@@ -61,7 +61,7 @@ public class SpawnUtil { - return Optional.of(t0); +diff --git a/net/minecraft/util/SpawnUtil.java b/net/minecraft/util/SpawnUtil.java +index f6fad24af884c8a37723c57718cee0096443efe6..ef75a71aee2576254e2c0752cc759c9637af9d69 100644 +--- a/net/minecraft/util/SpawnUtil.java ++++ b/net/minecraft/util/SpawnUtil.java +@@ -83,7 +83,7 @@ public class SpawnUtil { + return Optional.of(mob); } -- t0.discard(null); // CraftBukkit - add Bukkit remove cause -+ //t0.discard(null); // CraftBukkit - add Bukkit remove cause // Folia - region threading +- mob.discard(null); // CraftBukkit - add Bukkit remove cause ++ //mob.discard(null); // CraftBukkit - add Bukkit remove cause // Folia - region threading } } } -diff --git a/src/main/java/net/minecraft/world/RandomSequences.java b/src/main/java/net/minecraft/world/RandomSequences.java -index 75631d9368bfc4baec1631db4f7dbfcc2c6d8ac5..320e113db209881d5dd619c6056a19a18b988e4c 100644 ---- a/src/main/java/net/minecraft/world/RandomSequences.java -+++ b/src/main/java/net/minecraft/world/RandomSequences.java +diff --git a/net/minecraft/world/RandomSequences.java b/net/minecraft/world/RandomSequences.java +index f8e93fe461794058a26c90510cbd7698fa43b8f7..c1a62556546b05f79dad37875993c19bf9bb7c67 100644 +--- a/net/minecraft/world/RandomSequences.java ++++ b/net/minecraft/world/RandomSequences.java @@ -21,7 +21,7 @@ public class RandomSequences extends SavedData { private int salt; private boolean includeWorldSeed = true; @@ -14212,8 +13881,8 @@ index 75631d9368bfc4baec1631db4f7dbfcc2c6d8ac5..320e113db209881d5dd619c6056a19a1 + private final Map sequences = new java.util.concurrent.ConcurrentHashMap<>(); // Folia - region threading public static SavedData.Factory factory(long seed) { - return new SavedData.Factory<>(() -> new RandomSequences(seed), (nbt, registries) -> load(seed, nbt), DataFixTypes.SAVED_DATA_RANDOM_SEQUENCES); -@@ -114,61 +114,61 @@ public class RandomSequences extends SavedData { + return new SavedData.Factory<>( +@@ -120,61 +120,61 @@ public class RandomSequences extends SavedData { @Override public RandomSource fork() { RandomSequences.this.setDirty(); @@ -14285,19 +13954,19 @@ index 75631d9368bfc4baec1631db4f7dbfcc2c6d8ac5..320e113db209881d5dd619c6056a19a1 } @Override -diff --git a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -index 99a7e9eb75231c15bd8bb24fbb4e296bc9fdedff..b4a081392b68ccb869392f93ee1f259f0d4f6adc 100644 ---- a/src/main/java/net/minecraft/world/damagesource/CombatTracker.java -+++ b/src/main/java/net/minecraft/world/damagesource/CombatTracker.java +diff --git a/net/minecraft/world/damagesource/CombatTracker.java b/net/minecraft/world/damagesource/CombatTracker.java +index d3de87eaf0eb84af77165391c7b94085d425f21d..019d1435cfe7769ed85b40c1c19d2d271d96f913 100644 +--- a/net/minecraft/world/damagesource/CombatTracker.java ++++ b/net/minecraft/world/damagesource/CombatTracker.java @@ -53,7 +53,7 @@ public class CombatTracker { } - private Component getMessageForAssistedFall(Entity attacker, Component attackerDisplayName, String itemDeathTranslationKey, String deathTranslationKey) { -- ItemStack itemStack = attacker instanceof LivingEntity livingEntity ? livingEntity.getMainHandItem() : ItemStack.EMPTY; -+ ItemStack itemStack = attacker instanceof LivingEntity livingEntity && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(livingEntity) ? livingEntity.getMainHandItem() : ItemStack.EMPTY; // Folia - region threading + private Component getMessageForAssistedFall(Entity entity, Component entityDisplayName, String hasWeaponTranslationKey, String noWeaponTranslationKey) { +- ItemStack itemStack = entity instanceof LivingEntity livingEntity ? livingEntity.getMainHandItem() : ItemStack.EMPTY; ++ ItemStack itemStack = entity instanceof LivingEntity livingEntity && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(livingEntity) ? livingEntity.getMainHandItem() : ItemStack.EMPTY; // Folia - region threading return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME) - ? Component.translatable(itemDeathTranslationKey, this.mob.getDisplayName(), attackerDisplayName, itemStack.getDisplayName()) - : Component.translatable(deathTranslationKey, this.mob.getDisplayName(), attackerDisplayName); + ? Component.translatable(hasWeaponTranslationKey, this.mob.getDisplayName(), entityDisplayName, itemStack.getDisplayName()) + : Component.translatable(noWeaponTranslationKey, this.mob.getDisplayName(), entityDisplayName); @@ -80,7 +80,7 @@ public class CombatTracker { @Nullable @@ -14307,44 +13976,43 @@ index 99a7e9eb75231c15bd8bb24fbb4e296bc9fdedff..b4a081392b68ccb869392f93ee1f259f } public Component getDeathMessage() { -diff --git a/src/main/java/net/minecraft/world/damagesource/DamageSource.java b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -index bb1a60180e58c1333e7bb33e8acf1b0225eda8a8..bc7568c26e6f2b64365712b31d5fce708a0a272d 100644 ---- a/src/main/java/net/minecraft/world/damagesource/DamageSource.java -+++ b/src/main/java/net/minecraft/world/damagesource/DamageSource.java -@@ -178,13 +178,13 @@ public class DamageSource { - LivingEntity entityliving1 = killed.getKillCredit(); - String s1 = s + ".player"; - -- return entityliving1 != null ? Component.translatable(s1, killed.getDisplayName(), entityliving1.getDisplayName()) : Component.translatable(s, killed.getDisplayName()); -+ return entityliving1 != null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entityliving1) ? Component.translatable(s1, killed.getDisplayName(), entityliving1.getDisplayName()) : Component.translatable(s, killed.getDisplayName()); // Folia - region threading +diff --git a/net/minecraft/world/damagesource/DamageSource.java b/net/minecraft/world/damagesource/DamageSource.java +index 48c9b26e023ad236b0bcb6441e8aee8f107ae381..08779c641b3b8d8e2dcd734a4124a3c57a032cbd 100644 +--- a/net/minecraft/world/damagesource/DamageSource.java ++++ b/net/minecraft/world/damagesource/DamageSource.java +@@ -178,12 +178,12 @@ public class DamageSource { + if (this.causingEntity == null && this.directEntity == null) { + LivingEntity killCredit = livingEntity.getKillCredit(); + String string1 = string + ".player"; +- return killCredit != null ++ return killCredit != null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(killCredit) + ? Component.translatable(string1, livingEntity.getDisplayName(), killCredit.getDisplayName()) + : Component.translatable(string, livingEntity.getDisplayName()); } else { - Component ichatbasecomponent = this.causingEntity == null ? this.directEntity.getDisplayName() : this.causingEntity.getDisplayName(); - Entity entity = this.causingEntity; - ItemStack itemstack; - -- if (entity instanceof LivingEntity) { -+ if (entity instanceof LivingEntity livingEntity && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(livingEntity)) { // Folia - region threading - LivingEntity entityliving2 = (LivingEntity) entity; - - itemstack = entityliving2.getMainHandItem(); -diff --git a/src/main/java/net/minecraft/world/damagesource/FallLocation.java b/src/main/java/net/minecraft/world/damagesource/FallLocation.java -index e9df8f8541b8a1b85c7d2925ff3cba813007a1ef..d3f2775a68121ca80ef55ea4c280a0c9fcae2db3 100644 ---- a/src/main/java/net/minecraft/world/damagesource/FallLocation.java -+++ b/src/main/java/net/minecraft/world/damagesource/FallLocation.java + Component component = this.causingEntity == null ? this.directEntity.getDisplayName() : this.causingEntity.getDisplayName(); +- ItemStack itemStack = this.causingEntity instanceof LivingEntity livingEntity1 ? livingEntity1.getMainHandItem() : ItemStack.EMPTY; ++ ItemStack itemStack = this.causingEntity instanceof LivingEntity livingEntity1 && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(livingEntity1) ? livingEntity1.getMainHandItem() : ItemStack.EMPTY; // Folia - region threading + return !itemStack.isEmpty() && itemStack.has(DataComponents.CUSTOM_NAME) + ? Component.translatable(string + ".item", livingEntity.getDisplayName(), component, itemStack.getDisplayName()) + : Component.translatable(string, livingEntity.getDisplayName(), component); +diff --git a/net/minecraft/world/damagesource/FallLocation.java b/net/minecraft/world/damagesource/FallLocation.java +index a3c7d68469075bf8d33f2016149a181b0fb87e0e..73c581d3ee21d8fa96eae3e47afd6ce204e03160 100644 +--- a/net/minecraft/world/damagesource/FallLocation.java ++++ b/net/minecraft/world/damagesource/FallLocation.java @@ -35,7 +35,7 @@ public record FallLocation(String id) { @Nullable public static FallLocation getCurrentFallLocation(LivingEntity entity) { - Optional optional = entity.getLastClimbablePos(); -- if (optional.isPresent()) { -+ if (optional.isPresent() && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)entity.level(), optional.get())) { // Folia - region threading - BlockState blockState = entity.level().getBlockState(optional.get()); + Optional lastClimbablePos = entity.getLastClimbablePos(); +- if (lastClimbablePos.isPresent()) { ++ if (lastClimbablePos.isPresent() && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)entity.level(), lastClimbablePos.get())) { // Folia - region threading + BlockState blockState = entity.level().getBlockState(lastClimbablePos.get()); return blockToFallLocation(blockState); } else { -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a5406252f 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -186,7 +186,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java +index 1d0151a042ed5de4e235ef0bdac1a0e8240e85e7..dded82842fb0fc8f4b176c69f37f07e8400b7605 100644 +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -145,7 +145,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } // Paper start - Share random for entities to make them more random @@ -14353,25 +14021,25 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a // Paper start - replace random private static final class RandomRandomSource extends ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom { public RandomRandomSource() { -@@ -216,7 +216,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -175,7 +175,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason; // Paper - Entity#getEntitySpawnReason public boolean collisionLoadChunks = false; // Paper -- private CraftEntity bukkitEntity; -+ private volatile CraftEntity bukkitEntity; // Folia - region threading +- private org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity; ++ private volatile org.bukkit.craftbukkit.entity.CraftEntity bukkitEntity; // Folia - region threading - public CraftEntity getBukkitEntity() { + public org.bukkit.craftbukkit.entity.CraftEntity getBukkitEntity() { if (this.bukkitEntity == null) { -@@ -339,7 +339,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -294,7 +294,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess private boolean hasGlowingTag; - private final Set tags; - private final double[] pistonDeltas; + private final Set tags = new io.papermc.paper.util.SizeLimitedSet<>(new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(), MAX_ENTITY_TAG_COUNT); // Paper - fully limit tag size - replace set impl + private final double[] pistonDeltas = new double[]{0.0, 0.0, 0.0}; - private long pistonDeltasGameTime; + private long pistonDeltasGameTime = Long.MIN_VALUE; // Folia - region threading private EntityDimensions dimensions; private float eyeHeight; public boolean isInPowderSnow; -@@ -568,6 +568,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -525,6 +525,19 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } // Paper end - optimise entity tracker @@ -14389,9 +14057,9 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a + } + // Folia end - region ticking - public Entity(EntityType type, Level world) { - this.id = Entity.ENTITY_COUNTER.incrementAndGet(); -@@ -719,8 +732,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + public Entity(EntityType entityType, Level level) { + this.type = entityType; +@@ -655,8 +668,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess // due to interactions on the client. public void resendPossiblyDesyncedEntityData(net.minecraft.server.level.ServerPlayer player) { if (player.getBukkitEntity().canSee(this.getBukkitEntity())) { @@ -14401,7 +14069,7 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a if (tracker == null) { return; } -@@ -887,7 +899,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -823,7 +835,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess public void postTick() { // No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities @@ -14410,8 +14078,8 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a } } // CraftBukkit end -@@ -906,7 +918,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - --this.boardingCooldown; +@@ -841,7 +853,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.boardingCooldown--; } - if (this instanceof ServerPlayer) this.handlePortal(); // CraftBukkit - // Moved up to postTick @@ -14419,7 +14087,7 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a if (this.canSpawnSprintParticle()) { this.spawnSprintParticle(); } -@@ -1186,8 +1198,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -1104,8 +1116,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } else { this.wasOnFire = this.isOnFire(); if (type == MoverType.PISTON) { @@ -14430,16 +14098,16 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a movement = this.limitPistonMovement(movement); if (movement.equals(Vec3.ZERO)) { return; -@@ -1501,7 +1513,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (movement.lengthSqr() <= 1.0E-7D) { - return movement; +@@ -1404,7 +1416,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + if (pos.lengthSqr() <= 1.0E-7) { + return pos; } else { -- long i = this.level().getGameTime(); -+ long i = this.level().getRedstoneGameTime(); // Folia - region threading - - if (i != this.pistonDeltasGameTime) { - Arrays.fill(this.pistonDeltas, 0.0D); -@@ -3324,7 +3336,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +- long gameTime = this.level().getGameTime(); ++ long gameTime = this.level().getRedstoneGameTime(); // Folia - region threading + if (gameTime != this.pistonDeltasGameTime) { + Arrays.fill(this.pistonDeltas, 0.0); + this.pistonDeltasGameTime = gameTime; +@@ -3126,7 +3138,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.passengers = ImmutableList.copyOf(list); } @@ -14448,49 +14116,47 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a } } -@@ -3372,7 +3384,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3174,7 +3186,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } - entity.boardingCooldown = 60; -- this.gameEvent(GameEvent.ENTITY_DISMOUNT, entity); -+ if (!entity.hasNullCallback()) this.gameEvent(GameEvent.ENTITY_DISMOUNT, entity); // Folia - region threading - do not fire game events for entities not added + passenger.boardingCooldown = 60; +- this.gameEvent(GameEvent.ENTITY_DISMOUNT, passenger); ++ if (!passenger.hasNullCallback()) this.gameEvent(GameEvent.ENTITY_DISMOUNT, passenger); // Folia - region threading - do not fire game events for entities not added } return true; // CraftBukkit } -@@ -3459,7 +3471,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3258,7 +3270,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } - protected void handlePortal() { + public boolean handlePortal() { // Folia - region threading - public, ret type -> boolean - Level world = this.level(); - - if (world instanceof ServerLevel worldserver) { -@@ -3470,23 +3482,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - - gameprofilerfiller.push("portal"); + if (this.level() instanceof ServerLevel serverLevel) { + this.processPortalCooldown(); + if (this.portalProcess != null) { +@@ -3266,21 +3278,20 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("portal"); this.setPortalCooldown(); -- TeleportTransition teleporttransition = this.portalProcess.getPortalDestination(worldserver, this); -- -- if (teleporttransition != null) { -- ServerLevel worldserver1 = teleporttransition.newLevel(); -- -- if (this instanceof ServerPlayer || (worldserver1 != null && (worldserver1.dimension() == worldserver.dimension() || this.canTeleport(worldserver, worldserver1)))) { // CraftBukkit - always call event for players -- this.teleport(teleporttransition); +- TeleportTransition portalDestination = this.portalProcess.getPortalDestination(serverLevel, this); +- if (portalDestination != null) { +- ServerLevel level = portalDestination.newLevel(); +- if (this instanceof ServerPlayer // CraftBukkit - always call event for players +- || (level != null && (level.dimension() == serverLevel.dimension() || this.canTeleport(serverLevel, level)))) { // CraftBukkit +- this.teleport(portalDestination); - } + // Folia start - region threading + try { -+ return this.portalProcess.portalAsync(worldserver, this); ++ return this.portalProcess.portalAsync(serverLevel, this); + } finally { -+ gameprofilerfiller.pop(); ++ profilerFiller.pop(); } - -- gameprofilerfiller.pop(); +- profilerFiller.pop(); + // Folia end - region threading } else if (this.portalProcess.hasExpired()) { this.portalProcess = null; } - } } + @@ -14498,7 +14164,7 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a } public int getDimensionChangingDelay() { -@@ -3627,6 +3637,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -3420,6 +3431,11 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @Nullable public PlayerTeam getTeam() { @@ -14510,8 +14176,8 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a if (!this.level().paperConfig().scoreboards.allowNonPlayerEntitiesOnScoreboards && !(this instanceof Player)) { return null; } // Paper - Perf: Disable Scoreboards for non players by default return this.level().getScoreboard().getPlayersTeam(this.getScoreboardName()); } -@@ -3920,8 +3935,782 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - this.portalProcess = original.portalProcess; +@@ -3726,8 +3742,782 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + this.portalProcess = entity.portalProcess; } + // Folia start - region threading @@ -15284,17 +14950,17 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a + // Folia end - region threading + @Nullable - public Entity teleport(TeleportTransition teleportTarget) { + public Entity teleport(TeleportTransition teleportTransition) { + // Folia start - region threading + if (true) { + throw new UnsupportedOperationException("Must use teleportAsync while in region threading"); + } + // Folia end - region threading - Level world = this.level(); - // Paper start - Fix item duplication and teleport issues -@@ -4126,6 +4915,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - + if ((!this.isAlive() || !this.valid) && (teleportTransition.newLevel() != this.level)) { + LOGGER.warn("Illegal Entity Teleport " + this + " to " + teleportTransition.newLevel() + ":" + teleportTransition.position(), new Throwable()); +@@ -3911,6 +4701,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } } + // Folia start - region threading - move inventory clearing until after the dimension change @@ -15306,18 +14972,18 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a protected void removeAfterChangingDimensions() { this.setRemoved(Entity.RemovalReason.CHANGED_DIMENSION, null); // CraftBukkit - add Bukkit remove cause if (this instanceof Leashable leashable && leashable.isLeashed()) { // Paper - only call if it is leashed -@@ -5059,7 +5854,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4790,7 +5586,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess } } // Paper end - Fix MC-4 - if (this.position.x != x || this.position.y != y || this.position.z != z) { -+ boolean posChanged = this.position.x != x || this.position.y != y || this.position.z != z; // Folia - region threading ++ boolean posChanged = this.position.x != x || this.position.y != y || this.position.z != z; + if (posChanged) { // Folia - region threading - synchronized (this.posLock) { // Paper + synchronized (this.posLock) { // Paper - detailed watchdog information this.position = new Vec3(x, y, z); - } // Paper -@@ -5080,7 +5876,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - + } // Paper - detailed watchdog information +@@ -4809,7 +5606,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } // Paper start - Block invalid positions and bounding box; don't allow desync of pos and AABB // hanging has its own special logic - if (!(this instanceof net.minecraft.world.entity.decoration.HangingEntity) && (forceBoundingBoxUpdate || this.position.x != x || this.position.y != y || this.position.z != z)) { @@ -15325,7 +14991,7 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a this.setBoundingBox(this.makeBoundingBox()); } // Paper end - Block invalid positions and bounding box -@@ -5163,6 +5959,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4893,6 +5690,12 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess return this.removalReason != null; } @@ -15338,17 +15004,17 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a @Nullable public Entity.RemovalReason getRemovalReason() { return this.removalReason; -@@ -5185,6 +5987,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - CraftEventFactory.callEntityRemoveEvent(this, cause); +@@ -4915,6 +5718,9 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + org.bukkit.craftbukkit.event.CraftEventFactory.callEntityRemoveEvent(this, cause); // CraftBukkit end final boolean alreadyRemoved = this.removalReason != null; // Paper - Folia schedulers + // Folia start - region threading -+ this.preRemove(entity_removalreason); ++ this.preRemove(removalReason); + // Folia end - region threading if (this.removalReason == null) { - this.removalReason = entity_removalreason; + this.removalReason = removalReason; } -@@ -5208,6 +6013,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess +@@ -4938,6 +5744,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess this.removalReason = null; } @@ -15359,12 +15025,12 @@ index 7ac7d0729705cb02f22277be3c467aed4f69ec0e..35ff983cd84cb610b70e193220a97a3a // Paper start - Folia schedulers /** * Invoked only when the entity is truly removed from the server, never to be added to any world. -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..e6871fb4b58910043e88ea45564363aa854eb0ca 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -274,7 +274,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - private Optional lastClimbablePos; +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index 239c443ddc9bacc08a39a8ef2ab17016a2480549..8f9e64590400039566ee5c9628d82a0eb9e56be1 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -278,7 +278,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + private Optional lastClimbablePos = Optional.empty(); @Nullable private DamageSource lastDamageSource; - private long lastDamageStamp; @@ -15372,10 +15038,10 @@ index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..e6871fb4b58910043e88ea45564363aa protected int autoSpinAttackTicks; protected float autoSpinAttackDmg; @Nullable -@@ -308,6 +308,21 @@ public abstract class LivingEntity extends Entity implements Attackable { - ++this.noActionTime; // Above all the floats +@@ -307,6 +307,21 @@ public abstract class LivingEntity extends Entity implements Attackable { + return this.getYHeadRot(); } - // Spigot end + // CraftBukkit end + // Folia start - region threading + @Override + public void updateTicks(long fromTickOffset, long fromRedstoneTimeOffset) { @@ -15392,9 +15058,9 @@ index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..e6871fb4b58910043e88ea45564363aa + } + // Folia end - region threading - protected LivingEntity(EntityType type, Level world) { - super(type, world); -@@ -535,7 +550,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + protected LivingEntity(EntityType entityType, Level level) { + super(entityType, level); +@@ -528,7 +543,7 @@ public abstract class LivingEntity extends Entity implements Attackable { if (this.isDeadOrDying() && this.level().shouldTickDeath(this)) { this.tickDeath(); @@ -15402,54 +15068,53 @@ index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..e6871fb4b58910043e88ea45564363aa + } else { this.broadcastedDeath = false; } // Folia - region threading if (this.lastHurtByPlayerTime > 0) { - --this.lastHurtByPlayerTime; -@@ -625,11 +640,14 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.lastHurtByPlayerTime--; +@@ -611,11 +626,14 @@ public abstract class LivingEntity extends Entity implements Attackable { return true; } + public boolean broadcastedDeath = false; // Folia - region threading protected void tickDeath() { - ++this.deathTime; -- if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved()) { -+ if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved() && !this.broadcastedDeath) { // Folia - region threading - this.level().broadcastEntityEvent(this, (byte) 60); + this.deathTime++; + if (this.deathTime >= 20 && !this.level().isClientSide() && !this.isRemoved()) { + this.level().broadcastEntityEvent(this, (byte)60); - this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause + this.broadcastedDeath = true; // Folia - region threading - death has been broadcasted -+ if (!(this instanceof ServerPlayer)) this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause // Folia - region threading - don't remove, we want the tick scheduler to be running ++ if (!(this instanceof ServerPlayer)) this.remove(Entity.RemovalReason.KILLED, EntityRemoveEvent.Cause.DEATH); // CraftBukkit - add Bukkit remove cause // Folia - region threading - don't remove, we want the tick scheduler to be running + if ((this instanceof ServerPlayer)) this.unRide(); // Folia - region threading - unmount player when dead } - } -@@ -888,9 +906,9 @@ public abstract class LivingEntity extends Entity implements Attackable { + +@@ -851,9 +869,9 @@ public abstract class LivingEntity extends Entity implements Attackable { } - this.hurtTime = nbt.getShort("HurtTime"); -- this.deathTime = nbt.getShort("DeathTime"); -+ this.deathTime = nbt.getShort("DeathTime"); this.broadcastedDeath = false; // Folia - region threading - this.lastHurtByMobTimestamp = nbt.getInt("HurtByTimestamp"); -- if (nbt.contains("Team", 8)) { -+ if (false && nbt.contains("Team", 8)) { // Folia start - region threading - String s = nbt.getString("Team"); + this.hurtTime = compound.getShort("HurtTime"); +- this.deathTime = compound.getShort("DeathTime"); ++ this.deathTime = compound.getShort("DeathTime"); this.broadcastedDeath = false; // Folia - region threading + this.lastHurtByMobTimestamp = compound.getInt("HurtByTimestamp"); +- if (compound.contains("Team", 8)) { ++ if (false && compound.contains("Team", 8)) { // Folia start - region threading + String string = compound.getString("Team"); Scoreboard scoreboard = this.level().getScoreboard(); - PlayerTeam scoreboardteam = scoreboard.getPlayerTeam(s); -@@ -1167,6 +1185,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) { + PlayerTeam playerTeam = scoreboard.getPlayerTeam(string); +@@ -1115,6 +1133,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause, boolean fireEvent) { // Paper end - Don't fire sync event during generation // org.spigotmc.AsyncCatcher.catchOp("effect add"); // Spigot // Paper - move to API + if (!this.hasNullCallback()) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot add effects to entities asynchronously"); // Folia - region threading if (this.isTickingEffects) { - this.effectsToProcess.add(new ProcessableEffect(mobeffect, cause)); + this.effectsToProcess.add(new ProcessableEffect(effectInstance, cause)); return true; -@@ -1596,7 +1615,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - +@@ -1502,7 +1521,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + boolean flag2 = !flag; // CraftBukkit - Ensure to return false if damage is blocked if (flag2) { - this.lastDamageSource = source; + this.lastDamageSource = damageSource; - this.lastDamageStamp = this.level().getGameTime(); + this.lastDamageStamp = this.level().getRedstoneGameTime(); // Folia - region threading - Iterator iterator = this.getActiveEffects().iterator(); - while (iterator.hasNext()) { -@@ -1748,7 +1767,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + for (MobEffectInstance mobEffectInstance : this.getActiveEffects()) { + mobEffectInstance.onMobHurt(level, this, damageSource, amount); +@@ -1629,7 +1648,7 @@ public abstract class LivingEntity extends Entity implements Attackable { @Nullable public DamageSource getLastDamageSource() { @@ -15458,16 +15123,20 @@ index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..e6871fb4b58910043e88ea45564363aa this.lastDamageSource = null; } -@@ -2560,7 +2579,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2420,10 +2439,10 @@ public abstract class LivingEntity extends Entity implements Attackable { @Nullable public LivingEntity getKillCredit() { -- return (LivingEntity) (this.lastHurtByPlayer != null ? this.lastHurtByPlayer : (this.lastHurtByMob != null ? this.lastHurtByMob : null)); -+ return (LivingEntity) (this.lastHurtByPlayer != null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.lastHurtByPlayer) ? this.lastHurtByPlayer : (this.lastHurtByMob != null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.lastHurtByMob) ? this.lastHurtByMob : null)); // Folia - region threading +- if (this.lastHurtByPlayer != null) { ++ if (this.lastHurtByPlayer != null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.lastHurtByPlayer)) { // Folia - region threading + return this.lastHurtByPlayer; + } else { +- return this.lastHurtByMob != null ? this.lastHurtByMob : null; ++ return this.lastHurtByMob != null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.lastHurtByMob) ? this.lastHurtByMob : null; // Folia - region threading + } } - public final float getMaxHealth() { -@@ -2637,7 +2656,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2502,7 +2521,7 @@ public abstract class LivingEntity extends Entity implements Attackable { } this.lastDamageSource = damageSource; @@ -15476,29 +15145,29 @@ index 96b4fbe4a4655777ff10b32e3257e2fac2aba12a..e6871fb4b58910043e88ea45564363aa } @Override -@@ -3703,7 +3722,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -3479,7 +3498,7 @@ public abstract class LivingEntity extends Entity implements Attackable { this.pushEntities(); - gameprofilerfiller.pop(); + profilerFiller.pop(); // Paper start - Add EntityMoveEvent -- if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { -+ if (((ServerLevel) this.level()).getCurrentWorldData().hasEntityMoveEvent && !(this instanceof net.minecraft.world.entity.player.Player)) { // Folia - region threading +- if (((ServerLevel) this.level()).hasEntityMoveEvent && !(this instanceof Player)) { ++ if (((ServerLevel) this.level()).getCurrentWorldData().hasEntityMoveEvent && !(this instanceof Player)) { // Folia - region threading if (this.xo != this.getX() || this.yo != this.getY() || this.zo != this.getZ() || this.yRotO != this.getYRot() || this.xRotO != this.getXRot()) { Location from = new Location(this.level().getWorld(), this.xo, this.yo, this.zo, this.yRotO, this.xRotO); Location to = new Location(this.level().getWorld(), this.getX(), this.getY(), this.getZ(), this.getYRot(), this.getXRot()); -@@ -4413,7 +4432,7 @@ public abstract class LivingEntity extends Entity implements Attackable { - BlockPos blockposition = BlockPos.containing(d0, d1, d2); - Level world = this.level(); +@@ -4152,7 +4171,7 @@ public abstract class LivingEntity extends Entity implements Attackable { + boolean flag = false; + BlockPos blockPos = BlockPos.containing(x, y, z); + Level level = this.level(); +- if (level.hasChunkAt(blockPos)) { ++ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((ServerLevel)level, blockPos) && level.hasChunkAt(blockPos)) { // Folia - region threading + boolean flag1 = false; -- if (world.hasChunkAt(blockposition)) { -+ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((ServerLevel)world, blockposition) && world.hasChunkAt(blockposition)) { // Folia - region threading - boolean flag2 = false; - - while (!flag2 && blockposition.getY() > world.getMinY()) { -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 5a0b51342f4a646101f4588697bcae7d1ca8a010..e48728723e9f765099fc1cea8e6a2baa48d7fc75 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -292,9 +292,21 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab + while (!flag1 && blockPos.getY() > level.getMinY()) { +diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java +index 1ed07fd23985a6bf8cf8300f74c92b7531a79fc6..6394b0899095b047ca9266135fc44aa0c32467cf 100644 +--- a/net/minecraft/world/entity/Mob.java ++++ b/net/minecraft/world/entity/Mob.java +@@ -254,8 +254,20 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab @Nullable @Override public LivingEntity getTarget() { @@ -15508,59 +15177,59 @@ index 5a0b51342f4a646101f4588697bcae7d1ca8a010..e48728723e9f765099fc1cea8e6a2baa + return null; + } + // Folia end - region threading - return this.target; - } - -+ // Folia start - region threading -+ public LivingEntity getTargetRaw() { + return this.target; + } -+ // Folia end - region threading + ++ // Folia start - region threading ++ public LivingEntity getTargetRaw() { + return this.target; + } ++ // Folia end - region threading + @Nullable protected final LivingEntity getTargetFromBrain() { - return (LivingEntity) this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null); // CraftBukkit - decompile error -@@ -306,7 +318,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab +@@ -268,7 +280,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab } - public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) { -- if (this.getTarget() == entityliving) return false; -+ if (this.getTargetRaw() == entityliving) return false; // Folia - region threading + public boolean setTarget(LivingEntity target, EntityTargetEvent.TargetReason reason, boolean fireEvent) { +- if (this.getTarget() == target) { ++ if (this.getTargetRaw() == target) { // Folia - region threading + return false; + } if (fireEvent) { - if (reason == EntityTargetEvent.TargetReason.UNKNOWN && this.getTarget() != null && entityliving == null) { - reason = this.getTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED; -@@ -1779,16 +1791,22 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab - this.goalSelector.removeAllGoals(predicate); - } - -+ // Folia start - region threading - move inventory clearing until after the dimension change +@@ -1663,12 +1675,26 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab @Override -- protected void removeAfterChangingDimensions() { -- super.removeAfterChangingDimensions(); + protected void removeAfterChangingDimensions() { + super.removeAfterChangingDimensions(); ++ // Folia start - region threading - move inventory clearing until after the dimension change - move into postRemoveAfterChangingDimensions ++// this.getAllSlots().forEach(itemStack -> { ++// if (!itemStack.isEmpty()) { ++// itemStack.setCount(0); ++// } ++// }); ++ // Folia end - region threading - move inventory clearing until after the dimension change - move into postRemoveAfterChangingDimensions ++ } ++ ++ // Folia start - region threading ++ @Override + protected void postRemoveAfterChangingDimensions() { - this.getAllSlots().forEach((itemstack) -> { - if (!itemstack.isEmpty()) { - itemstack.setCount(0); ++ super.postRemoveAfterChangingDimensions(); + this.getAllSlots().forEach(itemStack -> { + if (!itemStack.isEmpty()) { + itemStack.setCount(0); } -- }); } -+ // Folia end - region threading - move inventory clearing until after the dimension change -+ -+ @Override -+ protected void removeAfterChangingDimensions() { -+ super.removeAfterChangingDimensions(); -+ // Folia - region threading - move inventory clearing until after the dimension change - move into postRemoveAfterChangingDimensions -+ } ++ // Folia end - region threading @Nullable @Override -diff --git a/src/main/java/net/minecraft/world/entity/PortalProcessor.java b/src/main/java/net/minecraft/world/entity/PortalProcessor.java -index b4a8249964786d484aa0767d0e73d71d2156f0e8..0ee15cb6cc2698c511b2ba274f976d32bb5fbf4c 100644 ---- a/src/main/java/net/minecraft/world/entity/PortalProcessor.java -+++ b/src/main/java/net/minecraft/world/entity/PortalProcessor.java +diff --git a/net/minecraft/world/entity/PortalProcessor.java b/net/minecraft/world/entity/PortalProcessor.java +index 88b07fbb96b20124777889830afa480673629d43..46d989aef0eceebd98bfd93999153319de77a8a0 100644 +--- a/net/minecraft/world/entity/PortalProcessor.java ++++ b/net/minecraft/world/entity/PortalProcessor.java @@ -33,6 +33,12 @@ public class PortalProcessor { - return this.portal.getPortalDestination(world, entity, this.entryPosition); + return this.portal.getPortalDestination(level, entity, this.entryPosition); } + // Folia start - region threading @@ -15572,30 +15241,30 @@ index b4a8249964786d484aa0767d0e73d71d2156f0e8..0ee15cb6cc2698c511b2ba274f976d32 public Portal.Transition getPortalLocalTransition() { return this.portal.getLocalTransition(); } -diff --git a/src/main/java/net/minecraft/world/entity/TamableAnimal.java b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -index 68224d1cdabdaf04e4d26dd07e222a312e8fc898..d66795269c955db6b871143a63b5e7fde3d68289 100644 ---- a/src/main/java/net/minecraft/world/entity/TamableAnimal.java -+++ b/src/main/java/net/minecraft/world/entity/TamableAnimal.java -@@ -288,6 +288,11 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { - LivingEntity entityliving = this.getOwner(); - - if (entityliving != null) { +diff --git a/net/minecraft/world/entity/TamableAnimal.java b/net/minecraft/world/entity/TamableAnimal.java +index fc3ba135ae502aaa5c3a9fa3297bf7b12c1ab063..b0b1e38f2b70ed548790fd0445db4541c34b0f34 100644 +--- a/net/minecraft/world/entity/TamableAnimal.java ++++ b/net/minecraft/world/entity/TamableAnimal.java +@@ -263,6 +263,11 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + public void tryToTeleportToOwner() { + LivingEntity owner = this.getOwner(); + if (owner != null) { + // Folia start - region threading -+ if (entityliving.isRemoved() || entityliving.level() != this.level()) { ++ if (owner.isRemoved() || owner.level() != this.level()) { + return; + } + // Folia end - region threading - this.teleportToAroundBlockPos(entityliving.blockPosition()); + this.teleportToAroundBlockPos(owner.blockPosition()); } - -@@ -325,7 +330,22 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { + } +@@ -295,7 +300,22 @@ public abstract class TamableAnimal extends Animal implements OwnableEntity { return false; } - Location to = event.getTo(); + org.bukkit.Location to = event.getTo(); - this.moveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); + // Folia start - region threading - can't teleport here, we may be removed by teleport logic - delay until next tick + // also, use teleportAsync so that crossing region boundaries will not blow up -+ Location finalTo = to; ++ org.bukkit.Location finalTo = to; + Level sourceWorld = this.level(); + this.getBukkitEntity().taskScheduler.schedule((TamableAnimal nmsEntity) -> { + if (nmsEntity.level() == sourceWorld) { @@ -15612,14 +15281,14 @@ index 68224d1cdabdaf04e4d26dd07e222a312e8fc898..d66795269c955db6b871143a63b5e7fd // CraftBukkit end this.navigation.stop(); return true; -diff --git a/src/main/java/net/minecraft/world/entity/ai/Brain.java b/src/main/java/net/minecraft/world/entity/ai/Brain.java -index af6f91c66e9cc7e0d491e6efed992a140947155e..d4e6198fdfbefe54e374479a1f1d835ab98ce93a 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/Brain.java -+++ b/src/main/java/net/minecraft/world/entity/ai/Brain.java -@@ -424,9 +424,17 @@ public class Brain { +diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java +index 450396468b23fd90cb8036dbbdd0927051f907af..65b2b3ece213d901cdd585093e2fafcd2ef4a7cd 100644 +--- a/net/minecraft/world/entity/ai/Brain.java ++++ b/net/minecraft/world/entity/ai/Brain.java +@@ -425,9 +425,17 @@ public class Brain { } - public void stopAll(ServerLevel world, E entity) { + public void stopAll(ServerLevel level, E owner) { + // Folia start - region threading + List> behaviors = this.getRunningBehaviors(); + if (behaviors.isEmpty()) { @@ -15628,62 +15297,62 @@ index af6f91c66e9cc7e0d491e6efed992a140947155e..d4e6198fdfbefe54e374479a1f1d835a + return; + } + // Folia end - region threading - long l = entity.level().getGameTime(); + long gameTime = owner.level().getGameTime(); - for (BehaviorControl behaviorControl : this.getRunningBehaviors()) { + for (BehaviorControl behaviorControl : behaviors) { // Folia - region threading - behaviorControl.doStop(world, entity, l); + behaviorControl.doStop(level, owner, gameTime); } } -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java b/src/main/java/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java -index 7302d397d39d8400527ab2da4adaf8d792256749..ee3b8de9b700202da776c68579532bf11319a001 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java +diff --git a/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java b/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java +index b11a16db0ea22ebd68db9c96e0ba0939b6596caf..9f5b5ad2fe08f25f4c922ae641d1a2e8bce18ccb 100644 +--- a/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java ++++ b/net/minecraft/world/entity/ai/behavior/PoiCompetitorScan.java @@ -19,6 +19,11 @@ public class PoiCompetitorScan { - context, - (jobSite, mobs) -> (world, entity, time) -> { - GlobalPos globalPos = context.get(jobSite); -+ // Folia start - region threading -+ if (globalPos.dimension() != world.dimension() || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(world, globalPos.pos())) { -+ return true; -+ } -+ // Folia end - region threading - world.getPoiManager() - .getType(globalPos.pos()) - .ifPresent( -diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java -index 15d7be9ed4a973044dd4399db46aaa244730b836..df4cce1d3baef0ad386f5bc201663ae569e7b36d 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java -+++ b/src/main/java/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java + instance, + (jobSite, nearestLivingEntities) -> (level, villager, gameTime) -> { + GlobalPos globalPos = instance.get(jobSite); ++ // Folia start - region threading ++ if (globalPos.dimension() != level.dimension() || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, globalPos.pos())) { ++ return true; ++ } ++ // Folia end - region threading + level.getPoiManager() + .getType(globalPos.pos()) + .ifPresent( +diff --git a/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java b/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java +index dde287e823f906681e3addf03fa821c8786c9900..e5e3ce6eeb01ac4387eaee20d09ef469d8b3bc5e 100644 +--- a/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java ++++ b/net/minecraft/world/entity/ai/goal/FollowOwnerGoal.java @@ -51,7 +51,7 @@ public class FollowOwnerGoal extends Goal { public boolean canContinueToUse() { return !this.navigation.isDone() && !this.tamable.unableToMoveToOwner() -- && !(this.tamable.distanceToSqr(this.owner) <= (double)(this.stopDistance * this.stopDistance)); -+ && !(this.owner.level() == this.tamable.level() && this.tamable.distanceToSqr(this.owner) <= (double)(this.stopDistance * this.stopDistance)); // Folia - region threading - check level +- && !(this.tamable.distanceToSqr(this.owner) <= this.stopDistance * this.stopDistance); ++ && !(this.owner.level() == this.tamable.level() && this.tamable.distanceToSqr(this.owner) <= this.stopDistance * this.stopDistance); // Folia - region threading - check level } @Override -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -index 2796df7af365c452b28373adfd7daf1d6730bac5..45b68a139956f2d59c8b9658692d01f1f79d33cc 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java +diff --git a/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java +index 045cfafb3afe8271d60852ae3c7cdcb039b44d4f..a24e964aff5623e3d7f2b79c87b6067f565458c2 100644 +--- a/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java ++++ b/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java @@ -42,6 +42,11 @@ public class GroundPathNavigation extends PathNavigation { @Override - public Path createPath(BlockPos target, @javax.annotation.Nullable Entity entity, int distance) { // Paper - EntityPathfindEvent + public Path createPath(BlockPos pos, @javax.annotation.Nullable Entity entity, int accuracy) { // Paper - EntityPathfindEvent + // Folia start - region threading -+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)this.level, target)) { ++ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)this.level, pos)) { + return null; + } + // Folia end - region threading - LevelChunk levelChunk = this.level - .getChunkSource() - .getChunkNow(SectionPos.blockToSectionCoord(target.getX()), SectionPos.blockToSectionCoord(target.getZ())); -diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 48c0de870a5bbf647309e69361dfb10ab56c65ab..71885b8b3f491fbe644efef02aebdd8b9f03a10b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -+++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java + LevelChunk chunkNow = this.level.getChunkSource().getChunkNow(SectionPos.blockToSectionCoord(pos.getX()), SectionPos.blockToSectionCoord(pos.getZ())); + if (chunkNow == null) { + return null; +diff --git a/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/net/minecraft/world/entity/ai/navigation/PathNavigation.java +index b44f2c49509d847817a78e9c4fb1499fb378054b..386580035e6789d6e668b924513ddfc81947a9b3 100644 +--- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java ++++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -96,11 +96,11 @@ public abstract class PathNavigation { } @@ -15698,7 +15367,7 @@ index 48c0de870a5bbf647309e69361dfb10ab56c65ab..71885b8b3f491fbe644efef02aebdd8b this.hasDelayedRecomputation = false; } } else { -@@ -220,7 +220,7 @@ public abstract class PathNavigation { +@@ -221,7 +221,7 @@ public abstract class PathNavigation { public boolean moveTo(Entity entity, double speed) { // Paper start - Perf: Optimise pathfinding @@ -15707,7 +15376,7 @@ index 48c0de870a5bbf647309e69361dfb10ab56c65ab..71885b8b3f491fbe644efef02aebdd8b return false; } // Paper end - Perf: Optimise pathfinding -@@ -232,7 +232,7 @@ public abstract class PathNavigation { +@@ -233,7 +233,7 @@ public abstract class PathNavigation { return true; } else { this.pathfindFailures++; @@ -15716,42 +15385,42 @@ index 48c0de870a5bbf647309e69361dfb10ab56c65ab..71885b8b3f491fbe644efef02aebdd8b return false; } // Paper end - Perf: Optimise pathfinding -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java -index e1ff702e56adef6c8a572b078b49de2143c4ce7e..6c9e9c4173e62fc69e6da2b0bc7e6cc886f39fbe 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/PlayerSensor.java +diff --git a/net/minecraft/world/entity/ai/sensing/PlayerSensor.java b/net/minecraft/world/entity/ai/sensing/PlayerSensor.java +index 6233e6b48aaa69ba9f577d0b480b1cdf2f55d16e..a4810c8a3b18082543d06787722d4ed5821a1943 100644 +--- a/net/minecraft/world/entity/ai/sensing/PlayerSensor.java ++++ b/net/minecraft/world/entity/ai/sensing/PlayerSensor.java @@ -22,7 +22,7 @@ public class PlayerSensor extends Sensor { @Override - protected void doTick(ServerLevel world, LivingEntity entity) { -- List list = world.players() -+ List list = world.getLocalPlayers() // Folia - region threading + protected void doTick(ServerLevel level, LivingEntity entity) { +- List list = level.players() ++ List list = level.getLocalPlayers() // Folia - region threading .stream() .filter(EntitySelector.NO_SPECTATORS) - .filter(player -> entity.closerThan(player, this.getFollowDistance(entity))) -diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/TemptingSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/TemptingSensor.java -index 4090d98b264d13f76f93742bac7e895a5b0a72ea..4dd2dcb092ef6301d9986d4217d8ca647ec4565b 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/sensing/TemptingSensor.java -+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/TemptingSensor.java -@@ -39,7 +39,7 @@ public class TemptingSensor extends Sensor { - protected void doTick(ServerLevel world, PathfinderMob entity) { - Brain behaviorcontroller = entity.getBrain(); - TargetingConditions pathfindertargetcondition = TemptingSensor.TEMPT_TARGETING.copy().range((double) ((float) entity.getAttributeValue(Attributes.TEMPT_RANGE))); -- Stream stream = world.players().stream().filter(EntitySelector.NO_SPECTATORS).filter((entityplayer) -> { // CraftBukkit - decompile error -+ Stream stream = world.getLocalPlayers().stream().filter(EntitySelector.NO_SPECTATORS).filter((entityplayer) -> { // CraftBukkit - decompile error // Folia - region threading - return pathfindertargetcondition.test(world, entity, entityplayer); - }).filter(this::playerHoldingTemptation).filter((entityplayer) -> { - return !entity.hasPassenger((Entity) entityplayer); -diff --git a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java -index bd3f71c3eaa33258ff56062ea3a2099cef310b7a..326be10d31d0b546a325f4af97bb413910e79e31 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java -+++ b/src/main/java/net/minecraft/world/entity/ai/village/VillageSiege.java -@@ -21,62 +21,66 @@ import org.slf4j.Logger; - public class VillageSiege implements CustomSpawner { + .filter(serverPlayer -> entity.closerThan(serverPlayer, this.getFollowDistance(entity))) +diff --git a/net/minecraft/world/entity/ai/sensing/TemptingSensor.java b/net/minecraft/world/entity/ai/sensing/TemptingSensor.java +index 4b3ba795bc18417f983600f1edbc1895ccb7deab..d06c2c72e6166bc8b7822966092b17440125b814 100644 +--- a/net/minecraft/world/entity/ai/sensing/TemptingSensor.java ++++ b/net/minecraft/world/entity/ai/sensing/TemptingSensor.java +@@ -36,7 +36,7 @@ public class TemptingSensor extends Sensor { + protected void doTick(ServerLevel level, PathfinderMob entity) { + Brain brain = entity.getBrain(); + TargetingConditions targetingConditions = TEMPT_TARGETING.copy().range((float)entity.getAttributeValue(Attributes.TEMPT_RANGE)); +- List list = level.players() ++ List list = level.getLocalPlayers() // Folia - region threading + .stream() + .filter(EntitySelector.NO_SPECTATORS) + .filter(serverPlayer -> targetingConditions.test(level, entity, serverPlayer)) +diff --git a/net/minecraft/world/entity/ai/village/VillageSiege.java b/net/minecraft/world/entity/ai/village/VillageSiege.java +index a1cea4a4f76a7bb771b8ab643bd9d473e16418bf..fa012c5b23f6fdd714d15282cc485492ae18672a 100644 +--- a/net/minecraft/world/entity/ai/village/VillageSiege.java ++++ b/net/minecraft/world/entity/ai/village/VillageSiege.java +@@ -18,68 +18,72 @@ import org.slf4j.Logger; + public class VillageSiege implements CustomSpawner { private static final Logger LOGGER = LogUtils.getLogger(); - private boolean hasSetupSiege; -- private VillageSiege.State siegeState; +- private VillageSiege.State siegeState = VillageSiege.State.SIEGE_DONE; - private int zombiesToSpawn; - private int nextSpawnTime; - private int spawnX; @@ -15759,28 +15428,22 @@ index bd3f71c3eaa33258ff56062ea3a2099cef310b7a..326be10d31d0b546a325f4af97bb4139 - private int spawnZ; + // Folia - region threading - public VillageSiege() { -- this.siegeState = VillageSiege.State.SIEGE_DONE; -+ // Folia - region threading - } - @Override - public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading + public int tick(ServerLevel level, boolean spawnHostiles, boolean spawnPassives) { ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading + // Folia start - region threading + // check if the spawn pos is no longer owned by this region + if (worldData.villageSiegeState.siegeState != State.SIEGE_DONE -+ && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(world, worldData.villageSiegeState.spawnX >> 4, worldData.villageSiegeState.spawnZ >> 4, 8)) { ++ && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, worldData.villageSiegeState.spawnX >> 4, worldData.villageSiegeState.spawnZ >> 4, 8)) { + // can't spawn here, just re-set + worldData.villageSiegeState = new io.papermc.paper.threadedregions.RegionizedWorldData.VillageSiegeState(); + } + // Folia end - region threading - if (!world.isDay() && spawnMonsters) { - float f = world.getTimeOfDay(0.0F); - - if ((double) f == 0.5D) { -- this.siegeState = world.random.nextInt(10) == 0 ? VillageSiege.State.SIEGE_TONIGHT : VillageSiege.State.SIEGE_DONE; -+ worldData.villageSiegeState.siegeState = world.random.nextInt(10) == 0 ? VillageSiege.State.SIEGE_TONIGHT : VillageSiege.State.SIEGE_DONE; // Folia - region threading + if (!level.isDay() && spawnHostiles) { + float timeOfDay = level.getTimeOfDay(0.0F); + if (timeOfDay == 0.5) { +- this.siegeState = level.random.nextInt(10) == 0 ? VillageSiege.State.SIEGE_TONIGHT : VillageSiege.State.SIEGE_DONE; ++ worldData.villageSiegeState.siegeState = level.random.nextInt(10) == 0 ? VillageSiege.State.SIEGE_TONIGHT : VillageSiege.State.SIEGE_DONE; // Folia - region threading } - if (this.siegeState == VillageSiege.State.SIEGE_DONE) { @@ -15789,7 +15452,7 @@ index bd3f71c3eaa33258ff56062ea3a2099cef310b7a..326be10d31d0b546a325f4af97bb4139 } else { - if (!this.hasSetupSiege) { + if (!worldData.villageSiegeState.hasSetupSiege) { // Folia - region threading - if (!this.tryToSetupSiege(world)) { + if (!this.tryToSetupSiege(level)) { return 0; } @@ -15798,18 +15461,18 @@ index bd3f71c3eaa33258ff56062ea3a2099cef310b7a..326be10d31d0b546a325f4af97bb4139 } - if (this.nextSpawnTime > 0) { -- --this.nextSpawnTime; +- this.nextSpawnTime--; + if (worldData.villageSiegeState.nextSpawnTime > 0) { // Folia - region threading -+ --worldData.villageSiegeState.nextSpawnTime; // Folia - region threading ++ worldData.villageSiegeState.nextSpawnTime--; // Folia - region threading return 0; } else { - this.nextSpawnTime = 2; - if (this.zombiesToSpawn > 0) { + worldData.villageSiegeState.nextSpawnTime = 2; // Folia - region threading + if (worldData.villageSiegeState.zombiesToSpawn > 0) { // Folia - region threading - this.trySpawn(world); -- --this.zombiesToSpawn; -+ --worldData.villageSiegeState.zombiesToSpawn; // Folia - region threading + this.trySpawn(level); +- this.zombiesToSpawn--; ++ worldData.villageSiegeState.zombiesToSpawn--; // Folia - region threading } else { - this.siegeState = VillageSiege.State.SIEGE_DONE; + worldData.villageSiegeState.siegeState = VillageSiege.State.SIEGE_DONE; // Folia - region threading @@ -15827,71 +15490,67 @@ index bd3f71c3eaa33258ff56062ea3a2099cef310b7a..326be10d31d0b546a325f4af97bb4139 } } - private boolean tryToSetupSiege(ServerLevel world) { -- Iterator iterator = world.players().iterator(); -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading -+ Iterator iterator = world.getLocalPlayers().iterator(); // Folia - region threading - - while (iterator.hasNext()) { - Player entityhuman = (Player) iterator.next(); -@@ -88,12 +92,12 @@ public class VillageSiege implements CustomSpawner { - for (int i = 0; i < 10; ++i) { - float f = world.random.nextFloat() * 6.2831855F; - -- this.spawnX = blockposition.getX() + Mth.floor(Mth.cos(f) * 32.0F); -- this.spawnY = blockposition.getY(); -- this.spawnZ = blockposition.getZ() + Mth.floor(Mth.sin(f) * 32.0F); -- if (this.findRandomSpawnPos(world, new BlockPos(this.spawnX, this.spawnY, this.spawnZ)) != null) { + private boolean tryToSetupSiege(ServerLevel level) { +- for (Player player : level.players()) { ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading ++ for (Player player : level.getLocalPlayers()) { // Folia - region threading + if (!player.isSpectator()) { + BlockPos blockPos = player.blockPosition(); + if (level.isVillage(blockPos) && !level.getBiome(blockPos).is(BiomeTags.WITHOUT_ZOMBIE_SIEGES)) { + for (int i = 0; i < 10; i++) { + float f = level.random.nextFloat() * (float) (Math.PI * 2); +- this.spawnX = blockPos.getX() + Mth.floor(Mth.cos(f) * 32.0F); +- this.spawnY = blockPos.getY(); +- this.spawnZ = blockPos.getZ() + Mth.floor(Mth.sin(f) * 32.0F); +- if (this.findRandomSpawnPos(level, new BlockPos(this.spawnX, this.spawnY, this.spawnZ)) != null) { - this.nextSpawnTime = 0; - this.zombiesToSpawn = 20; -+ worldData.villageSiegeState.spawnX = blockposition.getX() + Mth.floor(Mth.cos(f) * 32.0F); // Folia - region threading -+ worldData.villageSiegeState.spawnY = blockposition.getY(); // Folia - region threading -+ worldData.villageSiegeState.spawnZ = blockposition.getZ() + Mth.floor(Mth.sin(f) * 32.0F); // Folia - region threading -+ if (this.findRandomSpawnPos(world, new BlockPos(worldData.villageSiegeState.spawnX, worldData.villageSiegeState.spawnY, worldData.villageSiegeState.spawnZ)) != null) { // Folia - region threading ++ worldData.villageSiegeState.spawnX = blockPos.getX() + Mth.floor(Mth.cos(f) * 32.0F); // Folia - region threading ++ worldData.villageSiegeState.spawnY = blockPos.getY(); // Folia - region threading ++ worldData.villageSiegeState.spawnZ = blockPos.getZ() + Mth.floor(Mth.sin(f) * 32.0F); // Folia - region threading ++ if (this.findRandomSpawnPos(level, new BlockPos(worldData.villageSiegeState.spawnX, worldData.villageSiegeState.spawnY, worldData.villageSiegeState.spawnZ)) != null) { // Folia - region threading + worldData.villageSiegeState.nextSpawnTime = 0; // Folia - region threading + worldData.villageSiegeState.zombiesToSpawn = 20; // Folia - region threading break; } } -@@ -107,13 +111,15 @@ public class VillageSiege implements CustomSpawner { +@@ -93,11 +97,13 @@ public class VillageSiege implements CustomSpawner { } - private void trySpawn(ServerLevel world) { -- Vec3 vec3d = this.findRandomSpawnPos(world, new BlockPos(this.spawnX, this.spawnY, this.spawnZ)); -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading -+ Vec3 vec3d = this.findRandomSpawnPos(world, new BlockPos(worldData.villageSiegeState.spawnX, worldData.villageSiegeState.spawnY, worldData.villageSiegeState.spawnZ)); // Folia - region threading - - if (vec3d != null) { - Zombie entityzombie; - + private void trySpawn(ServerLevel level) { +- Vec3 vec3 = this.findRandomSpawnPos(level, new BlockPos(this.spawnX, this.spawnY, this.spawnZ)); ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading ++ Vec3 vec3 = this.findRandomSpawnPos(level, new BlockPos(worldData.villageSiegeState.spawnX, worldData.villageSiegeState.spawnY, worldData.villageSiegeState.spawnZ)); // Folia - region threading + if (vec3 != null) { + Zombie zombie; try { - entityzombie = new Zombie(world); -+ entityzombie.moveTo(vec3d.x, vec3d.y, vec3d.z, world.random.nextFloat() * 360.0F, 0.0F); // Folia - region threading - move up - entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), EntitySpawnReason.EVENT, (SpawnGroupData) null); - } catch (Exception exception) { - VillageSiege.LOGGER.warn("Failed to create zombie for village siege at {}", vec3d, exception); -@@ -121,7 +127,7 @@ public class VillageSiege implements CustomSpawner { + zombie = new Zombie(level); ++ zombie.moveTo(vec3.x, vec3.y, vec3.z, level.random.nextFloat() * 360.0F, 0.0F); // Folia - region threading - move up + zombie.finalizeSpawn(level, level.getCurrentDifficultyAt(zombie.blockPosition()), EntitySpawnReason.EVENT, null); + } catch (Exception var5) { + LOGGER.warn("Failed to create zombie for village siege at {}", vec3, var5); +@@ -105,7 +111,7 @@ public class VillageSiege implements CustomSpawner { return; } -- entityzombie.moveTo(vec3d.x, vec3d.y, vec3d.z, world.random.nextFloat() * 360.0F, 0.0F); -+ // Folia - region threading - move up - world.addFreshEntityWithPassengers(entityzombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_INVASION); // CraftBukkit +- zombie.moveTo(vec3.x, vec3.y, vec3.z, level.random.nextFloat() * 360.0F, 0.0F); ++ //zombie.moveTo(vec3.x, vec3.y, vec3.z, level.random.nextFloat() * 360.0F, 0.0F); // Folia - region threading - move up + level.addFreshEntityWithPassengers(zombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_INVASION); // CraftBukkit } } -@@ -142,7 +148,7 @@ public class VillageSiege implements CustomSpawner { +@@ -125,7 +131,7 @@ public class VillageSiege implements CustomSpawner { return null; } -- private static enum State { +- static enum State { + public static enum State { // Folia - region threading - - SIEGE_CAN_ACTIVATE, SIEGE_TONIGHT, SIEGE_DONE; - -diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -index 63a94b6068fdaef8bb26675c2927cb729ced1dac..f3f98e6276dda3bc4f290fc2d80569f7e1e7ef66 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java -+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java + SIEGE_CAN_ACTIVATE, + SIEGE_TONIGHT, + SIEGE_DONE; +diff --git a/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/net/minecraft/world/entity/ai/village/poi/PoiManager.java +index 618fc0eb4fe70e46e55f3aa28e8eac1d2d01b6d9..c10810bf00d75f459c3c6a9415c1e09f0519d50e 100644 +--- a/net/minecraft/world/entity/ai/village/poi/PoiManager.java ++++ b/net/minecraft/world/entity/ai/village/poi/PoiManager.java @@ -58,11 +58,13 @@ public class PoiManager extends SectionStorage im } @@ -15906,34 +15565,34 @@ index 63a94b6068fdaef8bb26675c2927cb729ced1dac..f3f98e6276dda3bc4f290fc2d80569f7 } @Override -@@ -345,10 +347,12 @@ public class PoiManager extends SectionStorage im +@@ -347,10 +349,12 @@ public class PoiManager extends SectionStorage im } - public int sectionsToVillage(SectionPos pos) { + public int sectionsToVillage(SectionPos sectionPos) { + synchronized (this.villageDistanceTracker) { // Folia - region threading // Paper start - rewrite chunk system this.villageDistanceTracker.propagateUpdates(); - return convertBetweenLevels(this.villageDistanceTracker.getLevel(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkSectionKey(pos))); + return convertBetweenLevels(this.villageDistanceTracker.getLevel(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkSectionKey(sectionPos))); // Paper end - rewrite chunk system + } // Folia - region threading } - boolean isVillageCenter(long pos) { -@@ -362,7 +366,9 @@ public class PoiManager extends SectionStorage im + boolean isVillageCenter(long chunkPos) { +@@ -364,7 +368,9 @@ public class PoiManager extends SectionStorage im @Override - public void tick(BooleanSupplier shouldKeepTicking) { + public void tick(BooleanSupplier aheadOfTime) { + synchronized (this.villageDistanceTracker) { // Folia - region threading this.villageDistanceTracker.propagateUpdates(); // Paper - rewrite chunk system + } // Folia - region threading } @Override -diff --git a/src/main/java/net/minecraft/world/entity/animal/Bee.java b/src/main/java/net/minecraft/world/entity/animal/Bee.java -index 0bafe14342c1acce131ad34717c18aed3718deed..63ee0cd25cf595196ad67d90737daf7826925b2a 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Bee.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Bee.java -@@ -1129,6 +1129,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { +diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java +index 94244b148533ef026bf5c56abbc2bb5cfa83c938..15360f560d9b6a762ebd4284b7d0ca0a3e13794e 100644 +--- a/net/minecraft/world/entity/animal/Bee.java ++++ b/net/minecraft/world/entity/animal/Bee.java +@@ -815,6 +815,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override public boolean canBeeUse() { @@ -15942,10 +15601,10 @@ index 0bafe14342c1acce131ad34717c18aed3718deed..63ee0cd25cf595196ad67d90737daf78 + Bee.this.hivePos = null; + } + // Folia end - region threading - return Bee.this.hivePos != null && !Bee.this.isTooFarAway(Bee.this.hivePos) && !Bee.this.hasRestriction() && Bee.this.wantsToEnterHive() && !this.hasReachedTarget(Bee.this.hivePos) && Bee.this.level().getBlockState(Bee.this.hivePos).is(BlockTags.BEEHIVES); - } - -@@ -1242,6 +1247,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { + return Bee.this.hivePos != null + && !Bee.this.isTooFarAway(Bee.this.hivePos) + && !Bee.this.hasRestriction() +@@ -925,6 +930,11 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal { @Override public boolean canBeeUse() { @@ -15954,67 +15613,67 @@ index 0bafe14342c1acce131ad34717c18aed3718deed..63ee0cd25cf595196ad67d90737daf78 + Bee.this.savedFlowerPos = null; + } + // Folia end - region threading - return Bee.this.savedFlowerPos != null && !Bee.this.hasRestriction() && this.wantsToGoToKnownFlower() && !Bee.this.closerThan(Bee.this.savedFlowerPos, 2); - } - -diff --git a/src/main/java/net/minecraft/world/entity/animal/Cat.java b/src/main/java/net/minecraft/world/entity/animal/Cat.java -index 989b7be74eaeba7f40eac87c7ee7f252cb0c05c9..d3110cbb22995fb197739cdbcf480f584507fc26 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/Cat.java -+++ b/src/main/java/net/minecraft/world/entity/animal/Cat.java -@@ -365,7 +365,7 @@ public class Cat extends TamableAnimal implements VariantHolder tagKey = flag ? CatVariantTags.FULL_MOON_SPAWNS : CatVariantTags.DEFAULT_SPAWNS; + BuiltInRegistries.CAT_VARIANT.getRandomElementOf(tagKey, level.getRandom()).ifPresent(this::setVariant); + ServerLevel level1 = level.getLevel(); +- if (level1.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK, level).isValid()) { // Paper - Fix swamp hut cat generation deadlock ++ if (level.structureManager().getStructureWithPieceAt(this.blockPosition(), StructureTags.CATS_SPAWN_AS_BLACK).isValid()) { // Paper - Fix swamp hut cat generation deadlock // Folia - region threading - properly fix this + this.setVariant(BuiltInRegistries.CAT_VARIANT.getOrThrow(CatVariant.ALL_BLACK)); this.setPersistenceRequired(); } -diff --git a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -index 7cb3d69a69e0e3ef4b7f9f9c8b1eb67edb5d116d..80590431ad85293effdde5fff6d0432de094d244 100644 ---- a/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -+++ b/src/main/java/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java -@@ -58,7 +58,7 @@ public class EndCrystal extends Entity { +diff --git a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +index ff1c84d37db48e1bd0283a900e199647c0e8eba1..fc64c36a01eb8efdcfa487059078787900e34d86 100644 +--- a/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java ++++ b/net/minecraft/world/entity/boss/enderdragon/EndCrystal.java +@@ -53,7 +53,7 @@ public class EndCrystal extends Entity { public void tick() { - ++this.time; + this.time++; this.applyEffectsFromBlocks(); - this.handlePortal(); + //this.handlePortal(); // Folia - region threading if (this.level() instanceof ServerLevel) { - BlockPos blockposition = this.blockPosition(); - -diff --git a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -index 7d83ad8a61f6aafbc063506c1858554f9b700b70..ada70345efbb620c1df6e68ab16a3fb29df43129 100644 ---- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java -@@ -262,7 +262,9 @@ public class ItemFrame extends HangingEntity { - MapItemSavedData worldmap = MapItem.getSavedData(mapid, this.level()); - - if (worldmap != null) { -+ synchronized (worldmap) { // Folia - make map data thread-safe - worldmap.removedFromFrame(this.pos, this.getId()); + BlockPos blockPos = this.blockPosition(); + if (((ServerLevel)this.level()).getDragonFight() != null && this.level().getBlockState(blockPos).isAir()) { +diff --git a/net/minecraft/world/entity/decoration/ItemFrame.java b/net/minecraft/world/entity/decoration/ItemFrame.java +index 65e1d7c5ac94b1cfb921fa009be59d3e5872f0b5..5aefec7ecc2085659bebca25992dd3a76fff2b5e 100644 +--- a/net/minecraft/world/entity/decoration/ItemFrame.java ++++ b/net/minecraft/world/entity/decoration/ItemFrame.java +@@ -242,7 +242,9 @@ public class ItemFrame extends HangingEntity { + if (framedMapId != null) { + MapItemSavedData savedData = MapItem.getSavedData(framedMapId, this.level()); + if (savedData != null) { ++ synchronized (savedData) { // Folia - make map data thread-safe + savedData.removedFromFrame(this.pos, this.getId()); + } // Folia - make map data thread-safe } } -diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 410c4e4a42640ebe8a9c233eb2064aad76e45a27..a498cdbe42df3161c35b2a1652dfa63693366bd6 100644 ---- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -170,7 +170,7 @@ public class FallingBlockEntity extends Entity { +diff --git a/net/minecraft/world/entity/item/FallingBlockEntity.java b/net/minecraft/world/entity/item/FallingBlockEntity.java +index 5746587666c7cb788764aab2f6ccf0f3ac5c282f..1fa5e6a12b943e889bde566038a632a6adcf319e 100644 +--- a/net/minecraft/world/entity/item/FallingBlockEntity.java ++++ b/net/minecraft/world/entity/item/FallingBlockEntity.java +@@ -162,7 +162,7 @@ public class FallingBlockEntity extends Entity { return; } // Paper end - Configurable falling blocks height nerf - this.handlePortal(); + //this.handlePortal(); // Folia - region threading - Level world = this.level(); - - if (world instanceof ServerLevel) { -diff --git a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -index 0f086af57a5ff08c264dcbf89a8c3931ec73a609..c81360b6cba1904ccd325c17da76d3ac223c88b8 100644 ---- a/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -+++ b/src/main/java/net/minecraft/world/entity/item/ItemEntity.java -@@ -576,14 +576,22 @@ public class ItemEntity extends Entity implements TraceableEntity { + if (this.level() instanceof ServerLevel serverLevel && (this.isAlive() || this.forceTickAfterTeleportToDuplicate)) { + BlockPos blockPos = this.blockPosition(); + boolean flag = this.blockState.getBlock() instanceof ConcretePowderBlock; +diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java +index 52a7ed0d991758bad0dcedcb7f97fb15ac6c6d04..7587130e021d494ae5013f7992b8f3c96590cbd7 100644 +--- a/net/minecraft/world/entity/item/ItemEntity.java ++++ b/net/minecraft/world/entity/item/ItemEntity.java +@@ -521,13 +521,21 @@ public class ItemEntity extends Entity implements TraceableEntity { return false; } @@ -16030,21 +15689,20 @@ index 0f086af57a5ff08c264dcbf89a8c3931ec73a609..c81360b6cba1904ccd325c17da76d3ac + @Nullable @Override - public Entity teleport(TeleportTransition teleportTarget) { - Entity entity = super.teleport(teleportTarget); - -- if (!this.level().isClientSide && entity instanceof ItemEntity entityitem) { -- entityitem.mergeWithNeighbours(); + public Entity teleport(TeleportTransition teleportTransition) { + Entity entity = super.teleport(teleportTransition); +- if (!this.level().isClientSide && entity instanceof ItemEntity itemEntity) { +- itemEntity.mergeWithNeighbours(); - } + if (entity != null) entity.postChangeDimension(); // Folia - region threading - move to post change return entity; } -diff --git a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -index 809f5e847e2f5bb594c130cebd2cb897ea768d82..09edb09cf6beacc8e7960d5d78fe88647525e257 100644 ---- a/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -+++ b/src/main/java/net/minecraft/world/entity/item/PrimedTnt.java -@@ -101,8 +101,8 @@ public class PrimedTnt extends Entity implements TraceableEntity { +diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java +index 40da052e7fea1306a007b3cb5c9daa33e0ef523e..88570bb4aa02896545805d7721c45cf9599befea 100644 +--- a/net/minecraft/world/entity/item/PrimedTnt.java ++++ b/net/minecraft/world/entity/item/PrimedTnt.java +@@ -98,8 +98,8 @@ public class PrimedTnt extends Entity implements TraceableEntity { @Override public void tick() { @@ -16055,7 +15713,7 @@ index 809f5e847e2f5bb594c130cebd2cb897ea768d82..09edb09cf6beacc8e7960d5d78fe8864 this.applyGravity(); this.move(MoverType.SELF, this.getDeltaMovement()); this.applyEffectsFromBlocks(); -@@ -142,7 +142,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { +@@ -137,7 +137,7 @@ public class PrimedTnt extends Entity implements TraceableEntity { */ // Send position and velocity updates to nearby players on every tick while the TNT is in water. // This does pretty well at keeping their clients in sync with the server. @@ -16064,59 +15722,47 @@ index 809f5e847e2f5bb594c130cebd2cb897ea768d82..09edb09cf6beacc8e7960d5d78fe8864 if (ete != null) { net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket velocityPacket = new net.minecraft.network.protocol.game.ClientboundSetEntityMotionPacket(this); net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket positionPacket = net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket.teleport(this.getId(), net.minecraft.world.entity.PositionMoveRotation.of(this), java.util.Set.of(), this.onGround); -diff --git a/src/main/java/net/minecraft/world/entity/monster/Vex.java b/src/main/java/net/minecraft/world/entity/monster/Vex.java -index 183a33b7d666d652b455baa7e8339e9c4a870a58..64af789f203275611e142955daef0a783ace7e26 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/Vex.java -+++ b/src/main/java/net/minecraft/world/entity/monster/Vex.java -@@ -347,7 +347,7 @@ public class Vex extends Monster implements TraceableEntity { +diff --git a/net/minecraft/world/entity/monster/Vex.java b/net/minecraft/world/entity/monster/Vex.java +index 7f1cdea810db24182f8f87076c42a19b1b43e98a..c41901c98687c25f8ff7e5eb3a052aeb9744640a 100644 +--- a/net/minecraft/world/entity/monster/Vex.java ++++ b/net/minecraft/world/entity/monster/Vex.java +@@ -349,7 +349,7 @@ public class Vex extends Monster implements TraceableEntity { + @Override public void tick() { - BlockPos blockposition = Vex.this.getBoundOrigin(); - -- if (blockposition == null) { -+ if (blockposition == null || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)Vex.this.level(), blockposition)) { // Folia - region threading - blockposition = Vex.this.blockPosition(); + BlockPos boundOrigin = Vex.this.getBoundOrigin(); +- if (boundOrigin == null) { ++ if (boundOrigin == null || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((net.minecraft.server.level.ServerLevel)Vex.this.level(), boundOrigin)) { // Folia - region threading + boundOrigin = Vex.this.blockPosition(); } -diff --git a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -index 30bce56a70f923b0ec77c8e3f29e435a71c71510..ded64f670120c6079fac7f44e8870ca8f97353ea 100644 ---- a/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/src/main/java/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -76,7 +76,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { +diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java +index 9061e0b6544d6a31a4dc5b51037f608031a00553..76fa0a25fe084f17045f72a1750c6e8b1eb7cb14 100644 +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -69,7 +69,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { @Nullable private MerchantOffers tradeOffers; private int villagerXp; -- private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field -+ // private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field // Folia - region threading - restore original timers +- private int lastTick = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit - add field ++ //private int lastTick = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit - add field // Folia - region threading - restore original timers - public ZombieVillager(EntityType type, Level world) { - super(type, world); -@@ -157,10 +157,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { - public void tick() { - if (!this.level().isClientSide && this.isAlive() && this.isConverting()) { - int i = this.getConversionProgress(); -- // CraftBukkit start - Use wall time instead of ticks for villager conversion -- int elapsedTicks = MinecraftServer.currentTick - this.lastTick; -- i *= elapsedTicks; -- // CraftBukkit end -+ // Folia - region threading - restore original timers - - this.villagerConversionTime -= i; - if (this.villagerConversionTime <= 0) { -@@ -169,7 +166,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { + public ZombieVillager(EntityType entityType, Level level) { + super(entityType, level); +@@ -149,7 +149,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder { } super.tick(); -- this.lastTick = MinecraftServer.currentTick; // CraftBukkit -+ // Folia - region threading - restore original timers +- this.lastTick = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit ++ //this.lastTick = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit // Folia - region threading - restore original timers } @Override -diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -index 3c037cabd8331eb96a6523b37abab4e73ab79a02..a1dee26ed47a423fbad57b9b2ec98b4f58b9470b 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -224,10 +224,18 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa - this.readInventoryFromTag(nbt, this.registryAccess()); +diff --git a/net/minecraft/world/entity/npc/AbstractVillager.java b/net/minecraft/world/entity/npc/AbstractVillager.java +index a71d16d968bb90fd7aca6f01a3dd56df4f9a7ce6..27ce04ecee778b73711ee55c7c75c541e1f86c38 100644 +--- a/net/minecraft/world/entity/npc/AbstractVillager.java ++++ b/net/minecraft/world/entity/npc/AbstractVillager.java +@@ -218,10 +218,18 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa + this.readInventoryFromTag(compound, this.registryAccess()); } + // Folia start - region threading @@ -16129,16 +15775,16 @@ index 3c037cabd8331eb96a6523b37abab4e73ab79a02..a1dee26ed47a423fbad57b9b2ec98b4f + @Nullable @Override - public Entity teleport(TeleportTransition teleportTarget) { + public Entity teleport(TeleportTransition teleportTransition) { - this.stopTrading(); + this.preChangeDimension(); // Folia - region threading - move into preChangeDimension - return super.teleport(teleportTarget); + return super.teleport(teleportTransition); } -diff --git a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -index b0236c7bf9441aa84d3795ffed05dd6099f29636..4a8214160946f94d8a2fa13785f205a324a32949 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java -+++ b/src/main/java/net/minecraft/world/entity/npc/CatSpawner.java +diff --git a/net/minecraft/world/entity/npc/CatSpawner.java b/net/minecraft/world/entity/npc/CatSpawner.java +index e6d368bc601357cfca694ce328c8e6e47491f3b5..010bee26dfdf5cad186fa57c030540693ff71f23 100644 +--- a/net/minecraft/world/entity/npc/CatSpawner.java ++++ b/net/minecraft/world/entity/npc/CatSpawner.java @@ -18,17 +18,18 @@ import net.minecraft.world.phys.AABB; public class CatSpawner implements CustomSpawner { @@ -16147,57 +15793,57 @@ index b0236c7bf9441aa84d3795ffed05dd6099f29636..4a8214160946f94d8a2fa13785f205a3 + //private int nextTick; // Folia - region threading @Override - public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { - if (spawnAnimals && world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { + public int tick(ServerLevel level, boolean spawnHostiles, boolean spawnPassives) { + if (spawnPassives && level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { - this.nextTick--; - if (this.nextTick > 0) { -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading -+ --worldData.catSpawnerNextTick; // Folia - region threading ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading ++ worldData.catSpawnerNextTick--; // Folia - region threading + if (worldData.catSpawnerNextTick > 0) { // Folia - region threading return 0; } else { - this.nextTick = 1200; -- Player player = world.getRandomPlayer(); +- Player randomPlayer = level.getRandomPlayer(); + worldData.catSpawnerNextTick = 1200; // Folia - region threading -+ Player player = world.getRandomLocalPlayer(); // Folia - region threading - if (player == null) { ++ Player randomPlayer = level.getRandomLocalPlayer(); // Folia - region threading + if (randomPlayer == null) { return 0; } else { -diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java -index 2d8ba55906c8da16fde850e3412f4a6bda3d56e7..07f50048e9748b28178847ad470b8b2ce37e0eea 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/Villager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java -@@ -204,7 +204,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - brain.setCoreActivities(ImmutableSet.of(Activity.CORE)); - brain.setDefaultActivity(Activity.IDLE); - brain.setActiveActivityIfPossible(Activity.IDLE); -- brain.updateActivityFromSchedule(this.level().getDayTime(), this.level().getGameTime()); -+ brain.updateActivityFromSchedule(this.level().getLevelData().getDayTime(), this.level().getLevelData().getGameTime()); // Folia - region threading - not in the world yet +diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java +index 2b83262e4a13eae86df82913ce4f3121e3631a43..7ea74aeb905b95e5919d74df5fbc5e8f7a9985e3 100644 +--- a/net/minecraft/world/entity/npc/Villager.java ++++ b/net/minecraft/world/entity/npc/Villager.java +@@ -246,7 +246,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + villagerBrain.setCoreActivities(ImmutableSet.of(Activity.CORE)); + villagerBrain.setDefaultActivity(Activity.IDLE); + villagerBrain.setActiveActivityIfPossible(Activity.IDLE); +- villagerBrain.updateActivityFromSchedule(this.level().getDayTime(), this.level().getGameTime()); ++ villagerBrain.updateActivityFromSchedule(this.level().getLevelData().getDayTime(), this.level().getLevelData().getGameTime()); // Folia - region threading - not in the world yet } @Override -@@ -710,6 +710,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - ServerLevel worldserver = minecraftserver.getLevel(globalpos.dimension()); - - if (worldserver != null) { +@@ -693,6 +693,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + this.brain.getMemory(moduleType).ifPresent(globalPos -> { + ServerLevel level = server.getLevel(globalPos.dimension()); + if (level != null) { + io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( // Folia - region threading -+ worldserver, globalpos.pos().getX() >> 4, globalpos.pos().getZ() >> 4, () -> { // Folia - region threading - PoiManager villageplace = worldserver.getPoiManager(); - Optional> optional = villageplace.getType(globalpos.pos()); - BiPredicate> bipredicate = (BiPredicate) Villager.POI_MEMORIES.get(pos); -@@ -718,6 +720,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler - villageplace.release(globalpos.pos()); - DebugPackets.sendPoiTicketCountPacket(worldserver, globalpos.pos()); ++ level, globalPos.pos().getX() >> 4, globalPos.pos().getZ() >> 4, () -> { // Folia - region threading + PoiManager poiManager = level.getPoiManager(); + Optional> type = poiManager.getType(globalPos.pos()); + BiPredicate> biPredicate = POI_MEMORIES.get(moduleType); +@@ -700,6 +702,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler + poiManager.release(globalPos.pos()); + DebugPackets.sendPoiTicketCountPacket(level, globalPos.pos()); } + }); // Folia - region threading - } }); -diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -index a728dcbf956f108f01c966c7531449a506a14a87..d8e5ef40b32dd2e8b5fb6f4a00a3d3faea6e66ba 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -+++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTraderSpawner.java -@@ -32,16 +32,14 @@ public class WanderingTraderSpawner implements CustomSpawner { + } +diff --git a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +index ef2afb17a22a703470e13d12c989a685e72f0ab8..984ac8efa2ed45be614e04eab8247481e3a08525 100644 +--- a/net/minecraft/world/entity/npc/WanderingTraderSpawner.java ++++ b/net/minecraft/world/entity/npc/WanderingTraderSpawner.java +@@ -30,16 +30,14 @@ public class WanderingTraderSpawner implements CustomSpawner { private static final int SPAWN_CHANCE_INCREASE = 25; private static final int SPAWN_ONE_IN_X_CHANCE = 10; private static final int NUMBER_OF_SPAWN_ATTEMPTS = 10; @@ -16209,89 +15855,88 @@ index a728dcbf956f108f01c966c7531449a506a14a87..d8e5ef40b32dd2e8b5fb6f4a00a3d3fa - private int spawnChance; + // Folia - region threading - public WanderingTraderSpawner(ServerLevelData properties) { - this.serverLevelData = properties; + public WanderingTraderSpawner(ServerLevelData serverLevelData) { + this.serverLevelData = serverLevelData; // Paper start - Add Wandering Trader spawn rate config options - this.tickDelay = Integer.MIN_VALUE; + //this.tickDelay = Integer.MIN_VALUE; // Folia - region threading - moved to regionisedworlddata - //this.spawnDelay = properties.getWanderingTraderSpawnDelay(); // Paper - This value is read from the world file only for the first spawn, after which vanilla uses a hardcoded value - //this.spawnChance = properties.getWanderingTraderSpawnChance(); // Paper - This value is read from the world file only for the first spawn, after which vanilla uses a hardcoded value - //if (this.spawnDelay == 0 && this.spawnChance == 0) { -@@ -56,36 +54,37 @@ public class WanderingTraderSpawner implements CustomSpawner { + // this.spawnDelay = serverLevelData.getWanderingTraderSpawnDelay(); + // this.spawnChance = serverLevelData.getWanderingTraderSpawnChance(); + // if (this.spawnDelay == 0 && this.spawnChance == 0) { +@@ -53,35 +51,36 @@ public class WanderingTraderSpawner implements CustomSpawner { @Override - public int tick(ServerLevel world, boolean spawnMonsters, boolean spawnAnimals) { -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading + public int tick(ServerLevel level, boolean spawnHostiles, boolean spawnPassives) { ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading // Paper start - Add Wandering Trader spawn rate config options - if (this.tickDelay == Integer.MIN_VALUE) { -- this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -- this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; -- this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; +- this.tickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; +- this.spawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; +- this.spawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; + if (worldData.wanderingTraderTickDelay == Integer.MIN_VALUE) { // Folia - region threading -+ worldData.wanderingTraderTickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; // Folia - region threading -+ worldData.wanderingTraderSpawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; // Folia - region threading -+ worldData.wanderingTraderSpawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; // Folia - region threading ++ worldData.wanderingTraderTickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; // Folia - region threading ++ worldData.wanderingTraderSpawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; // Folia - region threading ++ worldData.wanderingTraderSpawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; // Folia - region threading } - if (!world.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) { + if (!level.getGameRules().getBoolean(GameRules.RULE_DO_TRADER_SPAWNING)) { return 0; -- } else if (this.tickDelay - 1 > 0) { +- } else if (--this.tickDelay - 1 > 0) { - this.tickDelay = this.tickDelay - 1; -+ } else if (worldData.wanderingTraderTickDelay - 1 > 0) { // Folia - region threading ++ } else if (--worldData.wanderingTraderTickDelay - 1 > 0) { // Folia - region threading + worldData.wanderingTraderTickDelay = worldData.wanderingTraderTickDelay - 1; // Folia - region threading return 0; } else { -- this.tickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -- this.spawnDelay = this.spawnDelay - world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; -+ worldData.wanderingTraderTickDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; // Folia - region threading -+ worldData.wanderingTraderSpawnDelay = worldData.wanderingTraderSpawnDelay - world.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; // Folia - region threading +- this.tickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; +- this.spawnDelay = this.spawnDelay - level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; ++ worldData.wanderingTraderTickDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; // Folia - region threading ++ worldData.wanderingTraderSpawnDelay = worldData.wanderingTraderSpawnDelay - level.paperConfig().entities.spawning.wanderingTrader.spawnMinuteLength; // Folia - region threading //this.serverLevelData.setWanderingTraderSpawnDelay(this.spawnDelay); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways - if (this.spawnDelay > 0) { + if (worldData.wanderingTraderSpawnDelay > 0) { // Folia - region threading return 0; } else { -- this.spawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; -+ worldData.wanderingTraderSpawnDelay = world.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; // Folia - region threading - if (!world.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { +- this.spawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; ++ worldData.wanderingTraderSpawnDelay = level.paperConfig().entities.spawning.wanderingTrader.spawnDayLength; // Folia - region threading + if (!level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING)) { return 0; } else { - int i = this.spawnChance; +- this.spawnChance = Mth.clamp(this.spawnChance + level.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); + int i = worldData.wanderingTraderSpawnChance; // Folia - region threading - - // this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways -- this.spawnChance = Mth.clamp(i + world.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); -+ worldData.wanderingTraderSpawnChance = Mth.clamp(i + world.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); // Folia - region threading ++ worldData.wanderingTraderSpawnChance = Mth.clamp(worldData.wanderingTraderSpawnChance + level.paperConfig().entities.spawning.wanderingTrader.spawnChanceFailureIncrement, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin, level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMax); // Folia - region threading + //this.serverLevelData.setWanderingTraderSpawnChance(this.spawnChance); // Paper - We don't need to save this value to disk if it gets set back to a hardcoded value anyways if (this.random.nextInt(100) > i) { return 0; - } else if (this.spawn(world)) { -- this.spawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; -+ worldData.wanderingTraderSpawnChance = world.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; // Folia - region threading + } else if (this.spawn(level)) { +- this.spawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; ++ worldData.wanderingTraderSpawnChance = level.paperConfig().entities.spawning.wanderingTrader.spawnChanceMin; // Folia - region threading // Paper end - Add Wandering Trader spawn rate config options return 1; } else { -@@ -97,7 +96,7 @@ public class WanderingTraderSpawner implements CustomSpawner { +@@ -93,7 +92,7 @@ public class WanderingTraderSpawner implements CustomSpawner { } - private boolean spawn(ServerLevel world) { -- ServerPlayer entityplayer = world.getRandomPlayer(); -+ ServerPlayer entityplayer = world.getRandomLocalPlayer(); // Folia - region threading - - if (entityplayer == null) { + private boolean spawn(ServerLevel serverLevel) { +- Player randomPlayer = serverLevel.getRandomPlayer(); ++ Player randomPlayer = serverLevel.getRandomLocalPlayer(); // Folia - region threading + if (randomPlayer == null) { return true; -@@ -127,7 +126,7 @@ public class WanderingTraderSpawner implements CustomSpawner { - this.tryToSpawnLlamaFor(world, entityvillagertrader, 4); + } else if (this.random.nextInt(10) != 0) { +@@ -116,7 +115,7 @@ public class WanderingTraderSpawner implements CustomSpawner { + this.tryToSpawnLlamaFor(serverLevel, wanderingTrader, 4); } -- this.serverLevelData.setWanderingTraderId(entityvillagertrader.getUUID()); -+ //this.serverLevelData.setWanderingTraderId(entityvillagertrader.getUUID()); // Folia - region threading - doesn't appear to be used anywhere, so avoid the race condition here... - // entityvillagertrader.setDespawnDelay(48000); // CraftBukkit - moved to EntityVillagerTrader constructor. This lets the value be modified by plugins on CreatureSpawnEvent - entityvillagertrader.setWanderTarget(blockposition1); - entityvillagertrader.restrictTo(blockposition1, 16); -diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java -index 5b8b85a295a08ae495f729c595b3a78778965342..f2817f1c29431ef2c4a45dc9ef90f06d4982f7c9 100644 ---- a/src/main/java/net/minecraft/world/entity/player/Player.java -+++ b/src/main/java/net/minecraft/world/entity/player/Player.java -@@ -1518,6 +1518,14 @@ public abstract class Player extends LivingEntity { - +- this.serverLevelData.setWanderingTraderId(wanderingTrader.getUUID()); ++ //this.serverLevelData.setWanderingTraderId(wanderingTrader.getUUID()); // Folia - region threading - doesn't appear to be used anywhere, so avoid the race condition here... + // wanderingTrader.setDespawnDelay(48000); // Paper - moved above, modifiable by plugins on CreatureSpawnEvent + wanderingTrader.setWanderTarget(blockPos1); + wanderingTrader.restrictTo(blockPos1, 16); +diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java +index 3ae542153bf1538d17e7c0fe6acc9e7f8605750c..eaa77200d6bc33faeefdc2d07b73ee7ddcd3afe8 100644 +--- a/net/minecraft/world/entity/player/Player.java ++++ b/net/minecraft/world/entity/player/Player.java +@@ -1504,6 +1504,14 @@ public abstract class Player extends LivingEntity { + } } + // Folia start - region threading @@ -16305,11 +15950,11 @@ index 5b8b85a295a08ae495f729c595b3a78778965342..f2817f1c29431ef2c4a45dc9ef90f06d public boolean isLocalPlayer() { return false; } -diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -index f4513b1887f823b088dabe425be042b8fb2bde66..5d52f67b3e379e64d23a0429679c144373d20eac 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractArrow.java -@@ -198,6 +198,11 @@ public abstract class AbstractArrow extends Projectile { +diff --git a/net/minecraft/world/entity/projectile/AbstractArrow.java b/net/minecraft/world/entity/projectile/AbstractArrow.java +index 541ee32182b595de7dd6717f8faea00d53c105a3..4758f7063b0da1731899f8f6b4de97ae7b7fce55 100644 +--- a/net/minecraft/world/entity/projectile/AbstractArrow.java ++++ b/net/minecraft/world/entity/projectile/AbstractArrow.java +@@ -176,6 +176,11 @@ public abstract class AbstractArrow extends Projectile { @Override public void tick() { @@ -16319,14 +15964,14 @@ index f4513b1887f823b088dabe425be042b8fb2bde66..5d52f67b3e379e64d23a0429679c1443 + } + // Folia end - region threading - make sure entities do not move into regions they do not own boolean flag = !this.isNoPhysics(); - Vec3 vec3d = this.getDeltaMovement(); - BlockPos blockposition = this.blockPosition(); -diff --git a/src/main/java/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java b/src/main/java/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java -index 19ff16e1ba406584f3cdd760d0269a50980b0a26..3e059ce6b4e7b730d0e3460dc76591ea0c69cfe1 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java -@@ -89,6 +89,11 @@ public abstract class AbstractHurtingProjectile extends Projectile { - this.setPos(vec3d); + Vec3 deltaMovement = this.getDeltaMovement(); + BlockPos blockPos = this.blockPosition(); +diff --git a/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java b/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java +index 9a99b813de8b606fab26c87086a21372e5172ba3..4eeb1017576d23d206a7a47b9e9e74b19465b2ae 100644 +--- a/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java ++++ b/net/minecraft/world/entity/projectile/AbstractHurtingProjectile.java +@@ -80,6 +80,11 @@ public abstract class AbstractHurtingProjectile extends Projectile { + this.setPos(location); this.applyEffectsFromBlocks(); super.tick(); + // Folia start - region threading - make sure entities do not move into regions they do not own @@ -16337,12 +15982,12 @@ index 19ff16e1ba406584f3cdd760d0269a50980b0a26..3e059ce6b4e7b730d0e3460dc76591ea if (this.shouldBurn()) { this.igniteForSeconds(1.0F); } -diff --git a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -index 8a4e7e1c0c4919d2ee34121c14f9665b9ad95273..e6dedd9e1421515459dfc156007ecff5cba1faa5 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -@@ -144,6 +144,11 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier { - +diff --git a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java +index 774ca9e0b56fd175ae246051de762d0c4256ca58..0cfd2c937f93f1acb4afc01251f882710baf2591 100644 +--- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java ++++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java +@@ -130,6 +130,11 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier { + } }); } + // Folia start - region threading @@ -16352,64 +15997,64 @@ index 8a4e7e1c0c4919d2ee34121c14f9665b9ad95273..e6dedd9e1421515459dfc156007ecff5 + // Folia end - region threading if (this.attachedToEntity != null) { - if (this.attachedToEntity.isFallFlying()) { -diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -index 5e6ceb3c3728c0c08a516566c70a5c0d72d59196..50ab937bdbe444331fda91bf3bae99f0accaf735 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -@@ -105,7 +105,7 @@ public class FishingHook extends Projectile { + Vec3 handHoldingItemAngle; +diff --git a/net/minecraft/world/entity/projectile/FishingHook.java b/net/minecraft/world/entity/projectile/FishingHook.java +index 1e012c7ef699a64ff3f1b00f897bb893ab25ecbd..f9d7514764850fd02ed5853ba2fdf8ada40ce756 100644 +--- a/net/minecraft/world/entity/projectile/FishingHook.java ++++ b/net/minecraft/world/entity/projectile/FishingHook.java +@@ -94,7 +94,7 @@ public class FishingHook extends Projectile { - public FishingHook(net.minecraft.world.entity.player.Player thrower, Level world, int luckBonus, int waitTimeReductionTicks) { - this(EntityType.FISHING_BOBBER, world, luckBonus, waitTimeReductionTicks); -- this.setOwner(thrower); -+ //this.setOwner(thrower); // Folia - region threading - move this down after position so that thread-checks do not fail - float f = thrower.getXRot(); - float f1 = thrower.getYRot(); - float f2 = Mth.cos(-f1 * 0.017453292F - 3.1415927F); -@@ -117,6 +117,7 @@ public class FishingHook extends Projectile { - double d2 = thrower.getZ() - (double) f2 * 0.3D; - - this.moveTo(d0, d1, d2, f1, f); -+ this.setOwner(thrower); // Folia - region threading - move this down after position so that thread-checks do not fail - Vec3 vec3d = new Vec3((double) (-f3), (double) Mth.clamp(-(f5 / f4), -5.0F, 5.0F), (double) (-f2)); - double d3 = vec3d.length(); - -@@ -273,6 +274,11 @@ public class FishingHook extends Projectile { + public FishingHook(Player player, Level level, int luck, int lureSpeed) { + this(EntityType.FISHING_BOBBER, level, luck, lureSpeed); +- this.setOwner(player); ++ //this.setOwner(player); // Folia - region threading - move this down after position so that thread-checks do not fail + float xRot = player.getXRot(); + float yRot = player.getYRot(); + float cos = Mth.cos(-yRot * (float) (Math.PI / 180.0) - (float) Math.PI); +@@ -105,6 +105,7 @@ public class FishingHook extends Projectile { + double eyeY = player.getEyeY(); + double d1 = player.getZ() - cos * 0.3; + this.moveTo(d, eyeY, d1, yRot, xRot); ++ this.setOwner(player); // Folia - region threading - move this down after position so that thread-checks do not fail + Vec3 vec3 = new Vec3(-sin, Mth.clamp(-(sin1 / f), -5.0F, 5.0F), -cos); + double len = vec3.length(); + vec3 = vec3.multiply( +@@ -260,6 +261,11 @@ public class FishingHook extends Projectile { } - private boolean shouldStopFishing(net.minecraft.world.entity.player.Player player) { + private boolean shouldStopFishing(Player player) { + // Folia start - region threading + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player)) { + return true; + } + // Folia end - region threading - ItemStack itemstack = player.getMainHandItem(); - ItemStack itemstack1 = player.getOffhandItem(); - boolean flag = itemstack.is(Items.FISHING_ROD); -@@ -636,10 +642,18 @@ public class FishingHook extends Projectile { + ItemStack mainHandItem = player.getMainHandItem(); + ItemStack offhandItem = player.getOffhandItem(); + boolean isFishingRod = mainHandItem.is(Items.FISHING_ROD); +@@ -623,10 +629,18 @@ public class FishingHook extends Projectile { @Override - public void remove(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { + public void remove(Entity.RemovalReason reason, org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { // CraftBukkit end -- this.updateOwnerInfo((FishingHook) null); -+ // Folia - region threading - move into preRemove - super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause +- this.updateOwnerInfo(null); ++ //this.updateOwnerInfo(null); // Folia - region threading - move into preRemove + super.remove(reason, cause); // CraftBukkit - add Bukkit remove cause } + // Folia start - region threading + @Override + protected void preRemove(RemovalReason reason) { + super.preRemove(reason); -+ this.updateOwnerInfo((FishingHook) null); ++ this.updateOwnerInfo(null); + } + // Folia end - region threading + @Override public void onClientRemoval() { - this.updateOwnerInfo((FishingHook) null); -diff --git a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java -index 958ea103cc80da7366cc33dc385b76d4f5c809f2..40645ef84efb096646d7bf7cd8c445b981c15de6 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/LlamaSpit.java + this.updateOwnerInfo(null); +diff --git a/net/minecraft/world/entity/projectile/LlamaSpit.java b/net/minecraft/world/entity/projectile/LlamaSpit.java +index 4880db97135d54fa72f64c108b2bd4ded096438b..dc6ec52a513e2754a81733de5f389d6ada5215cc 100644 +--- a/net/minecraft/world/entity/projectile/LlamaSpit.java ++++ b/net/minecraft/world/entity/projectile/LlamaSpit.java @@ -41,6 +41,11 @@ public class LlamaSpit extends Projectile { @Override public void tick() { @@ -16419,14 +16064,14 @@ index 958ea103cc80da7366cc33dc385b76d4f5c809f2..40645ef84efb096646d7bf7cd8c445b9 + return; + } + // Folia end - region threading - make sure entities do not move into regions they do not own - Vec3 vec3d = this.getDeltaMovement(); - HitResult movingobjectposition = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); - -diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index 9a7b56b653848974e1194eb4f6d40cb99a96ff57..a6bcf7b57b804af74f75c0b24ff48ee2714c3b73 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -@@ -44,7 +44,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { + Vec3 deltaMovement = this.getDeltaMovement(); + HitResult hitResultOnMoveVector = ProjectileUtil.getHitResultOnMoveVector(this, this::canHitEntity); + this.preHitTargetOrDeflectSelf(hitResultOnMoveVector); // CraftBukkit - projectile hit event +diff --git a/net/minecraft/world/entity/projectile/Projectile.java b/net/minecraft/world/entity/projectile/Projectile.java +index af71a71ff11b418a43728fd464b1e673d593140f..20f8aed59ac953cac3029115f35e496f9784bec4 100644 +--- a/net/minecraft/world/entity/projectile/Projectile.java ++++ b/net/minecraft/world/entity/projectile/Projectile.java +@@ -38,7 +38,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { @Nullable public UUID ownerUUID; @Nullable @@ -16435,21 +16080,21 @@ index 9a7b56b653848974e1194eb4f6d40cb99a96ff57..a6bcf7b57b804af74f75c0b24ff48ee2 public boolean leftOwner; public boolean hasBeenShot; @Nullable -@@ -61,7 +61,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { - public void setOwner(@Nullable Entity entity) { - if (entity != null) { - this.ownerUUID = entity.getUUID(); -- this.cachedOwner = entity; -+ this.cachedOwner = entity.getBukkitEntity(); // Folia - region threading +@@ -52,7 +52,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { + public void setOwner(@Nullable Entity owner) { + if (owner != null) { + this.ownerUUID = owner.getUUID(); +- this.cachedOwner = owner; ++ this.cachedOwner = owner.getBukkitEntity(); // Folia - region threading } // Paper start - Refresh ProjectileSource for projectiles else { -@@ -77,22 +77,38 @@ public abstract class Projectile extends Entity implements TraceableEntity { +@@ -69,22 +69,38 @@ public abstract class Projectile extends Entity implements TraceableEntity { if (fillCache) { this.getOwner(); } -- if (this.cachedOwner != null && !this.cachedOwner.isRemoved() && this.projectileSource == null && this.cachedOwner.getBukkitEntity() instanceof ProjectileSource projSource) { -+ if (this.cachedOwner != null && !this.cachedOwner.getHandleRaw().isRemoved() && this.projectileSource == null && this.cachedOwner instanceof ProjectileSource projSource) { // Folia - region threading +- if (this.cachedOwner != null && !this.cachedOwner.isRemoved() && this.projectileSource == null && this.cachedOwner.getBukkitEntity() instanceof org.bukkit.projectiles.ProjectileSource projSource) { ++ if (this.cachedOwner != null && !this.cachedOwner.getHandleRaw().isRemoved() && this.projectileSource == null && this.cachedOwner instanceof org.bukkit.projectiles.ProjectileSource projSource) { // Folia - region threading this.projectileSource = projSource; } } @@ -16488,7 +16133,7 @@ index 9a7b56b653848974e1194eb4f6d40cb99a96ff57..a6bcf7b57b804af74f75c0b24ff48ee2 } else { return null; } -@@ -144,7 +160,12 @@ public abstract class Projectile extends Entity implements TraceableEntity { +@@ -130,7 +146,12 @@ public abstract class Projectile extends Entity implements TraceableEntity { protected void setOwnerThroughUUID(UUID uuid) { if (this.ownerUUID != uuid) { this.ownerUUID = uuid; @@ -16500,35 +16145,35 @@ index 9a7b56b653848974e1194eb4f6d40cb99a96ff57..a6bcf7b57b804af74f75c0b24ff48ee2 + } + // Folia end - region threading } - - } -@@ -468,7 +489,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { - public boolean mayInteract(ServerLevel world, BlockPos pos) { - Entity entity = this.getOwner(); - -- return entity instanceof Player ? entity.mayInteract(world, pos) : entity == null || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); -+ return entity instanceof Player && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity) ? entity.mayInteract(world, pos) : entity == null || world.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Folia - region threading } - public boolean mayBreak(ServerLevel world) { -diff --git a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java -index bb159ea4baf208aab6d6fcfbbddacd5b089b55c8..6a0c3e8e304f3861366e06345b20bd790d858e55 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/SmallFireball.java -@@ -29,7 +29,7 @@ public class SmallFireball extends Fireball { - public SmallFireball(Level world, LivingEntity owner, Vec3 velocity) { - super(EntityType.SMALL_FIREBALL, owner, velocity, world); +@@ -451,7 +472,7 @@ public abstract class Projectile extends Entity implements TraceableEntity { + @Override + public boolean mayInteract(ServerLevel level, BlockPos pos) { + Entity owner = this.getOwner(); +- return owner instanceof Player ? owner.mayInteract(level, pos) : owner == null || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ return owner instanceof Player && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(owner) ? owner.mayInteract(level, pos) : owner == null || level.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); // Folia - region threading + } + + public boolean mayBreak(ServerLevel level) { +diff --git a/net/minecraft/world/entity/projectile/SmallFireball.java b/net/minecraft/world/entity/projectile/SmallFireball.java +index 8c84cea43fc0e42a576004663670977eac99f1a6..ba70ce3df630532b646eab0a5fabca15d67c379b 100644 +--- a/net/minecraft/world/entity/projectile/SmallFireball.java ++++ b/net/minecraft/world/entity/projectile/SmallFireball.java +@@ -24,7 +24,7 @@ public class SmallFireball extends Fireball { + public SmallFireball(Level level, LivingEntity owner, Vec3 movement) { + super(EntityType.SMALL_FIREBALL, owner, movement, level); // CraftBukkit start - if (this.getOwner() != null && this.getOwner() instanceof Mob) { -+ if (owner != null && this.getOwner() instanceof Mob) { // Folia - region threading - this.isIncendiary = (world instanceof ServerLevel worldserver) && worldserver.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); ++ if (owner != null && this.getOwner() != null && this.getOwner() instanceof Mob) { // Folia - region threading + this.isIncendiary = (level instanceof ServerLevel serverLevel) && serverLevel.getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING); } // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java b/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java -index c309198d092fdae6bdcc5d773b7b707bab2738bd..ff53dfec183e7933e5ceda8bf5a88b179d8d8532 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrowableProjectile.java -@@ -46,6 +46,11 @@ public abstract class ThrowableProjectile extends Projectile { +diff --git a/net/minecraft/world/entity/projectile/ThrowableProjectile.java b/net/minecraft/world/entity/projectile/ThrowableProjectile.java +index f9fa2866cb28622785b4fcd54c0e2989569a401a..74590ac276965543c2d78fe85090097c8d3a7aed 100644 +--- a/net/minecraft/world/entity/projectile/ThrowableProjectile.java ++++ b/net/minecraft/world/entity/projectile/ThrowableProjectile.java +@@ -43,6 +43,11 @@ public abstract class ThrowableProjectile extends Projectile { @Override public void tick() { @@ -16540,12 +16185,12 @@ index c309198d092fdae6bdcc5d773b7b707bab2738bd..ff53dfec183e7933e5ceda8bf5a88b17 this.handleFirstTickBubbleColumn(); this.applyGravity(); this.applyInertia(); -diff --git a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -index bd2684528157f928460f2143dd71a48e11983123..3bd0f3ae53eaa22409152d7f41e511e76bdaa265 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/ThrownEnderpearl.java -@@ -120,6 +120,81 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { - entityHitResult.getEntity().hurt(this.damageSources().thrown(this, this.getOwner()), 0.0F); +diff --git a/net/minecraft/world/entity/projectile/ThrownEnderpearl.java b/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +index 128bf1555b996c454e753b1ed004cfeae4b0436f..12e563b04e6afcd227f3ef6cbdfcedf59be9509e 100644 +--- a/net/minecraft/world/entity/projectile/ThrownEnderpearl.java ++++ b/net/minecraft/world/entity/projectile/ThrownEnderpearl.java +@@ -99,6 +99,81 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { + result.getEntity().hurt(this.damageSources().thrown(this, this.getOwner()), 0.0F); } + // Folia start - region threading @@ -16571,7 +16216,7 @@ index bd2684528157f928460f2143dd71a48e11983123..3bd0f3ae53eaa22409152d7f41e511e7 + + entity.teleportAsync( + checkWorld, to, null, null, null, -+ PlayerTeleportEvent.TeleportCause.ENDER_PEARL, ++ org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.ENDER_PEARL, + // chunk could have been unloaded + Entity.TELEPORT_FLAG_TELEPORT_PASSENGERS | Entity.TELEPORT_FLAG_LOAD_CHUNK, + (Entity teleported) -> { @@ -16589,7 +16234,7 @@ index bd2684528157f928460f2143dd71a48e11983123..3bd0f3ae53eaa22409152d7f41e511e7 + float xRot = teleported.getXRot(); + Runnable spawn = () -> { + entityendermite.moveTo(endermitePos.x, endermitePos.y, endermitePos.z, yRot, xRot); -+ world.addFreshEntity(entityendermite, CreatureSpawnEvent.SpawnReason.ENDER_PEARL); ++ world.addFreshEntity(entityendermite, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.ENDER_PEARL); + }; + + if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(world, endermitePos, net.minecraft.world.phys.Vec3.ZERO, 1)) { @@ -16624,34 +16269,34 @@ index bd2684528157f928460f2143dd71a48e11983123..3bd0f3ae53eaa22409152d7f41e511e7 + // Folia end - region threading + @Override - protected void onHit(HitResult hitResult) { - super.onHit(hitResult); -@@ -132,6 +207,20 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { + protected void onHit(HitResult result) { + super.onHit(result); +@@ -117,6 +192,20 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { + } - if (world instanceof ServerLevel worldserver) { - if (!this.isRemoved()) { -+ // Folia start - region threading -+ if (true) { -+ // we can't fire events, because we do not actually know where the other entity is located -+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this)) { -+ throw new IllegalStateException("Must be on tick thread for ticking entity: " + this); -+ } -+ Entity entity = this.getOwnerRaw(); -+ if (entity != null) { -+ attemptTeleport(entity, (ServerLevel)this.level(), this.position()); -+ } -+ this.discard(EntityRemoveEvent.Cause.HIT); -+ return; + if (this.level() instanceof ServerLevel serverLevel && !this.isRemoved()) { ++ // Folia start - region threading ++ if (true) { ++ // we can't fire events, because we do not actually know where the other entity is located ++ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this)) { ++ throw new IllegalStateException("Must be on tick thread for ticking entity: " + this); + } -+ // Folia end - region threading - Entity entity = this.getOwner(); - - if (entity != null && ThrownEnderpearl.isAllowedToTeleportOwner(entity, worldserver)) { -@@ -242,7 +331,15 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { ++ Entity entity = this.getOwnerRaw(); ++ if (entity != null) { ++ attemptTeleport(entity, (ServerLevel)this.level(), this.position()); ++ } ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); ++ return; ++ } ++ // Folia end - region threading + Entity owner = this.getOwner(); + if (owner != null && isAllowedToTeleportOwner(owner, serverLevel)) { + if (owner.isPassenger()) { +@@ -212,7 +301,15 @@ public class ThrownEnderpearl extends ThrowableItemProjectile { } } -- private void playSound(Level world, Vec3 pos) { +- private void playSound(Level level, Vec3 pos) { + // Folia start - region threading + @Override + public void preChangeDimension() { @@ -16660,15 +16305,15 @@ index bd2684528157f928460f2143dd71a48e11983123..3bd0f3ae53eaa22409152d7f41e511e7 + } + // Folia end - region threading + -+ private static void playSound(Level world, Vec3 pos) { // Folia - region threading - static - world.playSound((Player) null, pos.x, pos.y, pos.z, SoundEvents.PLAYER_TELEPORT, SoundSource.PLAYERS); ++ private static void playSound(Level level, Vec3 pos) { // Folia - region threading - static + level.playSound(null, pos.x, pos.y, pos.z, SoundEvents.PLAYER_TELEPORT, SoundSource.PLAYERS); } -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raid.java b/src/main/java/net/minecraft/world/entity/raid/Raid.java -index 11cf2d9def087b0898c828eaa21eb5f7b8811d5f..5ff4a4af7f166f5f977efe41263ca487fe1b270b 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raid.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raid.java -@@ -113,6 +113,13 @@ public class Raid { +diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java +index 6e8c1a2863ac6e5137a26815ecf5142f0fcc9893..b7045b2d4665c72d0c4849c711be4e44f7d17ad3 100644 +--- a/net/minecraft/world/entity/raid/Raid.java ++++ b/net/minecraft/world/entity/raid/Raid.java +@@ -110,6 +110,13 @@ public class Raid { public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(PDC_TYPE_REGISTRY); // Paper end @@ -16679,47 +16324,47 @@ index 11cf2d9def087b0898c828eaa21eb5f7b8811d5f..5ff4a4af7f166f5f977efe41263ca487 + } + // Folia end - make raids thread-safe + - public Raid(int id, ServerLevel world, BlockPos pos) { - this.raidEvent = new ServerBossEvent(Raid.RAID_NAME_COMPONENT, BossEvent.BossBarColor.RED, BossEvent.BossBarOverlay.NOTCHED_10); - this.random = RandomSource.create(); -@@ -226,7 +233,7 @@ public class Raid { - return (entityplayer) -> { - BlockPos blockposition = entityplayer.blockPosition(); - -- return entityplayer.isAlive() && this.level.getRaidAt(blockposition) == this; -+ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entityplayer) && entityplayer.isAlive() && this.level.getRaidAt(blockposition) == this; // Folia - make raids thread-safe + public Raid(int id, ServerLevel level, BlockPos center) { + this.id = id; + this.level = level; +@@ -207,7 +214,7 @@ public class Raid { + private Predicate validPlayer() { + return player -> { + BlockPos blockPos = player.blockPosition(); +- return player.isAlive() && this.level.getRaidAt(blockPos) == this; ++ return ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player) && player.isAlive() && this.level.getRaidAt(blockPos) == this; // Folia - make raids thread-safe }; } -@@ -541,7 +548,7 @@ public class Raid { - boolean flag = true; - Collection collection = this.raidEvent.getPlayers(); - long i = this.random.nextLong(); -- Iterator iterator = this.level.players().iterator(); -+ Iterator iterator = this.level.getLocalPlayers().iterator(); // Folia - region threading - - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raider.java b/src/main/java/net/minecraft/world/entity/raid/Raider.java -index cee1e4db2312efb4843c4b6dc18f4af10b91d304..d833c92018895d0576ba08578be7b1c6c49ac1b2 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raider.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raider.java -@@ -92,7 +92,7 @@ public abstract class Raider extends PatrollingMonster { +@@ -496,7 +503,7 @@ public class Raid { + Collection players = this.raidEvent.getPlayers(); + long randomLong = this.random.nextLong(); +- for (ServerPlayer serverPlayer : this.level.players()) { ++ for (ServerPlayer serverPlayer : this.level.getLocalPlayers()) { // Folia - region threading + Vec3 vec3 = serverPlayer.position(); + Vec3 vec31 = Vec3.atCenterOf(pos); + double squareRoot = Math.sqrt((vec31.x - vec3.x) * (vec31.x - vec3.x) + (vec31.z - vec3.z) * (vec31.z - vec3.z)); +diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java +index 8270d76a753bfd26a4c8ef6610bee5c24ee59cfe..7c385baae81b9a987c0e1e4deb017884600331bc 100644 +--- a/net/minecraft/world/entity/raid/Raider.java ++++ b/net/minecraft/world/entity/raid/Raider.java +@@ -86,7 +86,7 @@ public abstract class Raider extends PatrollingMonster { + Raid currentRaid = this.getCurrentRaid(); if (this.canJoinRaid()) { - if (raid == null) { + if (currentRaid == null) { - if (this.level().getGameTime() % 20L == 0L) { + if (this.level().getRedstoneGameTime() % 20L == 0L) { // Folia - region threading - Raid raid1 = ((ServerLevel) this.level()).getRaidAt(this.blockPosition()); + Raid raidAt = ((ServerLevel)this.level()).getRaidAt(this.blockPosition()); + if (raidAt != null && Raids.canJoinRaid(this, raidAt)) { + raidAt.joinRaid(raidAt.getGroupsSpawned(), this, null, true); +diff --git a/net/minecraft/world/entity/raid/Raids.java b/net/minecraft/world/entity/raid/Raids.java +index 34eb038725d1577f1a2d7c35c897b1270eac5749..0ffc1956d9e808871c5b36f6eb5ed750abaa880c 100644 +--- a/net/minecraft/world/entity/raid/Raids.java ++++ b/net/minecraft/world/entity/raid/Raids.java +@@ -25,9 +25,9 @@ import net.minecraft.world.phys.Vec3; - if (raid1 != null && Raids.canJoinRaid(this, raid1)) { -diff --git a/src/main/java/net/minecraft/world/entity/raid/Raids.java b/src/main/java/net/minecraft/world/entity/raid/Raids.java -index 439d61d8689fabe940006b9b317a6810175dccfb..81ac4b7df5c402a618f6d7196b905ea065d6e822 100644 ---- a/src/main/java/net/minecraft/world/entity/raid/Raids.java -+++ b/src/main/java/net/minecraft/world/entity/raid/Raids.java -@@ -26,9 +26,9 @@ import net.minecraft.world.phys.Vec3; public class Raids extends SavedData { - private static final String RAID_FILE_ID = "raids"; - public final Map raidMap = Maps.newHashMap(); + public final Map raidMap = new java.util.concurrent.ConcurrentHashMap<>(); // Folia - make raids thread-safe @@ -16728,45 +16373,44 @@ index 439d61d8689fabe940006b9b317a6810175dccfb..81ac4b7df5c402a618f6d7196b905ea0 + private final java.util.concurrent.atomic.AtomicInteger nextAvailableID = new java.util.concurrent.atomic.AtomicInteger(); // Folia - make raids thread-safe private int tick; - public static SavedData.Factory factory(ServerLevel world) { -@@ -41,7 +41,7 @@ public class Raids extends SavedData { + public static SavedData.Factory factory(ServerLevel level) { +@@ -36,7 +36,7 @@ public class Raids extends SavedData { - public Raids(ServerLevel world) { - this.level = world; + public Raids(ServerLevel level) { + this.level = level; - this.nextAvailableID = 1; + this.nextAvailableID.set(1); // Folia - make raids thread-safe this.setDirty(); } -@@ -49,12 +49,26 @@ public class Raids extends SavedData { - return (Raid) this.raidMap.get(id); +@@ -44,12 +44,25 @@ public class Raids extends SavedData { + return this.raidMap.get(id); } -- public void tick() { + // Folia start - make raids thread-safe + public void globalTick() { - ++this.tick; ++ ++this.tick; + if (this.tick % 200 == 0) { + this.setDirty(); + } -+ // Folia end - make raids thread-safe + } + -+ public void tick() { -+ // Folia - make raids thread-safe - move to globalTick() + public void tick() { +- this.tick++; ++ // Folia end - make raids thread-safe Iterator iterator = this.raidMap.values().iterator(); while (iterator.hasNext()) { - Raid raid = (Raid) iterator.next(); + Raid raid = iterator.next(); + // Folia start - make raids thread-safe + if (!raid.ownsRaid()) { + continue; + } + // Folia end - make raids thread-safe - if (this.level.getGameRules().getBoolean(GameRules.RULE_DISABLE_RAIDS)) { raid.stop(); -@@ -68,14 +82,17 @@ public class Raids extends SavedData { + } +@@ -62,14 +75,17 @@ public class Raids extends SavedData { } } @@ -16784,37 +16428,37 @@ index 439d61d8689fabe940006b9b317a6810175dccfb..81ac4b7df5c402a618f6d7196b905ea0 + return false; + } + // Folia end - make raids thread-safe - return raider != null && raid != null && raid.getLevel() != null ? raider.isAlive() && raider.canJoinRaid() && raider.getNoActionTime() <= 2400 && raider.level().dimensionType() == raid.getLevel().dimensionType() : false; - } - -@@ -88,7 +105,7 @@ public class Raids extends SavedData { + return raider != null + && raid != null + && raid.getLevel() != null +@@ -87,7 +103,7 @@ public class Raids extends SavedData { + return null; } else { - DimensionType dimensionmanager = player.level().dimensionType(); - -- if (!dimensionmanager.hasRaids()) { -+ if (!dimensionmanager.hasRaids() || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player) || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, pos.getX() >> 4, pos.getZ() >> 4, 8) || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, player.chunkPosition().x, player.chunkPosition().z, 8)) { // Folia - region threading + DimensionType dimensionType = player.level().dimensionType(); +- if (!dimensionType.hasRaids()) { ++ if (!dimensionType.hasRaids() || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player) || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, pos.getX() >> 4, pos.getZ() >> 4, 8) || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, player.chunkPosition().x, player.chunkPosition().z, 8)) { // Folia - region threading return null; } else { - List list = this.level.getPoiManager().getInRange((holder) -> { -@@ -150,7 +167,7 @@ public class Raids extends SavedData { - public static Raids load(ServerLevel world, CompoundTag nbt) { - Raids persistentraid = new Raids(world); + List list = this.level +@@ -145,7 +161,7 @@ public class Raids extends SavedData { -- persistentraid.nextAvailableID = nbt.getInt("NextAvailableID"); -+ persistentraid.nextAvailableID.set(nbt.getInt("NextAvailableID")); // Folia - make raids thread-safe - persistentraid.tick = nbt.getInt("Tick"); - ListTag nbttaglist = nbt.getList("Raids", 10); + public static Raids load(ServerLevel level, CompoundTag tag) { + Raids raids = new Raids(level); +- raids.nextAvailableID = tag.getInt("NextAvailableID"); ++ raids.nextAvailableID.set(tag.getInt("NextAvailableID")); // Folia - make raids thread-safe + raids.tick = tag.getInt("Tick"); + ListTag list = tag.getList("Raids", 10); -@@ -166,7 +183,7 @@ public class Raids extends SavedData { +@@ -160,7 +176,7 @@ public class Raids extends SavedData { @Override - public CompoundTag save(CompoundTag nbt, HolderLookup.Provider registries) { -- nbt.putInt("NextAvailableID", this.nextAvailableID); -+ nbt.putInt("NextAvailableID", this.nextAvailableID.get()); // Folia - make raids thread-safe - nbt.putInt("Tick", this.tick); - ListTag nbttaglist = new ListTag(); - Iterator iterator = this.raidMap.values().iterator(); -@@ -188,7 +205,7 @@ public class Raids extends SavedData { + public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) { +- tag.putInt("NextAvailableID", this.nextAvailableID); ++ tag.putInt("NextAvailableID", this.nextAvailableID.get()); // Folia - make raids thread-safe + tag.putInt("Tick", this.tick); + ListTag listTag = new ListTag(); + +@@ -179,7 +195,7 @@ public class Raids extends SavedData { } private int getUniqueId() { @@ -16823,24 +16467,24 @@ index 439d61d8689fabe940006b9b317a6810175dccfb..81ac4b7df5c402a618f6d7196b905ea0 } @Nullable -@@ -199,6 +216,11 @@ public class Raids extends SavedData { +@@ -188,6 +204,11 @@ public class Raids extends SavedData { + double d = distance; - while (iterator.hasNext()) { - Raid raid1 = (Raid) iterator.next(); + for (Raid raid1 : this.raidMap.values()) { + // Folia start - make raids thread-safe + if (!raid1.ownsRaid()) { + continue; + } + // Folia end - make raids thread-safe double d1 = raid1.getCenter().distSqr(pos); - - if (raid1.isActive() && d1 < d0) { -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -index a811cdca34bb468ac355f72decd153d4f0618009..ef33d3cba37e2b2b70650af55841c21788699123 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java -@@ -142,5 +142,11 @@ public class MinecartCommandBlock extends AbstractMinecart { - return (org.bukkit.craftbukkit.entity.CraftMinecartCommand) MinecartCommandBlock.this.getBukkitEntity(); + if (raid1.isActive() && d1 < d) { + raid = raid1; +diff --git a/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java b/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java +index 82421d3b4116ca406cdfffec5a3d65a99cbe294b..3a575ff4860c3b000a23e7754181f48d942441e9 100644 +--- a/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java ++++ b/net/minecraft/world/entity/vehicle/MinecartCommandBlock.java +@@ -145,5 +145,11 @@ public class MinecartCommandBlock extends AbstractMinecart { + return net.minecraft.world.entity.vehicle.MinecartCommandBlock.this.getBukkitEntity(); } // CraftBukkit end + // Folia start @@ -16851,10 +16495,10 @@ index a811cdca34bb468ac355f72decd153d4f0618009..ef33d3cba37e2b2b70650af55841c217 + // Folia end } } -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java -index d81a6874e8b25f098df619f84c359e146c7f64de..e56d580a89931aba43602a758fad803fbe45f25e 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/MinecartHopper.java +diff --git a/net/minecraft/world/entity/vehicle/MinecartHopper.java b/net/minecraft/world/entity/vehicle/MinecartHopper.java +index 8341e7f01606fca90e69384c16fc19bb9e20d1b7..c07f6fefdba5242c09c0081a0f074948f9df9ae6 100644 +--- a/net/minecraft/world/entity/vehicle/MinecartHopper.java ++++ b/net/minecraft/world/entity/vehicle/MinecartHopper.java @@ -145,7 +145,7 @@ public class MinecartHopper extends AbstractMinecartContainer implements Hopper // Paper start @@ -16864,186 +16508,176 @@ index d81a6874e8b25f098df619f84c359e146c7f64de..e56d580a89931aba43602a758fad803f } // Paper end -diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java -index f29415b8dff7d17328e159b56ae4ad46452f018e..b4bf2069e78cb1408593ed41575ee747651e33c8 100644 ---- a/src/main/java/net/minecraft/world/item/ItemStack.java -+++ b/src/main/java/net/minecraft/world/item/ItemStack.java -@@ -429,31 +429,32 @@ public final class ItemStack implements DataComponentHolder { - DataComponentPatch oldData = this.components.asPatch(); +diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java +index b511fe8295369ac4014beb351cd2e3f770c10170..264d61426630f6c9c77d39c50006981fd3cd4948 100644 +--- a/net/minecraft/world/item/ItemStack.java ++++ b/net/minecraft/world/item/ItemStack.java +@@ -386,31 +386,32 @@ public final class ItemStack implements DataComponentHolder { + DataComponentPatch previousPatch = this.components.asPatch(); int oldCount = this.getCount(); - ServerLevel world = (ServerLevel) context.getLevel(); -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading + ServerLevel serverLevel = (ServerLevel) context.getLevel(); ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = serverLevel.getCurrentWorldData(); // Folia - region threading if (!(item instanceof BucketItem/* || item instanceof SolidBucketItem*/)) { // if not bucket // Paper - Fix cancelled powdered snow bucket placement -- world.captureBlockStates = true; +- serverLevel.captureBlockStates = true; + worldData.captureBlockStates = true; // Folia - region threading // special case bonemeal if (item == Items.BONE_MEAL) { -- world.captureTreeGeneration = true; +- serverLevel.captureTreeGeneration = true; + worldData.captureTreeGeneration = true; // Folia - region threading } } - InteractionResult enuminteractionresult; + InteractionResult interactionResult; try { - enuminteractionresult = item.useOn(context); + interactionResult = item.useOn(context); } finally { -- world.captureBlockStates = false; +- serverLevel.captureBlockStates = false; + worldData.captureBlockStates = false; // Folia - region threading } - DataComponentPatch newData = this.components.asPatch(); + DataComponentPatch newPatch = this.components.asPatch(); int newCount = this.getCount(); this.setCount(oldCount); - this.restorePatch(oldData); -- if (enuminteractionresult.consumesAction() && world.captureTreeGeneration && world.capturedBlockStates.size() > 0) { -- world.captureTreeGeneration = false; -+ if (enuminteractionresult.consumesAction() && worldData.captureTreeGeneration && worldData.capturedBlockStates.size() > 0) { // Folia - region threading -+ worldData.captureTreeGeneration = false; - Location location = CraftLocation.toBukkit(blockposition, world.getWorld()); -- TreeType treeType = SaplingBlock.treeType; -- SaplingBlock.treeType = null; -- List blocks = new java.util.ArrayList<>(world.capturedBlockStates.values()); -- world.capturedBlockStates.clear(); -+ TreeType treeType = SaplingBlock.treeTypeRT.get(); // Folia - region threading -+ SaplingBlock.treeTypeRT.set(null); // Folia - region threading -+ List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading + this.restorePatch(previousPatch); +- if (interactionResult.consumesAction() && serverLevel.captureTreeGeneration && !serverLevel.capturedBlockStates.isEmpty()) { +- serverLevel.captureTreeGeneration = false; ++ if (interactionResult.consumesAction() && worldData.captureTreeGeneration && !worldData.capturedBlockStates.isEmpty()) { // Folia - region threading ++ worldData.captureTreeGeneration = false; // Folia - region threading + org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(clickedPos, serverLevel.getWorld()); +- org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType; +- net.minecraft.world.level.block.SaplingBlock.treeType = null; +- List blocks = new java.util.ArrayList<>(serverLevel.capturedBlockStates.values()); +- serverLevel.capturedBlockStates.clear(); ++ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get(); // Folia - region threading ++ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null); // Folia - region threading ++ List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading + worldData.capturedBlockStates.clear(); // Folia - region threading - StructureGrowEvent structureEvent = null; + org.bukkit.event.world.StructureGrowEvent structureEvent = null; if (treeType != null) { boolean isBonemeal = this.getItem() == Items.BONE_MEAL; -@@ -479,10 +480,10 @@ public final class ItemStack implements DataComponentHolder { - entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat +@@ -436,15 +437,15 @@ public final class ItemStack implements DataComponentHolder { + player.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat } - SignItem.openSign = null; // SPIGOT-6758 - Reset on early return + SignItem.openSign.set(null); // SPIGOT-6758 - Reset on early return // Folia - region threading - return enuminteractionresult; + return interactionResult; } -- world.captureTreeGeneration = false; +- serverLevel.captureTreeGeneration = false; + worldData.captureTreeGeneration = false; // Folia - region threading - - if (entityhuman != null && enuminteractionresult instanceof InteractionResult.Success) { - InteractionResult.Success enuminteractionresult_d = (InteractionResult.Success) enuminteractionresult; -@@ -490,8 +491,8 @@ public final class ItemStack implements DataComponentHolder { - if (enuminteractionresult_d.wasItemInteraction()) { - InteractionHand enumhand = context.getHand(); - org.bukkit.event.block.BlockPlaceEvent placeEvent = null; -- List blocks = new java.util.ArrayList<>(world.capturedBlockStates.values()); -- world.capturedBlockStates.clear(); -+ List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading -+ worldData.capturedBlockStates.clear(); // Folia - region threading - if (blocks.size() > 1) { - placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, enumhand, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ()); - } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement -@@ -502,15 +503,15 @@ public final class ItemStack implements DataComponentHolder { - enuminteractionresult = InteractionResult.FAIL; // cancel placement - // PAIL: Remove this when MC-99075 fixed - placeEvent.getPlayer().updateInventory(); -- world.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot -+ worldData.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot // Folia - region threading - // revert back all captured blocks -- world.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 -- world.isBlockPlaceCancelled = true; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent -+ worldData.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 // Folia - region threading + if (player != null && interactionResult instanceof InteractionResult.Success success && success.wasItemInteraction()) { + InteractionHand hand = context.getHand(); + org.bukkit.event.block.BlockPlaceEvent placeEvent = null; +- List blocks = new java.util.ArrayList<>(serverLevel.capturedBlockStates.values()); +- serverLevel.capturedBlockStates.clear(); ++ List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading ++ worldData.capturedBlockStates.clear(); // Folia - region threading + if (blocks.size() > 1) { + placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(serverLevel, player, hand, blocks, clickedPos.getX(), clickedPos.getY(), clickedPos.getZ()); + } else if (blocks.size() == 1 && item != Items.POWDER_SNOW_BUCKET) { // Paper - Fix cancelled powdered snow bucket placement +@@ -455,17 +456,17 @@ public final class ItemStack implements DataComponentHolder { + interactionResult = InteractionResult.FAIL; // cancel placement + // PAIL: Remove this when MC-99075 fixed + placeEvent.getPlayer().updateInventory(); +- serverLevel.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot ++ worldData.capturedTileEntities.clear(); // Paper - Allow chests to be placed with NBT data; clear out block entities as chests and such will pop loot // Folia - region threading + // revert back all captured blocks +- serverLevel.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 +- serverLevel.isBlockPlaceCancelled = true; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent ++ worldData.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710 // Folia - region threading + worldData.isBlockPlaceCancelled = true; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent // Folia - region threading - for (BlockState blockstate : blocks) { - blockstate.update(true, false); - } -- world.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent -- world.preventPoiUpdated = false; -+ worldData.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent // Folia - region threading -+ worldData.preventPoiUpdated = false; // Folia - region threading - - // Brute force all possible updates - // Paper start - Don't resync blocks -@@ -519,7 +520,7 @@ public final class ItemStack implements DataComponentHolder { - // ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir))); - // } - // Paper end - Don't resync blocks -- SignItem.openSign = null; // SPIGOT-6758 - Reset on early return -+ SignItem.openSign.set(null); // SPIGOT-6758 - Reset on early return // Folia - region threading - } else { - // Change the stack to its new contents if it hasn't been tampered with. - if (this.getCount() == oldCount && Objects.equals(this.components.asPatch(), oldData)) { -@@ -527,7 +528,7 @@ public final class ItemStack implements DataComponentHolder { - this.setCount(newCount); - } - -- for (Map.Entry e : world.capturedTileEntities.entrySet()) { -+ for (Map.Entry e : worldData.capturedTileEntities.entrySet()) { // Folia - region threading - world.setBlockEntity(e.getValue()); - } - -@@ -562,15 +563,15 @@ public final class ItemStack implements DataComponentHolder { - } - - // SPIGOT-4678 -- if (this.item instanceof SignItem && SignItem.openSign != null) { -+ if (this.item instanceof SignItem && SignItem.openSign.get() != null) { // Folia - region threading - try { -- if (world.getBlockEntity(SignItem.openSign) instanceof SignBlockEntity tileentitysign) { -- if (world.getBlockState(SignItem.openSign).getBlock() instanceof SignBlock blocksign) { -+ if (world.getBlockEntity(SignItem.openSign.get()) instanceof SignBlockEntity tileentitysign) { // Folia - region threading -+ if (world.getBlockState(SignItem.openSign.get()).getBlock() instanceof SignBlock blocksign) { // Folia - region threading - blocksign.openTextEdit(entityhuman, tileentitysign, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // Craftbukkit // Paper - Add PlayerOpenSignEvent - } - } - } finally { -- SignItem.openSign = null; -+ SignItem.openSign.set(null); // Folia - region threading - } - } - -@@ -599,8 +600,8 @@ public final class ItemStack implements DataComponentHolder { + for (org.bukkit.block.BlockState blockstate : blocks) { + blockstate.update(true, false); } +- serverLevel.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent +- serverLevel.preventPoiUpdated = false; ++ worldData.isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent // Folia - region threading ++ worldData.preventPoiUpdated = false; // Folia - region threading + +- SignItem.openSign = null; // SPIGOT-6758 - Reset on early return ++ SignItem.openSign.set(null); // SPIGOT-6758 - Reset on early return // Folia - region threading + } else { + // Change the stack to its new contents if it hasn't been tampered with. + if (this.getCount() == oldCount && Objects.equals(this.components.asPatch(), previousPatch)) { +@@ -473,7 +474,7 @@ public final class ItemStack implements DataComponentHolder { + this.setCount(newCount); + } + +- for (java.util.Map.Entry e : serverLevel.capturedTileEntities.entrySet()) { ++ for (java.util.Map.Entry e : worldData.capturedTileEntities.entrySet()) { // Folia - region threading + serverLevel.setBlockEntity(e.getValue()); + } + +@@ -508,15 +509,15 @@ public final class ItemStack implements DataComponentHolder { + } + + // SPIGOT-4678 +- if (this.item instanceof SignItem && SignItem.openSign != null) { ++ if (this.item instanceof SignItem && SignItem.openSign.get() != null) { // Folia - region threading + try { +- if (serverLevel.getBlockEntity(SignItem.openSign) instanceof net.minecraft.world.level.block.entity.SignBlockEntity blockEntity) { +- if (serverLevel.getBlockState(SignItem.openSign).getBlock() instanceof net.minecraft.world.level.block.SignBlock signBlock) { ++ if (serverLevel.getBlockEntity(SignItem.openSign.get()) instanceof net.minecraft.world.level.block.entity.SignBlockEntity blockEntity) { // Folia - region threading ++ if (serverLevel.getBlockState(SignItem.openSign.get()).getBlock() instanceof net.minecraft.world.level.block.SignBlock signBlock) { // Folia - region threading + signBlock.openTextEdit(player, blockEntity, true, io.papermc.paper.event.player.PlayerOpenSignEvent.Cause.PLACE); // CraftBukkit // Paper - Add PlayerOpenSignEvent + } + } + } finally { +- SignItem.openSign = null; ++ SignItem.openSign.set(null); + } + } + +@@ -544,8 +545,8 @@ public final class ItemStack implements DataComponentHolder { + player.awardStat(Stats.ITEM_USED.get(item)); } } -- world.capturedTileEntities.clear(); -- world.capturedBlockStates.clear(); +- serverLevel.capturedTileEntities.clear(); +- serverLevel.capturedBlockStates.clear(); + worldData.capturedTileEntities.clear(); // Folia - region threading + worldData.capturedBlockStates.clear(); // Folia - region threading // CraftBukkit end - return enuminteractionresult; -diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java -index 8ff50a4c7461bbd9f469d503f6b5ee482d2463d7..65d1af43b8bc740a9dc77dd8d5ba99de000fe57a 100644 ---- a/src/main/java/net/minecraft/world/item/MapItem.java -+++ b/src/main/java/net/minecraft/world/item/MapItem.java -@@ -68,6 +68,7 @@ public class MapItem extends Item { + return interactionResult; +diff --git a/net/minecraft/world/item/MapItem.java b/net/minecraft/world/item/MapItem.java +index 8795d54cff569c911e0a535f38a0ec4130f7b4d5..9f07ce560e265582eec0fff5877a923f62a60e13 100644 +--- a/net/minecraft/world/item/MapItem.java ++++ b/net/minecraft/world/item/MapItem.java +@@ -70,6 +70,7 @@ public class MapItem extends Item { } - public void update(Level world, Entity entity, MapItemSavedData state) { -+ synchronized (state) { // Folia - make map data thread-safe - if (world.dimension() == state.dimension && entity instanceof Player) { - int i = 1 << state.scale; - int j = state.centerX; -@@ -97,8 +98,8 @@ public class MapItem extends Item { - int r = (j / i + o - 64) * i; - int s = (k / i + p - 64) * i; + public void update(Level level, Entity viewer, MapItemSavedData data) { ++ synchronized (data) { // Folia - make map data thread-safe + if (level.dimension() == data.dimension && viewer instanceof Player) { + int i = 1 << data.scale; + int i1 = data.centerX; +@@ -99,8 +100,8 @@ public class MapItem extends Item { + int i9 = (i1 / i + i6 - 64) * i; + int i10 = (i2 / i + i7 - 64) * i; Multiset multiset = LinkedHashMultiset.create(); -- LevelChunk levelChunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); // Paper - Maps shouldn't load chunks -- if (levelChunk != null && !levelChunk.isEmpty()) { // Paper - Maps shouldn't load chunks -+ LevelChunk levelChunk = world.getChunkIfLoaded(SectionPos.blockToSectionCoord(r), SectionPos.blockToSectionCoord(s)); // Paper - Maps shouldn't load chunks // Folia - super important that it uses getChunkIfLoaded -+ if (levelChunk != null && !levelChunk.isEmpty() && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor((ServerLevel)world, levelChunk.getPos())) { // Paper - Maps shouldn't load chunks // Folia - make sure chunk is owned - int t = 0; - double e = 0.0; - if (world.dimensionType().hasCeiling()) { -@@ -180,6 +181,7 @@ public class MapItem extends Item { +- LevelChunk chunk = level.getChunkIfLoaded(SectionPos.blockToSectionCoord(i9), SectionPos.blockToSectionCoord(i10)); // Paper - Maps shouldn't load chunks +- if (chunk != null && !chunk.isEmpty()) { // Paper - Maps shouldn't load chunks ++ LevelChunk chunk = level.getChunkIfLoaded(SectionPos.blockToSectionCoord(i9), SectionPos.blockToSectionCoord(i10)); // Paper - Maps shouldn't load chunks // Folia - super important that it uses getChunkIfLoaded ++ if (chunk != null && !chunk.isEmpty() && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, chunk.getPos())) { // Paper - Maps shouldn't load chunks // Folia - make sure chunk is owned + int i11 = 0; + double d1 = 0.0; + if (level.dimensionType().hasCeiling()) { +@@ -182,6 +183,7 @@ public class MapItem extends Item { } } } + } // Folia - make map data thread-safe } - private BlockState getCorrectStateForFluidBlock(Level world, BlockState state, BlockPos pos) { -@@ -194,6 +196,7 @@ public class MapItem extends Item { - public static void renderBiomePreviewMap(ServerLevel world, ItemStack map) { - MapItemSavedData mapItemSavedData = getSavedData(map, world); - if (mapItemSavedData != null) { -+ synchronized (mapItemSavedData) { // Folia - make map data thread-safe - if (world.dimension() == mapItemSavedData.dimension) { - int i = 1 << mapItemSavedData.scale; - int j = mapItemSavedData.centerX; -@@ -263,6 +266,7 @@ public class MapItem extends Item { + private BlockState getCorrectStateForFluidBlock(Level level, BlockState state, BlockPos pos) { +@@ -196,6 +198,7 @@ public class MapItem extends Item { + public static void renderBiomePreviewMap(ServerLevel serverLevel, ItemStack stack) { + MapItemSavedData savedData = getSavedData(stack, serverLevel); + if (savedData != null) { ++ synchronized (savedData) { // Folia - make map data thread-safe + if (serverLevel.dimension() == savedData.dimension) { + int i = 1 << savedData.scale; + int i1 = savedData.centerX; +@@ -265,6 +268,7 @@ public class MapItem extends Item { } } } @@ -17051,87 +16685,87 @@ index 8ff50a4c7461bbd9f469d503f6b5ee482d2463d7..65d1af43b8bc740a9dc77dd8d5ba99de } } -@@ -271,6 +275,7 @@ public class MapItem extends Item { - if (!world.isClientSide) { - MapItemSavedData mapItemSavedData = getSavedData(stack, world); - if (mapItemSavedData != null) { -+ synchronized (mapItemSavedData) { // Folia - region threading +@@ -273,6 +277,7 @@ public class MapItem extends Item { + if (!level.isClientSide) { + MapItemSavedData savedData = getSavedData(stack, level); + if (savedData != null) { ++ synchronized (savedData) { // Folia - region threading if (entity instanceof Player player) { - mapItemSavedData.tickCarriedBy(player, stack); + savedData.tickCarriedBy(player, stack); } -@@ -278,6 +283,7 @@ public class MapItem extends Item { - if (!mapItemSavedData.locked && (selected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) { - this.update(world, entity, mapItemSavedData); +@@ -280,6 +285,7 @@ public class MapItem extends Item { + if (!savedData.locked && (isSelected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) { + this.update(level, entity, savedData); } + } // Folia - region threading } } } -diff --git a/src/main/java/net/minecraft/world/item/SignItem.java b/src/main/java/net/minecraft/world/item/SignItem.java -index fcc78491cef1cf1535888c4ed43c3b71fb597848..d6ff4ad0b9fbba491e6d0c96aaa62a2eaca89fd6 100644 ---- a/src/main/java/net/minecraft/world/item/SignItem.java -+++ b/src/main/java/net/minecraft/world/item/SignItem.java -@@ -13,7 +13,7 @@ import net.minecraft.world.level.block.state.BlockState; +diff --git a/net/minecraft/world/item/SignItem.java b/net/minecraft/world/item/SignItem.java +index fffac12db30d4321981959a9149cc56f8b4f6df6..fdf4fa92a5ca98fae6266e29a54fb1b77e69407c 100644 +--- a/net/minecraft/world/item/SignItem.java ++++ b/net/minecraft/world/item/SignItem.java +@@ -11,7 +11,7 @@ import net.minecraft.world.level.block.entity.SignBlockEntity; + import net.minecraft.world.level.block.state.BlockState; public class SignItem extends StandingAndWallBlockItem { - - public static BlockPos openSign; // CraftBukkit + public static final ThreadLocal openSign = new ThreadLocal<>(); // CraftBukkit // Folia - region threading + public SignItem(Block standingBlock, Block wallBlock, Item.Properties properties) { + super(standingBlock, wallBlock, Direction.DOWN, properties); + } +@@ -30,7 +30,7 @@ public class SignItem extends StandingAndWallBlockItem { + && level.getBlockState(pos).getBlock() instanceof SignBlock signBlock) { + // CraftBukkit start - SPIGOT-4678 + // signBlock.openTextEdit(player, signBlockEntity, true); +- SignItem.openSign = pos; ++ SignItem.openSign.set(pos); // Folia - region threading + // CraftBukkit end + } - public SignItem(Block standingBlock, Block wallBlock, Item.Properties settings) { - super(standingBlock, wallBlock, Direction.DOWN, settings); -@@ -39,7 +39,7 @@ public class SignItem extends StandingAndWallBlockItem { - - // CraftBukkit start - SPIGOT-4678 - // blocksign.openTextEdit(entityhuman, tileentitysign, true); -- SignItem.openSign = pos; -+ SignItem.openSign.set(pos); // Folia - region threading - // CraftBukkit end - } - } -diff --git a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -index 5cb39f95bd2d45b6c18554605f01d2ebf6473428..ccf476d1ed22cf992e3cbca6a375d36f85a82fa8 100644 ---- a/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -+++ b/src/main/java/net/minecraft/world/level/BaseCommandBlock.java -@@ -22,7 +22,7 @@ import net.minecraft.world.phys.Vec3; +diff --git a/net/minecraft/world/level/BaseCommandBlock.java b/net/minecraft/world/level/BaseCommandBlock.java +index a67d40eb4bfa85888af8bf027a8859378d290cfa..b02b79ccedb8b87bc22270377dfc36e21ebe1724 100644 +--- a/net/minecraft/world/level/BaseCommandBlock.java ++++ b/net/minecraft/world/level/BaseCommandBlock.java +@@ -21,7 +21,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; + import net.minecraft.world.phys.Vec3; public abstract class BaseCommandBlock implements CommandSource { - - private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss"); + private static final ThreadLocal TIME_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss")); // Folia - region threading - SDF is not thread-safe private static final Component DEFAULT_NAME = Component.literal("@"); private long lastExecution = -1L; private boolean updateLastExecution = true; -@@ -117,6 +117,7 @@ public abstract class BaseCommandBlock implements CommandSource { +@@ -114,6 +114,7 @@ public abstract class BaseCommandBlock implements CommandSource { } - public boolean performCommand(Level world) { + public boolean performCommand(Level level) { + if (true) return false; // Folia - region threading - if (!world.isClientSide && world.getGameTime() != this.lastExecution) { - if ("Searge".equalsIgnoreCase(this.command)) { - this.lastOutput = Component.literal("#itzlipofutzli"); -@@ -175,11 +176,14 @@ public abstract class BaseCommandBlock implements CommandSource { + if (level.isClientSide || level.getGameTime() == this.lastExecution) { + return false; + } else if ("Searge".equalsIgnoreCase(this.command)) { +@@ -164,11 +165,14 @@ public abstract class BaseCommandBlock implements CommandSource { this.customName = customName; } + public void threadCheck() {} // Folia + @Override - public void sendSystemMessage(Component message) { + public void sendSystemMessage(Component component) { if (this.trackOutput) { org.spigotmc.AsyncCatcher.catchOp("sendSystemMessage to a command block"); // Paper - Don't broadcast messages to command blocks -- SimpleDateFormat simpledateformat = BaseCommandBlock.TIME_FORMAT; +- this.lastOutput = Component.literal("[" + TIME_FORMAT.format(new Date()) + "] ").append(component); + this.threadCheck(); // Folia -+ SimpleDateFormat simpledateformat = BaseCommandBlock.TIME_FORMAT.get(); // Folia - region threading - SDF is not thread-safe - Date date = new Date(); - - this.lastOutput = Component.literal("[" + simpledateformat.format(date) + "] ").append(message); -diff --git a/src/main/java/net/minecraft/world/level/EntityGetter.java b/src/main/java/net/minecraft/world/level/EntityGetter.java -index 5d7a6e4b73f032db356e7ec369b150013e940ee6..6e895ca2844fd2d8189a6cf173d0c5dc9aaf02a9 100644 ---- a/src/main/java/net/minecraft/world/level/EntityGetter.java -+++ b/src/main/java/net/minecraft/world/level/EntityGetter.java ++ this.lastOutput = Component.literal("[" + TIME_FORMAT.get().format(new Date()) + "] ").append(component); // Folia - region threading - SDF is not thread-safe + this.onUpdated(); + } + } +diff --git a/net/minecraft/world/level/EntityGetter.java b/net/minecraft/world/level/EntityGetter.java +index e81195df621159da67136f020fa7a6d39d1ee5ed..b9d4f766f30612add79974cfbf123d1b4684dc1c 100644 +--- a/net/minecraft/world/level/EntityGetter.java ++++ b/net/minecraft/world/level/EntityGetter.java @@ -24,6 +24,12 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst - return this.getEntities(EntityTypeTest.forClass(entityClass), box, predicate); + return this.getEntities(EntityTypeTest.forClass(entityClass), area, filter); } + // Folia start - region threading @@ -17142,17 +16776,17 @@ index 5d7a6e4b73f032db356e7ec369b150013e940ee6..6e895ca2844fd2d8189a6cf173d0c5dc + List players(); - default List getEntities(@Nullable Entity except, AABB box) { -@@ -122,7 +128,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst + default List getEntities(@Nullable Entity entity, AABB area) { +@@ -123,7 +129,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst double d = -1.0; Player player = null; -- for (Player player2 : this.players()) { -+ for (Player player2 : this.getLocalPlayers()) { // Folia - region threading - if (targetPredicate == null || targetPredicate.test(player2)) { - double e = player2.distanceToSqr(x, y, z); - if ((maxDistance < 0.0 || e < maxDistance * maxDistance) && (d == -1.0 || e < d)) { -@@ -143,7 +149,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst +- for (Player player1 : this.players()) { ++ for (Player player1 : this.getLocalPlayers()) { // Folia - region threading + if (predicate == null || predicate.test(player1)) { + double d1 = player1.distanceToSqr(x, y, z); + if ((distance < 0.0 || d1 < distance * distance) && (d == -1.0 || d1 < d)) { +@@ -144,7 +150,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst default List findNearbyBukkitPlayers(double x, double y, double z, double radius, @Nullable Predicate predicate) { com.google.common.collect.ImmutableList.Builder builder = com.google.common.collect.ImmutableList.builder(); @@ -17161,7 +16795,7 @@ index 5d7a6e4b73f032db356e7ec369b150013e940ee6..6e895ca2844fd2d8189a6cf173d0c5dc if (predicate == null || predicate.test(human)) { double distanceSquared = human.distanceToSqr(x, y, z); -@@ -170,7 +176,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst +@@ -171,7 +177,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst // Paper start - Affects Spawning API default boolean hasNearbyAlivePlayerThatAffectsSpawning(double x, double y, double z, double range) { @@ -17170,47 +16804,30 @@ index 5d7a6e4b73f032db356e7ec369b150013e940ee6..6e895ca2844fd2d8189a6cf173d0c5dc if (EntitySelector.PLAYER_AFFECTS_SPAWNING.test(player)) { // combines NO_SPECTATORS and LIVING_ENTITY_STILL_ALIVE with an "affects spawning" check double distanceSqr = player.distanceToSqr(x, y, z); if (range < 0.0D || distanceSqr < range * range) { -@@ -183,7 +189,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst +@@ -184,7 +190,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst // Paper end - Affects Spawning API - default boolean hasNearbyAlivePlayer(double x, double y, double z, double range) { + default boolean hasNearbyAlivePlayer(double x, double y, double z, double distance) { - for (Player player : this.players()) { + for (Player player : this.getLocalPlayers()) { // Folia - region threading if (EntitySelector.NO_SPECTATORS.test(player) && EntitySelector.LIVING_ENTITY_STILL_ALIVE.test(player)) { double d = player.distanceToSqr(x, y, z); - if (range < 0.0 || d < range * range) { -@@ -197,8 +203,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst + if (distance < 0.0 || d < distance * distance) { +@@ -198,8 +204,7 @@ public interface EntityGetter extends ca.spottedleaf.moonrise.patches.chunk_syst @Nullable - default Player getPlayerByUUID(UUID uuid) { + default Player getPlayerByUUID(UUID uniqueId) { - for (int i = 0; i < this.players().size(); i++) { - Player player = this.players().get(i); + for (Player player : this.getLocalPlayers()) { // Folia - region threading - if (uuid.equals(player.getUUID())) { + if (uniqueId.equals(player.getUUID())) { return player; } -diff --git a/src/main/java/net/minecraft/world/level/Explosion.java b/src/main/java/net/minecraft/world/level/Explosion.java -index 952c866bed29b412a48332ba1d98515f0f069781..68710af738fe6de115b75135f0f301763cb63b33 100644 ---- a/src/main/java/net/minecraft/world/level/Explosion.java -+++ b/src/main/java/net/minecraft/world/level/Explosion.java -@@ -17,10 +17,11 @@ public interface Explosion { - @Nullable - static LivingEntity getIndirectSourceEntity(@Nullable Entity entity) { - return switch (entity) { -- case null, default -> null; -+ // Folia - decompile error - move down - case PrimedTnt primedTnt -> primedTnt.getOwner(); - case LivingEntity livingEntity -> livingEntity; - case Projectile projectile when projectile.getOwner() instanceof LivingEntity livingEntity2 -> livingEntity2; -+ case null, default -> null; // Folia - decompile error - moved down - }; - } - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd06858b870e97 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -119,10 +119,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java +index 2bbebb4335d927f240abcac67a5b423e38dc33d7..d36b5ad7b386391e617895a33b919e29266220e2 100644 +--- a/net/minecraft/world/level/Level.java ++++ b/net/minecraft/world/level/Level.java +@@ -115,10 +115,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public static final int TICKS_PER_DAY = 24000; public static final int MAX_ENTITY_SPAWN_Y = 20000000; public static final int MIN_ENTITY_SPAWN_Y = -20000000; @@ -17225,16 +16842,16 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 public final Thread thread; private final boolean isDebug; private int skyDarken; -@@ -132,7 +132,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -128,7 +128,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public float rainLevel; protected float oThunderLevel; public float thunderLevel; - public final RandomSource random = new ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()); // Paper - replace random -+ public final RandomSource random = io.papermc.paper.threadedregions.util.ThreadLocalRandomSource.INSTANCE; // Folia - region threading - /** @deprecated */ ++ public final RandomSource random = io.papermc.paper.threadedregions.util.ThreadLocalRandomSource.INSTANCE; // Paper - replace random // Folia - region threading @Deprecated private final RandomSource threadSafeRandom = RandomSource.createThreadSafe(); -@@ -144,28 +144,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + private final Holder dimensionTypeRegistration; +@@ -139,28 +139,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl private final ResourceKey dimension; private final RegistryAccess registryAccess; private final DamageSources damageSources; @@ -17252,7 +16869,7 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 - public boolean isBlockPlaceCancelled = false; // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent - public Map capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper - public Map capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates -- public List captureDrops; +- public List captureDrops; + // Folia - region threading - moved to regionised data public final it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap ticksPerSpawnCategory = new it.unimi.dsi.fastutil.objects.Object2LongOpenHashMap<>(); - // Paper start @@ -17267,7 +16884,7 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 public final org.spigotmc.SpigotWorldConfig spigotConfig; // Spigot // Paper start - add paper world config private final io.papermc.paper.configuration.WorldConfiguration paperConfig; -@@ -178,9 +167,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -173,9 +162,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public static BlockPos lastPhysicsProblem; // Spigot private org.spigotmc.TickLimiter entityLimiter; private org.spigotmc.TickLimiter tileLimiter; @@ -17280,7 +16897,7 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 public CraftWorld getWorld() { return this.world; -@@ -830,6 +819,32 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -825,6 +814,32 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z); } // Paper end - optimise random ticking @@ -17311,18 +16928,18 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 + } + // Folia end - region ticking - protected Level(WritableLevelData worlddatamutable, ResourceKey resourcekey, RegistryAccess iregistrycustom, Holder holder, boolean flag, boolean flag1, long i, int j, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider, org.bukkit.World.Environment env, java.util.function.Function paperWorldConfigCreator, java.util.concurrent.Executor executor) { // Paper - create paper world config & Anti-Xray - // Paper start - getblock optimisations - cache world height/sections -@@ -879,7 +894,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + protected Level( + WritableLevelData levelData, +@@ -888,7 +903,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl this.thread = Thread.currentThread(); - this.biomeManager = new BiomeManager(this, i); - this.isDebug = flag1; -- this.neighborUpdater = new CollectingNeighborUpdater(this, j); -+ this.neighbourUpdateMax = j; // Folia - region threading - this.registryAccess = iregistrycustom; - this.damageSources = new DamageSources(iregistrycustom); - // CraftBukkit start -@@ -1024,8 +1039,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + this.biomeManager = new BiomeManager(this, biomeZoomSeed); + this.isDebug = isDebug; +- this.neighborUpdater = new CollectingNeighborUpdater(this, maxChainedNeighborUpdates); ++ this.neighbourUpdateMax = maxChainedNeighborUpdates; // Folia - region threading + this.registryAccess = registryAccess; + this.damageSources = new DamageSources(registryAccess); + +@@ -1035,8 +1050,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Nullable public final BlockState getBlockStateIfLoaded(BlockPos pos) { // CraftBukkit start - tree generation @@ -17333,10 +16950,10 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 if (previous != null) { return previous.getHandle(); } -@@ -1087,16 +1102,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1098,16 +1113,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Override - public boolean setBlock(BlockPos pos, BlockState state, int flags, int maxUpdateDepth) { + public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft) { + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, pos, "Updating block asynchronously"); // Folia - region threading + io.papermc.paper.threadedregions.RegionizedWorldData worldData = this.getCurrentWorldData(); // Folia - region threading // CraftBukkit start - tree generation @@ -17355,8 +16972,8 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 } blockstate.setData(state); blockstate.setFlag(flags); -@@ -1113,10 +1130,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - +@@ -1123,10 +1140,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + Block block = state.getBlock(); // CraftBukkit start - capture blockstates boolean captured = false; - if (this.captureBlockStates && !this.capturedBlockStates.containsKey(pos)) { @@ -17368,9 +16985,9 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 captured = true; } // CraftBukkit end -@@ -1126,8 +1143,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1136,8 +1153,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - if (iblockdata1 == null) { + if (blockState == null) { // CraftBukkit start - remove blockstate if failed (or the same) - if (this.captureBlockStates && captured) { - this.capturedBlockStates.remove(pos); @@ -17379,7 +16996,7 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 } // CraftBukkit end return false; -@@ -1164,7 +1181,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1174,7 +1191,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl */ // CraftBukkit start @@ -17388,7 +17005,7 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 // Modularize client and physic updates // Spigot start try { -@@ -1209,7 +1226,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1219,7 +1236,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl iblockdata1.updateIndirectNeighbourShapes(this, blockposition, k, j - 1); // Don't call an event for the old block to limit event spam CraftWorld world = ((ServerLevel) this).getWorld(); boolean cancelledUpdates = false; // Paper - Fix block place logic @@ -17397,7 +17014,7 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 BlockPhysicsEvent event = new BlockPhysicsEvent(world.getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ()), CraftBlockData.fromData(iblockdata)); this.getCraftServer().getPluginManager().callEvent(event); -@@ -1223,7 +1240,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1233,7 +1250,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } // CraftBukkit start - SPIGOT-5710 @@ -17406,16 +17023,16 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 this.onBlockStateChange(blockposition, iblockdata1, iblockdata2); } // CraftBukkit end -@@ -1309,7 +1326,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1322,7 +1339,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Override - public void neighborShapeChanged(Direction direction, BlockPos pos, BlockPos neighborPos, BlockState neighborState, int flags, int maxUpdateDepth) { -- this.neighborUpdater.shapeUpdate(direction, neighborState, pos, neighborPos, flags, maxUpdateDepth); -+ this.getCurrentWorldData().neighborUpdater.shapeUpdate(direction, neighborState, pos, neighborPos, flags, maxUpdateDepth); // Folia - region threading + public void neighborShapeChanged(Direction direction, BlockPos pos, BlockPos neighborPos, BlockState neighborState, int flags, int recursionLeft) { +- this.neighborUpdater.shapeUpdate(direction, neighborState, pos, neighborPos, flags, recursionLeft); ++ this.getCurrentWorldData().neighborUpdater.shapeUpdate(direction, neighborState, pos, neighborPos, flags, recursionLeft); // Folia - region threading } @Override -@@ -1334,11 +1351,34 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1346,11 +1363,34 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl return this.getChunkSource().getLightEngine(); } @@ -17452,7 +17069,7 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 if (previous != null) { return previous.getHandle(); } -@@ -1437,18 +1477,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1454,17 +1494,16 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } public void addBlockEntityTicker(TickingBlockEntity ticker) { @@ -17461,9 +17078,8 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 } protected void tickBlockEntities() { - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push("blockEntities"); + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("blockEntities"); - this.tickingBlockEntities = true; - if (!this.pendingBlockEntityTickers.isEmpty()) { - this.blockEntityTickers.addAll(this.pendingBlockEntityTickers); @@ -17475,20 +17091,20 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 + List blockEntityTickers = regionizedWorldData.getBlockEntityTickers(); // Folia - regionised ticking // Spigot start - // Iterator iterator = this.blockEntityTickers.iterator(); -@@ -1459,9 +1498,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - int tilesThisCycle = 0; + boolean runsNormally = this.tickRateManager().runsNormally(); +@@ -1472,9 +1511,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + int tickedEntities = 0; // Paper - rewrite chunk system var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet(); // Paper - Fix MC-117075; use removeAll toRemove.add(null); // Paper - Fix MC-117075 - for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters - this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0; -- TickingBlockEntity tickingblockentity = (TickingBlockEntity) this.blockEntityTickers.get(this.tileTickPosition); -+ for (int i = 0; i < blockEntityTickers.size(); i++) { // Paper - Disable tick limiters // Folia - regionised ticking -+ TickingBlockEntity tickingblockentity = (TickingBlockEntity) blockEntityTickers.get(i); // Folia - regionised ticking +- TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition); ++ for (int i = 0; i < blockEntityTickers.size(); i++) { // Paper - Disable tick limiters // Folia - regionised ticking ++ TickingBlockEntity tickingBlockEntity = blockEntityTickers.get(i); // Folia - regionised ticking // Spigot end - - if (tickingblockentity.isRemoved()) { -@@ -1478,11 +1516,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + if (tickingBlockEntity.isRemoved()) { + toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll +@@ -1487,11 +1525,11 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl // Paper end - rewrite chunk system } } @@ -17497,26 +17113,26 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 - this.tickingBlockEntities = false; + regionizedWorldData.seTtickingBlockEntities(false); // Folia - regionised ticking - gameprofilerfiller.pop(); + profilerFiller.pop(); - this.spigotConfig.currentPrimedTnt = 0; // Spigot + regionizedWorldData.currentPrimedTnt = 0; // Spigot // Folia - region threading } - public void guardEntityTick(Consumer tickConsumer, T entity) { -@@ -1494,7 +1532,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + public void guardEntityTick(Consumer consumerEntity, T entity) { +@@ -1502,7 +1540,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level().getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); - MinecraftServer.LOGGER.error(msg, throwable); - getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); // Paper - ServerExceptionEvent + MinecraftServer.LOGGER.error(msg, var6); + getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, var6))); // Paper - ServerExceptionEvent - entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); + if (!(entity instanceof net.minecraft.server.level.ServerPlayer)) entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD); // Folia - properly disconnect players + if (entity instanceof net.minecraft.server.level.ServerPlayer player) player.connection.disconnect(net.minecraft.network.chat.Component.translatable("multiplayer.disconnect.generic"), org.bukkit.event.player.PlayerKickEvent.Cause.UNKNOWN); // Folia - properly disconnect players // Paper end - Prevent block entity and entity crashes } this.moonrise$midTickTasks(); // Paper - rewrite chunk system -@@ -1555,9 +1594,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1648,9 +1687,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Nullable - public BlockEntity getBlockEntity(BlockPos blockposition, boolean validate) { + public BlockEntity getBlockEntity(BlockPos pos, boolean validate) { + // Folia start - region threading + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThread()) { + return null; @@ -17524,31 +17140,31 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 + // Folia end - region threading // Paper start - Perf: Optimize capturedTileEntities lookup net.minecraft.world.level.block.entity.BlockEntity blockEntity; -- if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(blockposition)) != null) { -+ if (!this.getCurrentWorldData().capturedTileEntities.isEmpty() && (blockEntity = this.getCurrentWorldData().capturedTileEntities.get(blockposition)) != null) { // Folia - region threading +- if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(pos)) != null) { ++ if (!this.getCurrentWorldData().capturedTileEntities.isEmpty() && (blockEntity = this.getCurrentWorldData().capturedTileEntities.get(pos)) != null) { // Folia - region threading return blockEntity; } // Paper end - Perf: Optimize capturedTileEntities lookup -@@ -1570,8 +1614,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - - if (!this.isOutsideBuildHeight(blockposition)) { +@@ -1668,8 +1712,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + BlockPos blockPos = blockEntity.getBlockPos(); + if (!this.isOutsideBuildHeight(blockPos)) { // CraftBukkit start - if (this.captureBlockStates) { -- this.capturedTileEntities.put(blockposition.immutable(), blockEntity); +- this.capturedTileEntities.put(blockPos.immutable(), blockEntity); + if (this.getCurrentWorldData().captureBlockStates) { // Folia - region threading -+ this.getCurrentWorldData().capturedTileEntities.put(blockposition.immutable(), blockEntity); // Folia - region threading ++ this.getCurrentWorldData().capturedTileEntities.put(blockPos.immutable(), blockEntity); // Folia - region threading return; } // CraftBukkit end -@@ -1651,6 +1695,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1749,6 +1793,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Override - public List getEntities(@Nullable Entity except, AABB box, Predicate predicate) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, box, "Cannot getEntities asynchronously"); // Folia - region threading + public List getEntities(@Nullable Entity entity, AABB boundingBox, Predicate predicate) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, boundingBox, "Cannot getEntities asynchronously"); // Folia - region threading Profiler.get().incrementCounter("getEntities"); List list = Lists.newArrayList(); -@@ -1681,6 +1726,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1778,6 +1823,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public void getEntities(final EntityTypeTest entityTypeTest, final AABB boundingBox, final Predicate predicate, final List into, final int maxCount) { @@ -17556,9 +17172,9 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 Profiler.get().incrementCounter("getEntities"); if (entityTypeTest instanceof net.minecraft.world.entity.EntityType byType) { -@@ -1780,13 +1826,34 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl - - public void disconnect() {} +@@ -1877,13 +1923,34 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + public void disconnect() { + } + @Override // Folia - region threading public long getGameTime() { @@ -17593,30 +17209,30 @@ index 27f9d167b5ae9ce5117798ea44324107df59425f..fc180c3f68a40e909f7e357a6fcd0685 public boolean mayInteract(Player player, BlockPos pos) { return true; -@@ -1979,8 +2046,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -2061,8 +2128,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public abstract RecipeAccess recipeAccess(); - public BlockPos getBlockRandomPos(int x, int y, int z, int l) { + public BlockPos getBlockRandomPos(int x, int y, int z, int yMask) { - this.randValue = this.randValue * 3 + 1013904223; -- int i1 = this.randValue >> 2; -+ int i1 = this.random.nextInt() >> 2; // Folia - region threading - - return new BlockPos(x + (i1 & 15), y + (i1 >> 16 & l), z + (i1 >> 8 & 15)); +- int i = this.randValue >> 2; ++ int i = this.random.nextInt() >> 2; // Folia - region threading + return new BlockPos(x + (i & 15), y + (i >> 16 & yMask), z + (i >> 8 & 15)); } -@@ -2002,7 +2068,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + +@@ -2083,7 +2149,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @Override public long nextSubTickCount() { -- return (long) (this.subTickCount++); +- return this.subTickCount++; + return this.subTickCount.getAndIncrement(); // Folia - region threading } @Override -diff --git a/src/main/java/net/minecraft/world/level/LevelAccessor.java b/src/main/java/net/minecraft/world/level/LevelAccessor.java -index e5c5698fd74cb916467bccead8c1f323c6e3cbb0..9bfb933a2b2af849286d53bd05a77ee3c1f9e665 100644 ---- a/src/main/java/net/minecraft/world/level/LevelAccessor.java -+++ b/src/main/java/net/minecraft/world/level/LevelAccessor.java -@@ -34,14 +34,24 @@ public interface LevelAccessor extends CommonLevelAccessor, LevelTimeAccess, Sch +diff --git a/net/minecraft/world/level/LevelAccessor.java b/net/minecraft/world/level/LevelAccessor.java +index ee9d320da1b4c3aa66be6592867e95c706b65b3a..cd5bfa374b0b1af64bc8415ace94fa43955e5145 100644 +--- a/net/minecraft/world/level/LevelAccessor.java ++++ b/net/minecraft/world/level/LevelAccessor.java +@@ -33,14 +33,24 @@ public interface LevelAccessor extends CommonLevelAccessor, LevelTimeAccess, Sch long nextSubTickCount(); @@ -17632,23 +17248,23 @@ index e5c5698fd74cb916467bccead8c1f323c6e3cbb0..9bfb933a2b2af849286d53bd05a77ee3 + @Override default ScheduledTick createTick(BlockPos pos, T type, int delay, TickPriority priority) { -- return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + (long) delay, priority, this.nextSubTickCount()); -+ return new ScheduledTick<>(type, pos, this.getRedstoneGameTime() + (long) delay, priority, this.nextSubTickCount()); // Folia - region threading +- return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + delay, priority, this.nextSubTickCount()); ++ return new ScheduledTick<>(type, pos, this.getRedstoneGameTime() + delay, priority, this.nextSubTickCount()); // Folia - region threading } @Override default ScheduledTick createTick(BlockPos pos, T type, int delay) { -- return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + (long) delay, this.nextSubTickCount()); -+ return new ScheduledTick<>(type, pos, this.getRedstoneGameTime() + (long) delay, this.nextSubTickCount()); // Folia - region threading +- return new ScheduledTick<>(type, pos, this.getLevelData().getGameTime() + delay, this.nextSubTickCount()); ++ return new ScheduledTick<>(type, pos, this.getRedstoneGameTime() + delay, this.nextSubTickCount()); // Folia - region threading } LevelData getLevelData(); -diff --git a/src/main/java/net/minecraft/world/level/LevelReader.java b/src/main/java/net/minecraft/world/level/LevelReader.java -index ade435de0af4ee3566fa4a490df53cddd2f6531c..8fd969d3fe8c9ea8dcb53b4187897b401d1af4a1 100644 ---- a/src/main/java/net/minecraft/world/level/LevelReader.java -+++ b/src/main/java/net/minecraft/world/level/LevelReader.java -@@ -206,6 +206,25 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste - return maxY >= this.getMinY() && minY <= this.getMaxY() && this.hasChunksAt(minX, minZ, maxX, maxZ); +diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java +index 26c8c1e5598daf3550aef05b12218c47bda6618b..e59e1bb91e446406e58cc8046a85b693adb11e86 100644 +--- a/net/minecraft/world/level/LevelReader.java ++++ b/net/minecraft/world/level/LevelReader.java +@@ -204,6 +204,25 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste + return toY >= this.getMinY() && fromY <= this.getMaxY() && this.hasChunksAt(fromX, fromZ, toX, toZ); } + // Folia start - region threading @@ -17671,26 +17287,26 @@ index ade435de0af4ee3566fa4a490df53cddd2f6531c..8fd969d3fe8c9ea8dcb53b4187897b40 + // Folia end - region threading + @Deprecated - default boolean hasChunksAt(int minX, int minZ, int maxX, int maxZ) { - int i = SectionPos.blockToSectionCoord(minX); -diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -index c1b76a1ebc1eea7ab70cf61d8175a31794dd122a..5403794f9613ecd976769240ccecd3c174118b46 100644 ---- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java -+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java -@@ -145,7 +145,7 @@ public final class NaturalSpawner { - int limit = enumcreaturetype.getMaxInstancesPerChunk(); - SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumcreaturetype); + default boolean hasChunksAt(int fromX, int fromZ, int toX, int toZ) { + int sectionPosCoord = SectionPos.blockToSectionCoord(fromX); +diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java +index 17ce115e887cbbb06ad02ab7ddb488e27342c0e4..5ce81eafee33d22b69029c088d4be497131338a2 100644 +--- a/net/minecraft/world/level/NaturalSpawner.java ++++ b/net/minecraft/world/level/NaturalSpawner.java +@@ -137,7 +137,7 @@ public final class NaturalSpawner { + int limit = mobCategory.getMaxInstancesPerChunk(); + SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(mobCategory); if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { -- spawnThisTick = worldserver.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worlddata.getGameTime() % worldserver.ticksPerSpawnCategory.getLong(spawnCategory) == 0; -+ spawnThisTick = worldserver.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worldserver.getRedstoneGameTime() % worldserver.ticksPerSpawnCategory.getLong(spawnCategory) == 0; // Folia - region threading - limit = worldserver.getWorld().getSpawnLimit(spawnCategory); +- spawnThisTick = level.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(spawnCategory) == 0; ++ spawnThisTick = level.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && level.getRedstoneGameTime() % level.ticksPerSpawnCategory.getLong(spawnCategory) == 0; // Folia - region threading + limit = level.getWorld().getSpawnLimit(spawnCategory); } -diff --git a/src/main/java/net/minecraft/world/level/ServerExplosion.java b/src/main/java/net/minecraft/world/level/ServerExplosion.java -index 685ccfb73bf7125585ef90b6a0f51b2f81daa428..0b49da093cdae2c2738f7977f38b39f1e8a29876 100644 ---- a/src/main/java/net/minecraft/world/level/ServerExplosion.java -+++ b/src/main/java/net/minecraft/world/level/ServerExplosion.java -@@ -795,17 +795,18 @@ public class ServerExplosion implements Explosion { +diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java +index 7b132c55caf9d3c3df3b0a123f4b5bfc7ae35984..cd584fd5ed007f3c05d60cf46adbf6ae40163db4 100644 +--- a/net/minecraft/world/level/ServerExplosion.java ++++ b/net/minecraft/world/level/ServerExplosion.java +@@ -773,17 +773,18 @@ public class ServerExplosion implements Explosion { if (!this.level.paperConfig().environment.optimizeExplosions) { return this.getSeenFraction(vec3d, entity, this.directMappedBlockCache, this.mutablePos); // Paper - collision optimisations } @@ -17712,12 +17328,12 @@ index 685ccfb73bf7125585ef90b6a0f51b2f81daa428..0b49da093cdae2c2738f7977f38b39f1 private final Level world; private final double posX, posY, posZ; private final double minX, minY, minZ; -diff --git a/src/main/java/net/minecraft/world/level/ServerLevelAccessor.java b/src/main/java/net/minecraft/world/level/ServerLevelAccessor.java -index 3d377b9e461040405e0a7dcbd72d1506b48eb44e..782890e227ff9dab44dd92327979c201985f116e 100644 ---- a/src/main/java/net/minecraft/world/level/ServerLevelAccessor.java -+++ b/src/main/java/net/minecraft/world/level/ServerLevelAccessor.java -@@ -7,6 +7,12 @@ public interface ServerLevelAccessor extends LevelAccessor { - +diff --git a/net/minecraft/world/level/ServerLevelAccessor.java b/net/minecraft/world/level/ServerLevelAccessor.java +index b4f14ff9ef0c212f4d0e0c2ccf20ce1e7af9e734..441ba6ae8885a968734ac0abdb8a9d09fa658430 100644 +--- a/net/minecraft/world/level/ServerLevelAccessor.java ++++ b/net/minecraft/world/level/ServerLevelAccessor.java +@@ -6,6 +6,12 @@ import net.minecraft.world.entity.Entity; + public interface ServerLevelAccessor extends LevelAccessor { ServerLevel getLevel(); + // Folia start - region threading @@ -17729,24 +17345,25 @@ index 3d377b9e461040405e0a7dcbd72d1506b48eb44e..782890e227ff9dab44dd92327979c201 default void addFreshEntityWithPassengers(Entity entity) { // CraftBukkit start this.addFreshEntityWithPassengers(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); -diff --git a/src/main/java/net/minecraft/world/level/StructureManager.java b/src/main/java/net/minecraft/world/level/StructureManager.java -index 03adb02297911e5a5051edac14453d7e3eeac29c..cd2785d084225e8a166b21324d830cf20298c439 100644 ---- a/src/main/java/net/minecraft/world/level/StructureManager.java -+++ b/src/main/java/net/minecraft/world/level/StructureManager.java -@@ -48,11 +48,7 @@ public class StructureManager { +diff --git a/net/minecraft/world/level/StructureManager.java b/net/minecraft/world/level/StructureManager.java +index 8bc6a6c86cd8db53feefba7508b6031ba67e242e..9abfcfa3e8d8319e98866b2a81f2eb9ac7269055 100644 +--- a/net/minecraft/world/level/StructureManager.java ++++ b/net/minecraft/world/level/StructureManager.java +@@ -48,12 +48,7 @@ public class StructureManager { } - public List startsForStructure(ChunkPos pos, Predicate predicate) { + public List startsForStructure(ChunkPos chunkPos, Predicate structurePredicate) { - // Paper start - Fix swamp hut cat generation deadlock -- return this.startsForStructure(pos, predicate, null); +- return this.startsForStructure(chunkPos, structurePredicate, null); - } -- public List startsForStructure(ChunkPos pos, Predicate predicate, @Nullable ServerLevelAccessor levelAccessor) { -- Map map = (levelAccessor == null ? this.level : levelAccessor).getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); -+ Map map = this.level.getChunk(pos.x, pos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); // Folia - region threading +- +- public List startsForStructure(ChunkPos chunkPos, Predicate structurePredicate, @Nullable ServerLevelAccessor levelAccessor) { +- Map allReferences = (levelAccessor == null ? this.level : levelAccessor).getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); ++ Map allReferences = this.level.getChunk(chunkPos.x, chunkPos.z, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); // Folia - region threading // Paper end - Fix swamp hut cat generation deadlock Builder builder = ImmutableList.builder(); -@@ -121,20 +117,12 @@ public class StructureManager { +@@ -124,20 +119,12 @@ public class StructureManager { } public StructureStart getStructureWithPieceAt(BlockPos pos, Predicate> predicate) { @@ -17769,7 +17386,7 @@ index 03adb02297911e5a5051edac14453d7e3eeac29c..cd2785d084225e8a166b21324d830cf2 )) { if (this.structureHasPieceAt(pos, structureStart)) { return structureStart; -@@ -179,7 +167,7 @@ public class StructureManager { +@@ -182,7 +169,7 @@ public class StructureManager { } public void addReference(StructureStart structureStart) { @@ -17778,113 +17395,122 @@ index 03adb02297911e5a5051edac14453d7e3eeac29c..cd2785d084225e8a166b21324d830cf2 this.structureCheck.incrementReference(structureStart.getChunkPos(), structureStart.getStructure()); } -diff --git a/src/main/java/net/minecraft/world/level/block/BedBlock.java b/src/main/java/net/minecraft/world/level/block/BedBlock.java -index be700995c3e7f63e0471712c3cd6fd83db583491..421403e714949739d4bab2fba7b7896d73cbd99a 100644 ---- a/src/main/java/net/minecraft/world/level/block/BedBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BedBlock.java -@@ -362,7 +362,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock - - world.setBlock(blockposition1, (BlockState) state.setValue(BedBlock.PART, BedPart.HEAD), 3); +diff --git a/net/minecraft/world/level/block/BedBlock.java b/net/minecraft/world/level/block/BedBlock.java +index c23c255cefe7c5be618bbe97a99ae3215d8e48c0..7425ef8a41aaac946f57d1b2105281339a7ba8ff 100644 +--- a/net/minecraft/world/level/block/BedBlock.java ++++ b/net/minecraft/world/level/block/BedBlock.java +@@ -346,7 +346,7 @@ public class BedBlock extends HorizontalDirectionalBlock implements EntityBlock + BlockPos blockPos = pos.relative(state.getValue(FACING)); + level.setBlock(blockPos, state.setValue(PART, BedPart.HEAD), 3); // CraftBukkit start - SPIGOT-7315: Don't updated if we capture block states -- if (world.captureBlockStates) { -+ if (world.getCurrentWorldData().captureBlockStates) { // Folia - region threading +- if (level.captureBlockStates) { ++ if (level.getCurrentWorldData().captureBlockStates) { // Folia - region threading return; } // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java -index c0b1f903962b25d8ff6c2b4fcd2be0e45de09b35..9b952e74ee705256cbe9390553432f6364d4f2c1 100644 ---- a/src/main/java/net/minecraft/world/level/block/Block.java -+++ b/src/main/java/net/minecraft/world/level/block/Block.java -@@ -382,8 +382,8 @@ public class Block extends BlockBehaviour implements ItemLike { - - entityitem.setDefaultPickUpDelay(); - // CraftBukkit start -- if (world.captureDrops != null) { -- world.captureDrops.add(entityitem); -+ if (world.getCurrentWorldData().captureDrops != null) { // Folia - region threading -+ world.getCurrentWorldData().captureDrops.add(entityitem); // Folia - region threading - } else { - world.addFreshEntity(entityitem); - } -diff --git a/src/main/java/net/minecraft/world/level/block/BushBlock.java b/src/main/java/net/minecraft/world/level/block/BushBlock.java -index eb324fda54ada3ed7941713a784ed2d686ec8c4b..b66ff600fbad81679f1f5b6108abccabd39d84ec 100644 ---- a/src/main/java/net/minecraft/world/level/block/BushBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/BushBlock.java -@@ -31,7 +31,7 @@ public abstract class BushBlock extends Block { - // CraftBukkit start - if (!state.canSurvive(world, pos)) { - // Suppress during worldgen -- if (!(world instanceof net.minecraft.server.level.ServerLevel world1 && world1.hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world1, pos).isCancelled()) { // Paper -+ if (!(world instanceof net.minecraft.server.level.ServerLevel world1 && world1.getCurrentWorldData().hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world1, pos).isCancelled()) { // Paper // Folia - region threading - return Blocks.AIR.defaultBlockState(); +diff --git a/net/minecraft/world/level/block/Block.java b/net/minecraft/world/level/block/Block.java +index 976de81d65b6494cdad20f4ec5125fceec86f951..aa09b2e8fac82ab954f581df3d41153c6244c2e8 100644 +--- a/net/minecraft/world/level/block/Block.java ++++ b/net/minecraft/world/level/block/Block.java +@@ -362,8 +362,8 @@ public class Block extends BlockBehaviour implements ItemLike { + ItemEntity itemEntity = itemEntitySupplier.get(); + itemEntity.setDefaultPickUpDelay(); + // CraftBukkit start +- if (level.captureDrops != null) { +- level.captureDrops.add(itemEntity); ++ if (level.getCurrentWorldData().captureDrops != null) { // Folia - region threading ++ level.getCurrentWorldData().captureDrops.add(itemEntity); // Folia - region threading + } else { + level.addFreshEntity(itemEntity); } - } -diff --git a/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java b/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java -index 6e63ecbf425950f71bee9bf416cb6a77b6005ab6..7eca80ae9d5f8c3582d8c4de5cfae3705cadaecc 100644 ---- a/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DaylightDetectorBlock.java -@@ -114,7 +114,7 @@ public class DaylightDetectorBlock extends BaseEntityBlock { +diff --git a/net/minecraft/world/level/block/BushBlock.java b/net/minecraft/world/level/block/BushBlock.java +index bc52568bfa56635300266424488e524d77d95e09..068e65fb7efd52b36ba7f49829da80d82753e78e 100644 +--- a/net/minecraft/world/level/block/BushBlock.java ++++ b/net/minecraft/world/level/block/BushBlock.java +@@ -38,7 +38,7 @@ public abstract class BushBlock extends Block { + // CraftBukkit start + if (!state.canSurvive(level, pos)) { + // Suppress during worldgen +- if (!(level instanceof net.minecraft.server.level.ServerLevel serverLevel && serverLevel.hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(serverLevel, pos).isCancelled()) { // Paper ++ if (!(level instanceof net.minecraft.server.level.ServerLevel serverLevel && serverLevel.getCurrentWorldData().hasPhysicsEvent) || !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(serverLevel, pos).isCancelled()) { // Paper // Folia - region threading + return Blocks.AIR.defaultBlockState(); + } + } +diff --git a/net/minecraft/world/level/block/DaylightDetectorBlock.java b/net/minecraft/world/level/block/DaylightDetectorBlock.java +index a83d1dd4cac85d34f695333fd917a41f14dd5715..17532ef2cc5e21e68a1d51146641ae124a67f79e 100644 +--- a/net/minecraft/world/level/block/DaylightDetectorBlock.java ++++ b/net/minecraft/world/level/block/DaylightDetectorBlock.java +@@ -110,7 +110,7 @@ public class DaylightDetectorBlock extends BaseEntityBlock { } - private static void tickEntity(Level world, BlockPos pos, BlockState state, DaylightDetectorBlockEntity blockEntity) { -- if (world.getGameTime() % 20L == 0L) { -+ if (world.getRedstoneGameTime() % 20L == 0L) { // Folia - region threading - DaylightDetectorBlock.updateSignalStrength(state, world, pos); + private static void tickEntity(Level level, BlockPos pos, BlockState state, DaylightDetectorBlockEntity blockEntity) { +- if (level.getGameTime() % 20L == 0L) { ++ if (level.getRedstoneGameTime() % 20L == 0L) { // Folia - region threading + updateSignalStrength(state, level, pos); } - -diff --git a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -index 01584d77a8877528c3ec65971a1a6377c09e763b..0537418c9337d95acdc80eead47c9cbf397e7042 100644 ---- a/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DispenserBlock.java -@@ -52,7 +52,7 @@ public class DispenserBlock extends BaseEntityBlock { + } +diff --git a/net/minecraft/world/level/block/DispenserBlock.java b/net/minecraft/world/level/block/DispenserBlock.java +index e0a4d41e5bcf144ea4c10d6f633c3a95ed2c5aec..0ff736a45776bbf16f32ac05f099bb656aa3b9a6 100644 +--- a/net/minecraft/world/level/block/DispenserBlock.java ++++ b/net/minecraft/world/level/block/DispenserBlock.java +@@ -50,7 +50,7 @@ public class DispenserBlock extends BaseEntityBlock { private static final DefaultDispenseItemBehavior DEFAULT_BEHAVIOR = new DefaultDispenseItemBehavior(); - public static final Map DISPENSER_REGISTRY = new IdentityHashMap(); + public static final Map DISPENSER_REGISTRY = new IdentityHashMap<>(); private static final int TRIGGER_DURATION = 4; - public static boolean eventFired = false; // CraftBukkit + public static ThreadLocal eventFired = ThreadLocal.withInitial(() -> Boolean.FALSE); // CraftBukkit // Folia - region threading @Override public MapCodec codec() { -@@ -109,7 +109,7 @@ public class DispenserBlock extends BaseEntityBlock { - - if (idispensebehavior != DispenseItemBehavior.NOOP) { - if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(world, pos, itemstack, i)) return; // Paper - Add BlockPreDispenseEvent +@@ -96,7 +96,7 @@ public class DispenserBlock extends BaseEntityBlock { + DispenseItemBehavior dispenseMethod = this.getDispenseMethod(level, item); + if (dispenseMethod != DispenseItemBehavior.NOOP) { + if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(level, pos, item, randomSlot)) return; // Paper - Add BlockPreDispenseEvent - DispenserBlock.eventFired = false; // CraftBukkit - reset event status + DispenserBlock.eventFired.set(Boolean.FALSE); // CraftBukkit - reset event status // Folia - region threading - tileentitydispenser.setItem(i, idispensebehavior.dispense(sourceblock, itemstack)); + dispenserBlockEntity.setItem(randomSlot, dispenseMethod.dispense(blockSource, item)); } + } +diff --git a/net/minecraft/world/level/block/DoublePlantBlock.java b/net/minecraft/world/level/block/DoublePlantBlock.java +index 7d033444ab5f89fae3c571a67ede6e7eff378945..e46c4071a955d880d61235d0861d8752ab3b860e 100644 +--- a/net/minecraft/world/level/block/DoublePlantBlock.java ++++ b/net/minecraft/world/level/block/DoublePlantBlock.java +@@ -118,7 +118,7 @@ public class DoublePlantBlock extends BushBlock { -diff --git a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java -index 4fe83bd0f355549847b66afb7e61f6f2a6d97016..fa140ec5a02cb9204a498864638e2da00709dedb 100644 ---- a/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/DoublePlantBlock.java -@@ -104,7 +104,7 @@ public class DoublePlantBlock extends BushBlock { - - protected static void preventDropFromBottomPart(Level world, BlockPos pos, BlockState state, Player player) { + protected static void preventDropFromBottomPart(Level level, BlockPos pos, BlockState state, Player player) { // CraftBukkit start -- if (((net.minecraft.server.level.ServerLevel)world).hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper -+ if (((net.minecraft.server.level.ServerLevel)world).getCurrentWorldData().hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(world, pos).isCancelled()) { // Paper // Folia - region threading +- if (((net.minecraft.server.level.ServerLevel)level).hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(level, pos).isCancelled()) { // Paper ++ if (((net.minecraft.server.level.ServerLevel)level).getCurrentWorldData().hasPhysicsEvent && org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPhysicsEvent(level, pos).isCancelled()) { // Paper // Folia - region threading return; } // CraftBukkit end -diff --git a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -index af46f2885ead1e3ec1734504d8ba134c886e04fb..d3848662cf2b2d4fc47c3bf321b9a25106cd572b 100644 ---- a/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EndGatewayBlock.java -@@ -120,12 +120,38 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { - if (tileentity instanceof TheEndGatewayBlockEntity tileentityendgateway) { - Vec3 vec3d = tileentityendgateway.getPortalPosition(world, pos); - -- return vec3d == null ? null : (entity instanceof ThrownEnderpearl ? new TeleportTransition(world, vec3d, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET, PlayerTeleportEvent.TeleportCause.END_GATEWAY) : new TeleportTransition(world, vec3d, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET, PlayerTeleportEvent.TeleportCause.END_GATEWAY)); // CraftBukkit -+ return vec3d == null ? null : getTeleportTransition(world, entity, vec3d); // Folia - region threading +diff --git a/net/minecraft/world/level/block/EndGatewayBlock.java b/net/minecraft/world/level/block/EndGatewayBlock.java +index 84a1bd5e40e635962d795506861447851e443eee..a7b8e2b702fbe512c9633075515da6a430e76861 100644 +--- a/net/minecraft/world/level/block/EndGatewayBlock.java ++++ b/net/minecraft/world/level/block/EndGatewayBlock.java +@@ -111,17 +111,43 @@ public class EndGatewayBlock extends BaseEntityBlock implements Portal { + if (portalPosition == null) { + return null; + } else { +- return entity instanceof ThrownEnderpearl +- ? new TeleportTransition(level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY) // CraftBukkit +- : new TeleportTransition( +- level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY // CraftBukkit +- ); ++ return getTeleportTransition(level, entity, portalPosition); // Folia - region threading + } } else { return null; } } + // Folia start - region threading -+ public static TeleportTransition getTeleportTransition(ServerLevel world, Entity entity, Vec3 targetPos) { -+ return (entity instanceof ThrownEnderpearl ? new TeleportTransition(world, targetPos, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET, PlayerTeleportEvent.TeleportCause.END_GATEWAY) : new TeleportTransition(world, targetPos, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET, PlayerTeleportEvent.TeleportCause.END_GATEWAY)); // CraftBukkit ++ public static TeleportTransition getTeleportTransition(ServerLevel level, Entity entity, Vec3 portalPosition) { ++ return entity instanceof ThrownEnderpearl ++ ? new TeleportTransition(level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Set.of(), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY) // CraftBukkit ++ : new TeleportTransition( ++ level, portalPosition, Vec3.ZERO, 0.0F, 0.0F, Relative.union(Relative.DELTA, Relative.ROTATION), TeleportTransition.PLACE_PORTAL_TICKET, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.END_GATEWAY // CraftBukkit ++ ); + } + + @Override @@ -17911,28 +17537,20 @@ index af46f2885ead1e3ec1734504d8ba134c886e04fb..d3848662cf2b2d4fc47c3bf321b9a251 @Override protected RenderShape getRenderShape(BlockState state) { return RenderShape.INVISIBLE; -diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -index 8cb4142562db0be1f1a7d961ec5a10d4abf31692..45b8ac1418864ea32bd625b0d57fcec288ea5b0c 100644 ---- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -@@ -75,15 +75,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { - world.getCraftServer().getPluginManager().callEvent(event); +diff --git a/net/minecraft/world/level/block/EndPortalBlock.java b/net/minecraft/world/level/block/EndPortalBlock.java +index 01cddd7001b4a7f99c1b1d147fac904d3064d733..177735cf744e564081e4c140a0f8210c3a07e037 100644 +--- a/net/minecraft/world/level/block/EndPortalBlock.java ++++ b/net/minecraft/world/level/block/EndPortalBlock.java +@@ -63,7 +63,7 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { + level.getCraftServer().getPluginManager().callEvent(event); if (event.isCancelled()) return; // Paper - make cancellable // CraftBukkit end -- if (!world.isClientSide && world.dimension() == Level.END && entity instanceof ServerPlayer) { -- ServerPlayer entityplayer = (ServerPlayer) entity; -- -- if (world.paperConfig().misc.disableEndCredits) entityplayer.seenCredits = true; // Paper - Option to disable end credits -- if (!entityplayer.seenCredits) { -- entityplayer.showEndCredits(); -- return; -- } -- } -+ // Folia - region threading - do not show credits - - entity.setAsInsidePortal(this, pos); - } -@@ -135,6 +127,20 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { +- if (!level.isClientSide && level.dimension() == Level.END && entity instanceof ServerPlayer serverPlayer && !serverPlayer.seenCredits) { ++ if (false && !level.isClientSide && level.dimension() == Level.END && entity instanceof ServerPlayer serverPlayer && !serverPlayer.seenCredits) { // Folia - region threading - do not show credits + if (level.paperConfig().misc.disableEndCredits) {serverPlayer.seenCredits = true; return;} // Paper - Option to disable end credits + serverPlayer.showEndCredits(); + } else { +@@ -113,6 +113,20 @@ public class EndPortalBlock extends BaseEntityBlock implements Portal { } } @@ -17951,43 +17569,43 @@ index 8cb4142562db0be1f1a7d961ec5a10d4abf31692..45b8ac1418864ea32bd625b0d57fcec2 + // Folia end - region threading + @Override - public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource random) { - double d0 = (double) pos.getX() + random.nextDouble(); -diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -index c3dba0c2c94f3804338f86621dc42405e380a6b3..e979f0410a37da490f788242fa64b0bc26f75027 100644 ---- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java -@@ -93,8 +93,8 @@ public class FarmBlock extends Block { + public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) { + double d = pos.getX() + random.nextDouble(); +diff --git a/net/minecraft/world/level/block/FarmBlock.java b/net/minecraft/world/level/block/FarmBlock.java +index 47c9b32c89e7e6f84a279c2f6098ada77dc58b6b..1d97daccd595df427104aadf37eaa2861e6cb6e1 100644 +--- a/net/minecraft/world/level/block/FarmBlock.java ++++ b/net/minecraft/world/level/block/FarmBlock.java +@@ -95,8 +95,8 @@ public class FarmBlock extends Block { @Override - protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { - int i = (Integer) state.getValue(FarmBlock.MOISTURE); -- if (i > 0 && world.paperConfig().tickRates.wetFarmland != 1 && (world.paperConfig().tickRates.wetFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks -- if (i == 0 && world.paperConfig().tickRates.dryFarmland != 1 && (world.paperConfig().tickRates.dryFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks -+ if (i > 0 && world.paperConfig().tickRates.wetFarmland != 1 && (world.paperConfig().tickRates.wetFarmland < 1 || (world.getRedstoneGameTime() + pos.hashCode()) % world.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks // Folia - region threading -+ if (i == 0 && world.paperConfig().tickRates.dryFarmland != 1 && (world.paperConfig().tickRates.dryFarmland < 1 || (world.getRedstoneGameTime() + pos.hashCode()) % world.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks // Folia - region threading - - if (!FarmBlock.isNearWater(world, pos) && !world.isRainingAt(pos.above())) { - if (i > 0) { -diff --git a/src/main/java/net/minecraft/world/level/block/FungusBlock.java b/src/main/java/net/minecraft/world/level/block/FungusBlock.java -index ba5fff8892593a921f57cd55ad60cd6744ab4cf1..844143011fbb3453557b6cbe562ae41c7646f454 100644 ---- a/src/main/java/net/minecraft/world/level/block/FungusBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/FungusBlock.java + protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + int moistureValue = state.getValue(MOISTURE); +- if (moistureValue > 0 && level.paperConfig().tickRates.wetFarmland != 1 && (level.paperConfig().tickRates.wetFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks +- if (moistureValue == 0 && level.paperConfig().tickRates.dryFarmland != 1 && (level.paperConfig().tickRates.dryFarmland < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks ++ if (moistureValue > 0 && level.paperConfig().tickRates.wetFarmland != 1 && (level.paperConfig().tickRates.wetFarmland < 1 || (level.getRedstoneGameTime() + pos.hashCode()) % level.paperConfig().tickRates.wetFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks // Folia - region threading ++ if (moistureValue == 0 && level.paperConfig().tickRates.dryFarmland != 1 && (level.paperConfig().tickRates.dryFarmland < 1 || (level.getRedstoneGameTime() + pos.hashCode()) % level.paperConfig().tickRates.dryFarmland != 0)) { return; } // Paper - Configurable random tick rates for blocks // Folia - region threading + if (!isNearWater(level, pos) && !level.isRainingAt(pos.above())) { + if (moistureValue > 0) { + org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, pos, state.setValue(FarmBlock.MOISTURE, moistureValue - 1), 2); // CraftBukkit +diff --git a/net/minecraft/world/level/block/FungusBlock.java b/net/minecraft/world/level/block/FungusBlock.java +index 85f0eac75784565c658c5178c544f969db3d6f54..81edac1fa383c6875c7a0439f2a160c11ef77a41 100644 +--- a/net/minecraft/world/level/block/FungusBlock.java ++++ b/net/minecraft/world/level/block/FungusBlock.java @@ -76,9 +76,9 @@ public class FungusBlock extends BushBlock implements BonemealableBlock { - this.getFeature(world).ifPresent((holder) -> { // CraftBukkit start - if (this == Blocks.WARPED_FUNGUS) { -- SaplingBlock.treeType = org.bukkit.TreeType.WARPED_FUNGUS; -+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.WARPED_FUNGUS); // Folia - region threading - } else if (this == Blocks.CRIMSON_FUNGUS) { -- SaplingBlock.treeType = org.bukkit.TreeType.CRIMSON_FUNGUS; -+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.CRIMSON_FUNGUS); // Folia - region threading - } - // CraftBukkit end - ((ConfiguredFeature) holder.value()).place(world, world.getChunkSource().getGenerator(), random, pos); -diff --git a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java -index 5c360c6768582c1a35431739613e9b406875cc21..7285dd70e73e1a15b6af6a679a1a0577afd39e44 100644 ---- a/src/main/java/net/minecraft/world/level/block/HoneyBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/HoneyBlock.java + .map((value) -> { + if (this == Blocks.WARPED_FUNGUS) { +- SaplingBlock.treeType = org.bukkit.TreeType.WARPED_FUNGUS; ++ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.WARPED_FUNGUS); // Folia - region threading + } else if (this == Blocks.CRIMSON_FUNGUS) { +- SaplingBlock.treeType = org.bukkit.TreeType.CRIMSON_FUNGUS; ++ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.CRIMSON_FUNGUS); // Folia - region threading + } + return value; + }) +diff --git a/net/minecraft/world/level/block/HoneyBlock.java b/net/minecraft/world/level/block/HoneyBlock.java +index bab3ac2c4be08ea7589752b8472c1e13bcaab76a..776216db8097ceadc81d2f8401ea71447769b396 100644 +--- a/net/minecraft/world/level/block/HoneyBlock.java ++++ b/net/minecraft/world/level/block/HoneyBlock.java @@ -94,7 +94,7 @@ public class HoneyBlock extends HalfTransparentBlock { } @@ -17997,37 +17615,37 @@ index 5c360c6768582c1a35431739613e9b406875cc21..7285dd70e73e1a15b6af6a679a1a0577 CriteriaTriggers.HONEY_BLOCK_SLIDE.trigger((ServerPlayer)entity, entity.level().getBlockState(pos)); } } -diff --git a/src/main/java/net/minecraft/world/level/block/LightningRodBlock.java b/src/main/java/net/minecraft/world/level/block/LightningRodBlock.java -index a1fee00d12342cbd20e79096b405f4b108236d37..256c577e269d483ef64d1a091c36601b0a7d2293 100644 ---- a/src/main/java/net/minecraft/world/level/block/LightningRodBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/LightningRodBlock.java -@@ -113,7 +113,7 @@ public class LightningRodBlock extends RodBlock implements SimpleWaterloggedBloc - +diff --git a/net/minecraft/world/level/block/LightningRodBlock.java b/net/minecraft/world/level/block/LightningRodBlock.java +index 534de49aec290766d6bc2523bb3975df775b5881..d79b3d328915096d723c0e3e6b6eb75cfe5bac51 100644 +--- a/net/minecraft/world/level/block/LightningRodBlock.java ++++ b/net/minecraft/world/level/block/LightningRodBlock.java +@@ -116,7 +116,7 @@ public class LightningRodBlock extends RodBlock implements SimpleWaterloggedBloc @Override - public void animateTick(BlockState state, Level world, BlockPos pos, RandomSource random) { -- if (world.isThundering() && (long) world.random.nextInt(200) <= world.getGameTime() % 200L && pos.getY() == world.getHeight(Heightmap.Types.WORLD_SURFACE, pos.getX(), pos.getZ()) - 1) { -+ if (world.isThundering() && (long) world.random.nextInt(200) <= world.getRedstoneGameTime() % 200L && pos.getY() == world.getHeight(Heightmap.Types.WORLD_SURFACE, pos.getX(), pos.getZ()) - 1) { // Folia - region threading - ParticleUtils.spawnParticlesAlongAxis(((Direction) state.getValue(LightningRodBlock.FACING)).getAxis(), world, pos, 0.125D, ParticleTypes.ELECTRIC_SPARK, UniformInt.of(1, 2)); + public void animateTick(BlockState state, Level level, BlockPos pos, RandomSource random) { + if (level.isThundering() +- && level.random.nextInt(200) <= level.getGameTime() % 200L ++ && level.random.nextInt(200) <= level.getRedstoneGameTime() % 200L // Folia - region threading + && pos.getY() == level.getHeight(Heightmap.Types.WORLD_SURFACE, pos.getX(), pos.getZ()) - 1) { + ParticleUtils.spawnParticlesAlongAxis(state.getValue(FACING).getAxis(), level, pos, 0.125, ParticleTypes.ELECTRIC_SPARK, UniformInt.of(1, 2)); } - } -diff --git a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java -index 7900856c9e86afe907c00c9ac31bec93ece50abe..c0843e7a0c173a734f5eab21172b5bbb0f3d3e3e 100644 ---- a/src/main/java/net/minecraft/world/level/block/MushroomBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/MushroomBlock.java -@@ -105,7 +105,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock { +diff --git a/net/minecraft/world/level/block/MushroomBlock.java b/net/minecraft/world/level/block/MushroomBlock.java +index 904369f4d7db41026183f2de7c96c2f0f4dc204d..223b1789ba94f763e29fb5e74aade787681e9f5b 100644 +--- a/net/minecraft/world/level/block/MushroomBlock.java ++++ b/net/minecraft/world/level/block/MushroomBlock.java +@@ -94,7 +94,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock { return false; } else { - world.removeBlock(pos, false); -- SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? TreeType.BROWN_MUSHROOM : TreeType.RED_MUSHROOM; // CraftBukkit -+ SaplingBlock.treeTypeRT.set((this == Blocks.BROWN_MUSHROOM) ? TreeType.BROWN_MUSHROOM : TreeType.RED_MUSHROOM); // CraftBukkit // Folia - region threading - if (((ConfiguredFeature) ((Holder) optional.get()).value()).place(world, world.getChunkSource().getGenerator(), random, pos)) { + level.removeBlock(pos, false); +- SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM; // CraftBukkit ++ SaplingBlock.treeTypeRT.set((this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM); // CraftBukkit // Folia - region threading + if (optional.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) { return true; } else { -diff --git a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -index 3e9642e5236d9a1cc8e8f3b375d76810f4bc7c6c..88e33ae16848afe9885684537ef32e1836425fa3 100644 ---- a/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/NetherPortalBlock.java -@@ -178,6 +178,33 @@ public class NetherPortalBlock extends Block implements Portal { +diff --git a/net/minecraft/world/level/block/NetherPortalBlock.java b/net/minecraft/world/level/block/NetherPortalBlock.java +index e2eb693b0130513115392cb0cb5a829ede5be8c5..68e1b1737c8b7af39f22dd4d28b879b5c3d52f65 100644 +--- a/net/minecraft/world/level/block/NetherPortalBlock.java ++++ b/net/minecraft/world/level/block/NetherPortalBlock.java +@@ -181,6 +181,33 @@ public class NetherPortalBlock extends Block implements Portal { } } @@ -18059,37 +17677,41 @@ index 3e9642e5236d9a1cc8e8f3b375d76810f4bc7c6c..88e33ae16848afe9885684537ef32e18 + // Folia end - region threading + @Nullable - private TeleportTransition getExitPortal(ServerLevel worldserver, Entity entity, BlockPos blockposition, BlockPos blockposition1, boolean flag, WorldBorder worldborder, int searchRadius, boolean canCreatePortal, int createRadius) { - Optional optional = worldserver.getPortalForcer().findClosestPortalPosition(blockposition1, worldborder, searchRadius); -@@ -186,10 +213,10 @@ public class NetherPortalBlock extends Block implements Portal { - + private TeleportTransition getExitPortal(ServerLevel level, Entity entity, BlockPos pos, BlockPos exitPos, boolean isNether, WorldBorder worldBorder, int searchRadius, boolean canCreatePortal, int createRadius) { // CraftBukkit + Optional optional = level.getPortalForcer().findClosestPortalPosition(exitPos, worldBorder, searchRadius); // CraftBukkit +@@ -188,14 +215,14 @@ public class NetherPortalBlock extends Block implements Portal { + TeleportTransition.PostTeleportTransition postTeleportTransition; if (optional.isPresent()) { - BlockPos blockposition2 = (BlockPos) optional.get(); -- BlockState iblockdata = worldserver.getBlockState(blockposition2); -+ BlockState iblockdata = worldserver.getBlockStateFromEmptyChunk(blockposition2); // Folia - region threading - - blockutil_rectangle = BlockUtil.getLargestRectangleAround(blockposition2, (Direction.Axis) iblockdata.getValue(BlockStateProperties.HORIZONTAL_AXIS), 21, Direction.Axis.Y, 21, (blockposition3) -> { -- return worldserver.getBlockState(blockposition3) == iblockdata; -+ return worldserver.getBlockStateFromEmptyChunk(blockposition3) == iblockdata; // Folia - region threading - }); - teleporttransition_a = TeleportTransition.PLAY_PORTAL_SOUND.then((entity1) -> { - entity1.placePortalTicket(blockposition2); -@@ -235,7 +262,7 @@ public class NetherPortalBlock extends Block implements Portal { - return NetherPortalBlock.createDimensionTransition(world, exitPortalRectangle, enumdirection_enumaxis, vec3d, entity, postDimensionTransition); + BlockPos blockPos = optional.get(); +- BlockState blockState = level.getBlockState(blockPos); ++ BlockState blockState = level.getBlockStateFromEmptyChunk(blockPos); // Folia - region threading + largestRectangleAround = BlockUtil.getLargestRectangleAround( + blockPos, + blockState.getValue(BlockStateProperties.HORIZONTAL_AXIS), + 21, + Direction.Axis.Y, + 21, +- blockPos1 -> level.getBlockState(blockPos1) == blockState ++ blockPos1 -> level.getBlockStateFromEmptyChunk(blockPos1) == blockState // Folia - region threading + ); + postTeleportTransition = TeleportTransition.PLAY_PORTAL_SOUND.then(entity1 -> entity1.placePortalTicket(blockPos)); + } else if (canCreatePortal) { // CraftBukkit +@@ -238,7 +265,7 @@ public class NetherPortalBlock extends Block implements Portal { + return createDimensionTransition(level, rectangle, axis, relativePortalPosition, entity, postTeleportTransition); } -- private static TeleportTransition createDimensionTransition(ServerLevel world, BlockUtil.FoundRectangle exitPortalRectangle, Direction.Axis axis, Vec3 positionInPortal, Entity entity, TeleportTransition.PostTeleportTransition postDimensionTransition) { -+ public static TeleportTransition createDimensionTransition(ServerLevel world, BlockUtil.FoundRectangle exitPortalRectangle, Direction.Axis axis, Vec3 positionInPortal, Entity entity, TeleportTransition.PostTeleportTransition postDimensionTransition) { // Folia - region threading - public - BlockPos blockposition = exitPortalRectangle.minCorner; - BlockState iblockdata = world.getBlockState(blockposition); - Direction.Axis enumdirection_enumaxis1 = (Direction.Axis) iblockdata.getOptionalValue(BlockStateProperties.HORIZONTAL_AXIS).orElse(Direction.Axis.X); -diff --git a/src/main/java/net/minecraft/world/level/block/Portal.java b/src/main/java/net/minecraft/world/level/block/Portal.java -index 35ed840c1aeb56432613ec346f16f793de1c498d..fce6ae0619e9c613208ce5eda4274fee384b561b 100644 ---- a/src/main/java/net/minecraft/world/level/block/Portal.java -+++ b/src/main/java/net/minecraft/world/level/block/Portal.java +- private static TeleportTransition createDimensionTransition( ++ public static TeleportTransition createDimensionTransition( // Folia - region threading - public + ServerLevel level, + BlockUtil.FoundRectangle rectangle, + Direction.Axis axis, +diff --git a/net/minecraft/world/level/block/Portal.java b/net/minecraft/world/level/block/Portal.java +index c941b0e05d98fa59669757174887955e6319eddb..3883a437d99e5d8b13c55764613d630e29e75bc4 100644 +--- a/net/minecraft/world/level/block/Portal.java ++++ b/net/minecraft/world/level/block/Portal.java @@ -14,6 +14,10 @@ public interface Portal { @Nullable - TeleportTransition getPortalDestination(ServerLevel world, Entity entity, BlockPos pos); + TeleportTransition getPortalDestination(ServerLevel level, Entity entity, BlockPos pos); + // Folia start - region threading + public boolean portalAsync(ServerLevel sourceWorld, Entity portalTarget, BlockPos portalPos); @@ -18098,10 +17720,10 @@ index 35ed840c1aeb56432613ec346f16f793de1c498d..fce6ae0619e9c613208ce5eda4274fee default Portal.Transition getLocalTransition() { return Portal.Transition.NONE; } -diff --git a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java -index 21f2c61023fadcce30452a02f067cd5d87e5d8dc..0020e7bb7b19179a898cd8835d12cfa37eccdcc2 100644 ---- a/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/RedStoneWireBlock.java +diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java +index 12c9d60314c99fb65e640d255a2d0c6b7790ad4d..6ba86c5e55d09fd99e81e40db4614ef14246bdc3 100644 +--- a/net/minecraft/world/level/block/RedStoneWireBlock.java ++++ b/net/minecraft/world/level/block/RedStoneWireBlock.java @@ -91,7 +91,7 @@ public class RedStoneWireBlock extends Block { private static final float PARTICLE_DENSITY = 0.2F; private final BlockState crossState; @@ -18111,20 +17733,19 @@ index 21f2c61023fadcce30452a02f067cd5d87e5d8dc..0020e7bb7b19179a898cd8835d12cfa3 @Override public MapCodec codec() { -@@ -292,7 +292,11 @@ public class RedStoneWireBlock extends Block { - +@@ -293,6 +293,11 @@ public class RedStoneWireBlock extends Block { // Paper start - Optimize redstone (Eigencraft) // The bulk of the new functionality is found in RedstoneWireTurbo.java -- com.destroystokyo.paper.util.RedstoneWireTurbo turbo = new com.destroystokyo.paper.util.RedstoneWireTurbo(this); + io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this); + // Folia start - region threading -+ private com.destroystokyo.paper.util.RedstoneWireTurbo getTurbo(Level world) { ++ private io.papermc.paper.redstone.RedstoneWireTurbo getTurbo(Level world) { + return world.getCurrentWorldData().turbo; + } + // Folia end - region threading /* * Modified version of pre-existing updateSurroundingRedstone, which is called from -@@ -308,7 +312,7 @@ public class RedStoneWireBlock extends Block { +@@ -308,7 +313,7 @@ public class RedStoneWireBlock extends Block { if (orientation != null) { source = pos.relative(orientation.getFront().getOpposite()); } @@ -18133,7 +17754,7 @@ index 21f2c61023fadcce30452a02f067cd5d87e5d8dc..0020e7bb7b19179a898cd8835d12cfa3 return; } updatePowerStrength(worldIn, pos, state, orientation, blockAdded); -@@ -336,7 +340,7 @@ public class RedStoneWireBlock extends Block { +@@ -336,7 +341,7 @@ public class RedStoneWireBlock extends Block { // [Space Walker] suppress shape updates and emit those manually to // bypass the new neighbor update stack. if (level.setBlock(pos, state, Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_CLIENTS)) { @@ -18142,34 +17763,34 @@ index 21f2c61023fadcce30452a02f067cd5d87e5d8dc..0020e7bb7b19179a898cd8835d12cfa3 } } } -@@ -353,9 +357,9 @@ public class RedStoneWireBlock extends Block { +@@ -353,9 +358,9 @@ public class RedStoneWireBlock extends Block { } - public int getBlockSignal(Level world, BlockPos pos) { + public int getBlockSignal(Level level, BlockPos pos) { - this.shouldSignal = false; + io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().shouldSignal = false; // Folia - region threading - int i = world.getBestNeighborSignal(pos); + int bestNeighborSignal = level.getBestNeighborSignal(pos); - this.shouldSignal = true; + io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().shouldSignal = true; // Folia - region threading - return i; + return bestNeighborSignal; } -@@ -449,12 +453,12 @@ public class RedStoneWireBlock extends Block { +@@ -450,12 +455,12 @@ public class RedStoneWireBlock extends Block { @Override - protected int getDirectSignal(BlockState state, BlockGetter world, BlockPos pos, Direction direction) { -- return !this.shouldSignal ? 0 : state.getSignal(world, pos, direction); -+ return !io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().shouldSignal ? 0 : state.getSignal(world, pos, direction); // Folia - region threading + protected int getDirectSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { +- return !this.shouldSignal ? 0 : blockState.getSignal(blockAccess, pos, side); ++ return !io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().shouldSignal ? 0 : blockState.getSignal(blockAccess, pos, side); // Folia - region threading } @Override - protected int getSignal(BlockState state, BlockGetter world, BlockPos pos, Direction direction) { -- if (this.shouldSignal && direction != Direction.DOWN) { -+ if (io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().shouldSignal && direction != Direction.DOWN) { // Folia - region threading - int i = state.getValue(POWER); - if (i == 0) { + protected int getSignal(BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side) { +- if (this.shouldSignal && side != Direction.DOWN) { ++ if (io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData().shouldSignal && side != Direction.DOWN) { // Folia - region threading + int powerValue = blockState.getValue(POWER); + if (powerValue == 0) { return 0; -@@ -486,7 +490,10 @@ public class RedStoneWireBlock extends Block { +@@ -487,7 +492,10 @@ public class RedStoneWireBlock extends Block { @Override protected boolean isSignalSource(BlockState state) { @@ -18180,54 +17801,53 @@ index 21f2c61023fadcce30452a02f067cd5d87e5d8dc..0020e7bb7b19179a898cd8835d12cfa3 + // Folia end - region threading } - public static int getColorForPower(int powerLevel) { -diff --git a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java -index 26319e8247e9dfa2068700d7fadc21ea5f715561..1d87310289ff28dacf3f5bfb8f3ae0593c533b25 100644 ---- a/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/RedstoneTorchBlock.java -@@ -82,10 +82,10 @@ public class RedstoneTorchBlock extends BaseTorchBlock { - protected void tick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { - boolean flag = this.hasNeighborSignal(world, pos, state); + public static int getColorForPower(int power) { +diff --git a/net/minecraft/world/level/block/RedstoneTorchBlock.java b/net/minecraft/world/level/block/RedstoneTorchBlock.java +index 18420ec1f5776b018010f26e59aba00ae5bd0723..d5ac5d8fddeaff0def61a909faf2c909337ada57 100644 +--- a/net/minecraft/world/level/block/RedstoneTorchBlock.java ++++ b/net/minecraft/world/level/block/RedstoneTorchBlock.java +@@ -73,10 +73,10 @@ public class RedstoneTorchBlock extends BaseTorchBlock { + protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { + boolean hasNeighborSignal = this.hasNeighborSignal(level, pos, state); // Paper start - Faster redstone torch rapid clock removal -- java.util.ArrayDeque redstoneUpdateInfos = world.redstoneUpdateInfos; -+ java.util.ArrayDeque redstoneUpdateInfos = world.getCurrentWorldData().redstoneUpdateInfos; // Folia - region threading +- java.util.ArrayDeque redstoneUpdateInfos = level.redstoneUpdateInfos; ++ java.util.ArrayDeque redstoneUpdateInfos = level.getCurrentWorldData().redstoneUpdateInfos; // Folia - region threading if (redstoneUpdateInfos != null) { RedstoneTorchBlock.Toggle curr; -- while ((curr = redstoneUpdateInfos.peek()) != null && world.getGameTime() - curr.when > 60L) { -+ while ((curr = redstoneUpdateInfos.peek()) != null && world.getRedstoneGameTime() - curr.when > 60L) { // Folia - region threading +- while ((curr = redstoneUpdateInfos.peek()) != null && level.getGameTime() - curr.when > 60L) { ++ while ((curr = redstoneUpdateInfos.peek()) != null && level.getRedstoneGameTime() - curr.when > 60L) { // Folia - region threading redstoneUpdateInfos.poll(); } } -@@ -166,14 +166,14 @@ public class RedstoneTorchBlock extends BaseTorchBlock { +@@ -154,13 +154,13 @@ public class RedstoneTorchBlock extends BaseTorchBlock { - private static boolean isToggledTooFrequently(Level world, BlockPos pos, boolean addNew) { + private static boolean isToggledTooFrequently(Level level, BlockPos pos, boolean logToggle) { // Paper start - Faster redstone torch rapid clock removal -- java.util.ArrayDeque list = world.redstoneUpdateInfos; -+ java.util.ArrayDeque list = world.getCurrentWorldData().redstoneUpdateInfos; // Folia - region threading +- java.util.ArrayDeque list = level.redstoneUpdateInfos; ++ java.util.ArrayDeque list = level.getCurrentWorldData().redstoneUpdateInfos; // Folia - region threading if (list == null) { -- list = world.redstoneUpdateInfos = new java.util.ArrayDeque<>(); -+ list = world.getCurrentWorldData().redstoneUpdateInfos = new java.util.ArrayDeque<>(); // Folia - region threading +- list = level.redstoneUpdateInfos = new java.util.ArrayDeque<>(); ++ list = level.getCurrentWorldData().redstoneUpdateInfos = new java.util.ArrayDeque<>(); // Folia - region threading } // Paper end - Faster redstone torch rapid clock removal - - if (addNew) { -- list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), world.getGameTime())); -+ list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), world.getRedstoneGameTime())); // Folia - region threading + if (logToggle) { +- list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), level.getGameTime())); ++ list.add(new RedstoneTorchBlock.Toggle(pos.immutable(), level.getRedstoneGameTime())); // Folia - region threading } int i = 0; -@@ -200,12 +200,18 @@ public class RedstoneTorchBlock extends BaseTorchBlock { +@@ -182,12 +182,18 @@ public class RedstoneTorchBlock extends BaseTorchBlock { + } public static class Toggle { - - final BlockPos pos; - final long when; + public final BlockPos pos; // Folia - region threading -+ long when; // Folia - region ticking ++ long when; // Folia - region threading - public Toggle(BlockPos pos, long time) { + public Toggle(BlockPos pos, long when) { this.pos = pos; - this.when = time; + this.when = when; } + + // Folia start - region ticking @@ -18237,111 +17857,111 @@ index 26319e8247e9dfa2068700d7fadc21ea5f715561..1d87310289ff28dacf3f5bfb8f3ae059 + // Folia end - region ticking } } -diff --git a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java -index d262a5a6da57ef9ba9a6fe0dfbc88f577105e74f..e842c05cfe5991ba33582b9399610affbd02913f 100644 ---- a/src/main/java/net/minecraft/world/level/block/SaplingBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SaplingBlock.java -@@ -35,7 +35,7 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { +diff --git a/net/minecraft/world/level/block/SaplingBlock.java b/net/minecraft/world/level/block/SaplingBlock.java +index e014f052e9b0f5ca6b28044e2389782b7d0e0cb8..cc9e253d3033d3e970891067329aa281e85464f7 100644 +--- a/net/minecraft/world/level/block/SaplingBlock.java ++++ b/net/minecraft/world/level/block/SaplingBlock.java +@@ -26,7 +26,7 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { protected static final float AABB_OFFSET = 6.0F; - protected static final VoxelShape SHAPE = Block.box(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D); + protected static final VoxelShape SHAPE = Block.box(2.0, 0.0, 2.0, 14.0, 12.0, 14.0); protected final TreeGrower treeGrower; -- public static TreeType treeType; // CraftBukkit -+ public static final ThreadLocal treeTypeRT = new ThreadLocal<>(); // CraftBukkit // Folia - region threading +- public static org.bukkit.TreeType treeType; // CraftBukkit ++ public static final ThreadLocal treeTypeRT = new ThreadLocal<>(); // CraftBukkit // Folia - region threading @Override public MapCodec codec() { -@@ -66,18 +66,19 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { - world.setBlock(pos, (net.minecraft.world.level.block.state.BlockState) state.cycle(SaplingBlock.STAGE), 4); +@@ -56,18 +56,19 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock { + level.setBlock(pos, state.cycle(STAGE), 4); } else { // CraftBukkit start -- if (world.captureTreeGeneration) { -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading +- if (level.captureTreeGeneration) { ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading + if (worldData.captureTreeGeneration) { // Folia - region threading - this.treeGrower.growTree(world, world.getChunkSource().getGenerator(), pos, state, random); + this.treeGrower.growTree(level, level.getChunkSource().getGenerator(), pos, state, random); } else { -- world.captureTreeGeneration = true; +- level.captureTreeGeneration = true; + worldData.captureTreeGeneration = true; // Folia - region threading - this.treeGrower.growTree(world, world.getChunkSource().getGenerator(), pos, state, random); -- world.captureTreeGeneration = false; -- if (world.capturedBlockStates.size() > 0) { -- TreeType treeType = SaplingBlock.treeType; + this.treeGrower.growTree(level, level.getChunkSource().getGenerator(), pos, state, random); +- level.captureTreeGeneration = false; +- if (!level.capturedBlockStates.isEmpty()) { +- org.bukkit.TreeType treeType = SaplingBlock.treeType; - SaplingBlock.treeType = null; + worldData.captureTreeGeneration = false; // Folia - region threading -+ if (worldData.capturedBlockStates.size() > 0) { // Folia - region threading -+ TreeType treeType = SaplingBlock.treeTypeRT.get(); // Folia - region threading ++ if (!worldData.capturedBlockStates.isEmpty()) { // Folia - region threading ++ org.bukkit.TreeType treeType = SaplingBlock.treeTypeRT.get(); // Folia - region threading + SaplingBlock.treeTypeRT.set(null); // Folia - region threading - Location location = CraftLocation.toBukkit(pos, world.getWorld()); -- java.util.List blocks = new java.util.ArrayList<>(world.capturedBlockStates.values()); -- world.capturedBlockStates.clear(); -+ java.util.List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading + org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level.getWorld()); +- java.util.List blocks = new java.util.ArrayList<>(level.capturedBlockStates.values()); +- level.capturedBlockStates.clear(); ++ java.util.List blocks = new java.util.ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading + worldData.capturedBlockStates.clear(); // Folia - region threading - StructureGrowEvent event = null; + org.bukkit.event.world.StructureGrowEvent event = null; if (treeType != null) { - event = new StructureGrowEvent(location, treeType, false, null, blocks); -diff --git a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -index 4e38d2e0ce156b4edbef67c82c845ceeebbbcd59..5e761ca2a8f1edaba2305c99f1310f3d7cab9cac 100644 ---- a/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java -@@ -54,7 +54,7 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock { + event = new org.bukkit.event.world.StructureGrowEvent(location, treeType, false, null, blocks); +diff --git a/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java b/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java +index 722f2b9a24679e0fc67aae2cd27051f96f962efe..fb8c09b18ea4112cbbe6e93bf6b9804d79628d36 100644 +--- a/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java ++++ b/net/minecraft/world/level/block/SpreadingSnowyDirtBlock.java +@@ -50,7 +50,7 @@ public abstract class SpreadingSnowyDirtBlock extends SnowyDirtBlock { @Override - protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) { -- if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks -+ if (this instanceof GrassBlock && world.paperConfig().tickRates.grassSpread != 1 && (world.paperConfig().tickRates.grassSpread < 1 || (io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + pos.hashCode()) % world.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks // Folia - regionised ticking + protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) { +- if (this instanceof GrassBlock && level.paperConfig().tickRates.grassSpread != 1 && (level.paperConfig().tickRates.grassSpread < 1 || (net.minecraft.server.MinecraftServer.currentTick + pos.hashCode()) % level.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks ++ if (this instanceof GrassBlock && level.paperConfig().tickRates.grassSpread != 1 && (level.paperConfig().tickRates.grassSpread < 1 || (io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + pos.hashCode()) % level.paperConfig().tickRates.grassSpread != 0)) { return; } // Paper - Configurable random tick rates for blocks // Folia - regionised ticking // Paper start - Perf: optimize dirt and snow spreading - final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = world.getChunkIfLoaded(pos); + final net.minecraft.world.level.chunk.ChunkAccess cachedBlockChunk = level.getChunkIfLoaded(pos); if (cachedBlockChunk == null) { // Is this needed? -diff --git a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -index 0fbe66cc02bd3d95c0a5dcd55380a1b4a2f17ca6..3e3fc48470cc058d84f8db3fa8dc6105eb52eb89 100644 ---- a/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/WitherSkullBlock.java -@@ -62,7 +62,7 @@ public class WitherSkullBlock extends SkullBlock { +diff --git a/net/minecraft/world/level/block/WitherSkullBlock.java b/net/minecraft/world/level/block/WitherSkullBlock.java +index dc70aaa8d929c40c5f34c8facc1ad2bff4e98768..3ea53116725798a1eedb4802d6ebd7a32d8cccfd 100644 +--- a/net/minecraft/world/level/block/WitherSkullBlock.java ++++ b/net/minecraft/world/level/block/WitherSkullBlock.java +@@ -51,7 +51,7 @@ public class WitherSkullBlock extends SkullBlock { } - public static void checkSpawn(Level world, BlockPos pos, SkullBlockEntity blockEntity) { -- if (world.captureBlockStates) return; // CraftBukkit -+ if (world.getCurrentWorldData().captureBlockStates) return; // CraftBukkit // Folia - region threading - if (!world.isClientSide) { - BlockState iblockdata = blockEntity.getBlockState(); - boolean flag = iblockdata.is(Blocks.WITHER_SKELETON_SKULL) || iblockdata.is(Blocks.WITHER_SKELETON_WALL_SKULL); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -index 0e0d178f2793ab014358f534c8dc53218b89f083..7144c4dd1091edc3bbaa0f862763e3e60f520c9e 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeaconBlockEntity.java -@@ -215,7 +215,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + public static void checkSpawn(Level level, BlockPos pos, SkullBlockEntity blockEntity) { +- if (level.captureBlockStates) return; // CraftBukkit ++ if (level.getCurrentWorldData().captureBlockStates) return; // CraftBukkit // Folia - region threading + if (!level.isClientSide) { + BlockState blockState = blockEntity.getBlockState(); + boolean flag = blockState.is(Blocks.WITHER_SKELETON_SKULL) || blockState.is(Blocks.WITHER_SKELETON_WALL_SKULL); +diff --git a/net/minecraft/world/level/block/entity/BeaconBlockEntity.java b/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +index deef33d96db188cb297f04b581ab29e77e3716a9..413288e4a654b5ff8cc009b401d602731f63ec6d 100644 +--- a/net/minecraft/world/level/block/entity/BeaconBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/BeaconBlockEntity.java +@@ -211,7 +211,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name } - i1 = blockEntity.levels; -- if (world.getGameTime() % 80L == 0L) { -+ if (world.getRedstoneGameTime() % 80L == 0L) { // Folia - region threading + int i = blockEntity.levels; final int originalLevels = i; // Paper - OBFHELPER +- if (level.getGameTime() % 80L == 0L) { ++ if (level.getRedstoneGameTime() % 80L == 0L) { // Folia - region threading if (!blockEntity.beamSections.isEmpty()) { - blockEntity.levels = BeaconBlockEntity.updateBase(world, i, j, k); + blockEntity.levels = updateBase(level, x, y, z); } -@@ -339,7 +339,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name - list = world.getEntitiesOfClass(Player.class, axisalignedbb); - } else { - list = new java.util.ArrayList<>(); -- for (Player player : world.players()) { -+ for (Player player : world.getLocalPlayers()) { // Folia - region threading - if (player.isSpectator()) { - continue; - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -index 1f664c10138a6e19bdc0051fa80575516d5602e7..edb7b9391855eba5d693f3d64b6fb14a1b1c4949 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java -@@ -33,7 +33,7 @@ import org.bukkit.inventory.InventoryHolder; - // CraftBukkit end +@@ -345,7 +345,7 @@ public class BeaconBlockEntity extends BlockEntity implements MenuProvider, Name + list = level.getEntitiesOfClass(Player.class, aabb); // Diff from applyEffect + } else { + list = new java.util.ArrayList<>(); +- for (final Player player : level.players()) { ++ for (final Player player : level.getLocalPlayers()) { // Folia - region threading + if (!net.minecraft.world.entity.EntitySelector.NO_SPECTATORS.test(player)) continue; + if (player.getBoundingBox().intersects(aabb)) { + list.add(player); +diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java +index 77618757c0e678532dbab814aceed83f7f1cd892..003e9db957023486278679803b313ce89d573587 100644 +--- a/net/minecraft/world/level/block/entity/BlockEntity.java ++++ b/net/minecraft/world/level/block/entity/BlockEntity.java +@@ -26,7 +26,7 @@ import net.minecraft.world.level.block.state.BlockState; + import org.slf4j.Logger; public abstract class BlockEntity { -- static boolean ignoreTileUpdates; // Paper - Perf: Optimize Hoppers +- static boolean ignoreBlockEntityUpdates; // Paper - Perf: Optimize Hoppers + static final ThreadLocal IGNORE_TILE_UPDATES = ThreadLocal.withInitial(() -> Boolean.FALSE); // Paper - Perf: Optimize Hoppers // Folia - region threading - // CraftBukkit start - data containers - private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); -@@ -48,6 +48,12 @@ public abstract class BlockEntity { + private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); + public org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer; +@@ -40,6 +40,12 @@ public abstract class BlockEntity { private BlockState blockState; - private DataComponentMap components; + private DataComponentMap components = DataComponentMap.EMPTY; + // Folia start - region ticking + public void updateTicks(final long fromTickOffset, final long fromRedstoneTimeOffset) { @@ -18349,24 +17969,24 @@ index 1f664c10138a6e19bdc0051fa80575516d5602e7..edb7b9391855eba5d693f3d64b6fb14a + } + // Folia end - region ticking + - public BlockEntity(BlockEntityType type, BlockPos pos, BlockState state) { - this.components = DataComponentMap.EMPTY; + public BlockEntity(BlockEntityType type, BlockPos pos, BlockState blockState) { this.type = type; -@@ -216,7 +222,7 @@ public abstract class BlockEntity { + this.worldPosition = pos.immutable(); +@@ -197,7 +203,7 @@ public abstract class BlockEntity { public void setChanged() { if (this.level != null) { -- if (ignoreTileUpdates) return; // Paper - Perf: Optimize Hoppers +- if (ignoreBlockEntityUpdates) return; // Paper - Perf: Optimize Hoppers + if (IGNORE_TILE_UPDATES.get().booleanValue()) return; // Paper - Perf: Optimize Hoppers // Folia - region threading - BlockEntity.setChanged(this.level, this.worldPosition, this.blockState); + setChanged(this.level, this.worldPosition, this.blockState); } - -diff --git a/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java -index e2123f1c5852a34fb92e900f25591284625f3494..a6009ce84f0f7795f132b5b7f9517ff1bd2da971 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/CommandBlockEntity.java -@@ -61,6 +61,13 @@ public class CommandBlockEntity extends BlockEntity { - return new CommandSourceStack(this, Vec3.atCenterOf(CommandBlockEntity.this.worldPosition), new Vec2(0.0F, enumdirection.toYRot()), this.getLevel(), this.getLevel().paperConfig().commandBlocks.permissionsLevel, this.getName().getString(), this.getName(), this.getLevel().getServer(), (Entity) null); // Paper - configurable command block perm level + } +diff --git a/net/minecraft/world/level/block/entity/CommandBlockEntity.java b/net/minecraft/world/level/block/entity/CommandBlockEntity.java +index de75569d44855d9d6ec28cfee4403ecb6b45c4d3..c1e3a99a5fe917c728763be16c9a92d7252739a3 100644 +--- a/net/minecraft/world/level/block/entity/CommandBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/CommandBlockEntity.java +@@ -66,6 +66,13 @@ public class CommandBlockEntity extends BlockEntity { + ); } + // Folia start @@ -18379,42 +17999,42 @@ index e2123f1c5852a34fb92e900f25591284625f3494..a6009ce84f0f7795f132b5b7f9517ff1 @Override public boolean isValid() { return !CommandBlockEntity.this.isRemoved(); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -index d354c2ad41533ec8d52f7c5f63f8f74a0b1ce235..290db66d88061edba14fefdd261364a82624a574 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/ConduitBlockEntity.java -@@ -85,7 +85,7 @@ public class ConduitBlockEntity extends BlockEntity { +diff --git a/net/minecraft/world/level/block/entity/ConduitBlockEntity.java b/net/minecraft/world/level/block/entity/ConduitBlockEntity.java +index 269994df977801c67b8c576bde2478624b2631a1..719d3de54d440f09ba6cc6407b38e17ddc00ef88 100644 +--- a/net/minecraft/world/level/block/entity/ConduitBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/ConduitBlockEntity.java +@@ -81,7 +81,7 @@ public class ConduitBlockEntity extends BlockEntity { - public static void clientTick(Level world, BlockPos pos, BlockState state, ConduitBlockEntity blockEntity) { - ++blockEntity.tickCount; -- long i = world.getGameTime(); -+ long i = world.getRedstoneGameTime(); // Folia - region threading + public static void clientTick(Level level, BlockPos pos, BlockState state, ConduitBlockEntity blockEntity) { + blockEntity.tickCount++; +- long gameTime = level.getGameTime(); ++ long gameTime = level.getRedstoneGameTime(); // Folia - region threading List list = blockEntity.effectBlocks; + if (gameTime % 40L == 0L) { + blockEntity.isActive = updateShape(level, pos, list); +@@ -97,7 +97,7 @@ public class ConduitBlockEntity extends BlockEntity { - if (i % 40L == 0L) { -@@ -103,7 +103,7 @@ public class ConduitBlockEntity extends BlockEntity { - - public static void serverTick(Level world, BlockPos pos, BlockState state, ConduitBlockEntity blockEntity) { - ++blockEntity.tickCount; -- long i = world.getGameTime(); -+ long i = world.getRedstoneGameTime(); // Folia - region threading + public static void serverTick(Level level, BlockPos pos, BlockState state, ConduitBlockEntity blockEntity) { + blockEntity.tickCount++; +- long gameTime = level.getGameTime(); ++ long gameTime = level.getRedstoneGameTime(); // Folia - region threading List list = blockEntity.effectBlocks; - - if (i % 40L == 0L) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 5ebbdb94d9b91c442ff60eb6872f740ebd790fa0..44aae845da6cd34fc00e0c71795d6f610679bd4b 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -49,7 +49,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + if (gameTime % 40L == 0L) { + boolean flag = updateShape(level, pos, list); +diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java +index 5cd1326ad5d046c88b2b3449d610a78fa880b4cd..ae988c4910421fb720177178ef6136e595ae6946 100644 +--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java +@@ -34,7 +34,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen private static final int[][] CACHED_SLOTS = new int[54][]; - private NonNullList items; - public int cooldownTime; + private NonNullList items = NonNullList.withSize(5, ItemStack.EMPTY); + public int cooldownTime = -1; - private long tickedGameTime; + private long tickedGameTime = Long.MIN_VALUE; // Folia - region threading private Direction facing; // CraftBukkit start - add fields and methods -@@ -82,6 +82,16 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -67,6 +67,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } // CraftBukkit end @@ -18427,26 +18047,25 @@ index 5ebbdb94d9b91c442ff60eb6872f740ebd790fa0..44aae845da6cd34fc00e0c71795d6f61 + } + } + // Folia end - region threading -+ - public HopperBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.HOPPER, pos, state); - this.items = NonNullList.withSize(5, ItemStack.EMPTY); -@@ -141,7 +151,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - public static void pushItemsTick(Level world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity) { - --blockEntity.cooldownTime; -- blockEntity.tickedGameTime = world.getGameTime(); -+ blockEntity.tickedGameTime = world.getRedstoneGameTime(); // Folia - region threading + public HopperBlockEntity(BlockPos pos, BlockState blockState) { + super(BlockEntityType.HOPPER, pos, blockState); +@@ -125,7 +134,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + + public static void pushItemsTick(Level level, BlockPos pos, BlockState state, HopperBlockEntity blockEntity) { + blockEntity.cooldownTime--; +- blockEntity.tickedGameTime = level.getGameTime(); ++ blockEntity.tickedGameTime = level.getRedstoneGameTime(); // Folia - region threading if (!blockEntity.isOnCooldown()) { blockEntity.setCooldown(0); // Spigot start -@@ -237,12 +247,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -213,12 +222,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } // Paper start - Perf: Optimize Hoppers +- public static boolean skipHopperEvents; - private static boolean skipPullModeEventFire; - private static boolean skipPushModeEventFire; -- public static boolean skipHopperEvents; + // Folia - region threading - moved to RegionizedWorldData private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) { @@ -18456,7 +18075,7 @@ index 5ebbdb94d9b91c442ff60eb6872f740ebd790fa0..44aae845da6cd34fc00e0c71795d6f61 boolean foundItem = false; for (int i = 0; i < hopper.getContainerSize(); ++i) { final ItemStack item = hopper.getItem(i); -@@ -257,7 +266,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -233,7 +241,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen // We only need to fire the event once to give protection plugins a chance to cancel this event // Because nothing uses getItem, every event call should end up the same result. @@ -18465,7 +18084,7 @@ index 5ebbdb94d9b91c442ff60eb6872f740ebd790fa0..44aae845da6cd34fc00e0c71795d6f61 movedItem = callPushMoveEvent(destination, movedItem, hopper); if (movedItem == null) { // cancelled origItemStack.setCount(originalItemCount); -@@ -287,13 +296,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -263,13 +271,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) { @@ -18481,99 +18100,100 @@ index 5ebbdb94d9b91c442ff60eb6872f740ebd790fa0..44aae845da6cd34fc00e0c71795d6f61 movedItem = callPullMoveEvent(hopper, container, movedItem); if (movedItem == null) { // cancelled origItemStack.setCount(originalItemCount); -@@ -313,9 +323,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -289,9 +298,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount); } -- ignoreTileUpdates = true; +- ignoreBlockEntityUpdates = true; + IGNORE_TILE_UPDATES.set(true); // Folia - region threading container.setItem(i, origItemStack); -- ignoreTileUpdates = false; +- ignoreBlockEntityUpdates = false; + IGNORE_TILE_UPDATES.set(false); // Folia - region threading container.setChanged(); return true; } -@@ -330,12 +340,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen +@@ -306,6 +315,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @Nullable - private static ItemStack callPushMoveEvent(Container iinventory, ItemStack itemstack, HopperBlockEntity hopper) { + private static ItemStack callPushMoveEvent(Container destination, ItemStack itemStack, HopperBlockEntity hopper) { + io.papermc.paper.threadedregions.RegionizedWorldData worldData = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); // Folia - region threading - final Inventory destinationInventory = getInventory(iinventory); - final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(hopper.getOwner(false).getInventory(), - CraftItemStack.asCraftMirror(itemstack), destinationInventory, true); + final org.bukkit.inventory.Inventory destinationInventory = getInventory(destination); + final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent( + hopper.getOwner(false).getInventory(), +@@ -315,7 +325,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + ); final boolean result = event.callEvent(); if (!event.calledGetItem && !event.calledSetItem) { - skipPushModeEventFire = true; + worldData.skipPushModeEventFire = true; // Folia - region threading } if (!result) { - cooldownHopper(hopper); -@@ -351,6 +362,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + applyCooldown(hopper); +@@ -331,6 +341,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @Nullable private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) { + io.papermc.paper.threadedregions.RegionizedWorldData worldData = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); // Folia - region threading - final Inventory sourceInventory = getInventory(container); - final Inventory destination = getInventory(hopper); + final org.bukkit.inventory.Inventory sourceInventory = getInventory(container); + final org.bukkit.inventory.Inventory destination = getInventory(hopper); -@@ -358,7 +370,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(sourceInventory, CraftItemStack.asCraftMirror(itemstack), destination, false); +@@ -338,7 +349,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(sourceInventory, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), destination, false); final boolean result = event.callEvent(); if (!event.calledGetItem && !event.calledSetItem) { - skipPullModeEventFire = true; + worldData.skipPullModeEventFire = true; // Folia - region threading } if (!result) { - cooldownHopper(hopper); -@@ -546,13 +558,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + applyCooldown(hopper); +@@ -524,12 +535,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } - public static boolean suckInItems(Level world, Hopper hopper) { + public static boolean suckInItems(Level level, Hopper hopper) { + io.papermc.paper.threadedregions.RegionizedWorldData worldData = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); // Folia - region threading - BlockPos blockposition = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY() + 1.0D, hopper.getLevelZ()); - BlockState iblockdata = world.getBlockState(blockposition); - Container iinventory = HopperBlockEntity.getSourceContainer(world, hopper, blockposition, iblockdata); - - if (iinventory != null) { - Direction enumdirection = Direction.DOWN; + BlockPos blockPos = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY() + 1.0, hopper.getLevelZ()); + BlockState blockState = level.getBlockState(blockPos); + Container sourceContainer = getSourceContainer(level, hopper, blockPos, blockState); + if (sourceContainer != null) { + Direction direction = Direction.DOWN; - skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers + worldData.skipPullModeEventFire = worldData.skipHopperEvents; // Paper - Perf: Optimize Hoppers // Folia - region threading - int[] aint = HopperBlockEntity.getSlots(iinventory, enumdirection); - int i = aint.length; -@@ -743,9 +756,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - stack = stack.split(to.getMaxStackSize()); + for (int i : getSlots(sourceContainer, direction)) { + if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction, level)) { // Spigot +@@ -678,9 +690,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen + stack = stack.split(destination.getMaxStackSize()); } // Spigot end -- ignoreTileUpdates = true; // Paper - Perf: Optimize Hoppers +- ignoreBlockEntityUpdates = true; // Paper - Perf: Optimize Hoppers + IGNORE_TILE_UPDATES.set(Boolean.TRUE); // Paper - Perf: Optimize Hoppers // Folia - region threading - to.setItem(slot, stack); -- ignoreTileUpdates = false; // Paper - Perf: Optimize Hoppers + destination.setItem(slot, stack); +- ignoreBlockEntityUpdates = false; // Paper - Perf: Optimize Hoppers + IGNORE_TILE_UPDATES.set(Boolean.FALSE); // Paper - Perf: Optimize Hoppers // Folia - region threading stack = leftover; // Paper - Make hoppers respect inventory max stack size flag = true; - } else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -index 4729befa12732a9fd65cce243b33b3b479026c41..8ad84c8fce0461457bf918b22cf55a0c47a2dbcc 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -@@ -46,9 +46,9 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi + } else if (canMergeItems(item, stack)) { +diff --git a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +index 1638eccef431fb68775af624110f1968f0c6dabd..bd6693af6412fb08a28ca9a71d5c70d54f72c6e6 100644 +--- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +@@ -43,9 +43,9 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi // Paper end - Fix NPE in SculkBloomEvent world access - public static void serverTick(Level world, BlockPos pos, BlockState state, SculkCatalystBlockEntity blockEntity) { -- org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = blockEntity.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. -+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverrideRT.set(blockEntity.getBlockPos()); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. // Folia - region threading - blockEntity.catalystListener.getSculkSpreader().updateCursors(world, pos, world.getRandom(), true); + public static void serverTick(Level level, BlockPos pos, BlockState state, SculkCatalystBlockEntity sculkCatalyst) { +- org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = sculkCatalyst.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. ++ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverrideRT.set(sculkCatalyst.getBlockPos()); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. // Folia - region threading + sculkCatalyst.catalystListener.getSculkSpreader().updateCursors(level, pos, level.getRandom(), true); - org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = null; // CraftBukkit + org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverrideRT.set(null); // CraftBukkit // Folia - region threading } @Override -diff --git a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -index 68fd5d3f6553af8af867e34946cb8b3f852da985..cccd9a2f4d13adaf5fe677fef6f8f9db72d9d87f 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java -@@ -39,9 +39,12 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { +diff --git a/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java b/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java +index 5bf39c542757bf97da8909b65c22786a8a30385a..61887e6b052bca715c90dff5d9cd657e0b3f6a78 100644 +--- a/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/TheEndGatewayBlockEntity.java +@@ -35,9 +35,12 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { public long age; private int teleportCooldown; @Nullable @@ -18584,10 +18204,10 @@ index 68fd5d3f6553af8af867e34946cb8b3f852da985..cccd9a2f4d13adaf5fe677fef6f8f9db + private static final java.util.concurrent.atomic.AtomicLong SEARCHING_FOR_EXIT_ID_GENERATOR = new java.util.concurrent.atomic.AtomicLong(); // Folia - region threading + private Long searchingForExitId; // Folia - region threading + - public TheEndGatewayBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.END_GATEWAY, pos, state); + public TheEndGatewayBlockEntity(BlockPos pos, BlockState blockState) { + super(BlockEntityType.END_GATEWAY, pos, blockState); } -@@ -140,6 +143,104 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { +@@ -129,6 +132,104 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { } } @@ -18640,7 +18260,7 @@ index 68fd5d3f6553af8af867e34946cb8b3f852da985..cccd9a2f4d13adaf5fe677fef6f8f9db + TheEndGatewayBlockEntity portalTile, + net.minecraft.world.level.portal.TeleportTransition.PostTeleportTransition post) { + // can we even teleport in this dimension? -+ if (portalTile.exitPortal == null && portalWorld.getTypeKey() != LevelStem.END) { ++ if (portalTile.exitPortal == null && portalWorld.getTypeKey() != net.minecraft.world.level.dimension.LevelStem.END) { + return false; + } + @@ -18690,10 +18310,10 @@ index 68fd5d3f6553af8af867e34946cb8b3f852da985..cccd9a2f4d13adaf5fe677fef6f8f9db + // Folia end - region threading + @Nullable - public Vec3 getPortalPosition(ServerLevel world, BlockPos pos) { - BlockPos blockposition1; -@@ -189,6 +290,124 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { - return TheEndGatewayBlockEntity.findTallestBlock(world, blockposition1, 16, true); + public Vec3 getPortalPosition(ServerLevel level, BlockPos pos) { + if (this.exitPortal == null && level.getTypeKey() == net.minecraft.world.level.dimension.LevelStem.END) { // CraftBukkit - work in alternate worlds +@@ -174,6 +275,124 @@ public class TheEndGatewayBlockEntity extends TheEndPortalBlockEntity { + return findTallestBlock(level, blockPos, 16, true); } + // Folia start - region threading @@ -18711,7 +18331,7 @@ index 68fd5d3f6553af8af867e34946cb8b3f852da985..cccd9a2f4d13adaf5fe677fef6f8f9db + world.registryAccess().lookup(Registries.CONFIGURED_FEATURE).flatMap((iregistry) -> { + return iregistry.get(EndFeatures.END_ISLAND); + }).ifPresent((holder_c) -> { -+ ((ConfiguredFeature) holder_c.value()).place(world, world.getChunkSource().getGenerator(), RandomSource.create(blockposition2.asLong()), blockposition2); ++ ((net.minecraft.world.level.levelgen.feature.ConfiguredFeature) holder_c.value()).place(world, world.getChunkSource().getGenerator(), RandomSource.create(blockposition2.asLong()), blockposition2); + }); + blockposition1 = blockposition2; + } else { @@ -18728,27 +18348,27 @@ index 68fd5d3f6553af8af867e34946cb8b3f852da985..cccd9a2f4d13adaf5fe677fef6f8f9db + + BlockPos finalBlockPosition1 = blockposition1; + world.moonrise$loadChunksAsync(blockposition1, radius, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (java.util.List chunks) -> { -+ // make sure chunks are kept loaded -+ for (net.minecraft.world.level.chunk.ChunkAccess access : chunks) { -+ world.chunkSource.addTicketAtLevel( -+ net.minecraft.server.level.TicketType.DELAYED, access.getPos(), -+ ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.FULL_LOADED_TICKET_LEVEL, -+ net.minecraft.util.Unit.INSTANCE ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (java.util.List chunks) -> { ++ // make sure chunks are kept loaded ++ for (net.minecraft.world.level.chunk.ChunkAccess access : chunks) { ++ world.chunkSource.addTicketAtLevel( ++ net.minecraft.server.level.TicketType.DELAYED, access.getPos(), ++ ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.FULL_LOADED_TICKET_LEVEL, ++ net.minecraft.util.Unit.INSTANCE ++ ); ++ } ++ // now after the chunks are loaded, we can delay by one tick ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( ++ world, posX >> 4, posZ >> 4, () -> { ++ // find final location ++ BlockPos tpLoc = TheEndGatewayBlockEntity.findTallestBlock(world, finalBlockPosition1, radius, true).above(GATEWAY_HEIGHT_ABOVE_SURFACE); ++ ++ // done ++ complete.complete(tpLoc); ++ } + ); + } -+ // now after the chunks are loaded, we can delay by one tick -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( -+ world, posX >> 4, posZ >> 4, () -> { -+ // find final location -+ BlockPos tpLoc = TheEndGatewayBlockEntity.findTallestBlock(world, finalBlockPosition1, radius, true).above(GATEWAY_HEIGHT_ABOVE_SURFACE); -+ -+ // done -+ complete.complete(tpLoc); -+ } -+ ); -+ } + ); + }); + @@ -18788,39 +18408,39 @@ index 68fd5d3f6553af8af867e34946cb8b3f852da985..cccd9a2f4d13adaf5fe677fef6f8f9db + vars.currPos = vars.currPos.add(posDirFromOrigin.scale(vars.mode ? 16.0 : -16.0)); + // schedule next iteration + world.moonrise$getChunkTaskScheduler().scheduleChunkLoad( -+ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(vars.currPos), -+ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(vars.currPos), -+ net.minecraft.world.level.chunk.status.ChunkStatus.FULL, -+ true, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (chunk) -> { -+ this.run(); -+ } ++ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(vars.currPos), ++ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(vars.currPos), ++ net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ++ true, ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (chunk) -> { ++ this.run(); ++ } + ); + } + }; + + // kick off first chunk load + world.moonrise$getChunkTaskScheduler().scheduleChunkLoad( -+ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(posDirExtruded), -+ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(posDirExtruded), -+ net.minecraft.world.level.chunk.status.ChunkStatus.FULL, -+ true, -+ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, -+ (chunk) -> { -+ handle.run(); -+ } ++ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkX(posDirExtruded), ++ ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(posDirExtruded), ++ net.minecraft.world.level.chunk.status.ChunkStatus.FULL, ++ true, ++ ca.spottedleaf.concurrentutil.util.Priority.NORMAL, ++ (chunk) -> { ++ handle.run(); ++ } + ); + } + // Folia end - region threading + - private static Vec3 findExitPortalXZPosTentative(ServerLevel world, BlockPos pos) { - Vec3 vec3d = (new Vec3((double) pos.getX(), 0.0D, (double) pos.getZ())).normalize(); - boolean flag = true; -diff --git a/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java + private static Vec3 findExitPortalXZPosTentative(ServerLevel level, BlockPos pos) { + Vec3 vec3 = new Vec3(pos.getX(), 0.0, pos.getZ()).normalize(); + int i = 1024; +diff --git a/net/minecraft/world/level/block/entity/TickingBlockEntity.java b/net/minecraft/world/level/block/entity/TickingBlockEntity.java index 28e3b73507b988f7234cbf29c4024c88180d0aef..c8facee29ee08e0975528083f89b64f0b593957f 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java +--- a/net/minecraft/world/level/block/entity/TickingBlockEntity.java ++++ b/net/minecraft/world/level/block/entity/TickingBlockEntity.java @@ -10,4 +10,6 @@ public interface TickingBlockEntity { BlockPos getPos(); @@ -18828,108 +18448,109 @@ index 28e3b73507b988f7234cbf29c4024c88180d0aef..c8facee29ee08e0975528083f89b64f0 + + BlockEntity getTileEntity(); // Folia - region threading } -diff --git a/src/main/java/net/minecraft/world/level/block/grower/TreeGrower.java b/src/main/java/net/minecraft/world/level/block/grower/TreeGrower.java -index 0a39c3ceaf091eeb9f8af979d0851bbda7bb2586..e1a67d8d4b2ad48b4f6c7baf19c028fb011c63eb 100644 ---- a/src/main/java/net/minecraft/world/level/block/grower/TreeGrower.java -+++ b/src/main/java/net/minecraft/world/level/block/grower/TreeGrower.java -@@ -175,55 +175,57 @@ public final class TreeGrower { +diff --git a/net/minecraft/world/level/block/grower/TreeGrower.java b/net/minecraft/world/level/block/grower/TreeGrower.java +index cf7311c507de09a8f89934e430b2201e8bdffe51..80de710b4e1528587b509e50bdd69983bcb608d0 100644 +--- a/net/minecraft/world/level/block/grower/TreeGrower.java ++++ b/net/minecraft/world/level/block/grower/TreeGrower.java +@@ -203,56 +203,58 @@ public final class TreeGrower { + // CraftBukkit start private void setTreeType(Holder> holder) { - ResourceKey> worldgentreeabstract = holder.unwrapKey().get(); -+ TreeType treeType; // Folia - region threading - if (worldgentreeabstract == TreeFeatures.OAK || worldgentreeabstract == TreeFeatures.OAK_BEES_005) { -- SaplingBlock.treeType = TreeType.TREE; -+ treeType = TreeType.TREE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.HUGE_RED_MUSHROOM) { -- SaplingBlock.treeType = TreeType.RED_MUSHROOM; -+ treeType = TreeType.RED_MUSHROOM; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.HUGE_BROWN_MUSHROOM) { -- SaplingBlock.treeType = TreeType.BROWN_MUSHROOM; -+ treeType = TreeType.BROWN_MUSHROOM; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.JUNGLE_TREE) { -- SaplingBlock.treeType = TreeType.COCOA_TREE; -+ treeType = TreeType.COCOA_TREE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.JUNGLE_TREE_NO_VINE) { -- SaplingBlock.treeType = TreeType.SMALL_JUNGLE; -+ treeType = TreeType.SMALL_JUNGLE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.PINE) { -- SaplingBlock.treeType = TreeType.TALL_REDWOOD; -+ treeType = TreeType.TALL_REDWOOD; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.SPRUCE) { -- SaplingBlock.treeType = TreeType.REDWOOD; -+ treeType = TreeType.REDWOOD; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.ACACIA) { -- SaplingBlock.treeType = TreeType.ACACIA; -+ treeType = TreeType.ACACIA; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.BIRCH || worldgentreeabstract == TreeFeatures.BIRCH_BEES_005) { -- SaplingBlock.treeType = TreeType.BIRCH; -+ treeType = TreeType.BIRCH; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.SUPER_BIRCH_BEES_0002) { -- SaplingBlock.treeType = TreeType.TALL_BIRCH; -+ treeType = TreeType.TALL_BIRCH; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.SWAMP_OAK) { -- SaplingBlock.treeType = TreeType.SWAMP; -+ treeType = TreeType.SWAMP; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.FANCY_OAK || worldgentreeabstract == TreeFeatures.FANCY_OAK_BEES_005) { -- SaplingBlock.treeType = TreeType.BIG_TREE; -+ treeType = TreeType.BIG_TREE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.JUNGLE_BUSH) { -- SaplingBlock.treeType = TreeType.JUNGLE_BUSH; -+ treeType = TreeType.JUNGLE_BUSH; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.DARK_OAK) { -- SaplingBlock.treeType = TreeType.DARK_OAK; -+ treeType = TreeType.DARK_OAK; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.MEGA_SPRUCE) { -- SaplingBlock.treeType = TreeType.MEGA_REDWOOD; -+ treeType = TreeType.MEGA_REDWOOD; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.MEGA_PINE) { -- SaplingBlock.treeType = TreeType.MEGA_PINE; -+ treeType = TreeType.MEGA_PINE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.MEGA_JUNGLE_TREE) { -- SaplingBlock.treeType = TreeType.JUNGLE; -+ treeType = TreeType.JUNGLE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.AZALEA_TREE) { -- SaplingBlock.treeType = TreeType.AZALEA; -+ treeType = TreeType.AZALEA; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.MANGROVE) { -- SaplingBlock.treeType = TreeType.MANGROVE; -+ treeType = TreeType.MANGROVE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.TALL_MANGROVE) { -- SaplingBlock.treeType = TreeType.TALL_MANGROVE; -+ treeType = TreeType.TALL_MANGROVE; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.CHERRY || worldgentreeabstract == TreeFeatures.CHERRY_BEES_005) { -- SaplingBlock.treeType = TreeType.CHERRY; -+ treeType = TreeType.CHERRY; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.PALE_OAK || worldgentreeabstract == TreeFeatures.PALE_OAK_BONEMEAL) { -- SaplingBlock.treeType = TreeType.PALE_OAK; -+ treeType = TreeType.PALE_OAK; // Folia - region threading - } else if (worldgentreeabstract == TreeFeatures.PALE_OAK_CREAKING) { -- SaplingBlock.treeType = TreeType.PALE_OAK_CREAKING; -+ treeType = TreeType.PALE_OAK_CREAKING; // Folia - region threading ++ org.bukkit.TreeType treeType; // Folia - region threading + ResourceKey> treeFeature = holder.unwrapKey().get(); + if (treeFeature == TreeFeatures.OAK || treeFeature == TreeFeatures.OAK_BEES_005) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TREE; ++ treeType = org.bukkit.TreeType.TREE; // Folia - region threading + } else if (treeFeature == TreeFeatures.HUGE_RED_MUSHROOM) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.RED_MUSHROOM; ++ treeType = org.bukkit.TreeType.RED_MUSHROOM; // Folia - region threading + } else if (treeFeature == TreeFeatures.HUGE_BROWN_MUSHROOM) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BROWN_MUSHROOM; ++ treeType = org.bukkit.TreeType.BROWN_MUSHROOM; // Folia - region threading + } else if (treeFeature == TreeFeatures.JUNGLE_TREE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.COCOA_TREE; ++ treeType = org.bukkit.TreeType.COCOA_TREE; // Folia - region threading + } else if (treeFeature == TreeFeatures.JUNGLE_TREE_NO_VINE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.SMALL_JUNGLE; ++ treeType = org.bukkit.TreeType.SMALL_JUNGLE; // Folia - region threading + } else if (treeFeature == TreeFeatures.PINE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_REDWOOD; ++ treeType = org.bukkit.TreeType.TALL_REDWOOD; // Folia - region threading + } else if (treeFeature == TreeFeatures.SPRUCE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.REDWOOD; ++ treeType = org.bukkit.TreeType.REDWOOD; // Folia - region threading + } else if (treeFeature == TreeFeatures.ACACIA) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.ACACIA; ++ treeType = org.bukkit.TreeType.ACACIA; // Folia - region threading + } else if (treeFeature == TreeFeatures.BIRCH || treeFeature == TreeFeatures.BIRCH_BEES_005) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BIRCH; ++ treeType = org.bukkit.TreeType.BIRCH; // Folia - region threading + } else if (treeFeature == TreeFeatures.SUPER_BIRCH_BEES_0002) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_BIRCH; ++ treeType = org.bukkit.TreeType.TALL_BIRCH; // Folia - region threading + } else if (treeFeature == TreeFeatures.SWAMP_OAK) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.SWAMP; ++ treeType = org.bukkit.TreeType.SWAMP; // Folia - region threading + } else if (treeFeature == TreeFeatures.FANCY_OAK || treeFeature == TreeFeatures.FANCY_OAK_BEES_005) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BIG_TREE; ++ treeType = org.bukkit.TreeType.BIG_TREE; // Folia - region threading + } else if (treeFeature == TreeFeatures.JUNGLE_BUSH) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE_BUSH; ++ treeType = org.bukkit.TreeType.JUNGLE_BUSH; // Folia - region threading + } else if (treeFeature == TreeFeatures.DARK_OAK) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.DARK_OAK; ++ treeType = org.bukkit.TreeType.DARK_OAK; // Folia - region threading + } else if (treeFeature == TreeFeatures.MEGA_SPRUCE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_REDWOOD; ++ treeType = org.bukkit.TreeType.MEGA_REDWOOD; // Folia - region threading + } else if (treeFeature == TreeFeatures.MEGA_PINE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_PINE; ++ treeType = org.bukkit.TreeType.MEGA_PINE; // Folia - region threading + } else if (treeFeature == TreeFeatures.MEGA_JUNGLE_TREE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE; ++ treeType = org.bukkit.TreeType.JUNGLE; // Folia - region threading + } else if (treeFeature == TreeFeatures.AZALEA_TREE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.AZALEA; ++ treeType = org.bukkit.TreeType.AZALEA; // Folia - region threading + } else if (treeFeature == TreeFeatures.MANGROVE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MANGROVE; ++ treeType = org.bukkit.TreeType.MANGROVE; // Folia - region threading + } else if (treeFeature == TreeFeatures.TALL_MANGROVE) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_MANGROVE; ++ treeType = org.bukkit.TreeType.TALL_MANGROVE; // Folia - region threading + } else if (treeFeature == TreeFeatures.CHERRY || treeFeature == TreeFeatures.CHERRY_BEES_005) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.CHERRY; ++ treeType = org.bukkit.TreeType.CHERRY; // Folia - region threading + } else if (treeFeature == TreeFeatures.PALE_OAK || treeFeature == TreeFeatures.PALE_OAK_BONEMEAL) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.PALE_OAK; ++ treeType = org.bukkit.TreeType.PALE_OAK; // Folia - region threading + } else if (treeFeature == TreeFeatures.PALE_OAK_CREAKING) { +- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.PALE_OAK_CREAKING; ++ treeType = org.bukkit.TreeType.PALE_OAK_CREAKING; // Folia - region threading } else { - throw new IllegalArgumentException("Unknown tree generator " + worldgentreeabstract); + throw new IllegalArgumentException("Unknown tree generator " + treeFeature); } -+ SaplingBlock.treeTypeRT.set(treeType); // Folia - region threading ++ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(treeType); // Folia - region threading } // CraftBukkit end - -diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -index 4b51472502d08ea357da437afeb4b581979e9cff..0a7b67863e6f75bfcde877d5d226ab60dbe5a81b 100644 ---- a/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonBaseBlock.java -@@ -156,7 +156,7 @@ public class PistonBaseBlock extends DirectionalBlock { - if (tileentity instanceof PistonMovingBlockEntity) { - PistonMovingBlockEntity tileentitypiston = (PistonMovingBlockEntity) tileentity; - -- if (tileentitypiston.isExtending() && (tileentitypiston.getProgress(0.0F) < 0.5F || world.getGameTime() == tileentitypiston.getLastTicked() || ((ServerLevel) world).isHandlingTick())) { -+ if (tileentitypiston.isExtending() && (tileentitypiston.getProgress(0.0F) < 0.5F || world.getRedstoneGameTime() == tileentitypiston.getLastTicked() || ((ServerLevel) world).isHandlingTick())) { // Folia - region threading - b0 = 2; - } - } -diff --git a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -index e1c9a961064887070b29207efd7af47884f8dc29..c3a04ef842630b3df447dea48b84bccde0c89e83 100644 ---- a/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java + } +diff --git a/net/minecraft/world/level/block/piston/PistonBaseBlock.java b/net/minecraft/world/level/block/piston/PistonBaseBlock.java +index 2b1d5328072710784d2399b523afcbcfb1d7f0cd..bbb6d89da4b2fb90d8c1bc7c0cea6c76da623f1a 100644 +--- a/net/minecraft/world/level/block/piston/PistonBaseBlock.java ++++ b/net/minecraft/world/level/block/piston/PistonBaseBlock.java +@@ -139,7 +139,7 @@ public class PistonBaseBlock extends DirectionalBlock { + && pistonMovingBlockEntity.isExtending() + && ( + pistonMovingBlockEntity.getProgress(0.0F) < 0.5F +- || level.getGameTime() == pistonMovingBlockEntity.getLastTicked() ++ || level.getRedstoneGameTime() == pistonMovingBlockEntity.getLastTicked() // Folia - region threading + || ((ServerLevel)level).isHandlingTick() + )) { + i = 2; +diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java +index 1e6e940fca9d96ef410c7bf05524bd9b24db4a79..3df23feff6937b6a2dbeff82e489a9a4ff644843 100644 +--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java ++++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java @@ -41,9 +41,19 @@ public class PistonMovingBlockEntity extends BlockEntity { private static final ThreadLocal NOCLIP = ThreadLocal.withInitial(() -> null); private float progress; @@ -18948,13 +18569,13 @@ index e1c9a961064887070b29207efd7af47884f8dc29..c3a04ef842630b3df447dea48b84bccd + } + // Folia end - region threading + - public PistonMovingBlockEntity(BlockPos pos, BlockState state) { - super(BlockEntityType.PISTON, pos, state); + public PistonMovingBlockEntity(BlockPos pos, BlockState blockState) { + super(BlockEntityType.PISTON, pos, blockState); } @@ -150,8 +160,8 @@ public class PistonMovingBlockEntity extends BlockEntity { - entity.setDeltaMovement(e, g, h); - // Paper - EAR items stuck in in slime pushed by a piston + entity.setDeltaMovement(d1, d2, d3); + // Paper - EAR items stuck in slime pushed by a piston - entity.activatedTick = Math.max(entity.activatedTick, net.minecraft.server.MinecraftServer.currentTick + 10); - entity.activatedImmunityTick = Math.max(entity.activatedImmunityTick, net.minecraft.server.MinecraftServer.currentTick + 10); + entity.activatedTick = Math.max(entity.activatedTick, io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + 10); // Folia - region threading @@ -18962,39 +18583,41 @@ index e1c9a961064887070b29207efd7af47884f8dc29..c3a04ef842630b3df447dea48b84bccd // Paper end break; } -@@ -299,7 +309,7 @@ public class PistonMovingBlockEntity extends BlockEntity { +@@ -292,7 +302,7 @@ public class PistonMovingBlockEntity extends BlockEntity { } - public static void tick(Level world, BlockPos pos, BlockState state, PistonMovingBlockEntity blockEntity) { -- blockEntity.lastTicked = world.getGameTime(); -+ blockEntity.lastTicked = world.getRedstoneGameTime(); // Folia - region threading + public static void tick(Level level, BlockPos pos, BlockState state, PistonMovingBlockEntity blockEntity) { +- blockEntity.lastTicked = level.getGameTime(); ++ blockEntity.lastTicked = level.getRedstoneGameTime(); // Folia - region threading blockEntity.progressO = blockEntity.progress; if (blockEntity.progressO >= 1.0F) { - if (world.isClientSide && blockEntity.deathTicks < 5) { -diff --git a/src/main/java/net/minecraft/world/level/border/WorldBorder.java b/src/main/java/net/minecraft/world/level/border/WorldBorder.java -index 807a097a7b6399f24ede741f94ce98eb67e55add..c2a0cd1c25b6d775b55f8c3aacca9837e35a5dfd 100644 ---- a/src/main/java/net/minecraft/world/level/border/WorldBorder.java -+++ b/src/main/java/net/minecraft/world/level/border/WorldBorder.java -@@ -34,6 +34,8 @@ public class WorldBorder { - - public WorldBorder() {} + if (level.isClientSide && blockEntity.deathTicks < 5) { +diff --git a/net/minecraft/world/level/border/WorldBorder.java b/net/minecraft/world/level/border/WorldBorder.java +index 7249292e77b4a54f1f4f707c4dc55924c96dd23f..eb0d3cc606fb7bb06871ea61c240873ed7e67bc5 100644 +--- a/net/minecraft/world/level/border/WorldBorder.java ++++ b/net/minecraft/world/level/border/WorldBorder.java +@@ -30,6 +30,8 @@ public class WorldBorder { + public static final WorldBorder.Settings DEFAULT_SETTINGS = new WorldBorder.Settings(0.0, 0.0, 0.2, 5.0, 5, 15, 5.999997E7F, 0L, 0.0); + public net.minecraft.server.level.ServerLevel world; // CraftBukkit + // Folia - region threading - TODO make this shit thread-safe + public boolean isWithinBounds(BlockPos pos) { - return this.isWithinBounds((double) pos.getX(), (double) pos.getZ()); + return this.isWithinBounds(pos.getX(), pos.getZ()); } -@@ -47,14 +49,12 @@ public class WorldBorder { +@@ -43,16 +45,14 @@ public class WorldBorder { } // Paper start - Bound treasure maps to world border - private final BlockPos.MutableBlockPos mutPos = new BlockPos.MutableBlockPos(); + private static final ThreadLocal mutPos = ThreadLocal.withInitial(() -> new BlockPos.MutableBlockPos()); // Folia - region threading + public boolean isBlockInBounds(int chunkX, int chunkZ) { - this.mutPos.set(chunkX, 64, chunkZ); - return this.isWithinBounds(this.mutPos); + return this.isWithinBounds(mutPos.get().set(chunkX, 64, chunkZ)); // Folia - region threading } + public boolean isChunkInBounds(int chunkX, int chunkZ) { - this.mutPos.set(((chunkX << 4) + 15), 64, (chunkZ << 4) + 15); - return this.isWithinBounds(this.mutPos); @@ -19002,26 +18625,26 @@ index 807a097a7b6399f24ede741f94ce98eb67e55add..c2a0cd1c25b6d775b55f8c3aacca9837 } // Paper end - Bound treasure maps to world border -diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -index e0cb360ece042c4fc6aa0d10106923fe25288f5c..7f6dd454e0794739dc1861f768aaed86c484afe7 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkGenerator.java -@@ -326,7 +326,7 @@ public abstract class ChunkGenerator { +diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java +index 6ed51cf42b5864194d671b5b56f5b9bdf0291dc0..b85c547f281c58bf45c9062d0b886cb4ff7b386b 100644 +--- a/net/minecraft/world/level/chunk/ChunkGenerator.java ++++ b/net/minecraft/world/level/chunk/ChunkGenerator.java +@@ -327,7 +327,7 @@ public abstract class ChunkGenerator { } - private static boolean tryAddReference(StructureManager structureAccessor, StructureStart start) { -- if (start.canBeReferenced()) { -+ if (start.tryReference()) { // Folia - region threading - structureAccessor.addReference(start); + private static boolean tryAddReference(StructureManager structureManager, StructureStart structureStart) { +- if (structureStart.canBeReferenced()) { ++ if (structureStart.tryReference()) { // Folia - region threading + structureManager.addReference(structureStart); return true; } else { -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 97937e3bd211997f0a0a3e9e671a1c59712d0003..2c421ddb759eae4fbf2f2420d3b8cab22e854b85 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -62,6 +62,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - @Override - public void tick() {} +diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java +index 761fdcd4a4e18f45547afd8edff44f61c6eeacb4..f83cfa85678d288ece2348aae41d315660095ad8 100644 +--- a/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/net/minecraft/world/level/chunk/LevelChunk.java +@@ -59,6 +59,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + public void tick() { + } + // Folia start - region threading + @Override @@ -19033,56 +18656,55 @@ index 97937e3bd211997f0a0a3e9e671a1c59712d0003..2c421ddb759eae4fbf2f2420d3b8cab2 @Override public boolean isRemoved() { return true; -@@ -223,12 +230,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -230,11 +237,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @Override public void markUnsaved() { -- boolean flag = this.isUnsaved(); -- +- boolean isUnsaved = this.isUnsaved(); - super.markUnsaved(); -- if (!flag) { +- if (!isUnsaved) { - this.unsavedListener.setUnsaved(this.chunkPos); - } -+ super.markUnsaved(); // Folia - region threading - unsavedListener is not really used - ++ super.markUnsaved(); // Folia - region threading - unsavedListener is not really use } -@@ -380,6 +382,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + @Override +@@ -360,6 +363,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @Nullable - public BlockState setBlockState(BlockPos blockposition, BlockState iblockdata, boolean flag, boolean doPlace) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, blockposition, "Updating block asynchronously"); // Folia - region threading + public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving, boolean doPlace) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, pos, "Updating block asynchronously"); // Folia - region threading // CraftBukkit end - int i = blockposition.getY(); - LevelChunkSection chunksection = this.getSection(this.getSectionIndex(i)); -@@ -421,7 +424,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - - boolean flag3 = iblockdata1.hasBlockEntity(); + int y = pos.getY(); + LevelChunkSection section = this.getSection(this.getSectionIndex(y)); +@@ -395,7 +399,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + } + boolean hasBlockEntity = blockState.hasBlockEntity(); - if (!this.level.isClientSide && !this.level.isBlockPlaceCancelled) { // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent + if (!this.level.isClientSide && !this.level.getCurrentWorldData().isBlockPlaceCancelled) { // Paper - prevent calling cleanup logic when undoing a block place upon a cancelled BlockPlaceEvent // Folia - region threading - iblockdata1.onRemove(this.level, blockposition, iblockdata, flag); - } else if (!iblockdata1.is(block) && flag3) { - this.removeBlockEntity(blockposition); -@@ -431,7 +434,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + blockState.onRemove(this.level, pos, state, isMoving); + } else if (!blockState.is(block) && hasBlockEntity) { + this.removeBlockEntity(pos); +@@ -404,7 +408,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + if (!section.getBlockState(i, i1, i2).is(block)) { return null; } else { - // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. -- if (!this.level.isClientSide && doPlace && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { -+ if (!this.level.isClientSide && doPlace && (!this.level.getCurrentWorldData().captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // Folia - region threading - iblockdata.onPlace(this.level, blockposition, iblockdata1, flag); +- if (!this.level.isClientSide && doPlace && (!this.level.captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. ++ if (!this.level.isClientSide && doPlace && (!this.level.getCurrentWorldData().captureBlockStates || block instanceof net.minecraft.world.level.block.BaseEntityBlock)) { // CraftBukkit - Don't place while processing the BlockPlaceEvent, unless it's a BlockContainer. Prevents blocks such as TNT from activating when cancelled. // Folia - region threading + state.onPlace(this.level, pos, blockState, isMoving); } -@@ -483,7 +486,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -459,7 +463,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @Nullable public BlockEntity getBlockEntity(BlockPos pos, LevelChunk.EntityCreationType creationType) { // CraftBukkit start -- BlockEntity tileentity = this.level.capturedTileEntities.get(pos); -+ BlockEntity tileentity = this.level.getCurrentWorldData().capturedTileEntities.get(pos); // Folia - region threading - if (tileentity == null) { - tileentity = (BlockEntity) this.blockEntities.get(pos); +- BlockEntity blockEntity = this.level.capturedTileEntities.get(pos); ++ BlockEntity blockEntity = this.level.getCurrentWorldData().capturedTileEntities.get(pos); // Folia - region threading + if (blockEntity == null) { + blockEntity = this.blockEntities.get(pos); } -@@ -705,13 +708,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -646,13 +650,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p org.bukkit.World world = this.level.getWorld(); if (world != null) { @@ -19098,7 +18720,7 @@ index 97937e3bd211997f0a0a3e9e671a1c59712d0003..2c421ddb759eae4fbf2f2420d3b8cab2 } } server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(bukkitChunk)); -@@ -737,7 +740,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p +@@ -678,7 +682,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @Override public boolean isUnsaved() { // Paper start - rewrite chunk system @@ -19107,22 +18729,8 @@ index 97937e3bd211997f0a0a3e9e671a1c59712d0003..2c421ddb759eae4fbf2f2420d3b8cab2 if (((ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks)this.blockTicks).moonrise$isDirty(gameTime) || ((ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks)this.fluidTicks).moonrise$isDirty(gameTime)) { return true; -@@ -1020,6 +1023,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - this.ticker = wrapped; - } - -+ // Folia start - region threading -+ @Override -+ public BlockEntity getTileEntity() { -+ return this.ticker == null ? null : this.ticker.getTileEntity(); -+ } -+ // Folia end - region threading -+ - @Override - public void tick() { - this.ticker.tick(); -@@ -1056,6 +1066,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - this.ticker = blockentityticker; +@@ -905,6 +909,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + this.ticker = ticker; } + // Folia start - region threading @@ -19135,197 +18743,214 @@ index 97937e3bd211997f0a0a3e9e671a1c59712d0003..2c421ddb759eae4fbf2f2420d3b8cab2 @Override public void tick() { if (!this.blockEntity.isRemoved() && this.blockEntity.hasLevel()) { -diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -index 018b24d7611c3fd11536441431abf8f125850129..ceea49a2b04d0493cfa8ad6629116e0c1a9c97b3 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -+++ b/src/main/java/net/minecraft/world/level/chunk/storage/SerializableChunkData.java -@@ -562,7 +562,7 @@ public record SerializableChunkData(Registry biomeRegistry, ChunkPos chun +@@ -983,6 +994,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + this.ticker = ticker; + } + ++ // Folia start - region threading ++ @Override ++ public BlockEntity getTileEntity() { ++ return this.ticker == null ? null : this.ticker.getTileEntity(); ++ } ++ // Folia end - region threading ++ + @Override + public void tick() { + this.ticker.tick(); +diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +index 6b6aaeca14178b5b709e20ae13552d42217f15c0..950977f8d123f903630541ded35dd86a1889240f 100644 +--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java ++++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java +@@ -574,7 +574,7 @@ public record SerializableChunkData( } } -- ChunkAccess.PackedTicks ichunkaccess_a = chunk.getTicksForSerialization(world.getGameTime()); -+ ChunkAccess.PackedTicks ichunkaccess_a = chunk.getTicksForSerialization(world.getRedstoneGameTime()); // Folia - region threading - ShortList[] ashortlist = (ShortList[]) Arrays.stream(chunk.getPostProcessing()).map((shortlist) -> { - return shortlist != null ? new ShortArrayList(shortlist) : null; - }).toArray((k) -> { -diff --git a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -index b331c93c82c27f9456fec208a0c008c5bedfa8c4..e5513271a24711f46e9107cbe526d533afa54ca5 100644 ---- a/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java -+++ b/src/main/java/net/minecraft/world/level/dimension/end/EndDragonFight.java +- ChunkAccess.PackedTicks ticksForSerialization = chunk.getTicksForSerialization(level.getGameTime()); ++ ChunkAccess.PackedTicks ticksForSerialization = chunk.getTicksForSerialization(level.getRedstoneGameTime()); // Folia - region threading + ShortList[] lists = Arrays.stream(chunk.getPostProcessing()) + .map(list3 -> list3 != null ? new ShortArrayList(list3) : null) + .toArray(ShortList[]::new); +diff --git a/net/minecraft/world/level/dimension/end/EndDragonFight.java b/net/minecraft/world/level/dimension/end/EndDragonFight.java +index 6e7e87c32734b3aae354bc34459e5f207da5c78f..2e156694b337760be986fdf1cbf863b0d896ef2d 100644 +--- a/net/minecraft/world/level/dimension/end/EndDragonFight.java ++++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java @@ -77,7 +77,7 @@ public class EndDragonFight { - private static final Component DEFAULT_BOSS_EVENT_NAME = Component.translatable("entity.minecraft.ender_dragon"); // Paper - ensure reset EnderDragon boss event name - public final ServerBossEvent dragonEvent; + .setPlayBossMusic(true) + .setCreateWorldFog(true); public final ServerLevel level; - private final BlockPos origin; + public final BlockPos origin; // Folia - region threading - public final ObjectArrayList gateways; + public final ObjectArrayList gateways = new ObjectArrayList<>(); private final BlockPattern exitPortalPattern; private int ticksSinceDragonSeen; -@@ -155,7 +155,7 @@ public class EndDragonFight { +@@ -162,7 +162,7 @@ public class EndDragonFight { if (!this.dragonEvent.getPlayers().isEmpty()) { this.level.getChunkSource().addRegionTicket(TicketType.DRAGON, new ChunkPos(0, 0), 9, Unit.INSTANCE); -- boolean flag = this.isArenaLoaded(); -+ boolean flag = this.isArenaLoaded(); if (!flag) { return; } // Folia - region threading - don't tick if we don't own the entire region - - if (this.needsStateScanning && flag) { +- boolean isArenaLoaded = this.isArenaLoaded(); ++ boolean isArenaLoaded = this.isArenaLoaded(); if (!isArenaLoaded) { return; } // Folia - region threading - don't tick if we don't own the entire region + if (this.needsStateScanning && isArenaLoaded) { this.scanState(); -@@ -204,6 +204,12 @@ public class EndDragonFight { + this.needsStateScanning = false; +@@ -208,6 +208,12 @@ public class EndDragonFight { } - List list = this.level.getDragons(); + List dragons = this.level.getDragons(); + // Folia start - region threading + // we do not want to deal with any dragons NOT nearby -+ list.removeIf((dragon) -> { ++ dragons.removeIf((EnderDragon dragon) -> { + return !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(dragon); + }); + // Folia end - region threading - - if (list.isEmpty()) { + if (dragons.isEmpty()) { this.dragonKilled = true; -@@ -350,9 +356,8 @@ public class EndDragonFight { + } else { +@@ -323,8 +329,8 @@ public class EndDragonFight { - for (int i = -8 + chunkcoordintpair.x; i <= 8 + chunkcoordintpair.x; ++i) { - for (int j = 8 + chunkcoordintpair.z; j <= 8 + chunkcoordintpair.z; ++j) { -- ChunkAccess ichunkaccess = this.level.getChunk(i, j, ChunkStatus.FULL, false); -- -- if (!(ichunkaccess instanceof LevelChunk)) { -+ ChunkAccess ichunkaccess = this.level.getChunkIfLoaded(i, j); // Folia - region threading -+ if (!(ichunkaccess instanceof LevelChunk) || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, i, j, this.level.regioniser.regionSectionChunkSize)) { // Folia - region threading + for (int i = -8 + chunkPos.x; i <= 8 + chunkPos.x; i++) { + for (int i1 = 8 + chunkPos.z; i1 <= 8 + chunkPos.z; i1++) { +- ChunkAccess chunk = this.level.getChunk(i, i1, ChunkStatus.FULL, false); +- if (!(chunk instanceof LevelChunk)) { ++ ChunkAccess chunk = this.level.getChunkIfLoaded(i, i1); // Folia - region threading ++ if (!(chunk instanceof LevelChunk) || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, i, i1, this.level.regioniser.regionSectionChunkSize)) { return false; } -@@ -539,6 +544,11 @@ public class EndDragonFight { +@@ -496,6 +502,11 @@ public class EndDragonFight { } - public void onCrystalDestroyed(EndCrystal enderCrystal, DamageSource source) { + public void onCrystalDestroyed(EndCrystal crystal, DamageSource dmgSrc) { + // Folia start - region threading + if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.origin)) { + return; + } + // Folia end - region threading - if (this.respawnStage != null && this.respawnCrystals.contains(enderCrystal)) { - EndDragonFight.LOGGER.debug("Aborting respawn sequence"); + if (this.respawnStage != null && this.respawnCrystals.contains(crystal)) { + LOGGER.debug("Aborting respawn sequence"); this.respawnStage = null; -@@ -569,7 +579,7 @@ public class EndDragonFight { +@@ -521,7 +532,7 @@ public class EndDragonFight { public boolean tryRespawn(@Nullable BlockPos placedEndCrystalPos) { // placedEndCrystalPos is null if the tryRespawn() call was not caused by a placed end crystal // Paper end - Perf: Do crystal-portal proximity check before entity lookup - if (this.dragonKilled && this.respawnStage == null) { + if (this.dragonKilled && this.respawnStage == null && ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.level, this.origin)) { // Folia - region threading - BlockPos blockposition = this.portalLocation; - - if (blockposition == null) { -diff --git a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java -index e93ef232b0426a1095dad05fc4acb2a74db5b689..6e0fafa0c8f8e91d10ec0cb71742d137e5522155 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/PatrolSpawner.java -@@ -18,7 +18,7 @@ import net.minecraft.world.level.block.state.BlockState; + BlockPos blockPos = this.portalLocation; + if (blockPos == null) { + LOGGER.debug("Tried to respawn, but need to find the portal first."); +diff --git a/net/minecraft/world/level/levelgen/PatrolSpawner.java b/net/minecraft/world/level/levelgen/PatrolSpawner.java +index 082c9b340765e3e98055a3c4444af68264a54826..9608e06c56f0aded4d6b4e9cf3d7eec348945600 100644 +--- a/net/minecraft/world/level/levelgen/PatrolSpawner.java ++++ b/net/minecraft/world/level/levelgen/PatrolSpawner.java +@@ -16,7 +16,7 @@ import net.minecraft.world.level.biome.Biome; + import net.minecraft.world.level.block.state.BlockState; public class PatrolSpawner implements CustomSpawner { - - private int nextTick; + //private int nextTick; // Folia - region threading - public PatrolSpawner() {} - -@@ -31,15 +31,16 @@ public class PatrolSpawner implements CustomSpawner { + @Override + public int tick(ServerLevel level, boolean spawnEnemies, boolean spawnFriendlies) { +@@ -27,6 +27,7 @@ public class PatrolSpawner implements CustomSpawner { return 0; } else { - RandomSource randomsource = world.random; -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading - + RandomSource randomSource = level.random; ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading + // this.nextTick--; + // if (this.nextTick > 0) { + // return 0; +@@ -38,12 +39,12 @@ public class PatrolSpawner implements CustomSpawner { + // } else if (randomSource.nextInt(5) != 0) { // Paper start - Pillager patrol spawn settings and per player options // Random player selection moved up for per player spawning and configuration -- int j = world.players().size(); -+ int j = world.getLocalPlayers().size(); // Folia - region threading - if (j < 1) { +- int size = level.players().size(); ++ int size = level.getLocalPlayers().size(); + if (size < 1) { return 0; } -- net.minecraft.server.level.ServerPlayer entityhuman = world.players().get(randomsource.nextInt(j)); -+ net.minecraft.server.level.ServerPlayer entityhuman = world.getLocalPlayers().get(randomsource.nextInt(j)); // Folia - region threading - if (entityhuman.isSpectator()) { +- net.minecraft.server.level.ServerPlayer player = level.players().get(randomSource.nextInt(size)); ++ net.minecraft.server.level.ServerPlayer player = level.getLocalPlayers().get(randomSource.nextInt(size)); // Folia - region threading + if (player.isSpectator()) { return 0; } -@@ -49,8 +50,8 @@ public class PatrolSpawner implements CustomSpawner { - --entityhuman.patrolSpawnDelay; - patrolSpawnDelay = entityhuman.patrolSpawnDelay; +@@ -53,8 +54,8 @@ public class PatrolSpawner implements CustomSpawner { + --player.patrolSpawnDelay; + patrolSpawnDelay = player.patrolSpawnDelay; } else { - this.nextTick--; - patrolSpawnDelay = this.nextTick; + worldData.patrolSpawnerNextTick--; // Folia - region threading + patrolSpawnDelay = worldData.patrolSpawnerNextTick; // Folia - region threading } - if (patrolSpawnDelay > 0) { -@@ -65,7 +66,7 @@ public class PatrolSpawner implements CustomSpawner { - if (world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { - entityhuman.patrolSpawnDelay += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); + return 0; +@@ -68,7 +69,7 @@ public class PatrolSpawner implements CustomSpawner { + if (level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.perPlayer) { + player.patrolSpawnDelay += level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomSource.nextInt(1200); } else { -- this.nextTick += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); -+ worldData.patrolSpawnerNextTick += world.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomsource.nextInt(1200); // Folia - region threading +- this.nextTick += level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomSource.nextInt(1200); ++ worldData.patrolSpawnerNextTick += level.paperConfig().entities.behavior.pillagerPatrols.spawnDelay.ticks + randomSource.nextInt(1200); // Folia - region threading } - if (days >= world.paperConfig().entities.behavior.pillagerPatrols.start.day && world.isDay()) { -diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -index 021221da5d0315f6e371380a705ac6b3f6ac18d3..ee9a0e0ce075e932a687d77594c687384ac19fb1 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -@@ -21,7 +21,7 @@ import net.minecraft.world.level.material.FluidState; + if (days < level.paperConfig().entities.behavior.pillagerPatrols.start.day || !level.isDay()) { +diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java +index 11d25e64349b27bf54dc1620e4cce444c79f581c..cef0474cf5f95bff717d49e58fe0a74ce6b7b345 100644 +--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java ++++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java +@@ -19,7 +19,7 @@ import net.minecraft.world.level.block.state.BlockState; + import net.minecraft.world.level.material.FluidState; public class PhantomSpawner implements CustomSpawner { - - private int nextTick; + //private int nextTick; // Folia - region threading - public PhantomSpawner() {} - -@@ -39,20 +39,22 @@ public class PhantomSpawner implements CustomSpawner { + @Override + public int tick(ServerLevel level, boolean spawnEnemies, boolean spawnFriendlies) { +@@ -34,21 +34,22 @@ public class PhantomSpawner implements CustomSpawner { + } // Paper end - Ability to control player's insomnia and phantoms - RandomSource randomsource = world.random; - -- --this.nextTick; + RandomSource randomSource = level.random; +- this.nextTick--; - if (this.nextTick > 0) { -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading -+ -+ --worldData.phantomSpawnerNextTick; // Folia - region threading ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = level.getCurrentWorldData(); // Folia - region threading ++ worldData.phantomSpawnerNextTick--; // Folia - region threading + if (worldData.phantomSpawnerNextTick > 0) { // Folia - region threading return 0; } else { // Paper start - Ability to control player's insomnia and phantoms - int spawnAttemptMinSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMinSeconds; - int spawnAttemptMaxSeconds = world.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; -- this.nextTick += (spawnAttemptMinSeconds + randomsource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; -+ worldData.phantomSpawnerNextTick += (spawnAttemptMinSeconds + randomsource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; // Folia - region threading + int spawnAttemptMinSeconds = level.paperConfig().entities.behavior.phantomsSpawnAttemptMinSeconds; + int spawnAttemptMaxSeconds = level.paperConfig().entities.behavior.phantomsSpawnAttemptMaxSeconds; +- this.nextTick += (spawnAttemptMinSeconds + randomSource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; ++ worldData.phantomSpawnerNextTick += (spawnAttemptMinSeconds + randomSource.nextInt(spawnAttemptMaxSeconds - spawnAttemptMinSeconds + 1)) * 20; // Folia - region threading // Paper end - Ability to control player's insomnia and phantoms - if (world.getSkyDarken() < 5 && world.dimensionType().hasSkyLight()) { + if (level.getSkyDarken() < 5 && level.dimensionType().hasSkyLight()) { return 0; } else { int i = 0; -- Iterator iterator = world.players().iterator(); -+ Iterator iterator = world.getLocalPlayers().iterator(); // Folia - region threading - while (iterator.hasNext()) { - ServerPlayer entityplayer = (ServerPlayer) iterator.next(); -diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java -index ff1f151b342a1567605f92a921fc7ab01f1c4807..27f428fc52cd371983c4f06329d22961ed32a15c 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java -@@ -55,7 +55,7 @@ public class EndPlatformFeature extends Feature { - } +- for (ServerPlayer serverPlayer : level.players()) { ++ for (ServerPlayer serverPlayer : level.getLocalPlayers()) { // Folia - region threading + if (!serverPlayer.isSpectator() && (!level.paperConfig().entities.behavior.phantomsDoNotSpawnOnCreativePlayers || !serverPlayer.isCreative())) { // Paper - Add phantom creative and insomniac controls + BlockPos blockPos = serverPlayer.blockPosition(); + if (!level.dimensionType().hasSkyLight() || blockPos.getY() >= level.getSeaLevel() && level.canSeeSky(blockPos)) { +diff --git a/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java b/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java +index 1f7005b01b56929fb694b69b37143b8d8c7b2898..f96fc1391167dea48cac1caa464b9026657df89a 100644 +--- a/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java ++++ b/net/minecraft/world/level/levelgen/feature/EndPlatformFeature.java +@@ -47,7 +47,7 @@ public class EndPlatformFeature extends Feature { + // CraftBukkit start // SPIGOT-7746: Entity will only be null during world generation, which is async, so just generate without event - if (entity != null) { + if (false) { // Folia - region threading - org.bukkit.World bworld = worldaccess.getLevel().getWorld(); - PortalCreateEvent portalEvent = new PortalCreateEvent((List) (List) blockList.getList(), bworld, entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.END_PLATFORM); - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureStart.java b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureStart.java -index d871d760581df082c47365ef246681faafb1f6a0..08e0fec629a74551a0a25990fea7ee9380a1021d 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/structure/StructureStart.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/StructureStart.java -@@ -28,7 +28,7 @@ public final class StructureStart { + org.bukkit.World bworld = level.getLevel().getWorld(); + org.bukkit.event.world.PortalCreateEvent portalEvent = new org.bukkit.event.world.PortalCreateEvent((java.util.List) (java.util.List) blockList.getList(), bworld, entity.getBukkitEntity(), org.bukkit.event.world.PortalCreateEvent.CreateReason.END_PLATFORM); + level.getLevel().getCraftServer().getPluginManager().callEvent(portalEvent); +diff --git a/net/minecraft/world/level/levelgen/structure/StructureStart.java b/net/minecraft/world/level/levelgen/structure/StructureStart.java +index 4dafa79dd4ec55a443ba3731a79e7cd6e8052f48..743b13693c8ef1d69751de42e9c6dadefe56395c 100644 +--- a/net/minecraft/world/level/levelgen/structure/StructureStart.java ++++ b/net/minecraft/world/level/levelgen/structure/StructureStart.java +@@ -26,7 +26,7 @@ public final class StructureStart { private final Structure structure; private final PiecesContainer pieceContainer; private final ChunkPos chunkPos; @@ -19334,25 +18959,25 @@ index d871d760581df082c47365ef246681faafb1f6a0..08e0fec629a74551a0a25990fea7ee93 @Nullable private volatile BoundingBox cachedBoundingBox; -@@ -41,7 +41,7 @@ public final class StructureStart { - public StructureStart(Structure structure, ChunkPos pos, int references, PiecesContainer children) { +@@ -39,7 +39,7 @@ public final class StructureStart { + public StructureStart(Structure structure, ChunkPos chunkPos, int references, PiecesContainer pieceContainer) { this.structure = structure; - this.chunkPos = pos; + this.chunkPos = chunkPos; - this.references = references; + this.references = new java.util.concurrent.atomic.AtomicInteger(references); // Folia - region threading - this.pieceContainer = children; + this.pieceContainer = pieceContainer; } -@@ -137,7 +137,7 @@ public final class StructureStart { - nbttagcompound.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString()); - nbttagcompound.putInt("ChunkX", chunkPos.x); - nbttagcompound.putInt("ChunkZ", chunkPos.z); -- nbttagcompound.putInt("references", this.references); -+ nbttagcompound.putInt("references", this.references.get()); // Folia - region threading - nbttagcompound.put("Children", this.pieceContainer.save(context)); - return nbttagcompound; +@@ -126,7 +126,7 @@ public final class StructureStart { + compoundTag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString()); + compoundTag.putInt("ChunkX", chunkPos.x); + compoundTag.putInt("ChunkZ", chunkPos.z); +- compoundTag.putInt("references", this.references); ++ compoundTag.putInt("references", this.references.get()); // Folia - region threading + compoundTag.put("Children", this.pieceContainer.save(context)); + return compoundTag; } else { -@@ -155,15 +155,29 @@ public final class StructureStart { +@@ -144,15 +144,29 @@ public final class StructureStart { } public boolean canBeReferenced() { @@ -19375,7 +19000,7 @@ index d871d760581df082c47365ef246681faafb1f6a0..08e0fec629a74551a0a25990fea7ee93 + // Folia end - region threading + public void addReference() { -- ++this.references; +- this.references++; + throw new UnsupportedOperationException("Use tryReference()"); // Folia - region threading } @@ -19385,22 +19010,22 @@ index d871d760581df082c47365ef246681faafb1f6a0..08e0fec629a74551a0a25990fea7ee93 } protected int getMaxReferences() { -diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -index 3a95e3236eafd14baed035e53503b58c2e21b68a..63b12dcb1b86e15607ebbaa157d7a330c089862d 100644 ---- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -+++ b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java -@@ -49,6 +49,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { +diff --git a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +index 028eae2f9a459b60e92f3344091083aa93b54485..e7ea9df8f404a6176435204a91edeefab8070c89 100644 +--- a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java ++++ b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +@@ -47,6 +47,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { } - private void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates entry) { + private void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates updates) { + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((net.minecraft.server.level.ServerLevel)this.level, pos, "Adding block without owning region"); // Folia - region threading - boolean bl = this.count > 0; - boolean bl2 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates; + boolean flag = this.count > 0; + boolean flag1 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates; this.count++; -diff --git a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java -index d114c62c4b0157e14fbdedebf675a53c401710ad..20da1447e036055d4c2748cc90eef15b4880e6b3 100644 ---- a/src/main/java/net/minecraft/world/level/saveddata/SavedData.java -+++ b/src/main/java/net/minecraft/world/level/saveddata/SavedData.java +diff --git a/net/minecraft/world/level/saveddata/SavedData.java b/net/minecraft/world/level/saveddata/SavedData.java +index b681a5ca1c4215d5afcc988c169e22a84996a88d..3879127f6c4a7977176bcea7ccc21561210addc6 100644 +--- a/net/minecraft/world/level/saveddata/SavedData.java ++++ b/net/minecraft/world/level/saveddata/SavedData.java @@ -8,7 +8,7 @@ import net.minecraft.nbt.NbtUtils; import net.minecraft.util.datafix.DataFixTypes; @@ -19408,7 +19033,7 @@ index d114c62c4b0157e14fbdedebf675a53c401710ad..20da1447e036055d4c2748cc90eef15b - private boolean dirty; + private volatile boolean dirty; // Folia - make map data thread-safe - public abstract CompoundTag save(CompoundTag nbt, HolderLookup.Provider registries); + public abstract CompoundTag save(CompoundTag tag, HolderLookup.Provider registries); @@ -26,9 +26,10 @@ public abstract class SavedData { @@ -19422,21 +19047,21 @@ index d114c62c4b0157e14fbdedebf675a53c401710ad..20da1447e036055d4c2748cc90eef15b return compoundTag; } -diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java -index 84f4664950e0cef7bd823bfc74f37cefce620d9e..8fb853d69691d7254abe6894a77270e844e3d9b8 100644 ---- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java -+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapIndex.java +diff --git a/net/minecraft/world/level/saveddata/maps/MapIndex.java b/net/minecraft/world/level/saveddata/maps/MapIndex.java +index ffe604f8397a002800e6ecc2f878d0f6f1c98703..7ee324c32efe1e63d310120e468a2f0d8ca262b4 100644 +--- a/net/minecraft/world/level/saveddata/maps/MapIndex.java ++++ b/net/minecraft/world/level/saveddata/maps/MapIndex.java @@ -34,17 +34,21 @@ public class MapIndex extends SavedData { @Override - public CompoundTag save(CompoundTag nbt, HolderLookup.Provider registries) { + public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) { + synchronized (this.usedAuxIds) { // Folia - make map data thread-safe for (Entry entry : this.usedAuxIds.object2IntEntrySet()) { - nbt.putInt(entry.getKey(), entry.getIntValue()); + tag.putInt(entry.getKey(), entry.getIntValue()); } + } // Folia - make map data thread-safe - return nbt; + return tag; } public MapId getFreeAuxValueForMap() { @@ -19448,139 +19073,134 @@ index 84f4664950e0cef7bd823bfc74f37cefce620d9e..8fb853d69691d7254abe6894a77270e8 + } // Folia - make map data thread-safe } } -diff --git a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -index ae321b3b8d98e42ef07fd1f0f738c1a2b428f6db..ed258986f2bdec9f78aa41d7dc49a5ec14094c57 100644 ---- a/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -+++ b/src/main/java/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java -@@ -212,7 +212,7 @@ public class MapItemSavedData extends SavedData { +diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +index f5a131e870a4f1ad06ebfb1f360720cf19656fb5..cf827e018eec4910b8319cee7202d480fee573f6 100644 +--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java ++++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +@@ -201,7 +201,7 @@ public class MapItemSavedData extends SavedData { } @Override -- public CompoundTag save(CompoundTag nbt, HolderLookup.Provider registries) { -+ public synchronized CompoundTag save(CompoundTag nbt, HolderLookup.Provider registries) { // Folia - make map data thread-safe - DataResult dataresult = ResourceLocation.CODEC.encodeStart(NbtOps.INSTANCE, this.dimension.location()); // CraftBukkit - decompile error - Logger logger = MapItemSavedData.LOGGER; - -@@ -262,7 +262,7 @@ public class MapItemSavedData extends SavedData { - return nbt; +- public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) { ++ public synchronized CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) { // Folia - make map data thread-safe + ResourceLocation.CODEC + .encodeStart(NbtOps.INSTANCE, this.dimension.location()) + .resultOrPartial(LOGGER::error) +@@ -244,7 +244,7 @@ public class MapItemSavedData extends SavedData { + return tag; } - public MapItemSavedData locked() { + public synchronized MapItemSavedData locked() { // Folia - make map data thread-safe - MapItemSavedData worldmap = new MapItemSavedData(this.centerX, this.centerZ, this.scale, this.trackingPosition, this.unlimitedTracking, true, this.dimension); - - worldmap.bannerMarkers.putAll(this.bannerMarkers); -@@ -272,7 +272,7 @@ public class MapItemSavedData extends SavedData { - return worldmap; + MapItemSavedData mapItemSavedData = new MapItemSavedData( + this.centerX, this.centerZ, this.scale, this.trackingPosition, this.unlimitedTracking, true, this.dimension + ); +@@ -255,7 +255,7 @@ public class MapItemSavedData extends SavedData { + return mapItemSavedData; } - public MapItemSavedData scaled() { + public synchronized MapItemSavedData scaled() { // Folia - make map data thread-safe - return MapItemSavedData.createFresh((double) this.centerX, (double) this.centerZ, (byte) Mth.clamp(this.scale + 1, 0, 4), this.trackingPosition, this.unlimitedTracking, this.dimension); + return createFresh(this.centerX, this.centerZ, (byte)Mth.clamp(this.scale + 1, 0, 4), this.trackingPosition, this.unlimitedTracking, this.dimension); } -@@ -284,7 +284,8 @@ public class MapItemSavedData extends SavedData { - }; +@@ -264,7 +264,8 @@ public class MapItemSavedData extends SavedData { + return itemStack -> itemStack == stack || itemStack.is(stack.getItem()) && Objects.equals(mapId, itemStack.get(DataComponents.MAP_ID)); } -- public void tickCarriedBy(Player player, ItemStack stack) { -+ public synchronized void tickCarriedBy(Player player, ItemStack stack) { // Folia - make map data thread-safe +- public void tickCarriedBy(Player player, ItemStack mapStack) { ++ public synchronized void tickCarriedBy(Player player, ItemStack mapStack) { // Folia - make map data thread-safe + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(player, "Ticking map player in incorrect region"); // Folia - region threading if (!this.carriedByPlayers.containsKey(player)) { - MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = new MapItemSavedData.HoldingPlayer(player); + MapItemSavedData.HoldingPlayer holdingPlayer = new MapItemSavedData.HoldingPlayer(player); + this.carriedByPlayers.put(player, holdingPlayer); +@@ -413,7 +414,7 @@ public class MapItemSavedData extends SavedData { -@@ -439,7 +440,7 @@ public class MapItemSavedData extends SavedData { - - private byte calculateRotation(@Nullable LevelAccessor world, double rotation) { - if (this.dimension == Level.NETHER && world != null) { -- int i = (int) (world.getLevelData().getDayTime() / 10L); -+ int i = (int) (world.dayTime() / 10L); // Folia - region threading - - return (byte) (i * i * 34187121 + i * 121 >> 15 & 15); + private byte calculateRotation(@Nullable LevelAccessor level, double yRot) { + if (this.dimension == Level.NETHER && level != null) { +- int i = (int)(level.getLevelData().getDayTime() / 10L); ++ int i = (int)(level.dayTime() / 10L); // Folia - region threading + return (byte)(i * i * 34187121 + i * 121 >> 15 & 15); } else { -@@ -470,14 +471,14 @@ public class MapItemSavedData extends SavedData { + double d = yRot < 0.0 ? yRot - 8.0 : yRot + 8.0; +@@ -447,25 +448,27 @@ public class MapItemSavedData extends SavedData { } @Nullable - public Packet getUpdatePacket(MapId mapId, Player player) { + public synchronized Packet getUpdatePacket(MapId mapId, Player player) { // Folia - make map data thread-safe - MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player); - - return worldmap_worldmaphumantracker == null ? null : worldmap_worldmaphumantracker.nextUpdatePacket(mapId); + MapItemSavedData.HoldingPlayer holdingPlayer = this.carriedByPlayers.get(player); + return holdingPlayer == null ? null : holdingPlayer.nextUpdatePacket(mapId); } - public void setColorsDirty(int x, int z) { - this.setDirty(); + public synchronized void setColorsDirty(int x, int z) { // Folia - make map data thread-safe -+ // Folia - make dirty only after updating data - moved down - Iterator iterator = this.carriedBy.iterator(); ++ //this.setDirty(); // Folia - make dirty only after updating data - moved down - while (iterator.hasNext()) { -@@ -485,15 +486,16 @@ public class MapItemSavedData extends SavedData { - - worldmap_worldmaphumantracker.markColorsDirty(x, z); + for (MapItemSavedData.HoldingPlayer holdingPlayer : this.carriedBy) { + holdingPlayer.markColorsDirty(x, z); } -- + this.setDirty(); // Folia - make dirty only after updating data - moved from above } - public void setDecorationsDirty() { - this.setDirty(); + public synchronized void setDecorationsDirty() { // Folia - make map data thread-safe -+ // Folia - make dirty only after updating data - moved down ++ //this.setDirty(); // Folia - make dirty only after updating data - moved down this.carriedBy.forEach(MapItemSavedData.HoldingPlayer::markDecorationsDirty); + this.setDirty(); // Folia - make dirty only after updating data - moved from above } - public MapItemSavedData.HoldingPlayer getHoldingPlayer(Player player) { + public synchronized MapItemSavedData.HoldingPlayer getHoldingPlayer(Player player) { // Folia - make map data thread-safe - MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = (MapItemSavedData.HoldingPlayer) this.carriedByPlayers.get(player); - - if (worldmap_worldmaphumantracker == null) { -@@ -505,7 +507,7 @@ public class MapItemSavedData extends SavedData { - return worldmap_worldmaphumantracker; + MapItemSavedData.HoldingPlayer holdingPlayer = this.carriedByPlayers.get(player); + if (holdingPlayer == null) { + holdingPlayer = new MapItemSavedData.HoldingPlayer(player); +@@ -476,7 +479,7 @@ public class MapItemSavedData extends SavedData { + return holdingPlayer; } -- public boolean toggleBanner(LevelAccessor world, BlockPos pos) { -+ public synchronized boolean toggleBanner(LevelAccessor world, BlockPos pos) { // Folia - make map data thread-safe - double d0 = (double) pos.getX() + 0.5D; - double d1 = (double) pos.getZ() + 0.5D; +- public boolean toggleBanner(LevelAccessor accessor, BlockPos pos) { ++ public synchronized boolean toggleBanner(LevelAccessor accessor, BlockPos pos) { // Folia - make map data thread-safe + double d = pos.getX() + 0.5; + double d1 = pos.getZ() + 0.5; int i = 1 << this.scale; -@@ -514,7 +516,7 @@ public class MapItemSavedData extends SavedData { - boolean flag = true; - - if (d2 >= -63.0D && d3 >= -63.0D && d2 <= 63.0D && d3 <= 63.0D) { -- MapBanner mapiconbanner = MapBanner.fromWorld(world, pos); -+ MapBanner mapiconbanner = world.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(world.getMinecraftWorld(), pos) ? null : MapBanner.fromWorld(world, pos); // Folia - make map data thread-safe - don't sync load or read data we do not own - - if (mapiconbanner == null) { +@@ -484,7 +487,7 @@ public class MapItemSavedData extends SavedData { + double d3 = (d1 - this.centerZ) / i; + int i1 = 63; + if (d2 >= -63.0 && d3 >= -63.0 && d2 <= 63.0 && d3 <= 63.0) { +- MapBanner mapBanner = MapBanner.fromWorld(accessor, pos); ++ MapBanner mapBanner = accessor.getChunkIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4) == null || !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(accessor.getMinecraftWorld(), pos) ? null : MapBanner.fromWorld(accessor, pos); // Folia - make map data thread-safe - don't sync load or read data we do not own + if (mapBanner == null) { return false; -@@ -535,7 +537,7 @@ public class MapItemSavedData extends SavedData { + } +@@ -504,7 +507,7 @@ public class MapItemSavedData extends SavedData { return false; } -- public void checkBanners(BlockGetter world, int x, int z) { -+ public synchronized void checkBanners(BlockGetter world, int x, int z) { // Folia - make map data thread-safe +- public void checkBanners(BlockGetter reader, int x, int z) { ++ public synchronized void checkBanners(BlockGetter reader, int x, int z) { // Folia - make map data thread-safe Iterator iterator = this.bannerMarkers.values().iterator(); while (iterator.hasNext()) { -@@ -557,13 +559,13 @@ public class MapItemSavedData extends SavedData { +@@ -523,13 +526,13 @@ public class MapItemSavedData extends SavedData { return this.bannerMarkers.values(); } -- public void removedFromFrame(BlockPos pos, int id) { -+ public synchronized void removedFromFrame(BlockPos pos, int id) { // Folia - make map data thread-safe - this.removeDecoration(MapItemSavedData.getFrameKey(id)); +- public void removedFromFrame(BlockPos pos, int entityId) { ++ public synchronized void removedFromFrame(BlockPos pos, int entityId) { // Folia - make map data thread-safe + this.removeDecoration(getFrameKey(entityId)); this.frameMarkers.remove(MapFrame.frameId(pos)); this.setDirty(); } - public boolean updateColor(int x, int z, byte color) { + public synchronized boolean updateColor(int x, int z, byte color) { // Folia - make map data thread-safe - byte b1 = this.colors[x + z * 128]; - - if (b1 != color) { -@@ -574,12 +576,12 @@ public class MapItemSavedData extends SavedData { + byte b = this.colors[x + z * 128]; + if (b != color) { + this.setColor(x, z, color); +@@ -539,12 +542,12 @@ public class MapItemSavedData extends SavedData { } } @@ -19592,11 +19212,11 @@ index ae321b3b8d98e42ef07fd1f0f738c1a2b428f6db..ed258986f2bdec9f78aa41d7dc49a5ec - public boolean isExplorationMap() { + public synchronized boolean isExplorationMap() { // Folia - make map data thread-safe - Iterator iterator = this.decorations.values().iterator(); - - MapDecoration mapicon; -@@ -595,7 +597,7 @@ public class MapItemSavedData extends SavedData { - return true; + for (MapDecoration mapDecoration : this.decorations.values()) { + if (mapDecoration.type().value().explorationMapElement()) { + return true; +@@ -554,7 +557,7 @@ public class MapItemSavedData extends SavedData { + return false; } - public void addClientSideDecorations(List decorations) { @@ -19604,54 +19224,54 @@ index ae321b3b8d98e42ef07fd1f0f738c1a2b428f6db..ed258986f2bdec9f78aa41d7dc49a5ec this.decorations.clear(); this.trackedDecorationCount = 0; -@@ -614,7 +616,7 @@ public class MapItemSavedData extends SavedData { +@@ -571,7 +574,7 @@ public class MapItemSavedData extends SavedData { return this.decorations.values(); } -- public boolean isTrackedCountOverLimit(int decorationCount) { -+ public synchronized boolean isTrackedCountOverLimit(int decorationCount) { // Folia - make map data thread-safe - return this.trackedDecorationCount >= decorationCount; +- public boolean isTrackedCountOverLimit(int trackedCount) { ++ public synchronized boolean isTrackedCountOverLimit(int trackedCount) { // Folia - make map data thread-safe + return this.trackedDecorationCount >= trackedCount; } -@@ -766,11 +768,13 @@ public class MapItemSavedData extends SavedData { +@@ -726,11 +729,13 @@ public class MapItemSavedData extends SavedData { } - public void applyToMap(MapItemSavedData mapState) { -+ synchronized (mapState) { // Folia - make map data thread-safe - for (int i = 0; i < this.width; ++i) { - for (int j = 0; j < this.height; ++j) { - mapState.setColor(this.startX + i, this.startY + j, this.mapColors[i + j * this.width]); + public void applyToMap(MapItemSavedData savedData) { ++ synchronized (savedData) { // Folia - make map data thread-safe + for (int i = 0; i < this.width; i++) { + for (int i1 = 0; i1 < this.height; i1++) { + savedData.setColor(this.startX + i, this.startY + i1, this.mapColors[i + i1 * this.width]); } } + } // Folia - make map data thread-safe - } } -diff --git a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java -index 9272c91e0ee489091fdf1fedcf3801c070e9e82a..188aac988659e8ee36d0990acb001868ba398a3c 100644 ---- a/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java -+++ b/src/main/java/net/minecraft/world/level/storage/DimensionDataStorage.java + } +diff --git a/net/minecraft/world/level/storage/DimensionDataStorage.java b/net/minecraft/world/level/storage/DimensionDataStorage.java +index d9a3b5a2e6495b7e22c114506c2bd1e406f58f8f..ab572ac18fd02306210c87eb9ba5e5d4197ff997 100644 +--- a/net/minecraft/world/level/storage/DimensionDataStorage.java ++++ b/net/minecraft/world/level/storage/DimensionDataStorage.java @@ -51,6 +51,7 @@ public class DimensionDataStorage implements AutoCloseable { } - public T computeIfAbsent(SavedData.Factory type, String id) { + public T computeIfAbsent(SavedData.Factory factory, String name) { + synchronized (this.cache) { // Folia - make map data thread-safe - T savedData = this.get(type, id); + T savedData = this.get(factory, name); if (savedData != null) { return savedData; @@ -59,10 +60,12 @@ public class DimensionDataStorage implements AutoCloseable { - this.set(id, savedData2); - return savedData2; + this.set(name, savedData1); + return savedData1; } + } // Folia - make map data thread-safe } @Nullable - public T get(SavedData.Factory type, String id) { + public T get(SavedData.Factory factory, String name) { + synchronized (this.cache) { // Folia - make map data thread-safe - Optional optional = this.cache.get(id); + Optional optional = this.cache.get(name); if (optional == null) { - optional = Optional.ofNullable(this.readSavedData(type.deserializer(), type.type(), id)); + optional = Optional.ofNullable(this.readSavedData(factory.deserializer(), factory.type(), name)); @@ -70,6 +73,7 @@ public class DimensionDataStorage implements AutoCloseable { } @@ -19663,18 +19283,18 @@ index 9272c91e0ee489091fdf1fedcf3801c070e9e82a..188aac988659e8ee36d0990acb001868 @@ -88,8 +92,10 @@ public class DimensionDataStorage implements AutoCloseable { } - public void set(String id, SavedData state) { + public void set(String name, SavedData savedData) { + synchronized (this.cache) { // Folia - make map data thread-safe - this.cache.put(id, Optional.of(state)); - state.setDirty(); + this.cache.put(name, Optional.of(savedData)); + savedData.setDirty(); + } // Folia - make map data thread-safe } - public CompoundTag readTagFromDisk(String id, DataFixTypes dataFixTypes, int currentSaveVersion) throws IOException { -diff --git a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java -index 3858c83c58e78435a6e29de84c33faa2f26d593d..4af07bd98b6bdb056b2e1138a9f9fc3dada725df 100644 ---- a/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java -+++ b/src/main/java/net/minecraft/world/ticks/LevelChunkTicks.java + public CompoundTag readTagFromDisk(String filename, DataFixTypes dataFixType, int version) throws IOException { +diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java +index faf45ac459f7c25309d6ef6dce371d484a0dae7b..8a98064f2e44b27947c1af9c80ae0d7a397db7e4 100644 +--- a/net/minecraft/world/ticks/LevelChunkTicks.java ++++ b/net/minecraft/world/ticks/LevelChunkTicks.java @@ -48,6 +48,21 @@ public class LevelChunkTicks implements SerializableTickContainer, TickCon this.dirty = false; } @@ -19697,22 +19317,22 @@ index 3858c83c58e78435a6e29de84c33faa2f26d593d..4af07bd98b6bdb056b2e1138a9f9fc3d public LevelChunkTicks() { } -diff --git a/src/main/java/net/minecraft/world/ticks/LevelTicks.java b/src/main/java/net/minecraft/world/ticks/LevelTicks.java -index 778e6476c86d823dc8efe603a95e589e8b2ea9d9..3fc6b4f93885fe447ed068bc5e0784daad655696 100644 ---- a/src/main/java/net/minecraft/world/ticks/LevelTicks.java -+++ b/src/main/java/net/minecraft/world/ticks/LevelTicks.java -@@ -38,12 +38,69 @@ public class LevelTicks implements LevelTickAccess { +diff --git a/net/minecraft/world/ticks/LevelTicks.java b/net/minecraft/world/ticks/LevelTicks.java +index 66abc2e7adee60fa98eed1ba36e018814fd02cad..2caedf1c12e5a388f7b14989310a2137bc1117c3 100644 +--- a/net/minecraft/world/ticks/LevelTicks.java ++++ b/net/minecraft/world/ticks/LevelTicks.java +@@ -39,12 +39,69 @@ public class LevelTicks implements LevelTickAccess { private final List> alreadyRunThisTick = new ArrayList<>(); private final Set> toRunThisTickSet = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH); - private final BiConsumer, ScheduledTick> chunkScheduleUpdater = (chunkTickScheduler, tick) -> { -- if (tick.equals(chunkTickScheduler.peek())) { -- this.updateContainerScheduling(tick); -+ if (tick.equals(chunkTickScheduler.peek())) { // Folia - diff on change -+ this.updateContainerScheduling(tick); // Folia - diff on change + private final BiConsumer, ScheduledTick> chunkScheduleUpdater = (levelChunkTicks, scheduledTick) -> { +- if (scheduledTick.equals(levelChunkTicks.peek())) { +- this.updateContainerScheduling(scheduledTick); ++ if (scheduledTick.equals(levelChunkTicks.peek())) { // Folia - diff on change ++ this.updateContainerScheduling(scheduledTick); // Folia - diff on change } }; -- public LevelTicks(LongPredicate tickingFutureReadyPredicate) { +- public LevelTicks(LongPredicate tickCheck) { + // Folia start - region threading + public final net.minecraft.server.level.ServerLevel world; + public final boolean isBlock; @@ -19748,7 +19368,7 @@ index 778e6476c86d823dc8efe603a95e589e8b2ea9d9..3fc6b4f93885fe447ed068bc5e0784da + final int chunkZ = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(chunkKey); + + final long regionSectionKey = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey( -+ chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift ++ chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift + ); + // Should always be non-null, since containers are removed on unload. + regionToData.get(regionSectionKey).allContainers.put(chunkKey, entry.getValue()); @@ -19761,7 +19381,7 @@ index 778e6476c86d823dc8efe603a95e589e8b2ea9d9..3fc6b4f93885fe447ed068bc5e0784da + final int chunkZ = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkZ(chunkKey); + + final long regionSectionKey = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey( -+ chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift ++ chunkX >> chunkToRegionShift, chunkZ >> chunkToRegionShift + ); + + // Should always be non-null, since containers are removed on unload. @@ -19770,1344 +19390,34 @@ index 778e6476c86d823dc8efe603a95e589e8b2ea9d9..3fc6b4f93885fe447ed068bc5e0784da + } + // Folia end - region threading + -+ public LevelTicks(LongPredicate tickingFutureReadyPredicate, net.minecraft.server.level.ServerLevel world, boolean isBlock) { this.world = world; this.isBlock = isBlock; // Folia - add world and isBlock - this.tickCheck = tickingFutureReadyPredicate; ++ public LevelTicks(LongPredicate tickCheck, net.minecraft.server.level.ServerLevel world, boolean isBlock) { this.world = world; this.isBlock = isBlock; // Folia - add world and isBlock + this.tickCheck = tickCheck; } -@@ -55,7 +112,17 @@ public class LevelTicks implements LevelTickAccess { - this.nextTickForContainer.put(l, scheduledTick.triggerTick()); +@@ -56,7 +113,17 @@ public class LevelTicks implements LevelTickAccess { + this.nextTickForContainer.put(packedChunkPos, scheduledTick.triggerTick()); } -- scheduler.setOnTickAdded(this.chunkScheduleUpdater); +- chunkTicks.setOnTickAdded(this.chunkScheduleUpdater); + // Folia start - region threading + final boolean isBlock = this.isBlock; + final net.minecraft.server.level.ServerLevel world = this.world; + // make sure the lambda contains no reference to this LevelTicks -+ scheduler.setOnTickAdded((chunkTickScheduler, tick) -> { -+ if (tick.equals(chunkTickScheduler.peek())) { ++ chunkTicks.setOnTickAdded((LevelChunkTicks levelChunkTicks, ScheduledTick tick) -> { ++ if (tick.equals(levelChunkTicks.peek())) { + io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); -+ (isBlock ? worldData.getBlockLevelTicks() : worldData.getFluidLevelTicks()).updateContainerScheduling((ScheduledTick)tick); ++ ((LevelTicks)(isBlock ? worldData.getBlockLevelTicks() : worldData.getFluidLevelTicks())).updateContainerScheduling(tick); + } + }); + // Folia end - region threading } - public void removeContainer(ChunkPos pos) { -@@ -69,6 +136,7 @@ public class LevelTicks implements LevelTickAccess { + public void removeContainer(ChunkPos chunkPos) { +@@ -70,6 +137,7 @@ public class LevelTicks implements LevelTickAccess { @Override - public void schedule(ScheduledTick orderedTick) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, orderedTick.pos(), "Cannot schedule tick for another region!"); // Folia - region threading - long l = ChunkPos.asLong(orderedTick.pos()); - LevelChunkTicks levelChunkTicks = this.allContainers.get(l); + public void schedule(ScheduledTick tick) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, tick.pos(), "Cannot schedule tick for another region!"); // Folia - region threading + long packedChunkPos = ChunkPos.asLong(tick.pos()); + LevelChunkTicks levelChunkTicks = this.allContainers.get(packedChunkPos); if (levelChunkTicks == null) { -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 97b5d6ba2b19a7c730730c74175a29157aed1840..26e1584557c8ba7b6bdf4a5ca7fc801d2f33fbdf 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -315,7 +315,7 @@ public final class CraftServer implements Server { - public final io.papermc.paper.SparksFly spark; // Paper - spark - - // Paper start - Folia region threading API -- private final io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler(); -+ private final io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler(); // Folia - region threading - private final io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler asyncScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler(); - private final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler globalRegionScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler(); - -@@ -392,7 +392,7 @@ public final class CraftServer implements Server { - - @Override - public final boolean isGlobalTickThread() { -- return ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); -+ return io.papermc.paper.threadedregions.RegionizedServer.isGlobalTickThread(); // Folia - region threading API - } - // Paper end - Folia reagion threading API - -@@ -987,6 +987,9 @@ public final class CraftServer implements Server { - - // NOTE: Should only be called from DedicatedServer.ah() - public boolean dispatchServerCommand(CommandSender sender, ConsoleInput serverCommand) { -+ // Folia start - region threading -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("May not dispatch server commands async"); -+ // Folia end - region threading - if (sender instanceof Conversable) { - Conversable conversable = (Conversable) sender; - -@@ -1006,12 +1009,46 @@ public final class CraftServer implements Server { - } - } - -+ // Folia start - region threading -+ public void dispatchCmdAsync(CommandSender sender, String commandLine) { -+ if ((sender instanceof Entity entity)) { -+ ((org.bukkit.craftbukkit.entity.CraftEntity)entity).taskScheduler.schedule( -+ (nmsEntity) -> { -+ CraftServer.this.dispatchCommand(nmsEntity.getBukkitEntity(), commandLine); -+ }, -+ null, -+ 1L -+ ); -+ } else if (sender instanceof ConsoleCommandSender || sender instanceof io.papermc.paper.commands.FeedbackForwardingSender) { -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { -+ CraftServer.this.dispatchCommand(sender, commandLine); -+ }); -+ } else { -+ // huh? -+ throw new UnsupportedOperationException("Dispatching command for " + sender); -+ } -+ } -+ // Folia end - region threading -+ - @Override - public boolean dispatchCommand(CommandSender sender, String commandLine) { - Preconditions.checkArgument(sender != null, "sender cannot be null"); - Preconditions.checkArgument(commandLine != null, "commandLine cannot be null"); - org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message - -+ // Folia start - region threading -+ if ((sender instanceof Entity entity)) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(((org.bukkit.craftbukkit.entity.CraftEntity)entity).getHandle(), "Dispatching command async"); -+ } else if (sender instanceof ConsoleCommandSender || sender instanceof net.minecraft.server.rcon.RconConsoleSource -+ || sender instanceof org.bukkit.craftbukkit.command.CraftRemoteConsoleCommandSender -+ || sender instanceof io.papermc.paper.commands.FeedbackForwardingSender) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Dispatching command async"); -+ } else { -+ // huh? -+ throw new UnsupportedOperationException("Dispatching command for " + sender); -+ } -+ // Folia end - region threading -+ - if (this.commandMap.dispatch(sender, commandLine)) { - return true; - } -@@ -3234,7 +3271,7 @@ public final class CraftServer implements Server { - - @Override - public int getCurrentTick() { -- return net.minecraft.server.MinecraftServer.currentTick; -+ return (int)io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - region threading - } - - @Override -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 92d9f0ea8f7810ae20d3996f49aefa539b4bcb69..f5412bdb4e80218de13b6beb62a50181fa2c3271 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -233,7 +233,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public int getTickableTileEntityCount() { -- return world.blockEntityTickers.size(); -+ throw new UnsupportedOperationException(); // Folia - region threading - TODO fix this? - } - - @Override -@@ -300,7 +300,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - // Paper start - per world spawn limits - for (SpawnCategory spawnCategory : SpawnCategory.values()) { - if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { -- setSpawnLimit(spawnCategory, this.world.paperConfig().entities.spawning.spawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); -+ this.spawnCategoryLimit.put(spawnCategory, this.world.paperConfig().entities.spawning.spawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); // Folia - region threading - } - } - // Paper end - per world spawn limits -@@ -370,6 +370,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public Chunk getChunkAt(int x, int z) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "Async chunk retrieval"); // Folia - region threading - warnUnsafeChunk("getting a faraway chunk", x, z); // Paper - net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) this.world.getChunk(x, z, ChunkStatus.FULL, true); - return new CraftChunk(chunk); -@@ -400,10 +401,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - public boolean isChunkGenerated(int x, int z) { - // Paper start - Fix this method -- if (!Bukkit.isPrimaryThread()) { -+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.getHandle(), x, z)) { // Folia - region threading - return java.util.concurrent.CompletableFuture.supplyAsync(() -> { - return CraftWorld.this.isChunkGenerated(x, z); -- }, world.getChunkSource().mainThreadProcessor).join(); -+ }, (run) -> { io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueChunkTask(this.getHandle(), x, z, run);}).join(); // Folia - region threading - } - ChunkAccess chunk = world.getChunkSource().getChunkAtImmediately(x, z); - if (chunk != null) { -@@ -460,7 +461,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - } - - private boolean unloadChunk0(int x, int z, boolean save) { -- org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot unload chunk asynchronously"); // Folia - region threading - if (!this.isChunkLoaded(x, z)) { - return true; - } -@@ -477,7 +478,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean regenerateChunk(int x, int z) { -- org.spigotmc.AsyncCatcher.catchOp("chunk regenerate"); // Spigot -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot regenerate chunk asynchronously"); // Folia - region threading - throw new UnsupportedOperationException("Not supported in this Minecraft version! Unless you can fix it, this is not a bug :)"); - /* - if (!unloadChunk0(x, z, false)) { -@@ -504,6 +505,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean refreshChunk(int x, int z) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot refresh chunk asynchronously"); // Folia - region threading - ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); - if (playerChunk == null) return false; - -@@ -553,7 +555,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean loadChunk(int x, int z, boolean generate) { -- org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "May not sync load chunks asynchronously"); // Folia - region threading - warnUnsafeChunk("loading a faraway chunk", x, z); // Paper - ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper - -@@ -594,7 +596,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - DistanceManager chunkDistanceManager = this.world.getChunkSource().chunkMap.distanceManager; - - if (chunkDistanceManager.addRegionTicketAtDistance(TicketType.PLUGIN_TICKET, new ChunkPos(x, z), 2, plugin)) { // keep in-line with force loading, add at level 31 -- this.getChunkAt(x, z); // ensure loaded -+ //this.getChunkAt(x, z); // ensure loaded // Folia - region threading - do not load chunks for tickets anymore to make this mt-safe - return true; - } - -@@ -805,13 +807,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { -- this.world.captureTreeGeneration = true; -- this.world.captureBlockStates = true; -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // Folia - region threading -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading -+ worldData.captureTreeGeneration = true; // Folia - region threading -+ worldData.captureBlockStates = true; // Folia - region threading - boolean grownTree = this.generateTree(loc, type); -- this.world.captureBlockStates = false; -- this.world.captureTreeGeneration = false; -+ worldData.captureBlockStates = false; // Folia - region threading -+ worldData.captureTreeGeneration = false; // Folia - region threading - if (grownTree) { // Copy block data to delegate -- for (BlockState blockstate : this.world.capturedBlockStates.values()) { -+ for (BlockState blockstate : worldData.capturedBlockStates.values()) { // Folia - region threading - BlockPos position = ((CraftBlockState) blockstate).getPosition(); - net.minecraft.world.level.block.state.BlockState oldBlock = this.world.getBlockState(position); - int flag = ((CraftBlockState) blockstate).getFlag(); -@@ -819,10 +823,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { - net.minecraft.world.level.block.state.BlockState newBlock = this.world.getBlockState(position); - this.world.notifyAndUpdatePhysics(position, null, oldBlock, newBlock, newBlock, flag, 512); - } -- this.world.capturedBlockStates.clear(); -+ worldData.capturedBlockStates.clear(); // Folia - region threading - return true; - } else { -- this.world.capturedBlockStates.clear(); -+ worldData.capturedBlockStates.clear(); // Folia - region threading - return false; - } - } -@@ -856,6 +860,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setTime(long time) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify time off of the global region"); // Folia - region threading - long margin = (time - this.getFullTime()) % 24000; - if (margin < 0) margin += 24000; - this.setFullTime(this.getFullTime() + margin); -@@ -868,6 +873,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setFullTime(long time) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify time off of the global region"); // Folia - region threading - // Notify anyone who's listening - TimeSkipEvent event = new TimeSkipEvent(this, TimeSkipEvent.SkipReason.CUSTOM, time - this.world.getDayTime()); - this.server.getPluginManager().callEvent(event); -@@ -895,7 +901,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public long getGameTime() { -- return this.world.levelData.getGameTime(); -+ return this.getHandle().getGameTime(); // Folia - region threading - } - - @Override -@@ -920,6 +926,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - } - public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source, Consumer configurator) { - // Paper end - expand explosion API -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // Folia - region threading - net.minecraft.world.level.Level.ExplosionInteraction explosionType; - if (!breakBlocks) { - explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks -@@ -929,6 +936,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - explosionType = net.minecraft.world.level.Level.ExplosionInteraction.MOB; // Respect mobGriefing gamerule - } - -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // Folia - region threading - net.minecraft.world.entity.Entity entity = (source == null) ? null : ((CraftEntity) source).getHandle(); - return !this.world.explode0(entity, Explosion.getDefaultDamageSource(this.world, entity), null, x, y, z, power, setFire, explosionType, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, SoundEvents.GENERIC_EXPLODE, configurator).wasCanceled; // Paper - expand explosion API - } -@@ -1011,6 +1019,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x >> 4, z >> 4, "Cannot retrieve chunk asynchronously"); // Folia - region threading - warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper - // Transient load for this tick - return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z); -@@ -1041,6 +1050,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - public void setBiome(int x, int y, int z, Holder bb) { - BlockPos pos = new BlockPos(x, 0, z); -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // Folia - region threading - if (this.world.hasChunkAt(pos)) { - net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos); - -@@ -1351,6 +1361,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setStorm(boolean hasStorm) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading - this.world.serverLevelData.setRaining(hasStorm, org.bukkit.event.weather.WeatherChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents - this.setWeatherDuration(0); // Reset weather duration (legacy behaviour) - this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) -@@ -1363,6 +1374,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setWeatherDuration(int duration) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading - this.world.serverLevelData.setRainTime(duration); - } - -@@ -1373,6 +1385,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setThundering(boolean thundering) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading - this.world.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents - this.setThunderDuration(0); // Reset weather duration (legacy behaviour) - this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) -@@ -1385,6 +1398,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setThunderDuration(int duration) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading - this.world.serverLevelData.setThunderTime(duration); - } - -@@ -1395,6 +1409,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setClearWeatherDuration(int duration) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading - this.world.serverLevelData.setClearWeatherTime(duration); - } - -@@ -1593,6 +1608,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setKeepSpawnInMemory(boolean keepLoaded) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify keep spawn in memory off of the global region"); // Folia - region threading - if (keepLoaded) { - this.setGameRule(GameRule.SPAWN_CHUNK_RADIUS, this.getGameRuleDefault(GameRule.SPAWN_CHUNK_RADIUS)); - } else { -@@ -1661,6 +1677,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setHardcore(boolean hardcore) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.world.serverLevelData.settings.hardcore = hardcore; - } - -@@ -1673,6 +1690,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setTicksPerAnimalSpawns(int ticksPerAnimalSpawns) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setTicksPerSpawns(SpawnCategory.ANIMAL, ticksPerAnimalSpawns); - } - -@@ -1685,6 +1703,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setTicksPerMonsterSpawns(int ticksPerMonsterSpawns) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setTicksPerSpawns(SpawnCategory.MONSTER, ticksPerMonsterSpawns); - } - -@@ -1697,6 +1716,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setTicksPerSpawns(SpawnCategory.WATER_ANIMAL, ticksPerWaterSpawns); - } - -@@ -1709,6 +1729,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setTicksPerWaterAmbientSpawns(int ticksPerWaterAmbientSpawns) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setTicksPerSpawns(SpawnCategory.WATER_AMBIENT, ticksPerWaterAmbientSpawns); - } - -@@ -1721,6 +1742,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setTicksPerWaterUndergroundCreatureSpawns(int ticksPerWaterUndergroundCreatureSpawns) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setTicksPerSpawns(SpawnCategory.WATER_UNDERGROUND_CREATURE, ticksPerWaterUndergroundCreatureSpawns); - } - -@@ -1733,11 +1755,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setTicksPerSpawns(SpawnCategory.AMBIENT, ticksPerAmbientSpawns); - } - - @Override - public void setTicksPerSpawns(SpawnCategory spawnCategory, int ticksPerCategorySpawn) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); - Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); - -@@ -1754,21 +1778,25 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify metadata off of the global region"); // Folia - region threading - this.server.getWorldMetadata().setMetadata(this, metadataKey, newMetadataValue); - } - - @Override - public List getMetadata(String metadataKey) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot retrieve metadata off of the global region"); // Folia - region threading - return this.server.getWorldMetadata().getMetadata(this, metadataKey); - } - - @Override - public boolean hasMetadata(String metadataKey) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot retrieve metadata off of the global region"); // Folia - region threading - return this.server.getWorldMetadata().hasMetadata(this, metadataKey); - } - - @Override - public void removeMetadata(String metadataKey, Plugin owningPlugin) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify metadata off of the global region"); // Folia - region threading - this.server.getWorldMetadata().removeMetadata(this, metadataKey, owningPlugin); - } - -@@ -1781,6 +1809,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setMonsterSpawnLimit(int limit) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setSpawnLimit(SpawnCategory.MONSTER, limit); - } - -@@ -1793,6 +1822,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setAnimalSpawnLimit(int limit) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setSpawnLimit(SpawnCategory.ANIMAL, limit); - } - -@@ -1805,6 +1835,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setWaterAnimalSpawnLimit(int limit) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setSpawnLimit(SpawnCategory.WATER_ANIMAL, limit); - } - -@@ -1817,6 +1848,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setWaterAmbientSpawnLimit(int limit) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setSpawnLimit(SpawnCategory.WATER_AMBIENT, limit); - } - -@@ -1829,6 +1861,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setWaterUndergroundCreatureSpawnLimit(int limit) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setSpawnLimit(SpawnCategory.WATER_UNDERGROUND_CREATURE, limit); - } - -@@ -1841,6 +1874,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - @Override - @Deprecated - public void setAmbientSpawnLimit(int limit) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - this.setSpawnLimit(SpawnCategory.AMBIENT, limit); - } - -@@ -1863,6 +1897,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void setSpawnLimit(SpawnCategory spawnCategory, int limit) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); - Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); - -@@ -1945,7 +1980,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; - - ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(CraftSound.bukkitToMinecraftHolder(sound), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); -- ChunkMap.TrackedEntity entityTracker = this.getHandle().getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); -+ ChunkMap.TrackedEntity entityTracker = ((CraftEntity) entity).getHandle().moonrise$getTrackedEntity(); // Folia - region threading - if (entityTracker != null) { - entityTracker.broadcastAndSend(packet); - } -@@ -1966,7 +2001,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; - - ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(Holder.direct(SoundEvent.createVariableRangeEvent(ResourceLocation.parse(sound))), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); -- ChunkMap.TrackedEntity entityTracker = this.getHandle().getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); -+ ChunkMap.TrackedEntity entityTracker = ((CraftEntity)entity).getHandle().moonrise$getTrackedEntity(); // Folia - region threading - if (entityTracker != null) { - entityTracker.broadcastAndSend(packet); - } -@@ -2049,6 +2084,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean setGameRuleValue(String rule, String value) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - // No null values allowed - if (rule == null || value == null) return false; - -@@ -2091,6 +2127,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public boolean setGameRule(GameRule rule, T newValue) { -+ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading - Preconditions.checkArgument(rule != null, "GameRule cannot be null"); - Preconditions.checkArgument(newValue != null, "GameRule value cannot be null"); - -@@ -2317,6 +2354,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { - - @Override - public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) { -+ // Folia start - region threading -+ if (sourceEntity != null && !Bukkit.isOwnedByCurrentRegion(sourceEntity)) { -+ throw new IllegalStateException("Cannot send game event asynchronously"); -+ } -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); -+ // Folia end - region threading - getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position)); - } - // Paper end -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -index 5cb69d0b822e11a99a96aef4f59986d083b079f4..a2f35f6d057b098a016a40094d84c54cb5e174fd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java -@@ -75,6 +75,11 @@ public class CraftBlock implements Block { - } - - public net.minecraft.world.level.block.state.BlockState getNMS() { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - return this.world.getBlockState(this.position); - } - -@@ -157,6 +162,11 @@ public class CraftBlock implements Block { - } - - private void setData(final byte data, int flag) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag); - } - -@@ -198,6 +208,11 @@ public class CraftBlock implements Block { - } - - public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) { -+ // Folia start - region threading -+ if (world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); -+ } -+ // Folia end - region threading - // SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup - if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes - // SPIGOT-4612: faster - just clear tile -@@ -343,18 +358,33 @@ public class CraftBlock implements Block { - - @Override - public Biome getBiome() { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ()); - } - - // Paper start - @Override - public Biome getComputedBiome() { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ()); - } - // Paper end - - @Override - public void setBiome(Biome bio) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio); - } - -@@ -402,6 +432,11 @@ public class CraftBlock implements Block { - - @Override - public boolean isBlockFaceIndirectlyPowered(BlockFace face) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face)); - - Block relative = this.getRelative(face); -@@ -414,6 +449,11 @@ public class CraftBlock implements Block { - - @Override - public int getBlockPower(BlockFace face) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - int power = 0; - net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); - int x = this.getX(); -@@ -500,6 +540,11 @@ public class CraftBlock implements Block { - - @Override - public boolean breakNaturally(ItemStack item, boolean triggerEffect, boolean dropExperience) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - // Paper end - // Order matters here, need to drop before setting to air so skulls can get their data - net.minecraft.world.level.block.state.BlockState iblockdata = this.getNMS(); -@@ -543,21 +588,27 @@ public class CraftBlock implements Block { - - @Override - public boolean applyBoneMeal(BlockFace face) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - Direction direction = CraftBlock.blockFaceToNotch(face); - BlockFertilizeEvent event = null; - ServerLevel world = this.getCraftWorld().getHandle(); - UseOnContext context = new UseOnContext(world, null, InteractionHand.MAIN_HAND, Items.BONE_MEAL.getDefaultInstance(), new BlockHitResult(Vec3.ZERO, direction, this.getPosition(), false)); - -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading - // SPIGOT-6895: Call StructureGrowEvent and BlockFertilizeEvent -- world.captureTreeGeneration = true; -+ worldData.captureTreeGeneration = true; // Folia - region threading - InteractionResult result = BoneMealItem.applyBonemeal(context); -- world.captureTreeGeneration = false; -+ worldData.captureTreeGeneration = false; // Folia - region threading - -- if (world.capturedBlockStates.size() > 0) { -- TreeType treeType = SaplingBlock.treeType; -- SaplingBlock.treeType = null; -- List blocks = new ArrayList<>(world.capturedBlockStates.values()); -- world.capturedBlockStates.clear(); -+ if (worldData.capturedBlockStates.size() > 0) { // Folia - region threading -+ TreeType treeType = SaplingBlock.treeTypeRT.get(); // Folia - region threading -+ SaplingBlock.treeTypeRT.set(null); // Folia - region threading -+ List blocks = new ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading -+ worldData.capturedBlockStates.clear(); // Folia - region threading - StructureGrowEvent structureEvent = null; - - if (treeType != null) { -@@ -644,6 +695,11 @@ public class CraftBlock implements Block { - - @Override - public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - Preconditions.checkArgument(start != null, "Location start cannot be null"); - Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world"); - start.checkFinite(); -@@ -685,6 +741,11 @@ public class CraftBlock implements Block { - - @Override - public boolean canPlace(BlockData data) { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - Preconditions.checkArgument(data != null, "BlockData cannot be null"); - net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState(); - net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); -@@ -719,18 +780,32 @@ public class CraftBlock implements Block { - - @Override - public void tick() { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - final ServerLevel level = this.world.getMinecraftWorld(); - this.getNMS().tick(level, this.position, level.random); - } - -- - @Override - public void fluidTick() { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - this.getNMSFluid().tick(this.world.getMinecraftWorld(), this.position, this.getNMS()); - } - - @Override - public void randomTick() { -+ // Folia start - region threading -+ if (this.world instanceof ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); -+ } -+ // Folia end - region threading - final ServerLevel level = this.world.getMinecraftWorld(); - this.getNMS().randomTick(level, this.position, level.random); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -index 04ae258a2f8e98421340d29d5cceedec045171b7..698a87ac30cc9efabeef3344ee254bcace1256c9 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java -@@ -25,7 +25,7 @@ public abstract class CraftBlockEntityState extends Craft - private final T tileEntity; - private final T snapshot; - public boolean snapshotDisabled; // Paper -- public static boolean DISABLE_SNAPSHOT = false; // Paper -+ public static final ThreadLocal DISABLE_SNAPSHOT = ThreadLocal.withInitial(() -> Boolean.FALSE); // Paper // Folia - region threading - - public CraftBlockEntityState(World world, T tileEntity) { - super(world, tileEntity.getBlockPos(), tileEntity.getBlockState()); -@@ -34,8 +34,8 @@ public abstract class CraftBlockEntityState extends Craft - - try { // Paper - Show blockstate location if we failed to read it - // Paper start -- this.snapshotDisabled = DISABLE_SNAPSHOT; -- if (DISABLE_SNAPSHOT) { -+ this.snapshotDisabled = DISABLE_SNAPSHOT.get().booleanValue(); // Folia - region threading -+ if (this.snapshotDisabled) { // Folia - region threading - this.snapshot = this.tileEntity; - } else { - this.snapshot = this.createSnapshot(tileEntity); -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..def7749e6dc4ae8351b72deefc75936629c33d7f 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java -@@ -215,6 +215,12 @@ public class CraftBlockState implements BlockState { - LevelAccessor access = this.getWorldHandle(); - CraftBlock block = this.getBlock(); - -+ // Folia start - region threading -+ if (access instanceof net.minecraft.server.level.ServerLevel serverWorld) { -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); -+ } -+ // Folia end - region threading -+ - if (block.getType() != this.getType()) { - if (!force) { - return false; -@@ -350,6 +356,9 @@ public class CraftBlockState implements BlockState { - - @Override - public java.util.Collection getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) { -+ // Folia start - region threading -+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); -+ // Folia end - region threading - this.requirePlaced(); - net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item); - -diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java -index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..69e8a170a80c2fde79bc015cd54879896c110d9d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java -+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java -@@ -249,8 +249,8 @@ public final class CraftBlockStates { - net.minecraft.world.level.block.state.BlockState blockData = craftBlock.getNMS(); - BlockEntity tileEntity = craftBlock.getHandle().getBlockEntity(blockPosition); - // Paper start - block state snapshots -- boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT; -- CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot; -+ boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT.get().booleanValue(); // Folia - region threading -+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(Boolean.valueOf(!useSnapshot)); // Folia - region threading - try { - // Paper end - CraftBlockState blockState = CraftBlockStates.getBlockState(world, blockPosition, blockData, tileEntity); -@@ -258,7 +258,7 @@ public final class CraftBlockStates { - return blockState; - // Paper start - } finally { -- CraftBlockEntityState.DISABLE_SNAPSHOT = prev; -+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(Boolean.valueOf(prev)); // Folia - region threading - } - // Paper end - } -diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java -index a45e658996e483e9a21cfd8178153ddb7b87ae69..25303f144422469350fdc6f84320b16bcc9f6e0c 100644 ---- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java -+++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java -@@ -50,7 +50,7 @@ public class ConsoleCommandCompleter implements Completer { - return syncEvent.callEvent() ? syncEvent.getCompletions() : com.google.common.collect.ImmutableList.of(); - } - }; -- server.getServer().processQueue.add(syncCompletions); -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(syncCompletions); // Folia - region threading - try { - final List legacyCompletions = syncCompletions.get(); - completions.removeIf(it -> !legacyCompletions.contains(it.suggestion())); // remove any suggestions that were removed -@@ -98,7 +98,7 @@ public class ConsoleCommandCompleter implements Completer { - return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions(); - } - }; -- server.getServer().processQueue.add(waitable); // Paper - Remove "this." -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(waitable); // Folia - region threading - try { - List offers = waitable.get(); - if (offers == null) { -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index b25b10c24a379097233e61bcc10add841b6a7115..5168cf0d58013aecfd80d37fb698014f38f8e08d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -80,6 +80,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return this.apiScheduler; - }; - // Paper end - Folia schedulers -+ // Folia start - region threading -+ public boolean isPurged() { -+ return this.taskScheduler.isRetired(); -+ } -+ // Folia end - region threading - - public CraftEntity(final CraftServer server, final Entity entity) { - this.server = server; -@@ -237,6 +242,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - - @Override - public boolean teleport(Location location, TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { -+ // Folia start - region threading -+ if (true) { -+ throw new UnsupportedOperationException("Must use teleportAsync while in region threading"); -+ } -+ // Folia end - region threading - // Paper end - Preconditions.checkArgument(location != null, "location cannot be null"); - location.checkFinite(); -@@ -698,7 +708,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - ImmutableSet.Builder players = ImmutableSet.builder(); - - ServerLevel world = ((CraftWorld) this.getWorld()).getHandle(); -- ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId()); -+ ChunkMap.TrackedEntity entityTracker = this.getHandle().moonrise$getTrackedEntity(); // Folia - region threading - - if (entityTracker != null) { - for (ServerPlayerConnection connection : entityTracker.seenBy) { -@@ -1002,7 +1012,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - } - - ServerLevel world = ((CraftWorld) this.getWorld()).getHandle(); -- ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId()); -+ ChunkMap.TrackedEntity entityTracker = this.getHandle().moonrise$getTrackedEntity(); // Folia - region threading - - if (entityTracker == null) { - return; -@@ -1021,7 +1031,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - } - - ServerLevel world = ((CraftWorld) this.getWorld()).getHandle(); -- ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId()); -+ ChunkMap.TrackedEntity entityTracker = this.entity.moonrise$getTrackedEntity(); // Folia - region threading - - if (entityTracker == null) { - return; -@@ -1055,29 +1065,43 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - location.checkFinite(); - Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. - -- net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle(); -+ // Folia start - region threading - java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); -- -- world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), -- this instanceof CraftPlayer ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, (list) -> { -- net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { -- final net.minecraft.server.level.ServerChunkCache chunkCache = world.getChunkSource(); -- for (final net.minecraft.world.level.chunk.ChunkAccess chunk : list) { -- chunkCache.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); -- } -- try { -- ret.complete(CraftEntity.this.teleport(locationClone, cause, teleportFlags) ? Boolean.TRUE : Boolean.FALSE); -- } catch (Throwable throwable) { -- if (throwable instanceof ThreadDeath) { -- throw (ThreadDeath)throwable; -- } -- net.minecraft.server.MinecraftServer.LOGGER.error("Failed to teleport entity " + CraftEntity.this, throwable); -- ret.completeExceptionally(throwable); -- } -- }); -- }); -+ java.util.function.Consumer run = (Entity nmsEntity) -> { -+ boolean success = nmsEntity.teleportAsync( -+ ((CraftWorld)locationClone.getWorld()).getHandle(), -+ new net.minecraft.world.phys.Vec3(locationClone.getX(), locationClone.getY(), locationClone.getZ()), -+ locationClone.getYaw(), locationClone.getPitch(), net.minecraft.world.phys.Vec3.ZERO, -+ cause == null ? TeleportCause.UNKNOWN : cause, -+ Entity.TELEPORT_FLAG_LOAD_CHUNK | Entity.TELEPORT_FLAG_TELEPORT_PASSENGERS, // preserve behavior with old API: dismount the entity so it can teleport -+ (Entity entityTp) -> { -+ ret.complete(Boolean.TRUE); -+ } -+ ); -+ if (!success) { -+ ret.complete(Boolean.FALSE); -+ } -+ }; -+ if (org.bukkit.Bukkit.isOwnedByCurrentRegion(this)) { -+ run.accept(this.getHandle()); -+ return ret; -+ } -+ boolean scheduled = this.taskScheduler.schedule( -+ // success -+ run, -+ // retired -+ (Entity nmsEntity) -> { -+ ret.complete(Boolean.FALSE); -+ }, -+ 1L -+ ); -+ -+ if (!scheduled) { -+ ret.complete(Boolean.FALSE); -+ } - - return ret; -+ // Folia end - region threading - } - // Paper end - more teleport API / async chunk API - -@@ -1190,8 +1214,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - // Paper start - tracked players API - @Override - public Set getTrackedPlayers() { -- ServerLevel world = (net.minecraft.server.level.ServerLevel)this.entity.level(); -- ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.entity.getId()); -+ ChunkMap.TrackedEntity tracker = this.entity.moonrise$getTrackedEntity(); // Folia - region threading - if (tracker == null) { - return java.util.Collections.emptySet(); - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 6a647cab8b2e476987931486e290703b8726f2c7..f2a847e590c72eee91a053cecdc691c53751ca3a 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -665,7 +665,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public void kickPlayer(String message) { -- org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot -+ //org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot // Folia - thread-safe now, as it will simply delay the kick - this.getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true), org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); // Paper - kick event cause - } - -@@ -1421,6 +1421,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - - @Override - public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { -+ // Folia start - region threading -+ if (true) { -+ throw new UnsupportedOperationException("Must use teleportAsync while in region threading"); -+ } -+ // Folia end - region threading - Set relativeArguments; - Set allFlags; - if (flags.length == 0) { -@@ -2085,7 +2090,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - private void unregisterEntity(Entity other) { - // Paper end - ChunkMap tracker = ((ServerLevel) this.getHandle().level()).getChunkSource().chunkMap; -- ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId()); -+ ChunkMap.TrackedEntity entry = other.moonrise$getTrackedEntity(); // Folia - region threading - if (entry != null) { - entry.removePlayer(this.getHandle()); - } -@@ -2182,7 +2187,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - if (original != null) otherPlayer.setUUID(original); // Paper - uuid override - } - -- ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId()); -+ ChunkMap.TrackedEntity entry = other.moonrise$getTrackedEntity(); // Folia - region threading - if (entry != null && !entry.seenBy.contains(this.getHandle().connection)) { - entry.updatePlayer(this.getHandle()); - } -@@ -3363,7 +3368,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { - { - if ( CraftPlayer.this.getHealth() <= 0 && CraftPlayer.this.isOnline() ) - { -- CraftPlayer.this.server.getServer().getPlayerList().respawn( CraftPlayer.this.getHandle(), false, Entity.RemovalReason.KILLED, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.PLUGIN ); -+ CraftPlayer.this.getHandle().respawn(null, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.PLUGIN); // Folia - region threading - } - } - -diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -index e37aaf77f94b97b736cc20ef070cefdff0400188..ebbe224d81f6a96f3b05e3379cd0c5b5ab50fcbd 100644 ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -951,7 +951,7 @@ public class CraftEventFactory { - return CraftEventFactory.handleBlockSpreadEvent(world, source, target, block, 2); - } - -- public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. -+ public static final ThreadLocal sourceBlockOverrideRT = new ThreadLocal<>(); // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. // Folia - region threading - - public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) { - // Suppress during worldgen -@@ -963,7 +963,7 @@ public class CraftEventFactory { - CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag); - state.setData(block); - -- BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), state); -+ BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverrideRT.get() != null ? CraftEventFactory.sourceBlockOverrideRT.get() : source), state); // Folia - region threading - Bukkit.getPluginManager().callEvent(event); - - if (!event.isCancelled()) { -@@ -2229,7 +2229,7 @@ public class CraftEventFactory { - CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1)); - - org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to)); -- if (!net.minecraft.world.level.block.DispenserBlock.eventFired) { -+ if (!net.minecraft.world.level.block.DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading - if (!event.callEvent()) { - return itemStack; - } -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index 1354ccfbf525e5e64483ac5f443cc2325ba63850..fad85bea8643a3a88ec5c4194de7a5060e81c136 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -514,6 +514,7 @@ public class CraftScheduler implements BukkitScheduler { - } - - protected CraftTask handle(final CraftTask task, final long delay) { // Paper -+ if (true) throw new UnsupportedOperationException(); // Folia - region threading - // Paper start - if (!this.isAsyncScheduler && !task.isSync()) { - this.asyncScheduler.handle(task, delay); -diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -index 15892c7769caa15f3d52a1ee2147cf9615aa0e25..f546cbe867d524f402491901df7d08e56668f406 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java -@@ -370,6 +370,12 @@ public final class CraftMagicNumbers implements UnsafeValues { - throw new InvalidPluginException("Unsupported API version " + pdf.getAPIVersion()); - } - -+ // Folia start - block plugins not marked as supported -+ if (!pdf.isFoliaSupported()) { -+ throw new InvalidPluginException("Plugin " + pdf.getFullName() + " is not marked as supporting regionised multithreading"); -+ } -+ // Folia end - block plugins not marked as supported -+ - if (toCheck.isOlderThan(minimumVersion)) { - // Older than supported - throw new InvalidPluginException("Plugin API version " + pdf.getAPIVersion() + " is lower than the minimum allowed version. Please update or replace it."); -diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index 37458e8fd5d57acbf90a6bea4e66797cb07f69fa..7b572e0b730ba989c5df62dcef458e5ead507870 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -@@ -66,6 +66,13 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { - this.handle = worldAccess; - } - -+ // Folia start - region threading -+ @Override -+ public net.minecraft.world.level.StructureManager structureManager() { -+ return this.handle.structureManager(); -+ } -+ // Folia end - region threading -+ - public WorldGenLevel getHandle() { - return this.handle; - } -diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 1d438ef44cbe4d1eedfba36d8fe5d2ad53464921..f2f5eb1a443ac411539e1c87eec60e76682b82fa 100644 ---- a/src/main/java/org/spigotmc/ActivationRange.java -+++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -51,7 +51,7 @@ public class ActivationRange - RAIDER, - MISC; - -- AABB boundingBox = new AABB( 0, 0, 0, 0, 0, 0 ); -+ // Folia - threaded regions - replaced by local variable - } - // Paper start - -@@ -64,26 +64,27 @@ public class ActivationRange - - private static int checkInactiveWakeup(Entity entity) { - Level world = entity.level(); -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - threaded regions - SpigotWorldConfig config = world.spigotConfig; -- long inactiveFor = MinecraftServer.currentTick - entity.activatedTick; -+ long inactiveFor = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() - entity.activatedTick; // Folia - threaded regions - if (entity.activationType == ActivationType.VILLAGER) { -- if (inactiveFor > config.wakeUpInactiveVillagersEvery && world.wakeupInactiveRemainingVillagers > 0) { -- world.wakeupInactiveRemainingVillagers--; -+ if (inactiveFor > config.wakeUpInactiveVillagersEvery && worldData.wakeupInactiveRemainingVillagers > 0) { // Folia - threaded regions -+ worldData.wakeupInactiveRemainingVillagers--; // Folia - threaded regions - return config.wakeUpInactiveVillagersFor; - } - } else if (entity.activationType == ActivationType.ANIMAL) { -- if (inactiveFor > config.wakeUpInactiveAnimalsEvery && world.wakeupInactiveRemainingAnimals > 0) { -- world.wakeupInactiveRemainingAnimals--; -+ if (inactiveFor > config.wakeUpInactiveAnimalsEvery && worldData.wakeupInactiveRemainingAnimals > 0) { // Folia - threaded regions -+ worldData.wakeupInactiveRemainingAnimals--; // Folia - threaded regions - return config.wakeUpInactiveAnimalsFor; - } - } else if (entity.activationType == ActivationType.FLYING_MONSTER) { -- if (inactiveFor > config.wakeUpInactiveFlyingEvery && world.wakeupInactiveRemainingFlying > 0) { -- world.wakeupInactiveRemainingFlying--; -+ if (inactiveFor > config.wakeUpInactiveFlyingEvery && worldData.wakeupInactiveRemainingFlying > 0) { // Folia - threaded regions -+ worldData.wakeupInactiveRemainingFlying--; // Folia - threaded regions - return config.wakeUpInactiveFlyingFor; - } - } else if (entity.activationType == ActivationType.MONSTER || entity.activationType == ActivationType.RAIDER) { -- if (inactiveFor > config.wakeUpInactiveMonstersEvery && world.wakeupInactiveRemainingMonsters > 0) { -- world.wakeupInactiveRemainingMonsters--; -+ if (inactiveFor > config.wakeUpInactiveMonstersEvery && worldData.wakeupInactiveRemainingMonsters > 0) { // Folia - threaded regions -+ worldData.wakeupInactiveRemainingMonsters--; // Folia - threaded regions - return config.wakeUpInactiveMonstersFor; - } - } -@@ -91,7 +92,7 @@ public class ActivationRange - } - // Paper end - -- static AABB maxBB = new AABB( 0, 0, 0, 0, 0, 0 ); -+ // Folia - threaded regions - replaced by local variable - - /** - * Initializes an entities type on construction to specify what group this -@@ -174,10 +175,11 @@ public class ActivationRange - final int waterActivationRange = world.spigotConfig.waterActivationRange; - final int flyingActivationRange = world.spigotConfig.flyingMonsterActivationRange; - final int villagerActivationRange = world.spigotConfig.villagerActivationRange; -- world.wakeupInactiveRemainingAnimals = Math.min(world.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals); -- world.wakeupInactiveRemainingVillagers = Math.min(world.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers); -- world.wakeupInactiveRemainingMonsters = Math.min(world.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters); -- world.wakeupInactiveRemainingFlying = Math.min(world.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying); -+ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - threaded regions -+ worldData.wakeupInactiveRemainingAnimals = Math.min(worldData.wakeupInactiveRemainingAnimals + 1, world.spigotConfig.wakeUpInactiveAnimals); // Folia - threaded regions -+ worldData.wakeupInactiveRemainingVillagers = Math.min(worldData.wakeupInactiveRemainingVillagers + 1, world.spigotConfig.wakeUpInactiveVillagers); // Folia - threaded regions -+ worldData.wakeupInactiveRemainingMonsters = Math.min(worldData.wakeupInactiveRemainingMonsters + 1, world.spigotConfig.wakeUpInactiveMonsters); // Folia - threaded regions -+ worldData.wakeupInactiveRemainingFlying = Math.min(worldData.wakeupInactiveRemainingFlying + 1, world.spigotConfig.wakeUpInactiveFlying); // Folia - threaded regions - final ServerChunkCache chunkProvider = (ServerChunkCache) world.getChunkSource(); - // Paper end - -@@ -191,9 +193,9 @@ public class ActivationRange - // Paper end - maxRange = Math.min( ( world.spigotConfig.simulationDistance << 4 ) - 8, maxRange ); - -- for ( Player player : world.players() ) -+ for ( Player player : world.getLocalPlayers() ) // Folia - region threading - { -- player.activatedTick = MinecraftServer.currentTick; -+ player.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - region threading - if ( world.spigotConfig.ignoreSpectatorActivation && player.isSpectator() ) - { - continue; -@@ -201,26 +203,33 @@ public class ActivationRange - - // Paper start - int worldHeight = world.getHeight(); -- ActivationRange.maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange ); -- ActivationType.MISC.boundingBox = player.getBoundingBox().inflate( miscActivationRange, worldHeight, miscActivationRange ); -- ActivationType.RAIDER.boundingBox = player.getBoundingBox().inflate( raiderActivationRange, worldHeight, raiderActivationRange ); -- ActivationType.ANIMAL.boundingBox = player.getBoundingBox().inflate( animalActivationRange, worldHeight, animalActivationRange ); -- ActivationType.MONSTER.boundingBox = player.getBoundingBox().inflate( monsterActivationRange, worldHeight, monsterActivationRange ); -- ActivationType.WATER.boundingBox = player.getBoundingBox().inflate( waterActivationRange, worldHeight, waterActivationRange ); -- ActivationType.FLYING_MONSTER.boundingBox = player.getBoundingBox().inflate( flyingActivationRange, worldHeight, flyingActivationRange ); -- ActivationType.VILLAGER.boundingBox = player.getBoundingBox().inflate( villagerActivationRange, worldHeight, villagerActivationRange ); -+ AABB maxBB = player.getBoundingBox().inflate( maxRange, worldHeight, maxRange ); // Folia - threaded regions -+ AABB[] bbByType = new AABB[ActivationType.values().length]; -+ bbByType[ActivationType.MISC.ordinal()] = player.getBoundingBox().inflate( miscActivationRange, worldHeight, miscActivationRange ); // Folia - threaded regions -+ bbByType[ActivationType.RAIDER.ordinal()] = player.getBoundingBox().inflate( raiderActivationRange, worldHeight, raiderActivationRange ); // Folia - threaded regions -+ bbByType[ActivationType.ANIMAL.ordinal()] = player.getBoundingBox().inflate( animalActivationRange, worldHeight, animalActivationRange ); // Folia - threaded regions -+ bbByType[ActivationType.MONSTER.ordinal()] = player.getBoundingBox().inflate( monsterActivationRange, worldHeight, monsterActivationRange ); // Folia - threaded regions -+ bbByType[ActivationType.WATER.ordinal()] = player.getBoundingBox().inflate( waterActivationRange, worldHeight, waterActivationRange ); // Folia - threaded regions -+ bbByType[ActivationType.FLYING_MONSTER.ordinal()] = player.getBoundingBox().inflate( flyingActivationRange, worldHeight, flyingActivationRange ); // Folia - threaded regions -+ bbByType[ActivationType.VILLAGER.ordinal()] = player.getBoundingBox().inflate( villagerActivationRange, worldHeight, villagerActivationRange ); // Folia - threaded regions - // Paper end - - // Paper start -- java.util.List entities = world.getEntities((Entity)null, ActivationRange.maxBB, null); -+ java.util.List entities = new java.util.ArrayList<>(); // Folia - region ticking - bypass getEntities thread check, we perform a check on the entities later -+ ((net.minecraft.server.level.ServerLevel)world).moonrise$getEntityLookup().getEntities((Entity)null, maxBB, entities, null); // Folia - region ticking - bypass getEntities thread check, we perform a check on the entities later - boolean tickMarkers = world.paperConfig().entities.markers.tick; // Paper - Configurable marker ticking - for (Entity entity : entities) { - // Paper start - Configurable marker ticking -+ // Folia start - region ticking -+ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(entity)) { -+ continue; -+ } -+ // Folia end - region ticking - if (!tickMarkers && entity instanceof net.minecraft.world.entity.Marker) { - continue; - } - // Paper end - Configurable marker ticking -- ActivationRange.activateEntity(entity); -+ ActivationRange.activateEntity(entity, bbByType); // Folia - threaded regions - } - // Paper end - } -@@ -231,18 +240,18 @@ public class ActivationRange - * - * @param chunk - */ -- private static void activateEntity(Entity entity) -+ private static void activateEntity(Entity entity, AABB[] bbByType) // Folia - threaded regions - { -- if ( MinecraftServer.currentTick > entity.activatedTick ) -+ if ( io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() > entity.activatedTick ) // Folia - threaded regions - { - if ( entity.defaultActivationState ) - { -- entity.activatedTick = MinecraftServer.currentTick; -+ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions - return; - } -- if ( entity.activationType.boundingBox.intersects( entity.getBoundingBox() ) ) -+ if ( bbByType[entity.activationType.ordinal()].intersects( entity.getBoundingBox() ) ) // Folia - threaded regions - { -- entity.activatedTick = MinecraftServer.currentTick; -+ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions - } - } - } -@@ -265,10 +274,10 @@ public class ActivationRange - if (entity.getRemainingFireTicks() > 0) { - return 2; - } -- if (entity.activatedImmunityTick >= MinecraftServer.currentTick) { -+ if (entity.activatedImmunityTick >= io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick()) { // Folia - threaded regions - return 1; - } -- long inactiveFor = MinecraftServer.currentTick - entity.activatedTick; -+ long inactiveFor = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() - entity.activatedTick; // Folia - threaded regions - // Paper end - // quick checks. - if ( (entity.activationType != ActivationType.WATER && entity.wasTouchingWater && entity.isPushedByFluid()) ) // Paper -@@ -391,19 +400,19 @@ public class ActivationRange - } - // Paper end - -- boolean isActive = entity.activatedTick >= MinecraftServer.currentTick; -+ boolean isActive = entity.activatedTick >= io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions - entity.isTemporarilyActive = false; // Paper - - // Should this entity tick? - if ( !isActive ) - { -- if ( ( MinecraftServer.currentTick - entity.activatedTick - 1 ) % 20 == 0 ) -+ if ( ( io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() - entity.activatedTick - 1 ) % 20 == 0 ) // Folia - threaded regions - { - // Check immunities every 20 ticks. - // Paper start - int immunity = checkEntityImmunities(entity); - if (immunity >= 0) { -- entity.activatedTick = MinecraftServer.currentTick + immunity; -+ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + immunity; // Folia - threaded regions - } else { - entity.isTemporarilyActive = true; - } -diff --git a/src/main/java/org/spigotmc/SpigotCommand.java b/src/main/java/org/spigotmc/SpigotCommand.java -index ac0fd418fcb437896dfdff53ab3eff19833d25fb..130220977477a5d8d51e17dcb989ae0c858643cb 100644 ---- a/src/main/java/org/spigotmc/SpigotCommand.java -+++ b/src/main/java/org/spigotmc/SpigotCommand.java -@@ -29,6 +29,7 @@ public class SpigotCommand extends Command { - Command.broadcastCommandMessage(sender, ChatColor.RED + "Please note that this command is not supported and may cause issues."); - Command.broadcastCommandMessage(sender, ChatColor.RED + "If you encounter any issues please use the /stop command to restart your server."); - -+ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading - MinecraftServer console = MinecraftServer.getServer(); - org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); - for (ServerLevel world : console.getAllLevels()) { -@@ -37,6 +38,7 @@ public class SpigotCommand extends Command { - console.server.reloadCount++; - - Command.broadcastCommandMessage(sender, ChatColor.GREEN + "Reload complete."); -+ }); // Folia - region threading - } - - return true; -diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java -index 4dbb109d0526afee99b9190fc256585121aac9b5..5c80e89034c1b3149729684ba4dd4ae26a4261c1 100644 ---- a/src/main/java/org/spigotmc/SpigotConfig.java -+++ b/src/main/java/org/spigotmc/SpigotConfig.java -@@ -224,7 +224,7 @@ public class SpigotConfig - SpigotConfig.restartOnCrash = SpigotConfig.getBoolean( "settings.restart-on-crash", SpigotConfig.restartOnCrash ); - SpigotConfig.restartScript = SpigotConfig.getString( "settings.restart-script", SpigotConfig.restartScript ); - SpigotConfig.restartMessage = SpigotConfig.transform( SpigotConfig.getString( "messages.restart", "Server is restarting" ) ); -- SpigotConfig.commands.put( "restart", new RestartCommand( "restart" ) ); -+ // SpigotConfig.commands.put( "restart", new RestartCommand( "restart" ) ); // Folia - region threading - // WatchdogThread.doStart( SpigotConfig.timeoutTime, SpigotConfig.restartOnCrash ); // Paper - moved to after paper config initialization - } - -@@ -279,7 +279,7 @@ public class SpigotConfig - - private static void tpsCommand() - { -- SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) ); -+ //SpigotConfig.commands.put( "tps", new TicksPerSecondCommand( "tps" ) ); // Folia - region threading - } - - public static int playerSample; -diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java -index 2c408fa4abcbe1171c58aee8799c8cf7867d0f0a..9f38a0763597d9d70cb8d1b636c7d4b14d32c535 100644 ---- a/src/main/java/org/spigotmc/SpigotWorldConfig.java -+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java -@@ -435,7 +435,7 @@ public class SpigotWorldConfig - this.otherMultiplier = (float) this.getDouble( "hunger.other-multiplier", 0.0 ); - } - -- public int currentPrimedTnt = 0; -+ //public int currentPrimedTnt = 0; // Folia - region threading - moved to regionised world data - public int maxTntTicksPerTick; - private void maxTntPerTick() { - if ( SpigotConfig.version < 7 ) diff --git a/patches/server/0004-Max-pending-logins.patch b/folia-server/minecraft-patches/features/0002-Max-pending-logins.patch similarity index 62% rename from patches/server/0004-Max-pending-logins.patch rename to folia-server/minecraft-patches/features/0002-Max-pending-logins.patch index 9db9e3e..e949319 100644 --- a/patches/server/0004-Max-pending-logins.patch +++ b/folia-server/minecraft-patches/features/0002-Max-pending-logins.patch @@ -5,24 +5,24 @@ Subject: [PATCH] Max pending logins Should help the floodgates on launch -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index 7fdb9304de7cf1979d57e3fac32415d7c674609d..227d62a69a453d49c28568ecb41ecef85a35405b 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index 6173f704b0d093813ec67eb231c75be49a462e7d..159f2f169d26b436a70006f7bc9bdc481315dd32 100644 +--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java @@ -117,7 +117,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, if (this.server.getPlayerList().pushPendingJoin(name, uniqueId, this.connection)) { // Folia end - region threading - rewrite login process - this.verifyLoginAndFinishConnectionSetup((GameProfile) Objects.requireNonNull(this.authenticatedProfile)); + this.verifyLoginAndFinishConnectionSetup(Objects.requireNonNull(this.authenticatedProfile)); - } // Paper - prevent logins to be processed even though disconnect was called + } else { --this.tick; } // Paper - prevent logins to be processed even though disconnect was called // Folia - max concurrent logins } // CraftBukkit start -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index b449de44b1911e2ff0701956bfba53fb5d2ed44e..c1574cdea90731dec4d24b15979209cce0c581af 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -175,6 +175,17 @@ public abstract class PlayerList { +diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java +index 65835fa09cdcd3bb158025f7d8b3cb29ac8b2549..bcfe3af0b0df25d4b308b11a64c361da1ab3eeca 100644 +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -151,6 +151,17 @@ public abstract class PlayerList { conflictingId = this.connectionById.get(byId); if (conflictingName == null && conflictingId == null) { diff --git a/patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch b/folia-server/minecraft-patches/features/0003-Add-chunk-system-throughput-counters-to-tps.patch similarity index 84% rename from patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch rename to folia-server/minecraft-patches/features/0003-Add-chunk-system-throughput-counters-to-tps.patch index 0a0d89d..2776532 100644 --- a/patches/server/0005-Add-chunk-system-throughput-counters-to-tps.patch +++ b/folia-server/minecraft-patches/features/0003-Add-chunk-system-throughput-counters-to-tps.patch @@ -4,10 +4,10 @@ Date: Fri, 10 Mar 2023 00:16:26 -0800 Subject: [PATCH] Add chunk system throughput counters to /tps -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java index 6ab353b0d2465c3680bb3c8d0852ba0f65c00fd2..4ad647a9f98cf1c11c45f85edcba3c29e343c236 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java +--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/task/ChunkFullTask.java @@ -30,6 +30,9 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl private final ChunkAccess fromChunk; private final PrioritisedExecutor.PrioritisedTask convertToFullTask; @@ -57,10 +57,10 @@ index 6ab353b0d2465c3680bb3c8d0852ba0f65c00fd2..4ad647a9f98cf1c11c45f85edcba3c29 if (this.fromChunk instanceof ImposterProtoChunk wrappedFull) { chunk = wrappedFull.getWrapped(); } else { -diff --git a/src/main/java/io/papermc/paper/threadedregions/commands/CommandServerHealth.java b/src/main/java/io/papermc/paper/threadedregions/commands/CommandServerHealth.java +diff --git a/io/papermc/paper/threadedregions/commands/CommandServerHealth.java b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java index 3bcb1dc98c61e025874cc9e008faa722581a530c..012d3a7da7fe483393a0888c823bd2e78f5c3908 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/commands/CommandServerHealth.java -+++ b/src/main/java/io/papermc/paper/threadedregions/commands/CommandServerHealth.java +--- a/io/papermc/paper/threadedregions/commands/CommandServerHealth.java ++++ b/io/papermc/paper/threadedregions/commands/CommandServerHealth.java @@ -170,6 +170,9 @@ public final class CommandServerHealth extends Command { totalUtil += (report == null ? 0.0 : report.utilisation()); } diff --git a/folia-server/minecraft-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch b/folia-server/minecraft-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch new file mode 100644 index 0000000..88bb656 --- /dev/null +++ b/folia-server/minecraft-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 19 Mar 2023 14:35:46 -0700 +Subject: [PATCH] Make CraftEntity#getHandle and overrides perform thread + checks + +While these checks are painful, it should assist in debugging +threading issues for plugins. + +diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java +index dbe049c164657ae352f4dadfa673a07dbef2054d..7d5368330870aca9d14ff43296d64c8db6a3e89b 100644 +--- a/net/minecraft/world/entity/Entity.java ++++ b/net/minecraft/world/entity/Entity.java +@@ -3050,6 +3050,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + } + + if (force || this.canRide(vehicle) && vehicle.canAddPassenger(this)) { ++ if (this.valid) { // Folia - region threading - suppress entire event logic during worldgen + // CraftBukkit start + if (vehicle.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && this.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { + org.bukkit.event.vehicle.VehicleEnterEvent event = new org.bukkit.event.vehicle.VehicleEnterEvent((org.bukkit.entity.Vehicle) vehicle.getBukkitEntity(), this.getBukkitEntity()); +@@ -3071,6 +3072,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return false; + } + // CraftBukkit end ++ } // Folia - region threading - suppress entire event logic during worldgen + if (this.isPassenger()) { + this.stopRiding(); + } +@@ -3152,6 +3154,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)"); + } else { + // CraftBukkit start ++ if (this.valid) { // Folia - region threading - suppress entire event logic during worldgen + org.bukkit.craftbukkit.entity.CraftEntity craft = (org.bukkit.craftbukkit.entity.CraftEntity) passenger.getBukkitEntity().getVehicle(); + Entity orig = craft == null ? null : craft.getHandle(); + if (this.getBukkitEntity() instanceof org.bukkit.entity.Vehicle && passenger.getBukkitEntity() instanceof org.bukkit.entity.LivingEntity) { +@@ -3179,6 +3182,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess + return false; + } + // CraftBukkit end ++ } // Folia - region threading - suppress entire event logic during worldgen + if (this.passengers.size() == 1 && this.passengers.get(0) == passenger) { + this.passengers = ImmutableList.of(); + } else { diff --git a/folia-server/minecraft-patches/features/0005-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch b/folia-server/minecraft-patches/features/0005-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch new file mode 100644 index 0000000..0e15d7c --- /dev/null +++ b/folia-server/minecraft-patches/features/0005-Prevent-block-updates-in-non-loaded-or-non-owned-chu.patch @@ -0,0 +1,111 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 17 Apr 2023 19:47:57 -0700 +Subject: [PATCH] Prevent block updates in non-loaded or non-owned chunks + +This is to prevent block physics from tripping thread checks by +far exceeding the bounds of the current region. While this does +add explicit block update suppression techniques, it's better +than the server crashing. + +diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java +index d36b5ad7b386391e617895a33b919e29266220e2..e16a824488d2b43c430f12b8416fdeb590e66d28 100644 +--- a/net/minecraft/world/level/Level.java ++++ b/net/minecraft/world/level/Level.java +@@ -2053,7 +2053,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + public void updateNeighbourForOutputSignal(BlockPos pos, Block block) { + for (Direction direction : Direction.Plane.HORIZONTAL) { + BlockPos blockPos = pos.relative(direction); +- if (this.hasChunkAt(blockPos)) { ++ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this, blockPos, 16) && this.hasChunkAt(blockPos)) { // Folia - block updates in unloaded chunks + BlockState blockState = this.getBlockState(blockPos); + if (blockState.is(Blocks.COMPARATOR)) { + this.neighborChanged(blockState, blockPos, block, null, false); +diff --git a/net/minecraft/world/level/block/DetectorRailBlock.java b/net/minecraft/world/level/block/DetectorRailBlock.java +index 8f0217f25a2faf23833be10c85c5febc896ae292..6994a95e846a19525da1360c33f858ed29b64193 100644 +--- a/net/minecraft/world/level/block/DetectorRailBlock.java ++++ b/net/minecraft/world/level/block/DetectorRailBlock.java +@@ -133,8 +133,8 @@ public class DetectorRailBlock extends BaseRailBlock { + RailState railState = new RailState(level, pos, state); + + for (BlockPos blockPos : railState.getConnections()) { +- BlockState blockState = level.getBlockState(blockPos); +- level.neighborChanged(blockState, blockPos, blockState.getBlock(), null, false); ++ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, blockPos, 16) ? null : level.getBlockState(blockPos); // Folia - block updates in unloaded chunks ++ if (blockState != null) level.neighborChanged(blockState, blockPos, blockState.getBlock(), null, false); // Folia - block updates in unloaded chunks + } + } + +diff --git a/net/minecraft/world/level/block/PoweredRailBlock.java b/net/minecraft/world/level/block/PoweredRailBlock.java +index f33b53257a231dccf16740f1e78a3cdfa6e70726..f87f59ea29bd288cd6b7ff877c517dc6d9cdefea 100644 +--- a/net/minecraft/world/level/block/PoweredRailBlock.java ++++ b/net/minecraft/world/level/block/PoweredRailBlock.java +@@ -108,8 +108,8 @@ public class PoweredRailBlock extends BaseRailBlock { + } + + protected boolean isSameRailWithPower(Level level, BlockPos state, boolean searchForward, int recursionCount, RailShape shape) { +- BlockState blockState = level.getBlockState(state); +- if (!blockState.is(this)) { ++ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, state, 16) ? null : level.getBlockState(state); // Folia - block updates in unloaded chunks ++ if (blockState == null || !blockState.is(this)) { // Folia - block updates in unloaded chunks + return false; + } else { + RailShape railShape = blockState.getValue(SHAPE); +diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java +index 6ba86c5e55d09fd99e81e40db4614ef14246bdc3..996e8d5b4e4aac7a0c0f846dd765711a2dfb5682 100644 +--- a/net/minecraft/world/level/block/RedStoneWireBlock.java ++++ b/net/minecraft/world/level/block/RedStoneWireBlock.java +@@ -236,8 +236,9 @@ public class RedStoneWireBlock extends Block { + BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + + for (Direction direction : Direction.Plane.HORIZONTAL) { ++ BlockState currState; mutableBlockPos.setWithOffset(pos, direction); // Folia - block updates in unloaded chunks + RedstoneSide redstoneSide = state.getValue(PROPERTY_BY_DIRECTION.get(direction)); +- if (redstoneSide != RedstoneSide.NONE && !level.getBlockState(mutableBlockPos.setWithOffset(pos, direction)).is(this)) { ++ if (redstoneSide != RedstoneSide.NONE && (currState = (level instanceof net.minecraft.server.level.ServerLevel serverLevel && !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(serverLevel, pos, 16) ? null : level.getBlockStateIfLoaded(mutableBlockPos.setWithOffset(pos, direction)))) != null && !currState.is(this)) { // Folia - block updates in unloaded chunks + mutableBlockPos.move(Direction.DOWN); + BlockState blockState = level.getBlockState(mutableBlockPos); + if (blockState.is(this)) { +diff --git a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +index e7ea9df8f404a6176435204a91edeefab8070c89..285fa83ee583595274f228e5981a67f67012d410 100644 +--- a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java ++++ b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java +@@ -122,7 +122,8 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + public boolean runNext(Level level) { + Direction direction = NeighborUpdater.UPDATE_ORDER[this.idx++]; + BlockPos blockPos = this.sourcePos.relative(direction); +- BlockState blockState = level.getBlockState(blockPos); ++ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, blockPos, 16) ? null : level.getBlockState(blockPos); // Folia - block updates in unloaded chunks ++ if (blockState != null) { // Folia - block updates in unloaded chunks + Orientation orientation = null; + if (level.enabledFeatures().contains(FeatureFlags.REDSTONE_EXPERIMENTS)) { + if (this.orientation == null) { +@@ -135,6 +136,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + } + + NeighborUpdater.executeUpdate(level, blockState, blockPos, this.sourceBlock, orientation, false, this.sourcePos); // Paper - Add source block to BlockPhysicsEvent ++ } // Folia - block updates in unloaded chunks + if (this.idx < NeighborUpdater.UPDATE_ORDER.length && NeighborUpdater.UPDATE_ORDER[this.idx] == this.skipDirection) { + this.idx++; + } +@@ -151,7 +153,9 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + implements CollectingNeighborUpdater.NeighborUpdates { + @Override + public boolean runNext(Level level) { ++ if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, this.pos, 16) && level.getChunkIfLoaded(this.pos) != null) { // Folia - block updates in unloaded chunks + NeighborUpdater.executeShapeUpdate(level, this.direction, this.pos, this.neighborPos, this.neighborState, this.updateFlags, this.updateLimit); ++ } // Folia - block updates in unloaded chunks + return false; + } + } +@@ -159,8 +163,8 @@ public class CollectingNeighborUpdater implements NeighborUpdater { + record SimpleNeighborUpdate(BlockPos pos, Block block, @Nullable Orientation orientation) implements CollectingNeighborUpdater.NeighborUpdates { + @Override + public boolean runNext(Level level) { +- BlockState blockState = level.getBlockState(this.pos); +- NeighborUpdater.executeUpdate(level, blockState, this.pos, this.block, this.orientation, false); ++ BlockState blockState = !ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(level, this.pos, 16) ? null : level.getBlockStateIfLoaded(this.pos); // Folia - block updates in unloaded chunks ++ if (blockState != null) NeighborUpdater.executeUpdate(level, blockState, this.pos, this.block, this.orientation, false); + return false; + } + } diff --git a/patches/server/0011-Block-reading-in-world-tile-entities-on-worldgen-thr.patch b/folia-server/minecraft-patches/features/0006-Block-reading-in-world-tile-entities-on-worldgen-thr.patch similarity index 69% rename from patches/server/0011-Block-reading-in-world-tile-entities-on-worldgen-thr.patch rename to folia-server/minecraft-patches/features/0006-Block-reading-in-world-tile-entities-on-worldgen-thr.patch index b35dfc8..cc6b59d 100644 --- a/patches/server/0011-Block-reading-in-world-tile-entities-on-worldgen-thr.patch +++ b/folia-server/minecraft-patches/features/0006-Block-reading-in-world-tile-entities-on-worldgen-thr.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Block reading in-world tile entities on worldgen threads The returned TE may be in the world, in which case it is unsafe for the current thread to modify or access its contents. -diff --git a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java -index 1eb8022f3e31603322e6c56516304afc9a11bbec..87ddae289972b8e0dd0b48a07e23c627b598bae3 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/ImposterProtoChunk.java +diff --git a/net/minecraft/world/level/chunk/ImposterProtoChunk.java b/net/minecraft/world/level/chunk/ImposterProtoChunk.java +index 41856c98d97e7eb0782f8e441b9a269a47ed1914..606b07ae06166f954b6aaa39d56f024c7ad8611f 100644 +--- a/net/minecraft/world/level/chunk/ImposterProtoChunk.java ++++ b/net/minecraft/world/level/chunk/ImposterProtoChunk.java @@ -91,6 +91,11 @@ public class ImposterProtoChunk extends ProtoChunk implements ca.spottedleaf.moo @Nullable @Override diff --git a/folia-server/minecraft-patches/features/0007-Skip-worldstate-access-when-waking-players-up-during.patch b/folia-server/minecraft-patches/features/0007-Skip-worldstate-access-when-waking-players-up-during.patch new file mode 100644 index 0000000..c42eb06 --- /dev/null +++ b/folia-server/minecraft-patches/features/0007-Skip-worldstate-access-when-waking-players-up-during.patch @@ -0,0 +1,39 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 23 Apr 2023 07:38:50 -0700 +Subject: [PATCH] Skip worldstate access when waking players up during data + deserialization + +In general, worldstate read/write is unacceptable during +data deserialization and is racey even in Vanilla. But in Folia, +some accesses may throw and as such we need to fix this directly. + +diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java +index ab85c5acc63abc07a55ff7c5e207527bb18d50b2..df0c10880c5aea110a4eade57d257d3a46e8c180 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -674,7 +674,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + this.getBukkitEntity().readExtraData(compound); // CraftBukkit + + if (this.isSleeping()) { +- this.stopSleeping(); ++ this.stopSleepingRaw(); // Folia - do not modify or read worldstate during data deserialization + } + + // CraftBukkit start +diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java +index 8f9e64590400039566ee5c9628d82a0eb9e56be1..5ba06cf6b26baa5acae9d64111ee3f61533e7867 100644 +--- a/net/minecraft/world/entity/LivingEntity.java ++++ b/net/minecraft/world/entity/LivingEntity.java +@@ -4333,6 +4333,11 @@ public abstract class LivingEntity extends Entity implements Attackable { + this.setXRot(0.0F); + } + }); ++ // Folia start - separate out ++ this.stopSleepingRaw(); ++ } ++ public void stopSleepingRaw() { ++ // Folia end - separate out + Vec3 vec3 = this.position(); + this.setPose(Pose.STANDING); + this.setPos(vec3.x, vec3.y, vec3.z); diff --git a/patches/server/0013-Do-not-access-POI-data-for-lodestone-compass.patch b/folia-server/minecraft-patches/features/0008-Do-not-access-POI-data-for-lodestone-compass.patch similarity index 61% rename from patches/server/0013-Do-not-access-POI-data-for-lodestone-compass.patch rename to folia-server/minecraft-patches/features/0008-Do-not-access-POI-data-for-lodestone-compass.patch index 3819c05..6c13513 100644 --- a/patches/server/0013-Do-not-access-POI-data-for-lodestone-compass.patch +++ b/folia-server/minecraft-patches/features/0008-Do-not-access-POI-data-for-lodestone-compass.patch @@ -8,19 +8,19 @@ the lodestone block, as that is at least safe enough for the light engine compared to the POI access. This should make it safe for off-region access. -diff --git a/src/main/java/net/minecraft/world/item/component/LodestoneTracker.java b/src/main/java/net/minecraft/world/item/component/LodestoneTracker.java -index cdd1f6939ce33e62f6609f7eb3a5dff59bf12675..5d92251dc5a53eb6b2f5ecfef1261ad6edd0e2a9 100644 ---- a/src/main/java/net/minecraft/world/item/component/LodestoneTracker.java -+++ b/src/main/java/net/minecraft/world/item/component/LodestoneTracker.java +diff --git a/net/minecraft/world/item/component/LodestoneTracker.java b/net/minecraft/world/item/component/LodestoneTracker.java +index 0c00c23743a4978e8dceed5bbee8ca44b0e0c8d6..b6de5d017bed5c71125f26881b95383386aa1a79 100644 +--- a/net/minecraft/world/item/component/LodestoneTracker.java ++++ b/net/minecraft/world/item/component/LodestoneTracker.java @@ -29,7 +29,10 @@ public record LodestoneTracker(Optional target, boolean tracked) { return this; } else { BlockPos blockPos = this.target.get().pos(); -- return world.isInWorldBounds(blockPos) && (!world.hasChunkAt(blockPos) || world.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos)) // Paper - Prevent compass from loading chunks +- return level.isInWorldBounds(blockPos) && (!level.hasChunkAt(blockPos) || level.getPoiManager().existsAtPosition(PoiTypes.LODESTONE, blockPos)) // Paper - Prevent compass from loading chunks + // Folia start - do not access the POI data off-region -+ net.minecraft.world.level.chunk.LevelChunk chunk = world.getChunkIfLoaded(blockPos); -+ return world.isInWorldBounds(blockPos) && (chunk == null || chunk.getBlockState(blockPos).getBlock() == net.minecraft.world.level.block.Blocks.LODESTONE) // Paper - Prevent compass from loading chunks -+ // Folia end - do not access the POI data off-region ++ net.minecraft.world.level.chunk.LevelChunk chunk = level.getChunkIfLoaded(blockPos); ++ return level.isInWorldBounds(blockPos) && (chunk == null || chunk.getBlockState(blockPos).getBlock() == net.minecraft.world.level.block.Blocks.LODESTONE) // Paper - Prevent compass from loading chunks ++ // Folia end - do not access the POI data off-region ? this : new LodestoneTracker(Optional.empty(), true); } diff --git a/folia-server/minecraft-patches/features/0009-Fix-off-region-raid-heroes.patch b/folia-server/minecraft-patches/features/0009-Fix-off-region-raid-heroes.patch new file mode 100644 index 0000000..0ad98a8 --- /dev/null +++ b/folia-server/minecraft-patches/features/0009-Fix-off-region-raid-heroes.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: WillQi +Date: Mon, 15 May 2023 23:45:09 -0600 +Subject: [PATCH] Fix off region raid heroes + +This patch aims to solve a potential incorrect thread call when completing a raid. +If a player is a hero of the village but proceeds to leave the region of the +raid before it's completion, it would throw an exception due to not being on the +same region thread anymore. + +diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java +index b7045b2d4665c72d0c4849c711be4e44f7d17ad3..58ea6738dd9a04831197b850850720d5a775a131 100644 +--- a/net/minecraft/world/entity/raid/Raid.java ++++ b/net/minecraft/world/entity/raid/Raid.java +@@ -391,14 +391,21 @@ public class Raid { + if (entity instanceof LivingEntity) { + LivingEntity livingEntity = (LivingEntity)entity; + if (!entity.isSpectator()) { +- livingEntity.addEffect( +- new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.raidOmenLevel - 1, false, false, true) +- ); ++ //livingEntity.addEffect(new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.raidOmenLevel - 1, false, false, true)); // Folia start - Fix off region raid heroes - moved down + if (livingEntity instanceof ServerPlayer serverPlayer) { +- serverPlayer.awardStat(Stats.RAID_WIN); +- CriteriaTriggers.RAID_WIN.trigger(serverPlayer); ++ //serverPlayer.awardStat(Stats.RAID_WIN); // Folia start - Fix off region raid heroes - moved down ++ //CriteriaTriggers.RAID_WIN.trigger(serverPlayer); // Folia start - Fix off region raid heroes - moved down + winners.add(serverPlayer.getBukkitEntity()); // CraftBukkit + } ++ // Folia start - Fix off region raid heroes ++ livingEntity.getBukkitEntity().taskScheduler.schedule((LivingEntity lv) -> { ++ lv.addEffect(new MobEffectInstance(MobEffects.HERO_OF_THE_VILLAGE, 48000, this.raidOmenLevel - 1, false, false, true)); ++ if (lv instanceof ServerPlayer serverPlayer) { ++ serverPlayer.awardStat(Stats.RAID_WIN); ++ CriteriaTriggers.RAID_WIN.trigger(serverPlayer); ++ } ++ }, null, 1L); ++ // Folia end - Fix off region raid heroes + } + } + } diff --git a/folia-server/minecraft-patches/features/0010-Sync-vehicle-position-to-player-position-on-player-d.patch b/folia-server/minecraft-patches/features/0010-Sync-vehicle-position-to-player-position-on-player-d.patch new file mode 100644 index 0000000..221433d --- /dev/null +++ b/folia-server/minecraft-patches/features/0010-Sync-vehicle-position-to-player-position-on-player-d.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 25 Jun 2023 13:57:30 -0700 +Subject: [PATCH] Sync vehicle position to player position on player data load + +This allows the player to be re-positioned before logging into +the world without causing thread checks to trip on Folia. + +diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java +index df0c10880c5aea110a4eade57d257d3a46e8c180..ca3770e9f77e583dfa6cef8ca884eaf6a43f5ffa 100644 +--- a/net/minecraft/server/level/ServerPlayer.java ++++ b/net/minecraft/server/level/ServerPlayer.java +@@ -775,8 +775,18 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc + public void loadAndSpawnParentVehicle(Optional tag) { + if (tag.isPresent() && tag.get().contains("RootVehicle", 10) && this.level() instanceof ServerLevel serverLevel) { + CompoundTag compound = tag.get().getCompound("RootVehicle"); ++ Vec3 playerPos = this.position(); // Paper - force sync root vehicle to player position + Entity entity = EntityType.loadEntityRecursive( +- compound.getCompound("Entity"), serverLevel, EntitySpawnReason.LOAD, entity2 -> !serverLevel.addWithUUID(entity2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity2 // Paper - Entity#getEntitySpawnReason ++ // Paper start - force sync root vehicle to player position ++ compound.getCompound("Entity"), serverLevel, EntitySpawnReason.LOAD, entity2 -> { ++ // Paper start - force sync root vehicle to player position ++ if (entity2.distanceToSqr(ServerPlayer.this) > (5.0 * 5.0)) { ++ entity2.setPosRaw(playerPos.x, playerPos.y, playerPos.z, true); ++ } ++ // Paper end - force sync root vehicle to player position ++ return !serverLevel.addWithUUID(entity2, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT) ? null : entity2; // Paper - Entity#getEntitySpawnReason ++ } ++ // Paper end - force sync root vehicle to player position + ); + if (entity == null) { + return; diff --git a/patches/server/0017-Region-profiler.patch b/folia-server/minecraft-patches/features/0011-Region-profiler.patch similarity index 79% rename from patches/server/0017-Region-profiler.patch rename to folia-server/minecraft-patches/features/0011-Region-profiler.patch index 78cb6f5..b7d40e1 100644 --- a/patches/server/0017-Region-profiler.patch +++ b/folia-server/minecraft-patches/features/0011-Region-profiler.patch @@ -76,11 +76,11 @@ The X is the average number of times the counter is invoked relative to the parent, exactly similar to the D field of Timers, where Y is the total number of times the counter is invoked. -diff --git a/src/main/java/ca/spottedleaf/leafprofiler/LProfileGraph.java b/src/main/java/ca/spottedleaf/leafprofiler/LProfileGraph.java +diff --git a/ca/spottedleaf/leafprofiler/LProfileGraph.java b/ca/spottedleaf/leafprofiler/LProfileGraph.java new file mode 100644 index 0000000000000000000000000000000000000000..19c13bd372711bce978a463f85130f1e10202da9 --- /dev/null -+++ b/src/main/java/ca/spottedleaf/leafprofiler/LProfileGraph.java ++++ b/ca/spottedleaf/leafprofiler/LProfileGraph.java @@ -0,0 +1,106 @@ +package ca.spottedleaf.leafprofiler; + @@ -188,11 +188,11 @@ index 0000000000000000000000000000000000000000..19c13bd372711bce978a463f85130f1e + return this.createNode(parent, timerId); + } +} -diff --git a/src/main/java/ca/spottedleaf/leafprofiler/LProfilerRegistry.java b/src/main/java/ca/spottedleaf/leafprofiler/LProfilerRegistry.java +diff --git a/ca/spottedleaf/leafprofiler/LProfilerRegistry.java b/ca/spottedleaf/leafprofiler/LProfilerRegistry.java new file mode 100644 index 0000000000000000000000000000000000000000..cf81748afe993e486ce27ae65e0148071b029423 --- /dev/null -+++ b/src/main/java/ca/spottedleaf/leafprofiler/LProfilerRegistry.java ++++ b/ca/spottedleaf/leafprofiler/LProfilerRegistry.java @@ -0,0 +1,118 @@ +package ca.spottedleaf.leafprofiler; + @@ -312,11 +312,11 @@ index 0000000000000000000000000000000000000000..cf81748afe993e486ce27ae65e014807 + public static final int TILE_ENTITY_PENDING = GLOBAL_REGISTRY.createType(ProfileType.TIMER, "Tile Entity Handle Pending"); + public static final int TILE_ENTITY_TICK = GLOBAL_REGISTRY.createType(ProfileType.TIMER, "Tile Entity Tick"); +} -diff --git a/src/main/java/ca/spottedleaf/leafprofiler/LeafProfiler.java b/src/main/java/ca/spottedleaf/leafprofiler/LeafProfiler.java +diff --git a/ca/spottedleaf/leafprofiler/LeafProfiler.java b/ca/spottedleaf/leafprofiler/LeafProfiler.java new file mode 100644 index 0000000000000000000000000000000000000000..d1d259fbf6633ea38799b1519bca6deb623704a3 --- /dev/null -+++ b/src/main/java/ca/spottedleaf/leafprofiler/LeafProfiler.java ++++ b/ca/spottedleaf/leafprofiler/LeafProfiler.java @@ -0,0 +1,413 @@ +package ca.spottedleaf.leafprofiler; + @@ -731,11 +731,11 @@ index 0000000000000000000000000000000000000000..d1d259fbf6633ea38799b1519bca6deb + } + */ +} -diff --git a/src/main/java/ca/spottedleaf/leafprofiler/RegionizedProfiler.java b/src/main/java/ca/spottedleaf/leafprofiler/RegionizedProfiler.java +diff --git a/ca/spottedleaf/leafprofiler/RegionizedProfiler.java b/ca/spottedleaf/leafprofiler/RegionizedProfiler.java new file mode 100644 index 0000000000000000000000000000000000000000..6e9b04613c5c867a74fa4f266a8ae8e60416cb6d --- /dev/null -+++ b/src/main/java/ca/spottedleaf/leafprofiler/RegionizedProfiler.java ++++ b/ca/spottedleaf/leafprofiler/RegionizedProfiler.java @@ -0,0 +1,277 @@ +package ca.spottedleaf.leafprofiler; + @@ -1014,11 +1014,11 @@ index 0000000000000000000000000000000000000000..6e9b04613c5c867a74fa4f266a8ae8e6 + TickData tickData + ) {} +} -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -index dbb5b6ee36a54d6682b2a6d9389aee721b95d506..811479551bad422123ad1b09329e6fc8e12c7c4e 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java -@@ -1461,7 +1461,9 @@ public final class ChunkHolderManager { +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java +index aae97116a22a87cffd4756d566da3acd96ce2ae0..5a59099c4dd375f5f163751655d774d70c42699f 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java +@@ -1460,7 +1460,9 @@ public final class ChunkHolderManager { } public boolean processTicketUpdates() { @@ -1028,11 +1028,11 @@ index dbb5b6ee36a54d6682b2a6d9389aee721b95d506..811479551bad422123ad1b09329e6fc8 } private static final ThreadLocal> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>(); -diff --git a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -index 9e7e10fe46dbbd03d690a65af6ae719d1665bc6a..6edbe46c5c2eb74bca7e437474a6e992f45a04f8 100644 ---- a/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -+++ b/src/main/java/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java -@@ -1680,6 +1680,8 @@ public final class NewChunkHolder { +diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java +index 601ed36413bbbf9c17e530b42906986e441237fd..6ae7d646c1173c4835fa235c7cee21ec463dbab2 100644 +--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java +@@ -1679,6 +1679,8 @@ public final class NewChunkHolder { public SaveStat save(final boolean shutdown) { TickThread.ensureTickThread(this.world, this.chunkX, this.chunkZ, "Cannot save data off-main"); @@ -1041,7 +1041,7 @@ index 9e7e10fe46dbbd03d690a65af6ae719d1665bc6a..6edbe46c5c2eb74bca7e437474a6e992 ChunkAccess chunk = this.getCurrentChunk(); PoiChunk poi = this.getPoiChunk(); -@@ -1738,6 +1740,7 @@ public final class NewChunkHolder { +@@ -1737,6 +1739,7 @@ public final class NewChunkHolder { canSavePOI | executedUnloadTasks[MoonriseRegionFileIO.RegionFileType.POI_DATA.ordinal()] ) : null; @@ -1049,22 +1049,10 @@ index 9e7e10fe46dbbd03d690a65af6ae719d1665bc6a..6edbe46c5c2eb74bca7e437474a6e992 } private boolean saveChunk(final ChunkAccess chunk, final boolean unloading) { -diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java -index a587d83b78af4efc484f939529acf70834f60d7e..45f76aaaa7dedb77a83b4a2c87905bf9a099a93c 100644 ---- a/src/main/java/io/papermc/paper/command/PaperCommands.java -+++ b/src/main/java/io/papermc/paper/command/PaperCommands.java -@@ -20,6 +20,7 @@ public final class PaperCommands { - COMMANDS.put("callback", new CallbackCommand("callback")); - COMMANDS.put("mspt", new MSPTCommand("mspt")); - COMMANDS.put("tps", new io.papermc.paper.threadedregions.commands.CommandServerHealth()); // Folia - region threading -+ COMMANDS.put("profiler", new io.papermc.paper.threadedregions.commands.CommandProfiler()); // Folia - region threading - profiler - } - - public static void registerCommands(final MinecraftServer server) { -diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java +diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java index 4471285a4358e51da9912ed791a824527f1a2e8e..a18da3f3f245031f0547efe9b52a1f2a219ef04a 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java -+++ b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java +--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java ++++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java @@ -67,8 +67,13 @@ public final class TickRegionScheduler { tickThreadRunner.currentTickingRegion = region; if (region != null) { @@ -1107,10 +1095,10 @@ index 4471285a4358e51da9912ed791a824527f1a2e8e..a18da3f3f245031f0547efe9b52a1f2a public TickThreadRunner(final Runnable run, final String name) { super(run, name); -diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java +diff --git a/io/papermc/paper/threadedregions/TickRegions.java b/io/papermc/paper/threadedregions/TickRegions.java index df15b1139e71dfe10b8f24ec6d235b99f6d5006a..b1c07e582dbf0a203cf734fdbcd8387a422af3a6 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java -+++ b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java +--- a/io/papermc/paper/threadedregions/TickRegions.java ++++ b/io/papermc/paper/threadedregions/TickRegions.java @@ -81,6 +81,11 @@ public final class TickRegions implements ThreadedRegionizer.RegionCallbacks region) { @@ -1196,11 +1184,11 @@ index df15b1139e71dfe10b8f24ec6d235b99f6d5006a..b1c07e582dbf0a203cf734fdbcd8387a } @Override -diff --git a/src/main/java/io/papermc/paper/threadedregions/commands/CommandProfiler.java b/src/main/java/io/papermc/paper/threadedregions/commands/CommandProfiler.java +diff --git a/io/papermc/paper/threadedregions/commands/CommandProfiler.java b/io/papermc/paper/threadedregions/commands/CommandProfiler.java new file mode 100644 index 0000000000000000000000000000000000000000..dbc6ffd8fec4570de4abdb3aa0a16d0e0cc09353 --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/commands/CommandProfiler.java ++++ b/io/papermc/paper/threadedregions/commands/CommandProfiler.java @@ -0,0 +1,245 @@ +package io.papermc.paper.threadedregions.commands; + @@ -1447,42 +1435,42 @@ index 0000000000000000000000000000000000000000..dbc6ffd8fec4570de4abdb3aa0a16d0e + return new ArrayList<>(); + } +} -diff --git a/src/main/java/net/minecraft/network/protocol/PacketUtils.java b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -index d6eb8f495688a1b65a4c419aa3ee655cd8eb322a..f338b273613840ed366ab13b528373e7091631e8 100644 ---- a/src/main/java/net/minecraft/network/protocol/PacketUtils.java -+++ b/src/main/java/net/minecraft/network/protocol/PacketUtils.java -@@ -52,7 +52,10 @@ public class PacketUtils { - if (listener instanceof ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // CraftBukkit - Don't handle sync packets for kicked players - if (listener.shouldHandleMessage(packet)) { +diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java +index b28ff2f18ab7e0e3a61e37ee46048ab5cb7ab45d..c7214f0457641b5550b98dbd2863c1d637faeaa5 100644 +--- a/net/minecraft/network/protocol/PacketUtils.java ++++ b/net/minecraft/network/protocol/PacketUtils.java +@@ -26,7 +26,10 @@ public class PacketUtils { + if (processor instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // Paper - Don't handle sync packets for kicked players + if (processor.shouldHandleMessage(packet)) { try { + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler + final int packetTimerId = profiler.getOrCreateTimerAndStart(() -> "Packet Handler: ".concat(io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(packet.getClass().getName()))); try { // Folia - profiler - packet.handle(listener); + packet.handle(processor); + } finally { profiler.stopTimer(packetTimerId); } // Folia - profiler - } catch (Exception exception) { - if (exception instanceof ReportedException) { - ReportedException reportedexception = (ReportedException) exception; -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 25b4b0d531f0698338ffeac686013a4631d60c00..1676c4abb3f6f71bb7b25351aa58b4e127786fca 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -1713,6 +1713,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0 && io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() % autosavePeriod == 0; // Folia - region threading @@ -1519,7 +1507,7 @@ index 25b4b0d531f0698338ffeac686013a4631d60c00..1676c4abb3f6f71bb7b25351aa58b4e1 try { this.isSaving = true; if (playerSaveInterval > 0) { -@@ -1818,6 +1830,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop serverPlayer1.connection.suspendFlushing()); // Folia - region threading +@@ -1815,7 +1829,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop chunks) { + private void tickChunks(ProfilerFiller profiler, long timeInhabited, List chunks) { io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.level.getCurrentWorldData(); // Folia - region threading + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle foliaProfiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler profiler.popPush("naturalSpawnCount"); - int j = this.distanceManager.getNaturalSpawnChunkCount(); + int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount(); // Paper start - Optional per player mob spawns - final int naturalSpawnChunkCount = j; - NaturalSpawner.SpawnState spawnercreature_d; // moved down + NaturalSpawner.SpawnState spawnState; + foliaProfiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MOB_SPAWN_ENTITY_COUNT); try { // Folia - profiler if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled // re-set mob counts for (ServerPlayer player : this.level.getLocalPlayers()) { // Folia - region threading -@@ -583,6 +597,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -597,6 +611,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } else { - spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all + spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, regionizedWorldData.getLoadedEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // Folia - region threading - note: function only cares about loaded entities, doesn't need all } + } finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MOB_SPAWN_ENTITY_COUNT); } // Folia - profiler // Paper end - Optional per player mob spawns - - regionizedWorldData.lastSpawnState = spawnercreature_d; // Folia - region threading -@@ -609,6 +624,9 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - - Iterator iterator = chunks.iterator(); + regionizedWorldData.lastSpawnState = spawnState; // Folia - region threading + profiler.popPush("spawnAndTick"); +@@ -618,21 +633,31 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + filteredSpawningCategories = List.of(); + } + long spawnChunkCount = 0L; // Folia - profiler + long randomChunkCount = 0L; // Folia - profiler + foliaProfiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.SPAWN_AND_RANDOM_TICK); try { // Folia - profiler - while (iterator.hasNext()) { - LevelChunk chunk = (LevelChunk) iterator.next(); - ChunkPos chunkcoordintpair = chunk.getPos(); -@@ -622,10 +640,15 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - this.level.tickChunk(chunk, k); + for (LevelChunk levelChunk : chunks) { + ChunkPos pos = levelChunk.getPos(); + levelChunk.incrementInhabitedTime(timeInhabited); + if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot ++ ++spawnChunkCount; // Folia - profiler + NaturalSpawner.spawnForChunk(this.level, levelChunk, spawnState, filteredSpawningCategories); + } + + if (true) { // Paper - rewrite chunk system ++ ++randomChunkCount; // Folia - profiler + this.level.tickChunk(levelChunk, _int); } } + foliaProfiler.addCounter(ca.spottedleaf.leafprofiler.LProfilerRegistry.SPAWN_CHUNK_COUNT, spawnChunkCount); // Folia - profiler @@ -1706,67 +1696,67 @@ index 1a43c6fba5eea514dd6cf406f600dc254282da35..ca47a512452ae425160e30dc7c4a79f4 + } finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.SPAWN_AND_RANDOM_TICK); } // Folia - profiler profiler.popPush("customSpawners"); - if (flag) { + if (_boolean) { + foliaProfiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MISC_MOB_SPAWN_TICK); try { // Folia - profiler this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies); + } finally { foliaProfiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.MISC_MOB_SPAWN_TICK); } // Folia - profiler } - } -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index e0ad5a7715949c281a94f000e2df5cb2a0a99dff..07037eb601f9dcae2cad5f3e3d5f9a0ac142b68a 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -726,6 +726,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - public void tick(BooleanSupplier shouldKeepTicking, io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking +diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java +index c09099070117483054f438b2bb77ff48a81610f0..a4aec91811cd986333cf6a818f70956d59bb3240 100644 +--- a/net/minecraft/server/level/ServerLevel.java ++++ b/net/minecraft/server/level/ServerLevel.java +@@ -729,6 +729,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + + public void tick(BooleanSupplier hasTimeLeft, io.papermc.paper.threadedregions.TickRegions.TickRegionData region) { // Folia - regionised ticking final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler - ProfilerFiller gameprofilerfiller = Profiler.get(); - + ProfilerFiller profilerFiller = Profiler.get(); regionizedWorldData.setHandlingTick(true); // Folia - regionised ticking -@@ -754,22 +755,32 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (!this.isDebug() && flag) { - j = regionizedWorldData.getRedstoneGameTime(); // Folia - region threading - gameprofilerfiller.push("blockTicks"); + TickRateManager tickRateManager = this.tickRateManager(); +@@ -752,22 +753,32 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (!this.isDebug() && runsNormally) { + long l = regionizedWorldData.getRedstoneGameTime(); // Folia - region threading + profilerFiller.push("blockTicks"); + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.BLOCK_TICK); try { // Folia - profiler - regionizedWorldData.getBlockLevelTicks().tick(j, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks // Folia - region ticking + regionizedWorldData.getBlockLevelTicks().tick(l, paperConfig().environment.maxBlockTicks, this::tickBlock); // Paper - configurable max block ticks // Folia - region ticking + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.BLOCK_TICK); } // Folia - profiler - gameprofilerfiller.popPush("fluidTicks"); + profilerFiller.popPush("fluidTicks"); + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.FLUID_TICK); try { // Folia - profiler - regionizedWorldData.getFluidLevelTicks().tick(j, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks // Folia - region ticking + regionizedWorldData.getFluidLevelTicks().tick(l, paperConfig().environment.maxFluidTicks, this::tickFluid); // Paper - configurable max fluid ticks // Folia - region ticking + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.FLUID_TICK); } // Folia - profiler - gameprofilerfiller.pop(); + profilerFiller.pop(); } - gameprofilerfiller.popPush("raid"); - if (flag) { + profilerFiller.popPush("raid"); + if (runsNormally) { + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.RAIDS_TICK); try { // Folia - profiler this.raids.tick(); + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.RAIDS_TICK); } // Folia - profiler } - gameprofilerfiller.popPush("chunkSource"); + profilerFiller.popPush("chunkSource"); + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.CHUNK_PROVIDER_TICK); try { // Folia - profiler - this.getChunkSource().tick(shouldKeepTicking, true); + this.getChunkSource().tick(hasTimeLeft, true); + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.CHUNK_PROVIDER_TICK); } // Folia - profiler - gameprofilerfiller.popPush("blockEvents"); - if (flag) { + profilerFiller.popPush("blockEvents"); + if (runsNormally) { + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.BLOCK_EVENT_TICK); try { // Folia - profiler this.runBlockEvents(); + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.BLOCK_EVENT_TICK); } // Folia - profiler } regionizedWorldData.setHandlingTick(false); // Folia - regionised ticking -@@ -783,6 +794,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - if (flag1 || this.emptyTime++ < 300) { - gameprofilerfiller.push("entities"); - if (this.dragonFight != null && flag) { +@@ -780,6 +791,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (flag || this.emptyTime++ < 300) { + profilerFiller.push("entities"); + if (this.dragonFight != null && runsNormally) { + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.DRAGON_FIGHT_TICK); try { // Folia - profiler if (ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this, this.dragonFight.origin)) { // Folia - region threading - gameprofilerfiller.push("dragonFight"); + profilerFiller.push("dragonFight"); this.dragonFight.tick(); -@@ -795,9 +807,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -792,9 +804,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe fightCenter ); } // Folia end - region threading @@ -1774,44 +1764,40 @@ index e0ad5a7715949c281a94f000e2df5cb2a0a99dff..07037eb601f9dcae2cad5f3e3d5f9a0a } + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ACTIVATE_ENTITIES); try { // Folia - profiler - org.spigotmc.ActivationRange.activateEntities(this); // Spigot + io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ACTIVATE_ENTITIES); } // Folia - profiler + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ENTITY_TICK); try { // Folia - profiler - regionizedWorldData.forEachTickingEntity((entity) -> { // Folia - regionised ticking - if (!entity.isRemoved()) { - if (!tickratemanager.isEntityFrozen(entity)) { -@@ -823,8 +839,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + regionizedWorldData // Folia - regionised ticking + .forEachTickingEntity( // Folia - regionised ticking + entity -> { +@@ -822,8 +838,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + } } - } - }); + ); + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ENTITY_TICK); } // Folia - profiler - gameprofilerfiller.pop(); + profilerFiller.pop(); + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.TILE_ENTITY); try { // Folia - profiler this.tickBlockEntities(); + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.TILE_ENTITY); } // Folia - profiler } - gameprofilerfiller.push("entityManagement"); -@@ -886,12 +905,15 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + profilerFiller.push("entityManagement"); +@@ -888,8 +907,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe } - public void tickCustomSpawners(boolean spawnMonsters, boolean spawnAnimals) { + public void tickCustomSpawners(boolean spawnEnemies, boolean spawnFriendlies) { + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler - Iterator iterator = this.customSpawners.iterator(); - - while (iterator.hasNext()) { - CustomSpawner mobspawner = (CustomSpawner) iterator.next(); - -+ final int customSpawnerTimer = profiler.getOrCreateTimerAndStart(() -> "Misc Spawner: ".concat(io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(mobspawner.getClass().getName()))); try { // Folia - profiler - mobspawner.tick(this, spawnMonsters, spawnAnimals); + for (CustomSpawner customSpawner : this.customSpawners) { ++ final int customSpawnerTimer = profiler.getOrCreateTimerAndStart(() -> "Misc Spawner: ".concat(io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(customSpawner.getClass().getName()))); try { // Folia - profiler + customSpawner.tick(this, spawnEnemies, spawnFriendlies); + } finally { profiler.stopTimer(customSpawnerTimer); } // Folia - profiler } - } -@@ -1346,6 +1368,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - }); - gameprofilerfiller.incrementCounter("tickNonPassenger"); - final boolean isActive = org.spigotmc.ActivationRange.checkIfActive(entity); // Paper - EAR 2 + +@@ -1312,6 +1334,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + profilerFiller.push(() -> BuiltInRegistries.ENTITY_TYPE.getKey(entity.getType()).toString()); + profilerFiller.incrementCounter("tickNonPassenger"); + final boolean isActive = io.papermc.paper.entity.activation.ActivationRange.checkIfActive(entity); // Paper - EAR 2 + // Folia start - profiler + final int timerId = isActive ? entity.getType().tickTimerId : entity.getType().inactiveTickTimerId; + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); @@ -1821,66 +1807,65 @@ index e0ad5a7715949c281a94f000e2df5cb2a0a99dff..07037eb601f9dcae2cad5f3e3d5f9a0a if (isActive) { // Paper - EAR 2 entity.tick(); // Folia start - region threading -@@ -1360,6 +1388,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe +@@ -1326,6 +1354,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe // Folia end - region threading - } else { entity.inactiveTick(); } // Paper - EAR 2 - gameprofilerfiller.pop(); -+ } finally { profiler.stopTimer(timerId); } // Folia - timer - Iterator iterator = entity.getPassengers().iterator(); + } else {entity.inactiveTick();} // Paper - EAR 2 + profilerFiller.pop(); ++ } finally { profiler.stopTimer(timerId); } // Folia - profiler - while (iterator.hasNext()) { -@@ -1378,6 +1407,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - private void tickPassenger(Entity vehicle, Entity passenger, boolean isActive) { // Paper - EAR 2 - if (!passenger.isRemoved() && passenger.getVehicle() == vehicle) { - if (passenger instanceof Player || this.getCurrentWorldData().hasEntityTickingEntity(passenger)) { // Folia - region threading -+ // Folia start - profiler -+ final int timerId = isActive ? passenger.getType().tickTimerId : passenger.getType().inactiveTickTimerId; -+ final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); -+ profiler.startTimer(timerId); -+ try { -+ // Folia end - profiler - passenger.setOldPosAndRot(); - ++passenger.tickCount; - ProfilerFiller gameprofilerfiller = Profiler.get(); -@@ -1415,6 +1450,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe - this.tickPassenger(passenger, entity2, isActive); // Paper - EAR 2 - } - -+ } finally { profiler.stopTimer(timerId); } // Folia - profiler + for (Entity entity1 : entity.getPassengers()) { + this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 +@@ -1341,6 +1370,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + if (passengerEntity.isRemoved() || passengerEntity.getVehicle() != ridingEntity) { + passengerEntity.stopRiding(); + } else if (passengerEntity instanceof Player || this.getCurrentWorldData().hasEntityTickingEntity(passengerEntity)) { // Folia - region threading ++ // Folia start - profiler ++ final int timerId = isActive ? passengerEntity.getType().tickTimerId : passengerEntity.getType().inactiveTickTimerId; ++ final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); ++ profiler.startTimer(timerId); ++ try { ++ // Folia end - profiler + passengerEntity.setOldPosAndRot(); + passengerEntity.tickCount++; + ProfilerFiller profilerFiller = Profiler.get(); +@@ -1371,6 +1406,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe + for (Entity entity : passengerEntity.getPassengers()) { + this.tickPassenger(passengerEntity, entity, isActive); // Paper - EAR 2 } - } else { - passenger.stopRiding(); -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index c1574cdea90731dec4d24b15979209cce0c581af..a809622f43a45fd77bbb07a24f21c841a90dc07a 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -1258,6 +1258,7 @@ public abstract class PlayerList { ++ } finally { profiler.stopTimer(timerId); } // Folia - profiler + } + } - public void saveAll(int interval) { +diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java +index bcfe3af0b0df25d4b308b11a64c361da1ab3eeca..422e4cd1606a612056ae335d92786d8a5c46fa1d 100644 +--- a/net/minecraft/server/players/PlayerList.java ++++ b/net/minecraft/server/players/PlayerList.java +@@ -1163,6 +1163,7 @@ public abstract class PlayerList { + + public void saveAll(final int interval) { io.papermc.paper.util.MCUtil.ensureMain("Save Players" , () -> { // Paper - Ensure main + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler int numSaved = 0; - long now = System.nanoTime(); // Folia - region threading + final long now = System.nanoTime(); // Folia - region threading long timeInterval = (long)interval * io.papermc.paper.threadedregions.TickRegionScheduler.TIME_BETWEEN_TICKS; // Folia - region threading -@@ -1268,7 +1269,9 @@ public abstract class PlayerList { +@@ -1173,7 +1174,9 @@ public abstract class PlayerList { } // Folia end - region threading if (interval == -1 || now - player.lastSave >= timeInterval) { // Folia - region threading + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.PLAYER_SAVE); try { // Folia - profiler this.save(player); + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.PLAYER_SAVE); } // Folia - profiler - if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { break; } - } - // Paper end - Incremental chunk and player saving -diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java -index d23914a3ab3723d532ae867db6b954c843030f75..635c9c7a8c8307c2bc845a8e1f24aacb526a3c92 100644 ---- a/src/main/java/net/minecraft/world/entity/EntityType.java -+++ b/src/main/java/net/minecraft/world/entity/EntityType.java -@@ -412,7 +412,20 @@ public class EntityType implements FeatureElement, EntityTypeT - return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.tryParse(id)); + if (interval != -1 && ++numSaved >= io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.maxPerTick()) { + break; + } +diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java +index 49201d6664656ebe34c84c1c84b5ea4878729062..d9cc1d7e56c37d5ce92544edc10e89dbc89dd15d 100644 +--- a/net/minecraft/world/entity/EntityType.java ++++ b/net/minecraft/world/entity/EntityType.java +@@ -1091,6 +1091,13 @@ public class EntityType implements FeatureElement, EntityTypeT + return BuiltInRegistries.ENTITY_TYPE.getOptional(ResourceLocation.tryParse(key)); } -- public EntityType(EntityType.EntityFactory factory, MobCategory spawnGroup, boolean saveable, boolean summonable, boolean fireImmune, boolean spawnableFarFromPlayer, ImmutableSet canSpawnInside, EntityDimensions dimensions, float spawnBoxScale, int maxTrackDistance, int trackTickInterval, String translationKey, Optional> lootTable, FeatureFlagSet requiredFeatures) { + // Folia start - profiler + public final int tickTimerId; + public final int inactiveTickTimerId; @@ -1888,30 +1873,40 @@ index d23914a3ab3723d532ae867db6b954c843030f75..635c9c7a8c8307c2bc845a8e1f24aacb + public final int passengerInactiveTickTimerId; + // Folia end - profiler + -+ // Folia start - profiler -+ public EntityType(EntityType.EntityFactory factory, MobCategory spawnGroup, boolean saveable, boolean summonable, boolean fireImmune, boolean spawnableFarFromPlayer, ImmutableSet canSpawnInside, EntityDimensions dimensions, float spawnBoxScale, int maxTrackDistance, int trackTickInterval, String translationKey, Optional> lootTable, FeatureFlagSet requiredFeatures, String id) { + public EntityType( + EntityType.EntityFactory factory, + MobCategory category, +@@ -1105,8 +1112,14 @@ public class EntityType implements FeatureElement, EntityTypeT + int updateInterval, + String descriptionId, + Optional> lootTable, +- FeatureFlagSet requiredFeatures ++ FeatureFlagSet requiredFeatures, // Folia start - profiler ++ String id + ) { + this.tickTimerId = ca.spottedleaf.leafprofiler.LProfilerRegistry.GLOBAL_REGISTRY.getOrCreateTimer("Entity Tick: " + id); + this.inactiveTickTimerId = ca.spottedleaf.leafprofiler.LProfilerRegistry.GLOBAL_REGISTRY.getOrCreateTimer("Inactive Entity Tick: " + id); + this.passengerTickTimerId = ca.spottedleaf.leafprofiler.LProfilerRegistry.GLOBAL_REGISTRY.getOrCreateTimer("Passenger Entity Tick: " + id); + this.passengerInactiveTickTimerId = ca.spottedleaf.leafprofiler.LProfilerRegistry.GLOBAL_REGISTRY.getOrCreateTimer("Passenger Inactive Entity Tick: " + id); + // Folia end - profiler - this.builtInRegistryHolder = BuiltInRegistries.ENTITY_TYPE.createIntrusiveHolder(this); this.factory = factory; - this.category = spawnGroup; -@@ -977,7 +990,7 @@ public class EntityType implements FeatureElement, EntityTypeT - Util.fetchChoiceType(References.ENTITY_TREE, registryKey.location().toString()); - } - -- return new EntityType<>(this.factory, this.category, this.serialize, this.summon, this.fireImmune, this.canSpawnFarFromPlayer, this.immuneTo, this.dimensions.withAttachments(this.attachments), this.spawnDimensionsScale, this.clientTrackingRange, this.updateInterval, (String) this.descriptionId.get(registryKey), (Optional) this.lootTable.get(registryKey), this.requiredFeatures); -+ return new EntityType<>(this.factory, this.category, this.serialize, this.summon, this.fireImmune, this.canSpawnFarFromPlayer, this.immuneTo, this.dimensions.withAttachments(this.attachments), this.spawnDimensionsScale, this.clientTrackingRange, this.updateInterval, (String) this.descriptionId.get(registryKey), (Optional) this.lootTable.get(registryKey), this.requiredFeatures, registryKey.toString()); // Folia - profiler + this.category = category; + this.canSpawnFarFromPlayer = canSpawnFarFromPlayer; +@@ -1680,7 +1693,8 @@ public class EntityType implements FeatureElement, EntityTypeT + this.updateInterval, + this.descriptionId.get(entityType), + this.lootTable.get(entityType), +- this.requiredFeatures ++ this.requiredFeatures, // Folia - profiler ++ entityType.toString()// Folia - profiler + ); } } - -diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java -index 7c18c298e26b2920ea588fc6a16c0baaea9f6fe5..456f15e44e41d65338c0346594be2b0042b84005 100644 ---- a/src/main/java/net/minecraft/world/level/Level.java -+++ b/src/main/java/net/minecraft/world/level/Level.java -@@ -205,6 +205,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java +index 7ad7b3b964939f5e389d968aa812d74ba96c9681..a7ca4fef8c97f19425fc0d05f5b32d357ceda5db 100644 +--- a/net/minecraft/world/level/Level.java ++++ b/net/minecraft/world/level/Level.java +@@ -200,6 +200,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl public final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup moonrise$getEntityLookup() { return this.entityLookup; } @@ -1921,24 +1916,23 @@ index 7c18c298e26b2920ea588fc6a16c0baaea9f6fe5..456f15e44e41d65338c0346594be2b00 @Override public final void moonrise$setEntityLookup(final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup entityLookup) { -@@ -937,6 +940,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -947,6 +950,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); - this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new com.destroystokyo.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : com.destroystokyo.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray + this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new io.papermc.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : io.papermc.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray this.entityLookup = new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup(this); // Paper - rewrite chunk system + // Folia start - profiler -+ this.tickTimerId = ca.spottedleaf.leafprofiler.LProfilerRegistry.GLOBAL_REGISTRY.getOrCreateTimer("Tick World: " + resourcekey.location().toString()); ++ this.tickTimerId = ca.spottedleaf.leafprofiler.LProfilerRegistry.GLOBAL_REGISTRY.getOrCreateTimer("Tick World: " + dimension.location().toString()); + // Folia end - profiler } // Paper start - Cancel hit for vanished players -@@ -1481,14 +1487,18 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl +@@ -1498,13 +1504,17 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } protected void tickBlockEntities() { + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push("blockEntities"); + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("blockEntities"); final io.papermc.paper.threadedregions.RegionizedWorldData regionizedWorldData = this.getCurrentWorldData(); // Folia - regionised ticking regionizedWorldData.seTtickingBlockEntities(true); // Folia - regionised ticking + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.TILE_ENTITY_PENDING); try { // Folia - profiler @@ -1948,70 +1942,67 @@ index 7c18c298e26b2920ea588fc6a16c0baaea9f6fe5..456f15e44e41d65338c0346594be2b00 + profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.TILE_ENTITY_TICK); try { // Folia - profiler // Spigot start - // Iterator iterator = this.blockEntityTickers.iterator(); - boolean flag = this.tickRateManager().runsNormally(); -@@ -1517,6 +1527,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl + boolean runsNormally = this.tickRateManager().runsNormally(); + +@@ -1526,6 +1536,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl } } blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 // Folia - regionised ticking + } finally { profiler.stopTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.TILE_ENTITY_TICK); } // Folia - profiler regionizedWorldData.seTtickingBlockEntities(false); // Folia - regionised ticking - gameprofilerfiller.pop(); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntityType.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntityType.java -index 63c5bc786010d96dc121ee14dbac99253b3c8168..47e9a10c8d1f12dff335cda787ce720357bdd969 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntityType.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntityType.java -@@ -81,11 +81,14 @@ public class BlockEntityType { - BlockEntityType.LOGGER.warn("Block entity type {} requires at least one valid block to be defined!", id); + profilerFiller.pop(); +diff --git a/net/minecraft/world/level/block/entity/BlockEntityType.java b/net/minecraft/world/level/block/entity/BlockEntityType.java +index a2a674f18d7f2c2e50a6b25f9ac3bf4534275976..ace04a8904338a622bdcdf9140b0dec44d3c7790 100644 +--- a/net/minecraft/world/level/block/entity/BlockEntityType.java ++++ b/net/minecraft/world/level/block/entity/BlockEntityType.java +@@ -246,10 +246,14 @@ public class BlockEntityType { } -- Util.fetchChoiceType(References.BLOCK_ENTITY, id); -- return (BlockEntityType) Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, id, new BlockEntityType<>(factory, Set.of(blocks))); -- } + Util.fetchChoiceType(References.BLOCK_ENTITY, name); +- return Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, name, new BlockEntityType<>(factory, Set.of(validBlocks))); ++ return Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, name, new BlockEntityType<>(factory, Set.of(validBlocks), name)); // Folia - profiler + } -- private BlockEntityType(BlockEntityType.BlockEntitySupplier factory, Set blocks) { -+ return (BlockEntityType) Registry.register(BuiltInRegistries.BLOCK_ENTITY_TYPE, id, new BlockEntityType<>(factory, Set.of(blocks), id)); // Folia - profiler -+ } +- private BlockEntityType(BlockEntityType.BlockEntitySupplier factory, Set validBlocks) { + // Folia start - profiler + public final int tileEntityTimingId; -+ private BlockEntityType(BlockEntityType.BlockEntitySupplier factory, Set blocks, String id) { ++ private BlockEntityType(BlockEntityType.BlockEntitySupplier factory, Set validBlocks, String id) { + this.tileEntityTimingId = ca.spottedleaf.leafprofiler.LProfilerRegistry.GLOBAL_REGISTRY.getOrCreateTimer("Tile Entity Tick: " + id); + // Folia end - profiler - this.builtInRegistryHolder = BuiltInRegistries.BLOCK_ENTITY_TYPE.createIntrusiveHolder(this); this.factory = factory; - this.validBlocks = blocks; -diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -index 2c421ddb759eae4fbf2f2420d3b8cab22e854b85..6003e3495e61073c39928918b9d9f4c2e20f3a49 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -1079,10 +1079,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - BlockPos blockposition = this.blockEntity.getBlockPos(); - - if (LevelChunk.this.isTicking(blockposition)) { + this.validBlocks = validBlocks; + } +diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java +index f83cfa85678d288ece2348aae41d315660095ad8..78211c68bf52c0cd402fee7bcdde223130d49b5c 100644 +--- a/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/net/minecraft/world/level/chunk/LevelChunk.java +@@ -921,9 +921,12 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + if (!this.blockEntity.isRemoved() && this.blockEntity.hasLevel()) { + BlockPos blockPos = this.blockEntity.getBlockPos(); + if (LevelChunk.this.isTicking(blockPos)) { + final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); // Folia - profiler + final int timerId = this.blockEntity.getType().tileEntityTimingId; // Folia - profiler try { - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push(this::getType); + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push(this::getType); + profiler.startTimer(timerId); try { // Folia - profiler - BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); - - if (this.blockEntity.getType().isValid(iblockdata)) { -@@ -1097,6 +1100,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + BlockState blockState = LevelChunk.this.getBlockState(blockPos); + if (this.blockEntity.getType().isValid(blockState)) { + this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity); +@@ -937,6 +940,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p } // Paper end - Remove the Block Entity if it's invalid } + } finally { profiler.stopTimer(timerId); } // Folia - profiler - gameprofilerfiller.pop(); - } catch (Throwable throwable) { -diff --git a/src/main/java/net/minecraft/world/ticks/LevelTicks.java b/src/main/java/net/minecraft/world/ticks/LevelTicks.java -index 3fc6b4f93885fe447ed068bc5e0784daad655696..7d3067a7df48171f6c8cda12d5da6d721c085a60 100644 ---- a/src/main/java/net/minecraft/world/ticks/LevelTicks.java -+++ b/src/main/java/net/minecraft/world/ticks/LevelTicks.java -@@ -248,6 +248,12 @@ public class LevelTicks implements LevelTickAccess { + profilerFiller.pop(); + } catch (Throwable var5) { +diff --git a/net/minecraft/world/ticks/LevelTicks.java b/net/minecraft/world/ticks/LevelTicks.java +index 2caedf1c12e5a388f7b14989310a2137bc1117c3..07e0258e8c2c0c0788e76822e2477fb6f5bc4447 100644 +--- a/net/minecraft/world/ticks/LevelTicks.java ++++ b/net/minecraft/world/ticks/LevelTicks.java +@@ -247,6 +247,12 @@ public class LevelTicks implements LevelTickAccess { } private void runCollectedTicks(BiConsumer ticker) { diff --git a/patches/server/0019-Add-watchdog-thread.patch b/folia-server/minecraft-patches/features/0012-Add-watchdog-thread.patch similarity index 82% rename from patches/server/0019-Add-watchdog-thread.patch rename to folia-server/minecraft-patches/features/0012-Add-watchdog-thread.patch index b32cf40..2eddd89 100644 --- a/patches/server/0019-Add-watchdog-thread.patch +++ b/folia-server/minecraft-patches/features/0012-Add-watchdog-thread.patch @@ -6,11 +6,11 @@ Subject: [PATCH] Add watchdog thread When regions take too long, having the server print the stacktrace of the ticking region should help debug the cause. -diff --git a/src/main/java/io/papermc/paper/threadedregions/FoliaWatchdogThread.java b/src/main/java/io/papermc/paper/threadedregions/FoliaWatchdogThread.java +diff --git a/io/papermc/paper/threadedregions/FoliaWatchdogThread.java b/io/papermc/paper/threadedregions/FoliaWatchdogThread.java new file mode 100644 index 0000000000000000000000000000000000000000..258d82ab2c78482e1561343e8e1f81fc33f1895e --- /dev/null -+++ b/src/main/java/io/papermc/paper/threadedregions/FoliaWatchdogThread.java ++++ b/io/papermc/paper/threadedregions/FoliaWatchdogThread.java @@ -0,0 +1,104 @@ +package io.papermc.paper.threadedregions; + @@ -116,10 +116,10 @@ index 0000000000000000000000000000000000000000..258d82ab2c78482e1561343e8e1f81fc + } + } +} -diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java +diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java index a18da3f3f245031f0547efe9b52a1f2a219ef04a..056fb1ca7b07d5e713dcbd951830b14fc9025f4c 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java -+++ b/src/main/java/io/papermc/paper/threadedregions/TickRegionScheduler.java +--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java ++++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java @@ -34,6 +34,13 @@ public final class TickRegionScheduler { public static final int TICK_RATE = 20; public static final long TIME_BETWEEN_TICKS = 1_000_000_000L / TICK_RATE; // ns @@ -168,10 +168,10 @@ index a18da3f3f245031f0547efe9b52a1f2a219ef04a..056fb1ca7b07d5e713dcbd951830b14f final long tickEnd = System.nanoTime(); final long cpuEnd = MEASURE_CPU_TIME ? THREAD_MX_BEAN.getCurrentThreadCpuTime() : 0L; -diff --git a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java +diff --git a/io/papermc/paper/threadedregions/TickRegions.java b/io/papermc/paper/threadedregions/TickRegions.java index b1c07e582dbf0a203cf734fdbcd8387a422af3a6..988fe74578065c9464f5639e5cc6af79619edef5 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/TickRegions.java -+++ b/src/main/java/io/papermc/paper/threadedregions/TickRegions.java +--- a/io/papermc/paper/threadedregions/TickRegions.java ++++ b/io/papermc/paper/threadedregions/TickRegions.java @@ -330,9 +330,9 @@ public final class TickRegions implements ThreadedRegionizer.RegionCallbacks -Date: Thu, 23 Feb 2023 07:56:29 -0800 -Subject: [PATCH] Build changes +Date: Fri, 20 Dec 2024 12:41:13 -0800 +Subject: [PATCH] Update Logo -diff --git a/build.gradle.kts b/build.gradle.kts -index 2da91ed6363c0851e4c459188f5e8ef5475e0c97..8d2b5fec6fe27dca3ce01ba1ce50506179fc3b4d 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -25,7 +25,7 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider { - // Paper end - configure mockito agent that is needed in newer java versions - - dependencies { -- implementation(project(":paper-api")) -+ implementation(project(":folia-api")) // Folia - implementation("ca.spottedleaf:concurrentutil:0.0.2") // Paper - Add ConcurrentUtil dependency - // Paper start - implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ -@@ -100,14 +100,14 @@ tasks.jar { - val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper - attributes( - "Main-Class" to "org.bukkit.craftbukkit.Main", -- "Implementation-Title" to "Paper", -+ "Implementation-Title" to "Folia", // Folia - "Implementation-Version" to implementationVersion, - "Implementation-Vendor" to date, // Paper -- "Specification-Title" to "Paper", -+ "Specification-Title" to "Folia", // Folia - "Specification-Version" to project.version, - "Specification-Vendor" to "Paper Team", -- "Brand-Id" to "papermc:paper", -- "Brand-Name" to "Paper", -+ "Brand-Id" to "papermc:folia", // Folia -+ "Brand-Name" to "Folia", // Folia - "Build-Number" to (build ?: ""), - "Build-Time" to Instant.now().toString(), - "Git-Branch" to gitBranch, // Paper -@@ -173,7 +173,7 @@ fun TaskContainer.registerRunTask( - name: String, - block: JavaExec.() -> Unit - ): TaskProvider = register(name) { -- group = "paper" -+ group = "paperweight" // Folia - mainClass.set("org.bukkit.craftbukkit.Main") - standardInput = System.`in` - workingDir = rootProject.layout.projectDirectory -diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java -index 8f62879582195d8ae4f64bd23f752fa133b1c973..f5ff71e31516327be71924926938f1c9f0e503df 100644 ---- a/src/main/java/com/destroystokyo/paper/Metrics.java -+++ b/src/main/java/com/destroystokyo/paper/Metrics.java -@@ -592,7 +592,7 @@ public class Metrics { - boolean logFailedRequests = config.getBoolean("logFailedRequests", false); - // Only start Metrics, if it's enabled in the config - if (config.getBoolean("enabled", true)) { -- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); -+ Metrics metrics = new Metrics("Folia", serverUUID, logFailedRequests, Bukkit.getLogger()); // Folia - we have our own bstats page - - metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { - String minecraftVersion = Bukkit.getVersion(); -@@ -606,11 +606,11 @@ public class Metrics { - final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion(); - if (implVersion != null) { - final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1); -- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); -+ paperVersion = "git-Folia-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); // Folia - we have our own bstats page - } else { - paperVersion = "unknown"; - } -- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion)); -+ metrics.addCustomChart(new Metrics.SimplePie("folia_version", () -> paperVersion)); // Folia - we have our own bstats page - - metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { - Map> map = new HashMap<>(); -diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -index 532306cacd52579cdf37e4aca25887b1ed3ba6a1..29bd788ae8bc61c1e62a4f84b9e259931a7041ce 100644 ---- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java -@@ -49,7 +49,7 @@ public class PaperVersionFetcher implements VersionFetcher { - if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) { - updateMessage = text("You are running a development version without access to version information", color(0xFF5300)); - } else { -- updateMessage = getUpdateStatusMessage("PaperMC/Paper", build); -+ updateMessage = getUpdateStatusMessage("PaperMC/Folia", build); // Folia - } - final @Nullable Component history = this.getHistory(); - -@@ -86,7 +86,7 @@ public class PaperVersionFetcher implements VersionFetcher { - private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) { - try { - try (final BufferedReader reader = Resources.asCharSource( -- URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(), -+ URI.create("https://api.papermc.io/v2/projects/folia/versions/" + build.minecraftVersionId()).toURL(), // Folia - Charsets.UTF_8 - ).openBufferedStream()) { - final JsonObject json = new Gson().fromJson(reader, JsonObject.class); -diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java -index 790bad0494454ca12ee152e3de6da3da634d9b20..e741201fdbea0dbbc0e42313ebd33368014c9dc4 100644 ---- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java -+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java -@@ -42,9 +42,9 @@ public record ServerBuildInfoImpl( - this( - getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID) - .map(Key::key) -- .orElse(BRAND_PAPER_ID), -+ .orElse(Key.key("papermc", "folia")), // Folia - getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) -- .orElse(BRAND_PAPER_NAME), -+ .orElse("Folia"), // Folia - SharedConstants.getCurrentVersion().getId(), - SharedConstants.getCurrentVersion().getName(), - getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) -diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -index 774556a62eb240da42e84db4502e2ed43495be17..e9b6ca3aa25e140467ae866d572483050ea3fa0e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java -@@ -11,7 +11,7 @@ public final class Versioning { - public static String getBukkitVersion() { - String result = "Unknown-Version"; - -- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); -+ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/dev.folia/folia-api/pom.properties"); // Folia - Properties properties = new Properties(); - - if (stream != null) { diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png index 8b924977b7886df9ab8790b1e4ff9b1c04a2af45..c06126b92e36566c93b901637926703bbfcc42ff 100644 GIT binary patch literal 36428 -zcmV(&K;gfMP);WtinuKj$t4c@tAY?f!f62s6;MC~ znNkH6{%4hvv=wF*(`jJlm}#XowOPBrp69ve$2S>_KnR2`;q?1DZ~)Hv_k9kBgUgr@ zLI@#*5JCtcgb+dqAw+LqufauxkTAGcZ9Bes^|l{36fjN*fpzp%39^xH2qSzrj^@(84$Mh|k>J_NC;Ly=6UHXuVu#{b~ZpbpNVj?N;6dr)2k8$xa|%aRh3kV2sV3By2uK*GRK02oHHq(lgrGT}3F z0%EAZQFI~=3`Pv{P_%rW<#>r@j?;Cw@gK{XKmaa(pbHzMC5~hR+GYb+81tH8F zanGqu``%|>&eAAz{v`+PiLd)h&OYx;S=o6&jb(BUEsS<@>dud{J}Xw{_8<=wLV~0U zav|Y}2;oX#EkXn$##KW%^uhyWY`;1&q85yd;2WCjgwJ2Ll5QHSM$LjOxp?=yo_@s++rDQ`AHMmt{ly*IIOoELGa9sDAdK)p3K_DM +zNRXSBrWs+@0w(l7ZGa1i02~3}76`Ku#XFj01`TaHGWSYRhvk9gX5L-#$x^m{6A=IL +zoC)LuANas@e%HaTvT=hsBojtbGt7ilJRAe=S>5Dik2s5qcDC$4Z-H0-;JeYv=drZo +zLXtHmgpn*|SX|u2(VO4K*2aW7e>Nqs2nZ!mGM5wKif}v}S;Cc(9EGSVDhfb^SA-)B +zw@mR$m=h65hRB4nVVO`E<^Yg{A&}!<&3#Jo84P02oz3}j1*4wpsQ7VH^p;e +z*sid!bQZgIoy+{<0k-eFjFq|b7%y&jx&FNNYhTDe>Wqf}0B*nM>R+21?)rvBOApR! +zXsEV4n4LjOxp?=yo_@s++rDQ`AHMmt{ly*IIOoELGa9sDAdK)p3K_DM z)&YqSx>QrZRcYrZ$yHSLx>b^9swb$J1(b5W4X2ng-L;jfFPm}?n1@PhVtqr ziI5W^03s?6Ocf=$2>=&_nJQ9{%?MRyUB{rw7Ct4Hj%@@F-`;cX0Ci2r`g+)%jJYd@ zY|M;}%|o~sk<5mJv5GeO$%(a>!}JaO-#Wwi4`T0y58YMoIdTkw>dr&YU*U@`-OKmA @@ -830,328 +711,327 @@ zBq)Y_UrzM}lhm^PIRFB#2ma}vTKd{uO*4J2?7EFMOsQs1p)$M^xuU52LS<5tyS|A0z!B~T1;5Y)8HZp -zUh9YE!*I`C!>au1!lt}?^7%)ymXa9F0E8%U6cA@Hs@r2|t2YjT?MMEK&sF!xR;P(1 -zJxFf8OgT_&`%_^18f74-j~9B>_v*F_4QG7P$=~I&{g0k-!dKZ;dhG_Yv84aKQ7`JU -zJ^ehid=1+b=_P#o97{5v??~H!^zyIS&U_=f-+Z&XS28Q#IuJUNE}ApzE+z8$!_(s%I3_!)=jTdGmXzz2p&3&czvSwVkj_PR|SM`xDjT-m<)@wFKtJ!fY -z+A9f&c$RQF&Z%Ui9@S9nRjlxMs@)Z5_OxNu^|5JS^tNFPeEv!Mp+fj^Yc}Scf482J -z_jv2_UYgabd?1AMePOH(|ApkUIjM`|sON7?4||4r>}#l#)Nj}LPNV67U-a5cAqgk9 -z4hA)b1i?G`_{?Is2NgH3=G*Y_oV4G*#y>w?4I7fSpx2h|vD&hsqdFVmofnVkNpM8o -zEDOkF7WVse0CrXXeH^X&Y+X5Ugeg(@8XVq_7ngH%kQ4q8to@(w`VD%+t{VjBlZzMA{89 -z;%$e2aiD==VT$}%!%lBbY3xicyog$jB!Djxd7vpR6bXArR{Oqv(5MfWsJg3Yy -zcUpf*M1f-z9ik)^?H|-}` -zxbJl0Xc<(adaW`;Xc^eA&$kJ4EZWH)dOO+mFzw;MBfNjA5<1ZP>E3RWzD|&L1WdK! -z2k&T-AdM3|);yD$reQ{x9G{_#6R5f}9%tdjf-W#_wS$qa(*X;ot*Gkja`g1Q_eN^= -z`0%;Ho3r-6zU-m(+)f%v8KxzXfn20UBXua$j&hd^L+a{0lv^F@IS92IL#!_sffCl2&zHVp_~j(J1np!W5n69+~xPAJ6}_zBa%4jtFt9W -z{@f*=wRJ|ZitBopGm@A{J`xa&M -z)PY`TF0^X2?f!}827nOWNuI-}Ne-gU_A_rT89Qjihq3d_{Ugx}ge|kRq}v@?<-}sM1htR5<=} -zI1L1)$lG(bP|&c#@>`Np6h0xGHe-S%SWq_O*_rH`M&)M5xj9Un#*HS!PqE5 -zISo-XF(NX8c$<8iK|uH&>qt?Q&-b}D+Tgr7t>MFp&WJTZFnPZ1>|RTVqu7iauEwTX -zVJi3CHpH3>2eq__Ox+k#@Bzl=K|7STdhX7MT{c8Ce71~q9Y&PXH}*iaRuCUgMZj4H -z)QyHub -z_qnc(rzc$MCNk878`Sofx_>n{BwDNL?TS=$RO_S6!R*Ey=`(aG@LbB{HGQ+@MqP=h -zu&0VvO0ab!36xlai&*>Xc+6_xPmdSo9TasQ3?*TY!)%lYzD(AZ0HWie+au=#fiLo& -zU+O6Y`-6UchQAZ*C2TI_f~f(2hrMt6KE)jP36+(ZZfle23Dx>Inkk_7xY0&pkp)+N -z%^^0b-mA7bkD<)a8%J{cvSRJ2S;}#v9g(doR}TQ3QGy%7T$YWkQuW{|T0eu$!D%Gg -zhIpru$xwR_h!F-%c~|@zigH-C2m=8{D8VNnCdFPc6Rfz(8f#dDmuUW@`u=TQn?l6ex-ha;(`` -zrS1uS-(@|j8cS+#fW*WdM9k{Fbp6f|!@JL%Gh}@yEWnTjE-DYfVpx0s5?hF9Qzi@Lf>~6Pm?DX{;HP^Q242(r1D1_=jrbppWF;PQk_!Ls -zS?3Zy6SOYNhA^`C9Gr`$aM+kF+PqIpNc~b)YOTag^;@K{!LHyR#-D?kKh>QZn&JHs -z(S}LQ;l-T8IWrlT$vDeig`Pf3fs);`cyZgTesw;vUk*#=1ZlB5zS``R@)U;`I^|DW -z?`Wu5^KI6hZo2(M-a~zF#>3kiX?zjyY=f@)xk3s24jF8WN!RqnV5qMC{5IS-?p~l` -z*Od<2Atam`NRWyKlq2%T>WdXRFci|p)_QD!{us*BG6#&@1J>-ygf`d(+Yt%AR?$|m -zG2&h}ZNhe;3iL&t-&Bo~bSQvwc_uqFF*q*u<%r&3Io&Jc -z8X3Bs8jXqH@NHmV7BRmCYCHHs=Nrep*-}>qojz9eD&96O%Es8n$%gaSnOL~VE%6i@ -z&N;!@pfy%G7dw?+2y1|uMDE?45uzNTNB_7>aX);UvtG>N2^CK4jXJOIypMJdF8LKU -zTYqIdp7&|wl19M2-A~xsFLDE9e-nocdK3)_YdtcQ)W%k7bx|ihJbIc=Z5ZyZ^yh9L -zz(%H87tSJzNkw!4yq5hajBkYU#kO&cksLk7!K-`GO(iyvT=U{|HBlNQU1VB|)w$-~ -z!`vE~Br`P8J<1%ly9{1OIZc%XlCTOPAdcit!jhpR;%=Zn+J^5sT)?#vtC4a+pY5iB -zJDz5Ru-Z>~+fH$VWPdd~FVQ(AT}O25HPC_wANYArttZij2ISLx>m75xSQO6+R*;0g -zmeuq!90F_}HX%kFZpuj4@q)SDa3k?+Bb2PrSZjTt%acFjLT3$4HPduPZ4Sfv?#~)_ -z*x>rvxpNnXh2P;_1YzBnVcqa9VK{mn1MhEaK>}|FhPXm?dB28(cqh2Ag&XIAnbGh%w38mufD688Vg0{`stk3i+PA1e~X7W%o(N09G -z(V+dK5Ra`6>fQc$6V4g$Mc;jTrbmt|ZcfPDi&luFxnBGk{2GGnMACo~C5VWy9A^BK -z%9O|VK>O{=o7e@%H==p}Gh9?4J3)S(^K@|@-bpGMlMM#a6u}N>;hDZ{$m0w+?{P+i -zv!bb`WN0Gnx5bB0s;!iJeK(?O@&xo_Yr==8dbs9N^gw0u(XKa5#%g4gLt%5d9^x&bUp+ -zI*CuQXb^F)LGcsTq00ke&-aZbA7b?Ow}kNZFJJuWYsoo#JJ -zd^|iHd;0^2Lk8)L=de&2-C9OWIvMMW>WH|w6peAk$qJ4MH%Wu;|h=~A6+4h{@J3knK0*pJ@vag9^60=vvWcI&Lb_(VX2 -zy)N7VOA=(g{REg_f)&_ekDo9i1vl8j0R0zl47}1}4kDqz)m%np1-97YCtxX^_8Eb1U&2>fjdHvFw8)9n=PT=mS{*wNJdpIN5Au>lfU5v4<160teocH-d>QHxOk-7@IW}47m1u$uA~w=(B0jA`kk+l2DCPaOxmP~ndvI$ -zYkm8H%IFn;s^>pUrvz6NLyr<`Ro3Korg8A+&kfO!G6vn2h>XJTf5yvnnk!b`Vn06= -zO|u}x(#U)>eRZq|c{Ep6$&^P+2{n)IUvm+$hJWpRp@dc$Pc5;};;;?#x;>0!Q&lV! -z`h5GsX89Y7O)`a6U8!1!!`XBAGrQC|6pr$y?Yi~{n@H;dTYvsSV}Guzrbl=`^4UoI -z8~S7M#L3iCl4D&LZY7p{pxhZgK`flMwzluNP~zogXL!BoNYnrwRFOn1!FLoBg%hgK -zT2%$)cYHjmbW$l?<>3q586J5ELJKn1OZfwK6zZEGypC8YxWSi_nBA+Z_&{j*y_tMb -z6C6(s<>8a1YQkTymwXrrI?Xm2Z(XHsp-_~6s;*Hc@MZxKw?mh=jIMvB--jM9zQDT5 -z_##%J(qN!>z*rOmA{Oc8*IOL7NzRt42R1uBo;?F>^ndx{qY!eko1xoqPknBbx`jeg -zBK1!If?!CHwgxmCjWr7V)0^wAxV{-lm1HGp@U)MCwN_MeX3LZ*jEL+Um3h1ahneA%41;uV#JudJYWnF4<o}yV;v9^YzeZ9DJPbxV -zCaJz8JMuzS|;y@^GISocc73^ZoFw_q)lcpJX%zS -z?3#&5BtAW>(BMlU0{VA<|F{5pf0gcm5ueT^9u0&(YN^<63?O&=!S{pn(` -zLg_%W?ebF_1IK2E8}fXKJRN7Sd1NEd3=zE}{Ff-55EeRtg*n1;E66aMQp_*vt;2W-BHy(2b;Flg4sLL8j`MDJ -zAbfu?@{0+Il12eRII46kiNKmt05>iU=h -z$)Irsw!hHw5wf7*gjxln_O`c8!(m4}pSsbqKLIVrd=!}5jW}+WPlzQ;+_e-& -z?Dy<48J&+h3*@LUmFxqzh_g>rb^`iEl)hiDf5($dZZJpaL!%i&d@Buf3+M~(|w0IKfQ -za3X0Srk%nLvE~Ab9|gBtt2_H<(fw_Zha@}t^K>=dbE+8{uYX2|#N=bmI)Wc;T*rwV -zwd5A@i2kamPB6hHF1AG?W!pUo_~vz+3wdlN<%QSGe!5}^qJ59h?#udS@qUf7 -zv-9ZWcl%ZgYEV62Ov?klP4Ypq+COVB -zzbpQbKJ4p#FTFlCeU?M~M)FWg!L^__)A~q8ym6&0c0f4_^d1Qsf;q;YQPHwFTKQaY -z@}^_vfdLrw7oSN5$O~22BEUPFgd#kF2FBsIH_Toz2Nw=v^=tZBu!NT|Lp7qp(fZ&&7q@7C0rFJD6; -z(%|4PztN>6GF#&@{I1tbNIIaALQ8ulFL8_Y1vGk-QMPKSZe0HpMtxgqkoct%kuq`w -z#x-}Cb*!ytPr?%+STtAMUu{{K-N%@g062$UWI7UOQm3=mc9wknbhD2qEj-!b^P -z%oYhuwx~lumz_3B^a7bYyyq-71@Fw*7ULPhNJocwr5CvLRsE<~sh>maF=R1p!hO** -zh+7MfH?17kb@`xEls`270@5OICG>$(UstdYt%lJ^wwiJK8I1@$5SE2?UF-^CtL8@; -zs4{#zGZBM@8f^QW&S9I{2Bl9>kdJkdQs6??R6c{5q%l*?6D-aNSM(>Zc4);q<1&7n -zVSb1AZyvYG&77Xtb`dpP1hGZw+U_-uc%-;be&gSUcbi*hJ9V!?LnI5O4d&1TOrlrE -z11&b|=uC!5&O5GB^zm!T#ncJ-bmy8|`YuXV_zy3)jPFmR0m -zFLy&N`z42~p5XU|+fn|GAIE2AfPi3JbxB>QXQ+7$3m_ug7v}~qfMAh#5*_)0mSKO^ -z)R>_thix1PNC=^T>X5@o5Ik^s!>_0nb%0+Qu?l@fMu||fRMI8(eq@a06~$a6goXp4 -zTc(!CW&GU`Z?7*~C%0!|`Po;Y-B>bq8(=^Pt0w>CW3cOKf|^OmN3o|I)zb~mlpR!VZRWgf3r$DjB6U@% -zJ!v9xOZ<+LBarT*ahaknq^miC#W^ANPQ%<$&RHDpEBCU_M(sbvsugC-mYh-fO{Sw9 -z2eEARzci;On#5;xRA{kHL-zc9^rxh(B6&XXZ*i0bo|+5(tR}B*i$>CjH@i(J`<5N< -zm*!QawcKB`2qVVWN|!2bmCj+qMz_>lyQe41Uc6GYo8|ZmgRouOWH<`fPtitAzEwsVe{gYe@!;OmfY1hA^J^GP2Zh7jc0#tW -zV;K{f-a2?ll{FjAo&kmu**_ByBXvrN+H7%pUgwrk*v>}T<%nfg$(O1#f`vAf;$Wwj -zK4OU>ekZ7*cXG`zK^{1Jk?6U1Z!$nXMaDUqNo}Oc<%5yn3pWZ=j1+|nlh9DXMmgJp -zw$>=#X^n__>Lz7RpGg`FbOM{jMF-I&Mx~Gtq{nwcJ*VwE0OFOdSNksknPO9!AjUy9a^u}; -zl{GfA#HVPd@8C*|vf;gcdLXrJL?MukrGr%c^ -z`dR^O=T^5*G@CU0fpX=d2?dv}l#Z}rvrURI+yrK9#ndWZg69>4-LW#tEa5!`s{Zgq -z8R@zhQOojaXAAXjJW6}a5>uV1LhgG$u5JQ_EBF0C=A-S5S2BuoH^CBy68!ST^VMKp -z5t!x0xnCI*Lk$t%?=aM?bAC5Sk&8&Qiu@hZj7DiJ;6#WZd1Z764c#+#;>O(U9%lfW -z>suxqZ)SVz&lYoFmEAcgM7u2vPU$2e-Hjzv>AJy1PeOk$DMk`K`~^i^seLl#HX2s@ -z&vS?_kECyji(-+eKdk1750r)$2U(RhTgkZT@l<$kC`GSck-TzG(h{pKG1aJhxkqgZ -zItykNw;mTU?xiP8Q;PAKW4yNPGkd;&0<^_8y4rHh6AzZ1@@Og1z$t3+RoVK`LOEWpvj)dqZ+bn-ZI_R@g2TDm -zUOXS$8{AioF8c*Kd%YqEKoqkyqA= -z;h>9H=F|lLAffO3sj^3_YLHV~t7o60Afgf+&g?fx9El~tAP}$YS=MFe#gI{HMPF+3A4XgD2y6V7pZ8*{ -zm8;APEKL9wC2F|aO=CXGJo^TSmQpb}X_X3Im%nsfn-Yr)Ip(;&N*#Ay_m3?ila&Xh -zA6V?kP!$WD1kP``H7hg@QY|w7?54~1UuB*oXqD_ePJg`i3GPV0EM`;%joWPh;8C{7 -zYdmIemNAl|da??P+nTE06i%eXK303w@_~!CLz4QEZFdnUm~0^2U*Dh4GePdBsTQhV -zsihVr6*e(LETK(_Y=c5vXJenfn3=4BLe-LG|E6?ccR#tlx)pG=|6cC;SaBt^!li5R -zcPgX&c2MsDL}~N-O+3=a0$|oiwZm$c)<&SyI4_0A@|JEcP=7FY3^?#Of0zNSfD^&A$%$p{mSW|9&i*6 -zj(_qDpxvBQ=^ptttH-vj$9~Va*80<33lpe5w3*6)d5BABGb>2&T7!J8KM%t$O}n*W -zJo+7yk8gR<_bN{XJ|u{lon5UfZc>HMFjulERk&KL*jqG{qadfz)xhuQcg|aymb_Y? -zVYhel3JJX|M+K*)DQMX1IZ`*_*vfscZkpLiT)9gL=cKs}uA(KzRP<4d8#RxOLcE#D -zJP9@OB>kt#JaeOXaqm4Kc^GYiehxcy4(-(f*^`-a9<3OAl0lXjMU1hK=(Co4O{$8%UM|E#&*;l(B?QsiT24bqlr*B{Z7V`VuFjMMHlGAysOT^==1z=5qZQ_2R -z-1qLb)#p6A6j}B#jg`CWg~=F5uJg4=mk4 -zMbEFlbNEc>OXUCT5piF*6@<3E+@D1YQ`=LOmdxBa$alJ^s;X9Vnwl%91RCi4CyD~~ -zEfY~;r~^+zF4y_)m=yu>0s3+B%|pI?8RS^ct^$kP#XRzE>S#R+#~GhIc~p)Cii4cW -z9H*m(D~n23;e5HIw0*7&$Qv-cSkS?#GB%E4^9a4Zdg>n0VB=s|P>wkUFR@1Py;++p -zX;6LW6tT+67ZSct6f1(Z{;9<&8!$Q%dsr@?heJCLyu$kE{QNwMcpba!S7M2R5q^_F -z1m`x@%z~KAD3f^-kF`7BW3BU>kYEeLw+hLBNDUxD$O}Z7ySX3c -zb)wd!i4k24wW1_C2@tbyw%f-8qhJmP`&caiZ`w$^LAjZS5Sn#m^9yX>OCkC~g$Cc7>RooBAs^cU -zIlTk#)OXQ82-Til1rliQ85sNCA>X3OzZ4b&8XPSua_&2S?i?lbG}vKCBGdB|nXS>g -zJ0*+o--w^syM8BpvQ@ycNTP2WG0U^*#8-MC0N=cB;m&`}!LXiv%vI8XM1O%D865l( -z{g6XRuw=jeOMjz9WK|@yzj!yA9i}KA0|SHG1bi12L)S{x7e=_kAN~FN)m7xbSP^arS9Rd{|t-bdQUEl`8{54zNMvQ -zmVu~1GPeH>P7JxwZV*CX5cIQzmo3E{siDMziZ%E7Tl9Q4KN4`#}D9_*vX?k}pO!=)gn7_4Bb4bJT -zqDaOnV(7U1_j;to@cwADU9mBc-@BdBUmAHSzyI{7YGVPi_y~b*r-e;$%CQnDe?9;8 -zfw~{4mSb>(|FgeRQE<@@i1>JZxfuACaFBgBIQO3(xsqo~Se?tnEhWOPgi|!6k69%H -zBXMEw6q@;gX1q%5b}P&*(QhwjwHm7%kJPg>aV1XSsKm6t<)rE6*j;x$hUQ|hu`kT) -zV+}ADC0AEh_W-HRr1Y}-%^FExK~@Y^t(ANZuuEJ`p#^k<`-MWnN77L2@X=9jV+>R; -zXOQ`#-WMm65hugihkOgXY4OID(WpNU{=B$ZDs8X^hCKKCdranviTkKK>$2J_;-Ga6 -z>WBEX7GD$0K(CoP7J96eYCwj_U5&HrOXJSWm=N0MQ^#7X5>(8zV6XiWLH3_ZhnV9@qF1Eb95#jw+CTK -zcnC_X6?w!ouwb8!t?ZeXbU*`_*tn=L1`tKaPq~o#XH-LT(pdaeEr(+5o7_BF^YP^9 -z=s=xqrRelm)Z^rj$VCV;RnXkG!NaMn=)gAL=kN77LMYwzIqFtY;-;Q!9U{UKkl*Z; -zxmwdAck=k)YYlsT2UM!0spVa*x7IFL)Qt{!?hIJJcZxQPc`eiw~~Oj@Tz_oM0xtx3Lb{5kxu -zyBD?uz>WN#g_E*U&crG80;MCX-DnFuJuz_nIeOw6$6c?&s+F|L2zU?5G!ekeS!llo -zFPgW-3Pcj`}O?5W?ab_h%Gy97f=v~(o -zy&qFFhNcAIGR5-l!~O!ti+&6tBv?y$VCZ!G*COZC^Rd=v3DD{VK&YZV`0rM0q-=5@nOTtcx@ -z-`GfyVTF_)=xoTY-xG)BHAl-#;@k>0Kap5G)B~X77JGh`U;(W#+Xleny2|+?3X~v9 -z@j4(Oa(GxV=hv@n1U4Y(PY6pg$c&Ot;)efq)~zTw>;uHy`pS!hYaNUHxEYhbgRg4R -z+}+}7o`g)4OPEQ|;tiYeawTA$%HmQyClOH{QqjoI$3uxnpv;6|Hoy*8NC^3e-^$N* -zqqby_w*0S5T>t%`@v?z_`@m;FByBE`COSJ7m_~uq^-Bim*HTzq_chCA9jeHpXN(2n -zwRqW7h)`1w=SY~Q#F+#wWc43wU)ql>D-{W#MMi*+Rc<(sqj$1IsI?*Vo~~JX4iGFY -zSjVn{Ia}(<$;mhGkK6li&$laGUX5+PgyS=U#yks+rN3QUeb1{R0P)Mr;duDNP0Yns -zOl80yG--mz(9cLJmrW%6skc}}J*KYlL*%B2MMfm>8W3{uoeA1tCC=;U0l+}4z>%rz1`1Gu3qlk(DUqGWSub-M#qTbUB+d9M069OLgJ6ct8Id?;aM)g-r9s^V6BrQ}Q;SCiP`udh7DC -zQX$nG;n1i3pom{#4@R?{E?z&>^3sL?I2rH<%HigVl9la73e4N^TR>PE}F -zsi3VDlCxI}2NOm!ndIQSbW~gNZ4rN(jki^a>Fbq! -zqTN5 -zzb`nx8&_h%Jrt7lQxR^o;6yE0jUGfj6BHagGKnEIbC?*Yeh-mN_p6 -zlPomN>R(3=k&0Ki-xElR=54S -ziifTvyozV0-H|T?}miG^F_wtBpw#IDTI~O&zZ=pp6zI7~U;(eX9v~ -z%_Rrklp$gbO-9{o@iq>QY$8+WLWjtqUprlw=!9l&&i<-B;;B?gDuUYF04x={Q|PYo -z11qyPuIW6^msVN_PE8KdAMXa}bHL6LC^fQ9sh369#H1cfF?JZ}v`b#V$&6F1HA?9- -z8rMp!9QAw;KUupJE(75s%Q_j;=twh?gcLwR?pti!=J%3LhEmj*cmxEL#xOjNHpVeK -zJkF%}PF#r=gweO>TUjCt`~eJ7()chG!YE-`x^-8vG;ltjSQ*{>Exm{gthe@Wqr_;) -z0wt5sLc;HhZgRcM=_rjYuGPk6qTcdMHcs}#u#-NnrJ>ijEn2POpi%bVAyH$%NC@JW -z!9x#~LZ0#)=w{X8oW39GR&eJl^`<7%yQQ1IMRYe1(f#2jGXHCzX6=QT%WeN8>DptC -zHdSdtJVzrAI(JAmUV3k0>(|f-Xp$15@*N%7K>n%=8xkhRkB3QAUtf=ah{(e3zoSSq -z_gFfN{zLz`jCqlr&;1O+r(+F_Z0oUu;MXftO1`Y -z9;O;>OCXbj;jbt_S7jVfllzmVYhq*#nMM~j1j#8VFg%#?vdErxSYKI2XR#z#^jrF| -z60VzCe$K!`P7W(fGZ`zDbu=Gj|Fluc!xb3b3?KS{Jm5T)ZILV)F5q8zrZN3x1!?Fl -zj24#65txQAH>pypq52gcF^Lw8LkW1LoMwVHld&c-soCEOJ`7#g5|?z#rkMgkK7BD? -zv5)5fIFMR6Y+7b6;Ou);_P~PlRc2e$)>HPum(WG>M&1%61LbYx=>T1OuOHP=A_2Ml -zUJa0_6*NB&eSM@;e}$dm67YWg_RVCo!)>o6Rkzh4GG20Rk8#RK+5)kj -zy-EvI3s#yE&SmNou7&*UrnmOiQ_-c!M98x?rSX}WW}0I7mNW&~u)Vo_w^FUmMKUp> -z8k)=i)!=z!;!K+sl(Lhz*Vd$PEuCsaMon#-vS>REEy6K+i5a(<$=x(75fa)xG@=%o -zR1GQOG=s!5g(EG{JieFH*|kCh7=CEGG~xLSIY@MDuIiAnc`G2Ge{P@B(m6G -z!ibqfOA9p9!7d%@C@Z6Oj!J3yF%OjokW8F{Y}gut?pbEsRm(4LL??RqN~(!1fsK#O -zx=08kW?ie)L(K_4s$=P~flB)?RT~0m>*m4)K}Eg&^ysOF8lN -zUHK0Q90oI&{$mRN4;~O7eZ2)RYWiOSNUxax118K@axIASH?!$hWNTeE-m< -z9|d2NgO0N~GYHc0yR$}HApgS_*(Si(CRarIKe5r*$mNd^46r(X7=_aLFxEIYsbgvH -znrzh|J#4IY*379ZTcw$}tG6{QE7PnE4Rz`3%NtHKG_U~aaSk@Sx>k@6ej8+~c|Yc1 -zO&By$u_ANpr;D`5D&%W#Fdl9`BhvdZ5`UZwLv{1Hpy9lA>ut_To&@^KV8eBInUrO5 -zh52}zCbS}L24&AucCm_(e?;?E_ef|R)nd$k+BOlW94v|UU~blRLjQ0ZP-4r2%|3Mn -z>o)c|#p9v2Mo^cLhvg|xC^b2rL@3y2qYKOs?@M}`_`2q==9(4=kTk_PZBIhX-PBrZ -zr~4n>by9I>XJ-@K+>o8|G;Pd^cW)?r)m~#|TJhd}QmeX{jlF$FjtCHM4zkU<60>Zs -z%Hys(I^Fbs!^Li)<*(mdMDF~twQ_bC9DMnUdoO<&F-3^A3(9GW4BH?t7v#5rXa(*RMsaFXpk@rOtgnql#(8*wa~=>H&U=;wN0Q<% -z=~0Qf+>{j>5oC?u{)Ajpd<^k1GgPzB2_X=HLz81#(ra*Wz}OO-za_H(wqrv+ -zz0y`v?a{P}lFJz=@BUy(A)pd~b{ghG$JJ7r@AlNxR+>kt6nYMil7}v99Ja?<@UZ3T -zeP1&kMRSM{5+R84Gc9j#ct$;ly+^es_n)lXhG>_EcB%`8iYCWLpCv8)3~8MaxHrGc -zWH36`!Flt6p(JJsBEPqrE&gHZ?iZtxyx?@fgPx*GS)go(Nf7>mW01|;SB);nF)3s-o4wF7D!)tc}@L$K1~NQb -z#Yr2Tunx+&wm$nlh2CtbCg8*b5`pf^Y+pukoQ>UqK#>9GQek~Po6Bh899xq^a4oaN -z9sDuzXNM=T^ExFYu?oyxI-}8y%D;slDQ*$`e5+$KKq!pF-*Qc6*L_WdXk^K$IEown -zc`-GIjJQlcjeh%cL}$EWcnajL%v-BuW@70M(BzzY-<$NJlWQg2rNIpwvZO(rx6c;G -z_UBD)7Cj+GP^Rw?)N_Nikx*qcIPWa%MBy?TL-6TWG;|5d3z|f%7il*;Ac9f={o-sOWXfH2ow& -z+F%t%kw65bbTBi=kaCFWiK~y^%2iyKohma@H`Ql2SmxhqN|;zqx3*C&8_FG(8wPqn -z80VlP%Gr)DvZLLlMf_OsXDo*4wm909tv4{~9yF8NS%e&sJ#dPsVWzk;(a?)XK|KjU -zmKml2h#A~>%-bFxM<7`wSX>`I?z8$Ca++fy%HqqV=8QYYD~bl^Hz_tBVxFF`f!?T6 -z!OC4>a={OOkbTFV#ew8k2GrG${kNo(rcXXA_NWUqI*@?8f!7jnu3$bUg%u}bhY5Q));;cCAc0gS -zHeTk{K!dAfJ6}@_zTLUn#qe2z2>ZdYkePg(!A+9v>R>`9$hU~PuED*xe7hANwC~xc -zzMc7YMmZr7Iy0P~w;nbL>dml8nV{FL;+xs}qjWkGV5~K1I6DPEC&#K9z5E?@9vBT9 -zvo#L&#*9687;Wd0D#-M4&3F8(7sFq)qrj$;8%`og3#@6+hSB^|^UtXtP#SOBvdY^G -znH{rdVJq%P=QxzF3KPx3etK`XD%|1rVH#OZ35YdYtyAh8`vg5MWd_yI4)jPAmo4j_!3e<(RzCocf`Y+$BAs988hq->eMY}S?z>|#t_c*3a#|wBAi{r! -z{dW0rO)!J3t~1!Um(@E{ATxo*eW!!k$}$1~;aQ@PPH8`A%_SDxVmA)U!Hw)$KXA7$ -zqdYbaY15D(b-OI$URl0+-TYf+!wm}Fwiu|ApRr6t288`7`y!ZbjuZgH`OF0cwYAez -zqSFt2_caUMO6L4Xk>1Be-C -zNHX4bgVd8eU&h^$7@$FnL%%Qp$e+fZ(4dAotr#y7!RrZ>u)-F!F&*jOE8kA5rqU|| -zkg!kLmDxaol3FWgZ=YGJwHYE#cf7j}8z24RotEJKC)?r64}@x}^89m-1nf0~ -z*_bz@JP+Ml3hd*HWuOR@sNVh74L-Sw?LaYKwKo+rvy}#|aFc!~jT1o|KFR)cI+)Bn -z7Gg?S>|0zfR!%gT?WBBV*!!8j6W>|lJse7F&5>m#;ooWbRQhP@izf8nK?3n;AClTI -z6#M340iQgXluMzeY19}<(0FQ=O$wq@ql-?Y9&<2A-S>4Nw#z1Z-(eOaL`iCMI&1sAHP4i1wfU%}{TH10ti=qYU -zDz0-eM;$$6p`VP-jrsMCM}MB&A!(m3WE#f9F_{oZS)?8^0-?^g11w23S(X*2v9^k* -zKU)$N`g+?WLff<~UDFNP<{vgF`ivNrY!#|!D3|%nvN;axyiKQdEH}n|UAvW!JH2@P -z6TzqIA6}zL<{b4pMQp)4ffz(REKD*y3@}3^xF7ui{>6upo0Tm&dOIrt&>JXx_VQrn -z?-nhZdK!u;m!%$urT+S%i$tA>aj?l1`%j#jH%{|kdYyAos^NAM25jH<6TePW$nes= -z1!HeZ;$v}XEv4u4(RnINU~U}A*?wwCqU9m|k--nxsx^vf5AeRn$pVh?0Mnuc`C!uLu2;Vg{7)wfw`U -zX;*Wa;BHUq-TwcZ=lb=LAJ!W;9=uX-aQwln)6svvPf%SQ<1JdhQIPpzpQJ_KDid+% -z!(xv_|7G`-+M9p4uk#~(Mx)cG<|di_EPs|%wf~Qb+;nQM%q9N4&z7FNB6Z+G+^+MR -zj)|=QD8BER{dSeRdtd$LH*1N?VC!qI+*y}-;)|d!tvt|0N -zm5Vlct%>!zH1~C#{PXnRXO%R17-p8ep7o3QUvcWms)tYH$`9TvKIF>&@BVzZ?VI=h -zpErH+ydwvGOs@R*Hs)&kpXVngrCvTXb;0-d@xj~oPM7_l|L;HY`3dlY6p$IBU;poR -XXyugpZ1#qMfq}u()z4*}Q$iB}^Bg|U +zcmaicV|1Ng^k&Q(Hn!T>_Kj`Zc4OO48rwD-Gw*(Xv_UIGaL4*?7e3`t5-R2lSh^xqd84Cs4}W^FDQn9zijsF13M{zVR~<`0dB +z;hww3Rk_uLO*yyZ^N(arMN#SjFcHEi60E_fZug`IjtJ^LVtno=lKj+Jze{_WszRIN1X*HUTCH>C_wc;+D)6YYT +z*RWmTUi`Puu_Uwkj6-qwu_Ue*kO&$%=o%J?6*rej_Ock3znkGIb6 +zWm&yS2Z9LS7slFgUx+?ilDgQBdj7`ruw|IVzJ@wV{&tD)G@SPTMW@9Wl5lcsuU~6` +z7raw|%Or|@Pnlh`7!!rA1H$`p;zz}+92Tp2bFmKDAL`nrC>)<{qBHso +zvJ6|o^vMxL?frh4XZ`3WdH7s_NI0p@{EElbnX*!yp;Vtx&K&w$&to`sW +z79>enm;xWhu;ZKKIN}-h!eBKZM6j$9~*Q(SlE*i_bHS0o#tPY +z5-j+ww|x>h9%`RLUixM!e%f0qVAe5GH83X6?!#^_j-M@lO@*-aD%NMF2;Hg^Wgh@}elrPA3o_&(- +zeNyws4es~%;K1o+pfG(Z!G-nFWzl7)ejRNxY?M~uI=I&MYuz@4>GLH*ptjlQJ`LYr +z*KIIVzBhKHIDwe`X2hc@gsdjzXxX%b<_#kc$vIHFi2)-XM1=fs(`g?0)M{lcJXwp< +zBgIdDXM&n-=+_%;1a?sE$oeN{r%w=8tFfAlQopAk +z%wrVN=r>)oZ0w7^M~Xi~qp6lEaABgF(ck7V3Un;@cg|ODuD7@fw~OZ;^TQV +z$&4AiUj}-4;o`6JV$Y4C2G +z8hVweUdzl78hWzD|&J_)oRr2JdJP +zA&lca);^P(q@hQb9-kqNXVo9An7Q3NoAtyRQw-@JUDD$oluryjE +z3{zzbZhStP-K;xw@Yxf-B=4h(p=4f`k8p2DH$>qQLPR!szD!2|vJ}J`C6=EoRwG^+ +z;`ZDv1SGVO+?IqSxpxSM^_V~@2E+~dZQdl+oz;TP1MX+XXwugMy?Z5AoZ7#R33Y@T +zM)w4;9L0szO3>6i#4fV3q49@wu&`zcvQ!d8!m*dpn&7pp0Y=;QbiyOzhC7)Ki7tDt +zXaIqysWqx53ZgHlO)|YRDG**$7&F{0a8VEECY`3;yx)F>2;4Xr&gC;Iqiqx;orWkF +z8xk0Ty-mK&z`^~Fbs#S;;Qd@1ZFJh4R`+H>Wx$xgn>^oka;w9~QfR>rS7lYHG?D#o +z6Jo`Qg_-DP +zX@kdURs~L5?afF*73QF!=HQ?vIysP;FNCMBfA*}*&%$eDHh5L|y~D=C^v8(wdtcYZ +z)8Q|56BuZ~3~KpF-oKg|5Uf@Ac15Z>sP<9hpm(E>^cgr8dMxGhn7mnWA+JPK+EGR; +zCfK+V1&Xi1M6CUFIA+oJqr(aF3W_=ph7h;IVlqq&xJ=d(CqczQwL>f*A$gJW_|iZw +z&>!^cGyI)UH(_%jFMta0ci8K;?^D#C4_`@%@wP6R4qvs8y@ecdj|*ia7Exg3*BpG4 +z%Dqav(-_hWolzv04-3Ygs)Z~U$`R?hQq2Is2`RWS%z4?!GF2CryzMjCEFg_Y%K+yz +zG8tm;0X{;XG5?BBT|pMZ296(fGUtoF_$Ryrso&s;Cc!g3a;pYOn-tjPvW+1)iAQ)I +zaPyG(wl0MZUqz_Z!4+oEh$t>QIaiZ+J1|fQdfugliOCAg+6D!~3<-k#gA8N#Rk3@5 +z&u3Yevetsi3m`sm2Ntt>FV(PfME~wR=LFu+2@Noy&wr###hgP3mjy&H03re#97OQ% +zsZ;NtktNoC?s@G44Num-@G1zw*?jMf)dA`SWJHyI-Lp=m +zyv8V97L8$~?>Sf(&Ee27TQvEf=-_%~EL56_n`*ZRVS`=4Ka4&HGjr9P8e3rf;8BK& +z&0s~H!Z|V-mPt9vUj?5&%Sa@;XK~`TS$ylgW4|1h&I!<9c6_zoDdR2)FLErHw%Sow +zwc_2ZKizcAMchMvZ^6OY8)uiUt&RwA(`3@dzgihQ1MSrNi;ruq-C+?oVa@U0x +z(>^4ei3Bedg+!LX52G(u@W4P&3sdv45%OawU(*aQat~OuEf?Hi6Zi>__qCd)nw0_j +zvUwA_6WQ5tnFsl_AZNz8L8L*=L4?0A>inj9l&C`AC71u=H +z?bu{Q_=al@1+|F&El|te2eQB@?#+g(D(LjFx>w=0X;CJ|CQc@tuin_)Rd$KH$Y9P9 +z${MAq+Ns2`>_SLAfKm9~%?U2bK6>hiDEbdUD#NMd$hR*wFx8TxWVY3Za +zM&tRPhR$htT-*KlZT-SGBy4YD;6aZfAz^Jt1`=ABifztn#D_;u)2WTa-Bo^EKL;=o +zDc6Ov2x3ybU1B6gkFjv-UvyFl^(EFkIb4ht2Z(*io4 +zW(6^Rp7OMxVh73mYH?bkbxgXB=+TL>U^8OY>=P$oXPkGAmF?6#80T +z+e?24uzuJC8?nCu`7)ef&Nu8x+`0%wOB9wmZ^(+|&$!T80~3uj?NRH)aNhf~#vN9e +zem1VW#bKd$SZ4ufS0-pzoJ%P7UWdT@8yg`1+kpYLV153t;UJy~P8@7sO+#{ePIXcSgw}v2XayA<>Jxh}D)tMOGRgJY0QEJs` +z{>aB;ssVeqKi-6L#(PnBpPuOu<4Rf*GWVk8BdMCd} +zc^_!LU3n2YWBEk1?0<%f@MkB;t#h0%&cixNCZn@Lft$eDVl6z=l@Ga}k<7cF5n!!o +zXet^Q3;AyG!j)+$=3U>7D5cEf)=YMZ)jSZ?)!6EoSa3kU!3W2Xn`K`PqR|ML`Ju!A)|K2`l1>ErJG>o*qIC72B&jHYe36od@P! +zi)qQ9Y7g*>N;Y4;sSLlPxvM;q-Tzw2m;Zx=x>{mk0;Ed5zA?Hb1FrDGc6-;m+iSFU +zc22aC&R^-iyw5vE$D?GWWo7A5o@@>d3_uD92sGM_-tlsdQ?ZbAnF4LsSxDj&0TFgO +zFbB*@;0<;Y0es>tB&~M12_up)gRS(Ce{seFR$9$~MC8~S%gCTV+2AIiH`gndEW2~H +z`z|RK5KuxIccy|!;Bkm8puw0EcWFE{ij71G*o4( +z0~y!3%z_nq1kdh3x<;XVQS{_v?Q3|H1so1Z#CL|Zm2Z&7-mTO?&1?U-oogOAE4Cm{ +z`d4o(XCnWH-J^hx&?7X^xHns&B`u2*skUy`s~w=0252bVaZy(}U?e5?u>fG!UbYaS +z4Gz$YBX|~|U$??YUR+zxw2g5F_OJB7viI^}qx|ouEswnc0o{D4T~~|912EVr9)4P& +zS=*@uBmgy>GC)sz_8A$Iga2y-R#LKP$zyVe7P=4Vrn@Q)Fp6mG;Nall=^07<{OPT~ +zPDD~5M}Py>^H&ikOMCrXaXjFMyNuyNg$gXaPOE4z3=$o3Jt(guFuvAQbA?*MR;Dx}r~+zsgJ +zzCtQ*$r?UAKNl$E39K|(pdcV17*;zU{VtG7{)QDicnC&XAit07AxkJs2xbNxkEh-l +ztI=-hZ#0{5e0{huHk5pMKFXUdk-_HT=8j~#**>ze%L-Vq--ELbc7OqlEqqgfDL$7| +z^zia3^m~7il#>&4bK{s6W!C%o9eQ_nw_LRXoq&)qk2e`~Carh!_+@C+^?4E@nB?8v +zrP(B~aF_-3_5wx4#3EgX2f|T2iDX6dBot9e+}zxz-+7y;fop?^#LWumnJ%(ER<|F> +z44(0)x_-m7iZI17bV#w5<;|{V>IZ-R+z|XI2d!L0M$z{_~PzI|b} +z_>I9TkwT-USfkDEyuoB7YJe7^SUeW*JCd>d31w)Viag>w +zE)Hcnu_U(A@CEh^w;UM0IVsDf+yNUB)lCpiM=a>2dMSVx95URpuHBLGh>h8fgM&77%eeba~6*@>lA8=;7iEw2QP4d^IvP +z8fpiWc?lq5kxp*C)nS|HY^i2ov(x?A!{1u(mk%xyJ_nmAsx{Zt=LV=Ta0-O}2|y4O +z5yIAhMw5|xp3lvw|Ps$0W*KZd^Wlj=W@{AaG=^es3_){Y~Jis`IYYiWN~ho|DLil1qRD5 +zN6xAlvXG=U-8`VKVHr!k-;5Bi)EfnJRTtvY$;jR$#e%~lxMV?xboY;JA{IT_^y}D0 +zw1mJ8tVoSO-(}absB6M8b$Zqe)Ok0$OkaA#I +z48@e8TAlv;PmB6dbP|{7<%qt@Ea>I;PRL4)=M`_G!A40Y$Xy1Mum)I0#!3<77H4)u +zI6c{)TUsy&o^*@2H9Bp>QJA#S8$`zN?+@z^IIQL|VxYEQfVw~Oc}Wq!FS`G2T=aDu +z-DMYe(1$x=331oN(i#yV%?Q)lcY`}FpGRp*74@@$fX%pE+dAGOh5QRhJ&mcaXOhk4 +zLi_pirw^Zws;d9n^#IE8T1ypZDX|crNABquU?iL2;Ql%4Vg5cNBt}OJdbLKnEi|`g2q%v70%eM&7 +z5gdFefu8Ix3n54MC +zW40SGT11ajrrm5AI24T?-2$|VMsU%VX}AMmt>Pr~B}#An{>%QG>_1FQYV^)CExzx2 +z&7E_9c!fpiCLci|F3H*eM2DQQRtQp4>V2RP=KX3ZVw#OXuFxj$VDmM&HQD{*dc7301976VQyI69%EFvxxn>qC&Lo-`%ImvM +zCv>AXKPcD26Z_;m`1pw)uF6Mp=RnShU^yM81!?jbl!v#-kSa#RLhSOG0?yp1YB6Jr +zW=GrO|0zIRSHiH?DYiO+$EpdMkwz#4I6V(J12-W0+dAo4J*?nDQrFI<*}a92Y%1bU +z`RC_4tyg7>R(8{ +zA8*g?PWv##WoF+p0bJe>whg#+(1_+A+)9HS$|n?k;(r=Le*vR;57rn)2& +zEkD8KBSZm#3Drt?t!*#s#>0+yUNysIKRg=t`KSOcSHieiUP0z8F_$tZ(ciPnq_o~@ +z%-{zhbs{i7 +zt~8q8%WO|MF(FE_ye*bl_-@NcA!S9$IMb6x0`e_oNF!hy5a)H^H)5)t(}ek4a1Nc~FF4@f;5aO%aB&3O%B8NuMWWCzYb`d> +zQ-&3)G|5M|pzcLy>pA(p=?3&XKn+v0^`HNsS?M0eb+60BxF|&Y{?>MI^x``)Vp}1V +z;<0N$BUc(0=p=y>zD3k_I~ +zMC>T|rn!T!wN%lqT@ +z&Afsj|04$m&CH2M?F|6yeqb+e`&JWTP^~~z(;c>5;z6RuFKe)%3j|YzeZB9c)5E08 +zvX9?L9%?PT7Vu(RAIXR}s*=I*@Qp<*vA{&7B2uwdBH$_I`33U5di9weG|3 +zx-Iy`1L`R>G-q<+w-{f5qc<7ls}^cT4Y^Qi+meHXFIDgqkt0wpdBZGY?LB+q9&o`T +zd18L5%R+44Ml^UNbEw58BXP#{+I#J1$;VGO`#6Grd<=RWgP+T+ktE6H^>C;%(}szj +zK;wt^oW!yG4Fz=zm4zKw@$Wdo`VJm=879kp$F&$uMP_qiKSB4L@SV)g55F9Rb=3ocrK>iqIRR9n!X0Do*Ldi{9M&^sg&T_TZz~>`tbXc$p%%BI% +z#MahUA?U0t#2ZA4_41*w&52#TXU^_G4)$#uGOnpIb{Gs?Bge_xP|beH;cUSBec^gk +zu;a`And#3j5LZ)LALL9lQ0{$A?tzx&K6M(;#M))7n&`7KTkT>KvjI7O4?mTa;X`81yn7WAir6 +z^Dv#2{~#3{X=5gyP*2v`3yoLJl)--n2rC2}*3n8(L~4ohHzT6QbyEu{!K3q#&p9Lp +z?3#RrZR0JWoh5V%Au%m2?uSB&RO!i99khjDd#7P;NaxJ<_f>mYXQOtXqBZifoWn1d5WC&hmG;&Gv(>!l)|)selJ-m-pz9Og@*rA +z%Xl~n+gHI_Rjy513U_dEaq-~ZLm%H7RpVbREoW=Zu*D?n%JFyy6(v}{RCOy +z>_wu--o5bv-4rRuWG0oN3a2+(f)C6nR0%>9HdI1mB`d{jE6Q4vSf>>{@~N-bGMc6~ +zn=1MB2?XIjZuOC!s@-pN5{60UUw-L4f1L-3Ohud?4)I$4Y&#w^A*ij(1$$3|Vskv} +z#YKCOBnHKh5QN8fd|k)wI{^HZj_1!`{L&>R(m@P^tYk*J)5>eCrio9{j>kWLDCGrM +z*O<)utCbjQiH>aHzD!~>SNyzV|B?uyizaR*!v`(g6N5ks=aSqWHk#wzbQOx2Ehc(>s +zfl`oSK+EzLOKDeK?n#pu;5qF1g-8bXyN##%K`x2R14CxOh8w&P-kz4U}>3Q=A& +zwAa>sCXe?|fR^Y+S9_jW;=!_GK`1Bc2HY6Y)*s}A##+#}239~LV&Q~wL&4n_6^@vW +z;nGUYJ$5-C#kJr2EtD&Ty$t-H)#GyT->}39LWB1gdo%LwqR8{YbRBL*-FCEc5iY{; +z#TpZ~y8yolNKuWi&enqz%<*)Y)j#ff)9q1ezkI|N7|zr3b=T|b>+m?)d% +zKJ;1@L~w8ZQn0MxZS*{ew-;Ohn^Jl!+U{m|QvgB~tai**t#d>0E=CMjN*SZ+36QnO +z4NrSN!Cd>9SLf?=!Hjh+ek}c}ND_U`vvi9(MS>7nGZ*lPm%4(7(bhfuTHod8y%;N{YO_KMV}N<7D)x5snD;XG +zzCOH#WK2$4mAvQWFCCZW#F8TRInJ+=$6eR`V~dES6+!6-=6lkVCHyCW^Bb-$@=b%3 +zi%hxQwAp^EOp|zR61~UikJsM89qE@P3@X5J>+K)hO6K`Z$80UqhLV&|mVt3wQ#G4H +zi4>T}s*jr9pkN+B@=LbuMW8^kzEFQde*yOdnXiUws9u#OD8dYzm?0F`qCm7pBCNNz +zOJB@PR!5?2&9Zw_Jg~i=TwmStKiYq1_@$ +zZKB*^u}y2o({7rV#Nl+8$2T5 +zthMF3X`+*;4Q-~&-*4NzrU=7>#}h=jB}<^tsAch7Ac~Vq;V7 +ziknpCHOP}_P8F&VE%6e`WG~EVa?$ra`knKZrYWbIZ_w@4vO+{B!(Pb&!YhY8pCfe= +zjxF8x>Zh3;#gw`fu})grVJcf=Ohg_Xc9m?(57$!NXQ#N%;Q{V}EjtmA$m<@Ie2(h2j9T2Xq=0<2R#daW&$ +z85=lCIqjn+?h$SF4u|?#DOOKg9>2c{9GSdlh{<(WR;Mb+bxH>u95roevUiqSmcdG* +zEL`{Qv+mA#hjLxuC*l?ROBgDsPYkDNU%;m09$2^ni=SVA=kS_) +z_h->URCbhQr89T-a-Gg9Dk?P`CT8-=f%@A28AYMmma&Ks#DNDsr^|eI%nHBQ0Nps* +z<{@u^G-9krSD|^{Vm?_nRkW_T!;E*n95To#4sxn;9FH2W%&T043S^Vg_Bk^^&J9*H +z=-^Zd6GYUG(CMkA?hy<&4Tc5fn4$3ys+ZiGw!07qHH1zPDzAJY;{8Oj#B1-LTAZ>D +zKqX)c%j0#o|H%z2zdkxYKaV6<&nEMgP`q%2&v+2dsa++rFeWoOnf$VkCAY6|8|kw{ +zdwe(maC?oeGlx#HVClH?)W&QZ`+=l3PIeQ%9cb~nWxJ9)YD|MPt`v?0-3bMcbZ<2Z +zG7xSnH{QoOr#C@?R{C$168|JMfCxcPAVuEhewgQpYO@AfbP3Fw+|Vi7h~L@$6ydj5 +zyf7_h9Rp$0Gii0mkT9xddqw>hIVCXV203~$D~swIj_)TV=zX)@-tK6Hb66mM;EywH +zsMV;{!i^8fvae3b)iz7_f6$4yU2i-b%Bh|o@eU2$RD^G(AtWlyl0^8dxd<9 +zCi_xU0%&wFugtmc%-uOk=xMY?lR%{7BQRZ~b8}1<=DQI)v2*#3|70VNVV*?SK4O}0 +z-HEICfCoyTwy@{F=Ac>4KISQEgQLDcj|>j}hzn(*RSn +zZw&u6!^Z2~7ae&u`+{IHYm_vxJJ@RRZ!LoCjQ2ecK6E;AqeyJZxfuAC +zaFBgBIQO4DawgA~vN)BCS%`;S38kn@9kWOTMq)$V$+z&4nDQvH*{(1#N58$C)v2#; +zJW|ch#FaXRBNNj6mX)HNV{_ScADWB7#Jn(Th}B15lvrI|-2fj-=SL1AY +zQrI&y#`tyxRIyenc$G7)m}|d;5&h;8q8?ap1~7v{vEXIAhojO|^XI$6=K!f+>;5yx +zJJXiq*Z?mW;Ak{?4<=)9$$a@6Q*=1_%}Nx&bGA3oqS%{I)k3y{#DALAzrPw)h(FU +zj}8a8Xte($dBpT +z_ZLeg50aO#zhmy?M*+dS#c4NyP>CZSyS+OOi>@2;)lr;&A$)(OEO;kV+bz6O57by +zyW>9>Ij2^Du|A83(r~$46%S7?Ancv(6R +zJK?TL+k$9p$KMJgY}hdrTzyS}0it==hvU?8YM**7M}l@-W{&s26~NM6 +z#U8(RCX-=6Lw%{$D&=aKSfE%aJ<__RASP1DaZcJPva<-yi3NH#t$OuNk6wlp&CD~1 +zanJ|7AhF;l{a^)Qhr_9Bo;2ZG8=}0whx#r7zZ6W`Fs5 +zJEbvhZVJVsORu$w4Y1HyT1E4?Vka&kS*mSpBuKM>OAT~3W;g7KLGzfQWF~QJ1)H6S +zFCOXwP_auqzKSygLBPB}EH;Q1gXb@Wm*lZWfM<8NWGZM_*$8Ze)0+^IpqCyco5T+P +z>!edzc-RMsx%H6~4%a*u{&6!V2Xf)f8oOKEEtBAhvI#TkSv+Ago-TMSQ(2q}=S0FP +zL(1v}1vp6Ya1@zfO!}Dq3ke|~@mmFXu2dHEQWpO$6X$;c8V@V*w>NACSkmSKF-THX +zXc85Wu2(uhx0b@}vaeA-YhO(oJ!8ZlugSxzOn{tnI7h@dCB`UVE~EEY_ww_|qDlb| +zQh0>qvDy{uar91x0J$!N&ch{3*B*?y730`NAZJT0IXU?T1Oo1Zc+QnB&!+ZYLh%_v +zV;)6DQs1sEzvoxu0r{lou-yG%CgwotYzFK>vqr!e>KRehvaz@y)fTge`_wgV2*|2H +zVl|vbxEx$3ymn~uGqN65%FYqJ<_)*Uqs49;KY2h*(Xa?Tk7AFfl-xf>irJoUyL*;0 +z19&1GQV*5Ni~#kTnaq0ymCiLjk_=0q&=&|cG{r57n*6NwV6zJl5K*ED&DsZy8iEL_rr +zgsLXr6cN9-S7dCo0TeKI3ByoGNNBIG{4b4m4=LB^FstU0B?!6TBZ1v~zn%e*Xk=B) +z@_rySE6iHcIxSfbe^sRAkjZKFfR!7A5uNa|Q%HSV{);)`X_I$=Rz#g9)RV +zjIuDE+A6IDHt@Noy^%sCnU|?kL3tCMU12QN7688MFeYr;%^{CT)BqX<4rY8gFNo(^2<+x6~@> +z0Y;8%xJK3sk3si!JoTyNPRqf>i>%mkw_b{g-~}-aAljQww_S1L53kdn=uMDZM5$#ndk +z&22o*u=b&^trc3UMGkzzrL*~$;t?gd{w8WCC+z$)6{fY`v4CL%;?|JZtR3}&oLz8* +zT?G#HsX)xAYvWho@h=pJpzsjcWp0%LD4s08onG)Nb4)MY=8K^XfVvcKVvP||0{idF +zr>Wx=dX&);ID@-|u5Y#BAa0c8rW_t)Xfo4c@By|jKCCPsr7DjJ6t;eTIrmF;CpM`~(ysWB=S@seY-cC;IYp7eGp3%$l} +z)oc?3jDrN<0qs>+yfj#>o^%eHp8`K^wUK{qUM_Xl#K;;VHK+>&$DqLQV1~BoxLuBrt&0}DAhEKn_^ER` +zz-29QNvC|8F%an87xNYKcn*LCu89T8nVkc&?~&O83)5GbY)slt*#=)i7s;A_C=2r7N7+fk`X1KngTDCyUEafq@X5m_z1=DeiD@Q38P{+Ou8AdwgrjC5 +zajlbj!7Ae^jZ~9GGnmvF%|dV*Siz7~1$lG}zFHP5%BV8TD09lQN!w79WRZ;`=PM(z +z0;YT`0PcRb5SM~SQ_OKjwTc~?W_G_IPe||U$;Um2U%fe+7X>%Nvy!xcXUbbT1miw0 +z=$X7_W&m0ay!h~`ae>C68mu@al*ia7R0saqO=sn$tE@ww372nWLhU^>%{WE>Eoln8 +zaeH(5Zly+xlW1Z@B{Z2HqS52V*oh`BC}k&quf19RS}N6$l#0qGWzl9DQkZ@85(#UMH4E) +z!&hPrOmR$HRF*}2C{e3A#U3h9d)gN68^|>O9=TO4Ga~u#5kl0}_*QP9IxEl~Ce;Vj +zS3zvyQ+p-TKYiV8z>J$akDBH=i$W7}&)8|aN%_17$7$H|;eKWRKgAtrMwoyE;#kJp +z>iJ{R+d4p$2q2;Y5EBQ7>@E&mk*MzVW>!EDsQ9Pd1Icl|=0d^U2HU!hP6MLe0bwp2 +zA=U!|OQM?{{^8dU?o^&w|I~Y5fw~zw)IT&*mzBRUy1Ljo^-=Z`fvN|N_JgxG~k*Hc%03VftQZkoi*AD{-11-bt2%}_=-R;7ZY`jOzsFyAEWb! +zVJNLPL#@4|8iv-c@m4Lu!^Uc7?VOsDWty>@T6^QN67|~9P?w&boWVpR2)d)gI@s*$ +zT0uPct)H#x^_Y(_q2El&g2<(pF8niAzCde(;c)XAp3awn@Z)3{qMO$l1?#O_cXL+a +zB+yS96Q;w{xIBw9%-h2xp$%a(D0`Noi$$31BbukCM_lu$4sG_+rWsH9U`eD0eY3t3 +z@`vkyB5OW$_NhyNPE(&_JPvYO1XVd%SiaJPVza|ZguGogD*p`OzJ!Odk4wR7o=G7; +zQFEN*_9WQcO`Vliy5G@VCnZ;Qb~fJ44e1$o^Tw=L_lA;Z-8Dw0CC}X_m5Q_J*xP61 +z2tVQGAnU9PA@k;{9QL{c=-~c_joC`W*8qxTI)7}foE-)SU;g6SD;S1P5oGCta0DrC +zGXz?khB$Fn{Ycwuk%t&RTyJ!Mz8mnC0U+AYu}PkaA-t-gE*25%;RVKNKyWz!scpu6 +zZDKFBX5S4#lCQK!Ip%UxMsP%cC4T!8d`;mo#M{(B)h;Ilk3UVA`-O^+JuQDuUnt-K +z=jEH2NuzvVs7mGT0rJ;Nz54;;pVk-{O`o<8h5~yAG9cx)%sJ+#d0-B8j!9{+{>1@9 +zYiz-m^g@6wE8^*umZD0JhIN!|&Ok-?2XhJ@B|oI&FfS^$rs90JhlZBoJW`e5b9j^- +zWO>uD9oB-o4QKEBn$akVeT1MeUX-s%#m~lPXZR!_h7SU~%Y_rx{QlrO`$o+{oUb!PIS+x5N +z+{O+YLa6?IE1#&A?RMZ&J}!O!vj>Os^y>J_BMi^Cu8;>FP)!5eagStg`4k8`f<9)s +zLv>uniXJHc5tD}2a*xO+UycHT8lGykAS#tq7H&?$Q|yXO#aH{77;M;}%#Rn*u_i#Q#=kFoCjB +zxM)O)sW@_wx=K{lJ|iyESH0iv9Nr111eP3eEA!SenTb%U12{RS*7qj0=;%^Kd#QiJ +ziYTEU=jFY{zWsSqmqmw<7L@5T1o7NxWhht`9gu$(b|QZnjVAE)D;lyC=>~hv=8piE3T9#-QVKCSaq-q&xr*zuRbfKtru+;Kkp5Si5+<6{tz}rp +zigZWmiiYYR#xdxCbhhJz=wN$k9zPcR8H;AJErv2><3*Bm51h&CEJlpT9yo5`1`w{pnaAJ%0k=ISmg0E +zo$J6^H1-w0!^WV5w|yx36dtal`WN}DGpD-gqYjDTfjIaLtR}xxCDSo6v=}KHRM^9@ +z&T;nw5x5ee(K3%Z3QQF%sMId_cIRpr&3g$f><9ZoX7X_c7g4f{y)mf(?;`TLI@jLv +z?N)ryzDJ)LsBZU+VnRH0X1E}KJ!}%#n_-hEY9w +z`8(=7Fd9^wGY;{_ggJK@ZR?yW!1!^^d;F^x%}=DG(7K8XMm$L~K*Np|t>vZmA5%Y| +zINrWxnZFq_J7&ksTGEluekfNRCX$8u^xk+?w8Q1iII^7LA8Wc=uh=>E34C14fN(+~ +zjb&LKSzG|ur8^cG=n*d|U)DK;5`-D7c>o{;1qb8{cYdL5^ll*Y29ag^ZWs(}{Dq?& +z7Vt6fu%BVSoqvD;RYW!I!KS^e-kCz_2@FvAByt<`2mpvxlE{aWp)% +z7->KZs4&!M+Z9|_;(QrbPRGNC2zLU&;bq*v@zaDlNR7 +zR!OB(0w7?XvMI3w1tc_A&fY$=RO&K>9q)K{?KeL9#X2nl`k!ouFF)XFC@Tui*%L4~ +zwNvTu3}=K5TH;uDS!^k3d+!l_hx$f?(hkYU(6NBYx@mz*Y6dZ7D@JF^5^p{aiT5zv +z;Xjc--#|sw407DGZz<4^FBXBq5F)zwTQ|65$~FTfyft2wOiY&QG(ydKoz#wa?YKny +z)9C@EX0c#XN}}K5dNFdMNo^+Os>0sS^c;E5Ky4zm)q;>J{J+z3sdUj)7tN@@gZSf7 +zJ|wiD$oI`e{Xe-gDV9P_(x}i7AaPVJn&m~NMi(84-RGbXy6@{lY?h66ze7!6Ee=i! +zInre-6PCHrI9+8v4+)Zge*esLVEy0*)t)o|)801Zf98hgQ=EZH2bpZ=)5NN_2yjw# +zP8Ewr(5WN{8DJpt*e!|G(gvZ5Pxywag$Agdns%%4+IH>|FMw9b +zKb<-v)*Cb*Ao~hb;B*`Ee&trZYBi`{$ru%gmKbuXcPNb3lD3H3Jimki7;BEFp{bxX +zFJ7Rk<~$d5(AGs1%w=$DDrj&3=?C4wX`U{m8^^=Z8R3YTB_A>ZAOkmldWl +zwo0ZyTNCB`dfUZA+chm*()HWtA2!JQ3>g${8%Vr% +zasf==&095e)fG}M%iIsk{PaQ>2|D59ppz^2pExvb9Ou9EI^`kN!0aXr*u3p0ex0b4 +z=AnHH#@v>`#o*LjN-yB0^^l)H2Nm=yD3|>1aNigv$f`s680kxF8B%d>SUG)YF0R~W +z$TI5rvll2~&q4RSwu3})*@1!~z4l}@NsY#MwV(2Y=hbLZh-ce*Eq3<#rZ +zxra}au9h@`-JaCDeW|)St?N40z`g~4rjZ?xu=?#W;cJyHNPXCV2DuxD%N1A2hAlFH +zwTJm(6XPn#dA&{dq>&yd{5Lp=pa<%$*em=~TdQ%rn_v#5`>I!IS>M^uNpl#N|wC@HMBcRTMT#SL;d7 +z<(&BuA6dLkkx|8fWw@PXzCeCBgDx@HJs@)L+j8y~gZ)7)${p-|O7{G? +z&|M6FI|A*^d_U+Of-3`+w(c~-YsQby|NH)g|G7xv|Nek^|Jex)g~z+)I0xPC0460S +LFIp>X81%mY^Bg|U diff --git a/folia-server/paper-patches/features/0002-Build-changes.patch b/folia-server/paper-patches/features/0002-Build-changes.patch new file mode 100644 index 0000000..d7f6555 --- /dev/null +++ b/folia-server/paper-patches/features/0002-Build-changes.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Fri, 10 Jan 2025 22:35:07 -0800 +Subject: [PATCH] Build changes + + +diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java +index 8f62879582195d8ae4f64bd23f752fa133b1c973..f5ff71e31516327be71924926938f1c9f0e503df 100644 +--- a/src/main/java/com/destroystokyo/paper/Metrics.java ++++ b/src/main/java/com/destroystokyo/paper/Metrics.java +@@ -592,7 +592,7 @@ public class Metrics { + boolean logFailedRequests = config.getBoolean("logFailedRequests", false); + // Only start Metrics, if it's enabled in the config + if (config.getBoolean("enabled", true)) { +- Metrics metrics = new Metrics("Paper", serverUUID, logFailedRequests, Bukkit.getLogger()); ++ Metrics metrics = new Metrics("Folia", serverUUID, logFailedRequests, Bukkit.getLogger()); // Folia - we have our own bstats page + + metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { + String minecraftVersion = Bukkit.getVersion(); +@@ -606,11 +606,11 @@ public class Metrics { + final String implVersion = org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion(); + if (implVersion != null) { + final String buildOrHash = implVersion.substring(implVersion.lastIndexOf('-') + 1); +- paperVersion = "git-Paper-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); ++ paperVersion = "git-Folia-%s-%s".formatted(Bukkit.getServer().getMinecraftVersion(), buildOrHash); // Folia - we have our own bstats page + } else { + paperVersion = "unknown"; + } +- metrics.addCustomChart(new Metrics.SimplePie("paper_version", () -> paperVersion)); ++ metrics.addCustomChart(new Metrics.SimplePie("folia_version", () -> paperVersion)); // Folia - we have our own bstats page + + metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { + Map> map = new HashMap<>(); +diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +index 532306cacd52579cdf37e4aca25887b1ed3ba6a1..29bd788ae8bc61c1e62a4f84b9e259931a7041ce 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java ++++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +@@ -49,7 +49,7 @@ public class PaperVersionFetcher implements VersionFetcher { + if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) { + updateMessage = text("You are running a development version without access to version information", color(0xFF5300)); + } else { +- updateMessage = getUpdateStatusMessage("PaperMC/Paper", build); ++ updateMessage = getUpdateStatusMessage("PaperMC/Folia", build); // Folia + } + final @Nullable Component history = this.getHistory(); + +@@ -86,7 +86,7 @@ public class PaperVersionFetcher implements VersionFetcher { + private static int fetchDistanceFromSiteApi(final ServerBuildInfo build, final int jenkinsBuild) { + try { + try (final BufferedReader reader = Resources.asCharSource( +- URI.create("https://api.papermc.io/v2/projects/paper/versions/" + build.minecraftVersionId()).toURL(), ++ URI.create("https://api.papermc.io/v2/projects/folia/versions/" + build.minecraftVersionId()).toURL(), // Folia + Charsets.UTF_8 + ).openBufferedStream()) { + final JsonObject json = new Gson().fromJson(reader, JsonObject.class); +diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java +index 790bad0494454ca12ee152e3de6da3da634d9b20..e741201fdbea0dbbc0e42313ebd33368014c9dc4 100644 +--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java ++++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java +@@ -42,9 +42,9 @@ public record ServerBuildInfoImpl( + this( + getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID) + .map(Key::key) +- .orElse(BRAND_PAPER_ID), ++ .orElse(Key.key("papermc", "folia")), // Folia + getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) +- .orElse(BRAND_PAPER_NAME), ++ .orElse("Folia"), // Folia + SharedConstants.getCurrentVersion().getId(), + SharedConstants.getCurrentVersion().getName(), + getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) +diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java +index 774556a62eb240da42e84db4502e2ed43495be17..e9b6ca3aa25e140467ae866d572483050ea3fa0e 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java +@@ -11,7 +11,7 @@ public final class Versioning { + public static String getBukkitVersion() { + String result = "Unknown-Version"; + +- InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); ++ InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/dev.folia/folia-api/pom.properties"); // Folia + Properties properties = new Properties(); + + if (stream != null) { diff --git a/folia-server/paper-patches/features/0003-Threaded-Regions.patch b/folia-server/paper-patches/features/0003-Threaded-Regions.patch new file mode 100644 index 0000000..8eb14ab --- /dev/null +++ b/folia-server/paper-patches/features/0003-Threaded-Regions.patch @@ -0,0 +1,1622 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Sun, 2 Oct 2022 21:28:53 -0700 +Subject: [PATCH] Threaded Regions + +See https://docs.papermc.io/folia/reference/overview and +https://docs.papermc.io/folia/reference/region-logic + +diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java +index 157e5edb507d6d2a922833c70a1c27abc93c9c34..5aa2891d52fb246329bf3483059b069b86fd621a 100644 +--- a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java ++++ b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java +@@ -1,5 +1,11 @@ + package ca.spottedleaf.moonrise.common.util; + ++import io.papermc.paper.threadedregions.RegionShutdownThread; ++import io.papermc.paper.threadedregions.RegionizedServer; ++import io.papermc.paper.threadedregions.RegionizedWorldData; ++import io.papermc.paper.threadedregions.ThreadedRegionizer; ++import io.papermc.paper.threadedregions.TickRegionScheduler; ++import io.papermc.paper.threadedregions.TickRegions; + import net.minecraft.core.BlockPos; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.level.ChunkPos; +@@ -119,50 +125,157 @@ public class TickThread extends Thread { + } + + public static boolean isShutdownThread() { +- return false; ++ return Thread.currentThread().getClass() == RegionShutdownThread.class; + } + + public static boolean isTickThreadFor(final Level world, final BlockPos pos) { +- return isTickThread(); ++ return isTickThreadFor(world, pos.getX() >> 4, pos.getZ() >> 4); + } + + public static boolean isTickThreadFor(final Level world, final BlockPos pos, final int blockRadius) { +- return isTickThread(); ++ return isTickThreadFor( ++ world, ++ (pos.getX() - blockRadius) >> 4, (pos.getZ() - blockRadius) >> 4, ++ (pos.getX() + blockRadius) >> 4, (pos.getZ() + blockRadius) >> 4 ++ ); + } + + public static boolean isTickThreadFor(final Level world, final ChunkPos pos) { +- return isTickThread(); ++ return isTickThreadFor(world, pos.x, pos.z); + } + + public static boolean isTickThreadFor(final Level world, final Vec3 pos) { +- return isTickThread(); ++ return isTickThreadFor(world, net.minecraft.util.Mth.floor(pos.x) >> 4, net.minecraft.util.Mth.floor(pos.z) >> 4); + } + + public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ) { +- return isTickThread(); ++ final ThreadedRegionizer.ThreadedRegion region = ++ TickRegionScheduler.getCurrentRegion(); ++ if (region == null) { ++ return isShutdownThread(); ++ } ++ return ((net.minecraft.server.level.ServerLevel)world).regioniser.getRegionAtUnsynchronised(chunkX, chunkZ) == region; + } + + public static boolean isTickThreadFor(final Level world, final AABB aabb) { +- return isTickThread(); ++ return isTickThreadFor( ++ world, ++ CoordinateUtils.getChunkCoordinate(aabb.minX), CoordinateUtils.getChunkCoordinate(aabb.minZ), ++ CoordinateUtils.getChunkCoordinate(aabb.maxX), CoordinateUtils.getChunkCoordinate(aabb.maxZ) ++ ); + } + + public static boolean isTickThreadFor(final Level world, final double blockX, final double blockZ) { +- return isTickThread(); ++ return isTickThreadFor(world, CoordinateUtils.getChunkCoordinate(blockX), CoordinateUtils.getChunkCoordinate(blockZ)); + } + + public static boolean isTickThreadFor(final Level world, final Vec3 position, final Vec3 deltaMovement, final int buffer) { +- return isTickThread(); ++ final int fromChunkX = CoordinateUtils.getChunkX(position); ++ final int fromChunkZ = CoordinateUtils.getChunkZ(position); ++ ++ final int toChunkX = CoordinateUtils.getChunkCoordinate(position.x + deltaMovement.x); ++ final int toChunkZ = CoordinateUtils.getChunkCoordinate(position.z + deltaMovement.z); ++ ++ // expect from < to, but that may not be the case ++ return isTickThreadFor( ++ world, ++ Math.min(fromChunkX, toChunkX) - buffer, ++ Math.min(fromChunkZ, toChunkZ) - buffer, ++ Math.max(fromChunkX, toChunkX) + buffer, ++ Math.max(fromChunkZ, toChunkZ) + buffer ++ ); + } + + public static boolean isTickThreadFor(final Level world, final int fromChunkX, final int fromChunkZ, final int toChunkX, final int toChunkZ) { +- return isTickThread(); ++ final ThreadedRegionizer.ThreadedRegion region = ++ TickRegionScheduler.getCurrentRegion(); ++ if (region == null) { ++ return isShutdownThread(); ++ } ++ ++ final int shift = ((net.minecraft.server.level.ServerLevel)world).regioniser.sectionChunkShift; ++ ++ final int minSectionX = fromChunkX >> shift; ++ final int maxSectionX = toChunkX >> shift; ++ final int minSectionZ = fromChunkZ >> shift; ++ final int maxSectionZ = toChunkZ >> shift; ++ ++ for (int secZ = minSectionZ; secZ <= maxSectionZ; ++secZ) { ++ for (int secX = minSectionX; secX <= maxSectionX; ++secX) { ++ final int lowerLeftCX = secX << shift; ++ final int lowerLeftCZ = secZ << shift; ++ if (((net.minecraft.server.level.ServerLevel)world).regioniser.getRegionAtUnsynchronised(lowerLeftCX, lowerLeftCZ) != region) { ++ return false; ++ } ++ } ++ } ++ ++ return true; + } + + public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ, final int radius) { +- return isTickThread(); ++ return isTickThreadFor(world, chunkX - radius, chunkZ - radius, chunkX + radius, chunkZ + radius); + } + + public static boolean isTickThreadFor(final Entity entity) { +- return isTickThread(); ++ if (entity == null) { ++ return true; ++ } ++ final ThreadedRegionizer.ThreadedRegion region = ++ TickRegionScheduler.getCurrentRegion(); ++ if (region == null) { ++ if (RegionizedServer.isGlobalTickThread()) { ++ if (entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ final net.minecraft.server.network.ServerGamePacketListenerImpl possibleBad = serverPlayer.connection; ++ if (possibleBad == null) { ++ return true; ++ } ++ ++ final net.minecraft.network.PacketListener packetListener = possibleBad.connection.getPacketListener(); ++ if (packetListener instanceof net.minecraft.server.network.ServerGamePacketListenerImpl gamePacketListener) { ++ return gamePacketListener.waitingForSwitchToConfig; ++ } ++ if (packetListener instanceof net.minecraft.server.network.ServerConfigurationPacketListenerImpl configurationPacketListener) { ++ return !configurationPacketListener.switchToMain; ++ } ++ return true; ++ } else { ++ return false; ++ } ++ } ++ if (isShutdownThread()) { ++ return true; ++ } ++ if (entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ // off-main access to server player is never ok, server player is owned by one of global context or region context always ++ return false; ++ } ++ // only own entities that have not yet been added to the world ++ ++ // if the entity is removed, then it was in the world previously - which means that a region containing its location ++ // owns it ++ // if the entity has a callback, then it is contained in a world ++ return entity.hasNullCallback() && !entity.isRemoved(); ++ } ++ ++ final Level world = entity.level(); ++ if (world != region.regioniser.world) { ++ // world mismatch ++ return false; ++ } ++ ++ final RegionizedWorldData worldData = io.papermc.paper.threadedregions.TickRegionScheduler.getCurrentRegionizedWorldData(); ++ ++ // pass through the check if the entity is removed and we own its chunk ++ if (worldData.hasEntity(entity)) { ++ return true; ++ } ++ ++ if (entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) { ++ net.minecraft.server.network.ServerGamePacketListenerImpl conn = serverPlayer.connection; ++ return conn != null && worldData.connections.contains(conn.connection); ++ } else { ++ return ((entity.hasNullCallback() || entity.isRemoved())) && isTickThreadFor((net.minecraft.server.level.ServerLevel)world, entity.chunkPosition()); ++ } + } + } +diff --git a/src/main/java/io/papermc/paper/SparksFly.java b/src/main/java/io/papermc/paper/SparksFly.java +index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..2ad5b9b0b7e18780ee73310451d9fa73f44c4bdb 100644 +--- a/src/main/java/io/papermc/paper/SparksFly.java ++++ b/src/main/java/io/papermc/paper/SparksFly.java +@@ -33,13 +33,13 @@ public final class SparksFly { + + private final Logger logger; + private final PaperSparkModule spark; +- private final ConcurrentLinkedQueue mainThreadTaskQueue; ++ // Folia - region threading + + private boolean enabled; + private boolean disabledInConfigurationWarningLogged; + + public SparksFly(final Server server) { +- this.mainThreadTaskQueue = new ConcurrentLinkedQueue<>(); ++ // Folia - region threading + this.logger = Logger.getLogger(ID); + this.logger.log(Level.INFO, "This server bundles the spark profiler. For more information please visit https://docs.papermc.io/paper/profiling"); + this.spark = PaperSparkModule.create(Compatibility.VERSION_1_0, server, this.logger, new PaperScheduler() { +@@ -50,7 +50,7 @@ public final class SparksFly { + + @Override + public void executeSync(final Runnable runnable) { +- SparksFly.this.mainThreadTaskQueue.offer(this.catching(runnable, "synchronous")); ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(this.catching(runnable, "synchronous")); // Folia - region threading + } + + private Runnable catching(final Runnable runnable, final String type) { +@@ -88,10 +88,7 @@ public final class SparksFly { + } + + public void executeMainThreadTasks() { +- Runnable task; +- while ((task = this.mainThreadTaskQueue.poll()) != null) { +- task.run(); +- } ++ throw new UnsupportedOperationException(); // Folia - region threading + } + + public void enableEarlyIfRequested() { +diff --git a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java +index 14e412ebf75b0e06ab53a1c8f9dd1be6ad1e2680..3f733319482fedcf7461f4b7466e84afeae1fc2b 100644 +--- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java ++++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java +@@ -83,7 +83,7 @@ public final class ChatProcessor { + final CraftPlayer player = this.player.getBukkitEntity(); + final AsyncPlayerChatEvent ae = new AsyncPlayerChatEvent(this.async, player, this.craftbukkit$originalMessage, new LazyPlayerSet(this.server)); + this.post(ae); +- if (listenersOnSyncEvent) { ++ if (false && listenersOnSyncEvent) { // Folia - region threading + final PlayerChatEvent se = new PlayerChatEvent(player, ae.getMessage(), ae.getFormat(), ae.getRecipients()); + se.setCancelled(ae.isCancelled()); // propagate cancelled state + this.queueIfAsyncOrRunImmediately(new Waitable() { +@@ -150,7 +150,7 @@ public final class ChatProcessor { + ae.setCancelled(cancelled); // propagate cancelled state + this.post(ae); + final boolean listenersOnSyncEvent = canYouHearMe(ChatEvent.getHandlerList()); +- if (listenersOnSyncEvent) { ++ if (false && listenersOnSyncEvent) { // Folia - region threading + this.queueIfAsyncOrRunImmediately(new Waitable() { + @Override + protected Void evaluate() { +diff --git a/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java b/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java +index 23432eea862c6df716d7726a32da3a0612a3fb77..f59e8bb72c5233f26a8a0d506ac64bb37fef97a5 100644 +--- a/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java ++++ b/src/main/java/io/papermc/paper/adventure/providers/ClickCallbackProviderImpl.java +@@ -23,35 +23,42 @@ public class ClickCallbackProviderImpl implements ClickCallback.Provider { + + public static final class CallbackManager { + +- private final Map callbacks = new HashMap<>(); +- private final Queue queue = new ConcurrentLinkedQueue<>(); ++ private final java.util.concurrent.ConcurrentHashMap callbacks = new java.util.concurrent.ConcurrentHashMap<>(); // Folia - region threading ++ // Folia - region threading + + private CallbackManager() { + } + + public UUID addCallback(final @NotNull ClickCallback callback, final ClickCallback.@NotNull Options options) { + final UUID id = UUID.randomUUID(); +- this.queue.add(new StoredCallback(callback, options, id)); ++ final StoredCallback scb = new StoredCallback(callback, options, id); // Folia - region threading ++ this.callbacks.put(scb.id(), scb); // Folia - region threading + return id; + } + + public void handleQueue(final int currentTick) { + // Evict expired entries + if (currentTick % 100 == 0) { +- this.callbacks.values().removeIf(callback -> !callback.valid()); ++ this.callbacks.values().removeIf(StoredCallback::expired); // Folia - region threading - don't read uses field + } + +- // Add entries from queue +- StoredCallback callback; +- while ((callback = this.queue.poll()) != null) { +- this.callbacks.put(callback.id(), callback); +- } ++ // Folia - region threading + } + + public void runCallback(final @NotNull Audience audience, final UUID id) { +- final StoredCallback callback = this.callbacks.get(id); +- if (callback != null && callback.valid()) { //TODO Message if expired/invalid? +- callback.takeUse(); ++ // Folia start - region threading ++ final StoredCallback[] use = new StoredCallback[1]; ++ this.callbacks.computeIfPresent(id, (final UUID keyInMap, final StoredCallback value) -> { ++ if (!value.valid()) { ++ return null; ++ } ++ use[0] = value; ++ value.takeUse(); ++ return value.valid() ? value : null; ++ }); ++ final StoredCallback callback = use[0]; ++ if (callback != null) { //TODO Message if expired/invalid? ++ // Folia end - region threading + callback.callback.accept(audience); + } + } +diff --git a/src/main/java/io/papermc/paper/command/PaperCommands.java b/src/main/java/io/papermc/paper/command/PaperCommands.java +index 7b58b2d6297800c2dcdbf7539e5ab8e7703f39f1..a587d83b78af4efc484f939529acf70834f60d7e 100644 +--- a/src/main/java/io/papermc/paper/command/PaperCommands.java ++++ b/src/main/java/io/papermc/paper/command/PaperCommands.java +@@ -19,6 +19,7 @@ public final class PaperCommands { + COMMANDS.put("paper", new PaperCommand("paper")); + COMMANDS.put("callback", new CallbackCommand("callback")); + COMMANDS.put("mspt", new MSPTCommand("mspt")); ++ COMMANDS.put("tps", new io.papermc.paper.threadedregions.commands.CommandServerHealth()); // Folia - region threading + } + + public static void registerCommands(final MinecraftServer server) { +diff --git a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java +index bbd29bcca94a81ad2603afa9ddcb160e925b405e..6284384299000480e9d5c0b62e8d88b2c922e776 100644 +--- a/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java ++++ b/src/main/java/io/papermc/paper/command/subcommands/EntityCommand.java +@@ -129,7 +129,7 @@ public final class EntityCommand implements PaperSubcommand { + final int z = (e.getKey().z << 4) + 8; + final Component message = text(" " + e.getValue() + ": " + e.getKey().x + ", " + e.getKey().z + (chunkProviderServer.isPositionTicking(e.getKey().toLong()) ? " (Ticking)" : " (Non-Ticking)")) + .hoverEvent(HoverEvent.showText(text("Click to teleport to chunk", GREEN))) +- .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (world.getWorld().getHighestBlockYAt(x, z, HeightMap.MOTION_BLOCKING) + 1) + " " + z)); ++ .clickEvent(ClickEvent.clickEvent(ClickEvent.Action.RUN_COMMAND, "/minecraft:execute as @s in " + world.getWorld().getKey() + " run tp " + x + " " + (128) + " " + z)); // Folia - region threading - avoid sync load here + sender.sendMessage(message); + }); + } else { +diff --git a/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java +index cd2e4d792e972b8bf1e07b8961594a670ae949cf..3ab8dbf2768a4ef8fb53af6f5431f7f6afe6d168 100644 +--- a/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java ++++ b/src/main/java/io/papermc/paper/command/subcommands/HeapDumpCommand.java +@@ -18,7 +18,9 @@ import static net.kyori.adventure.text.format.NamedTextColor.YELLOW; + public final class HeapDumpCommand implements PaperSubcommand { + @Override + public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading + this.dumpHeap(sender); ++ }); // Folia - region threading + return true; + } + +diff --git a/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java +index bd68139ae635f2ad7ec8e7a21e0056a139c4c62e..48a43341b17247355a531164019d5cc9c5555f26 100644 +--- a/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java ++++ b/src/main/java/io/papermc/paper/command/subcommands/ReloadCommand.java +@@ -16,7 +16,9 @@ import static net.kyori.adventure.text.format.NamedTextColor.RED; + public final class ReloadCommand implements PaperSubcommand { + @Override + public boolean execute(final CommandSender sender, final String subCommand, final String[] args) { ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading + this.doReload(sender); ++ }); // Folia - region threading + return true; + } + +diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +index 0b8e0ff5ce628cd1023de45ab0bff112f74dc695..c6805510805c91e301da2363b7011f93174bc7f0 100644 +--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java ++++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java +@@ -396,4 +396,17 @@ public class GlobalConfiguration extends ConfigurationPart { + } + } + } ++ // Folia start - threaded regions ++ public ThreadedRegions threadedRegions; ++ public class ThreadedRegions extends ConfigurationPart { ++ ++ public int threads = -1; ++ public int gridExponent = 4; ++ ++ @PostProcess ++ public void postProcess() { ++ io.papermc.paper.threadedregions.TickRegions.init(this); ++ } ++ } ++ // Folia end - threaded regions + } +diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +index d7c9acaffdcff5e35e026ae90a3e521bab13b074..321c4cad4f84c57f56e5bec3bcdbbef8823f70fe 100644 +--- a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java ++++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java +@@ -493,6 +493,14 @@ public class WorldConfiguration extends ConfigurationPart { + public Chunks chunks; + + public class Chunks extends ConfigurationPart { ++ ++ // Folia start - region threading - force prevent moving into unloaded chunks ++ @PostProcess ++ public void postProcess() { ++ this.preventMovingIntoUnloadedChunks = true; ++ } ++ // Folia end - region threading - force prevent moving into unloaded chunks ++ + public AutosavePeriod autoSaveInterval = AutosavePeriod.def(); + public int maxAutoSaveChunksPerTick = 24; + public int fixedChunkInhabitedTime = -1; +diff --git a/src/main/java/io/papermc/paper/entity/activation/ActivationType.java b/src/main/java/io/papermc/paper/entity/activation/ActivationType.java +index cd43845a0819b5b63259d7a87ebb1cf5659ea5bc..01fef8353934f22a5176e731847d3df4a7df5306 100644 +--- a/src/main/java/io/papermc/paper/entity/activation/ActivationType.java ++++ b/src/main/java/io/papermc/paper/entity/activation/ActivationType.java +@@ -19,7 +19,7 @@ public enum ActivationType { + RAIDER, + MISC; + +- AABB boundingBox = new AABB(0, 0, 0, 0, 0, 0); ++ //AABB boundingBox = new AABB(0, 0, 0, 0, 0, 0); // Folia - threaded regions - replaced by local variable + + /** + * Returns the activation type for the given entity. +diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java +index 3e82ea07ca4194844c5528446e2c4a46ff4acee5..adfd4c16809f6ddd9cc73e4bd845d7aed4925068 100644 +--- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java ++++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginInstanceManager.java +@@ -256,12 +256,7 @@ class PaperPluginInstanceManager { + + pluginName + " (Is it up to date?)", ex, plugin); // Paper + } + +- try { +- this.server.getScheduler().cancelTasks(plugin); +- } catch (Throwable ex) { +- this.handlePluginException("Error occurred (in the plugin loader) while cancelling tasks for " +- + pluginName + " (Is it up to date?)", ex, plugin); // Paper +- } ++ // Folia - region threading + + // Paper start - Folia schedulers + try { +diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java +index c03608fec96b51e1867f43d8f42e5aefb1520e46..127d96280cad2d4e5db574a089d67ad68977b34e 100644 +--- a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java ++++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java +@@ -50,6 +50,14 @@ public final class EntityScheduler { + this.entity = Validate.notNull(entity); + } + ++ // Folia start - region threading ++ public boolean isRetired() { ++ synchronized (this.stateLock) { ++ return this.tickCount == RETIRED_TICK_COUNT; ++ } ++ } ++ // Folia end - region threading ++ + /** + * Retires the scheduler, preventing new tasks from being scheduled and invoking the retired callback + * on all currently scheduled tasks. +diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java +index a4ac34ebb58a404f4fca7e763e61d4ab05ee3af4..4dcec640f5870d713bd3b98389a45dbef8a4ea8a 100644 +--- a/src/main/java/io/papermc/paper/util/MCUtil.java ++++ b/src/main/java/io/papermc/paper/util/MCUtil.java +@@ -94,6 +94,7 @@ public final class MCUtil { + */ + public static void ensureMain(String reason, Runnable run) { + if (!isMainThread()) { ++ if (true) throw new UnsupportedOperationException(); // Folia - region threading + if (reason != null) { + MinecraftServer.LOGGER.warn("Asynchronous " + reason + "!", new IllegalStateException()); + } +@@ -148,6 +149,30 @@ public final class MCUtil { + return new Location(world.getWorld(), pos.getX(), pos.getY(), pos.getZ()); + } + ++ // Folia start - TODO MERGE INTO MCUTIL ++ /** ++ * Converts a NMS World/Vector to Bukkit Location ++ * @param world ++ * @param pos ++ * @return ++ */ ++ public static Location toLocation(Level world, Vec3 pos) { ++ return new Location(world.getWorld(), pos.x(), pos.y(), pos.z()); ++ } ++ ++ /** ++ * Converts a NMS World/Vector to Bukkit Location ++ * @param world ++ * @param pos ++ * @param yaw ++ * @param pitch ++ * @return ++ */ ++ public static Location toLocation(Level world, Vec3 pos, float yaw, float pitch) { ++ return new Location(world.getWorld(), pos.x(), pos.y(), pos.z(), yaw, pitch); ++ } ++ // Folia end - TODO MERGE INTO MCUTIL ++ + public static BlockPos toBlockPosition(Location loc) { + return new BlockPos(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +index fda9daa6369933c80051ae007ba89513aa19227c..f12ac98285a18ce30fd5593aba9c0ef0b65622c5 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +@@ -315,7 +315,7 @@ public final class CraftServer implements Server { + public final io.papermc.paper.SparksFly spark; // Paper - spark + + // Paper start - Folia region threading API +- private final io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler(); ++ private final io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler(); // Folia - region threading + private final io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler asyncScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler(); + private final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler globalRegionScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler(); + +@@ -392,7 +392,7 @@ public final class CraftServer implements Server { + + @Override + public final boolean isGlobalTickThread() { +- return ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); ++ return io.papermc.paper.threadedregions.RegionizedServer.isGlobalTickThread(); // Folia - region threading API + } + // Paper end - Folia reagion threading API + +@@ -987,6 +987,9 @@ public final class CraftServer implements Server { + + // NOTE: Should only be called from DedicatedServer.ah() + public boolean dispatchServerCommand(CommandSender sender, ConsoleInput serverCommand) { ++ // Folia start - region threading ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("May not dispatch server commands async"); ++ // Folia end - region threading + if (sender instanceof Conversable) { + Conversable conversable = (Conversable) sender; + +@@ -1006,12 +1009,46 @@ public final class CraftServer implements Server { + } + } + ++ // Folia start - region threading ++ public void dispatchCmdAsync(CommandSender sender, String commandLine) { ++ if ((sender instanceof Entity entity)) { ++ ((org.bukkit.craftbukkit.entity.CraftEntity)entity).taskScheduler.schedule( ++ (nmsEntity) -> { ++ CraftServer.this.dispatchCommand(nmsEntity.getBukkitEntity(), commandLine); ++ }, ++ null, ++ 1L ++ ); ++ } else if (sender instanceof ConsoleCommandSender || sender instanceof io.papermc.paper.commands.FeedbackForwardingSender) { ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { ++ CraftServer.this.dispatchCommand(sender, commandLine); ++ }); ++ } else { ++ // huh? ++ throw new UnsupportedOperationException("Dispatching command for " + sender); ++ } ++ } ++ // Folia end - region threading ++ + @Override + public boolean dispatchCommand(CommandSender sender, String commandLine) { + Preconditions.checkArgument(sender != null, "sender cannot be null"); + Preconditions.checkArgument(commandLine != null, "commandLine cannot be null"); + org.spigotmc.AsyncCatcher.catchOp("Command Dispatched Async: " + commandLine); // Spigot // Paper - Include command in error message + ++ // Folia start - region threading ++ if ((sender instanceof Entity entity)) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(((org.bukkit.craftbukkit.entity.CraftEntity)entity).getHandle(), "Dispatching command async"); ++ } else if (sender instanceof ConsoleCommandSender || sender instanceof net.minecraft.server.rcon.RconConsoleSource ++ || sender instanceof org.bukkit.craftbukkit.command.CraftRemoteConsoleCommandSender ++ || sender instanceof io.papermc.paper.commands.FeedbackForwardingSender) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Dispatching command async"); ++ } else { ++ // huh? ++ throw new UnsupportedOperationException("Dispatching command for " + sender); ++ } ++ // Folia end - region threading ++ + if (this.commandMap.dispatch(sender, commandLine)) { + return true; + } +@@ -3252,7 +3289,7 @@ public final class CraftServer implements Server { + + @Override + public int getCurrentTick() { +- return net.minecraft.server.MinecraftServer.currentTick; ++ return (int)io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - region threading + } + + @Override +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 28196931453c6c65599d33915130fdfe009f1d11..3d7dd06f4d0b612f04d0f9a627c7d8215f50d915 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -228,7 +228,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public int getTickableTileEntityCount() { +- return world.blockEntityTickers.size(); ++ throw new UnsupportedOperationException(); // Folia - region threading - TODO fix this? + } + + @Override +@@ -295,7 +295,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + // Paper start - per world spawn limits + for (SpawnCategory spawnCategory : SpawnCategory.values()) { + if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { +- setSpawnLimit(spawnCategory, this.world.paperConfig().entities.spawning.spawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); ++ this.spawnCategoryLimit.put(spawnCategory, this.world.paperConfig().entities.spawning.spawnLimits.getInt(CraftSpawnCategory.toNMS(spawnCategory))); // Folia - region threading + } + } + // Paper end - per world spawn limits +@@ -365,6 +365,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public Chunk getChunkAt(int x, int z) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "Async chunk retrieval"); // Folia - region threading + warnUnsafeChunk("getting a faraway chunk", x, z); // Paper + net.minecraft.world.level.chunk.LevelChunk chunk = (net.minecraft.world.level.chunk.LevelChunk) this.world.getChunk(x, z, ChunkStatus.FULL, true); + return new CraftChunk(chunk); +@@ -395,10 +396,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + public boolean isChunkGenerated(int x, int z) { + // Paper start - Fix this method +- if (!Bukkit.isPrimaryThread()) { ++ if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(this.getHandle(), x, z)) { // Folia - region threading + return java.util.concurrent.CompletableFuture.supplyAsync(() -> { + return CraftWorld.this.isChunkGenerated(x, z); +- }, world.getChunkSource().mainThreadProcessor).join(); ++ }, (run) -> { io.papermc.paper.threadedregions.RegionizedServer.getInstance().taskQueue.queueChunkTask(this.getHandle(), x, z, run);}).join(); // Folia - region threading + } + ChunkAccess chunk = world.getChunkSource().getChunkAtImmediately(x, z); + if (chunk != null) { +@@ -455,7 +456,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + } + + private boolean unloadChunk0(int x, int z, boolean save) { +- org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot unload chunk asynchronously"); // Folia - region threading + if (!this.isChunkLoaded(x, z)) { + return true; + } +@@ -472,7 +473,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean regenerateChunk(int x, int z) { +- org.spigotmc.AsyncCatcher.catchOp("chunk regenerate"); // Spigot ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot regenerate chunk asynchronously"); // Folia - region threading + throw new UnsupportedOperationException("Not supported in this Minecraft version! Unless you can fix it, this is not a bug :)"); + /* + if (!unloadChunk0(x, z, false)) { +@@ -499,6 +500,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean refreshChunk(int x, int z) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot refresh chunk asynchronously"); // Folia - region threading + ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); + if (playerChunk == null) return false; + +@@ -549,7 +551,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean loadChunk(int x, int z, boolean generate) { +- org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "May not sync load chunks asynchronously"); // Folia - region threading + warnUnsafeChunk("loading a faraway chunk", x, z); // Paper + ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper + +@@ -589,7 +591,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + final DistanceManager distanceManager = this.world.getChunkSource().chunkMap.distanceManager; + if (distanceManager.addPluginRegionTicket(new ChunkPos(x, z), plugin)) { +- this.getChunkAt(x, z); // ensure it's loaded ++ //this.getChunkAt(x, z); // ensure it's loaded // Folia - region threading - do not load chunks for tickets anymore to make this mt-safe + return true; + } + +@@ -777,13 +779,15 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { +- this.world.captureTreeGeneration = true; +- this.world.captureBlockStates = true; ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // Folia - region threading ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading ++ worldData.captureTreeGeneration = true; // Folia - region threading ++ worldData.captureBlockStates = true; // Folia - region threading + boolean grownTree = this.generateTree(loc, type); +- this.world.captureBlockStates = false; +- this.world.captureTreeGeneration = false; ++ worldData.captureBlockStates = false; // Folia - region threading ++ worldData.captureTreeGeneration = false; // Folia - region threading + if (grownTree) { // Copy block data to delegate +- for (BlockState blockstate : this.world.capturedBlockStates.values()) { ++ for (BlockState blockstate : worldData.capturedBlockStates.values()) { // Folia - region threading + BlockPos position = ((CraftBlockState) blockstate).getPosition(); + net.minecraft.world.level.block.state.BlockState oldBlock = this.world.getBlockState(position); + int flag = ((CraftBlockState) blockstate).getFlag(); +@@ -791,10 +795,10 @@ public class CraftWorld extends CraftRegionAccessor implements World { + net.minecraft.world.level.block.state.BlockState newBlock = this.world.getBlockState(position); + this.world.notifyAndUpdatePhysics(position, null, oldBlock, newBlock, newBlock, flag, 512); + } +- this.world.capturedBlockStates.clear(); ++ worldData.capturedBlockStates.clear(); // Folia - region threading + return true; + } else { +- this.world.capturedBlockStates.clear(); ++ worldData.capturedBlockStates.clear(); // Folia - region threading + return false; + } + } +@@ -828,6 +832,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setTime(long time) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify time off of the global region"); // Folia - region threading + long margin = (time - this.getFullTime()) % 24000; + if (margin < 0) margin += 24000; + this.setFullTime(this.getFullTime() + margin); +@@ -840,6 +845,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setFullTime(long time) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify time off of the global region"); // Folia - region threading + // Notify anyone who's listening + TimeSkipEvent event = new TimeSkipEvent(this, TimeSkipEvent.SkipReason.CUSTOM, time - this.world.getDayTime()); + this.server.getPluginManager().callEvent(event); +@@ -867,7 +873,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public long getGameTime() { +- return this.world.levelData.getGameTime(); ++ return this.getHandle().getGameTime(); // Folia - region threading + } + + @Override +@@ -892,6 +898,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + } + public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source, Consumer configurator) { + // Paper end - expand explosion API ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // Folia - region threading + net.minecraft.world.level.Level.ExplosionInteraction explosionType; + if (!breakBlocks) { + explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks +@@ -901,6 +908,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + explosionType = net.minecraft.world.level.Level.ExplosionInteraction.MOB; // Respect mobGriefing gamerule + } + ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // Folia - region threading + net.minecraft.world.entity.Entity entity = (source == null) ? null : ((CraftEntity) source).getHandle(); + return !this.world.explode0(entity, Explosion.getDefaultDamageSource(this.world, entity), null, x, y, z, power, setFire, explosionType, ParticleTypes.EXPLOSION, ParticleTypes.EXPLOSION_EMITTER, SoundEvents.GENERIC_EXPLODE, configurator).wasCanceled; // Paper - expand explosion API + } +@@ -983,6 +991,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x >> 4, z >> 4, "Cannot retrieve chunk asynchronously"); // Folia - region threading + warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper + // Transient load for this tick + return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z); +@@ -1013,6 +1022,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + public void setBiome(int x, int y, int z, Holder bb) { + BlockPos pos = new BlockPos(x, 0, z); ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // Folia - region threading + if (this.world.hasChunkAt(pos)) { + net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos); + +@@ -1323,6 +1333,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setStorm(boolean hasStorm) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading + this.world.serverLevelData.setRaining(hasStorm, org.bukkit.event.weather.WeatherChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents + this.setWeatherDuration(0); // Reset weather duration (legacy behaviour) + this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) +@@ -1335,6 +1346,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setWeatherDuration(int duration) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading + this.world.serverLevelData.setRainTime(duration); + } + +@@ -1345,6 +1357,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setThundering(boolean thundering) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading + this.world.serverLevelData.setThundering(thundering, org.bukkit.event.weather.ThunderChangeEvent.Cause.PLUGIN); // Paper - Add cause to Weather/ThunderChangeEvents + this.setThunderDuration(0); // Reset weather duration (legacy behaviour) + this.setClearWeatherDuration(0); // Reset clear weather duration (reset "/weather clear" commands) +@@ -1357,6 +1370,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setThunderDuration(int duration) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading + this.world.serverLevelData.setThunderTime(duration); + } + +@@ -1367,6 +1381,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setClearWeatherDuration(int duration) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify weather off of the global region"); // Folia - region threading + this.world.serverLevelData.setClearWeatherTime(duration); + } + +@@ -1565,6 +1580,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setKeepSpawnInMemory(boolean keepLoaded) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify keep spawn in memory off of the global region"); // Folia - region threading + if (keepLoaded) { + this.setGameRule(GameRule.SPAWN_CHUNK_RADIUS, this.getGameRuleDefault(GameRule.SPAWN_CHUNK_RADIUS)); + } else { +@@ -1633,6 +1649,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setHardcore(boolean hardcore) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.world.serverLevelData.settings.hardcore = hardcore; + } + +@@ -1645,6 +1662,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setTicksPerAnimalSpawns(int ticksPerAnimalSpawns) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setTicksPerSpawns(SpawnCategory.ANIMAL, ticksPerAnimalSpawns); + } + +@@ -1657,6 +1675,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setTicksPerMonsterSpawns(int ticksPerMonsterSpawns) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setTicksPerSpawns(SpawnCategory.MONSTER, ticksPerMonsterSpawns); + } + +@@ -1669,6 +1688,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setTicksPerWaterSpawns(int ticksPerWaterSpawns) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setTicksPerSpawns(SpawnCategory.WATER_ANIMAL, ticksPerWaterSpawns); + } + +@@ -1681,6 +1701,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setTicksPerWaterAmbientSpawns(int ticksPerWaterAmbientSpawns) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setTicksPerSpawns(SpawnCategory.WATER_AMBIENT, ticksPerWaterAmbientSpawns); + } + +@@ -1693,6 +1714,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setTicksPerWaterUndergroundCreatureSpawns(int ticksPerWaterUndergroundCreatureSpawns) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setTicksPerSpawns(SpawnCategory.WATER_UNDERGROUND_CREATURE, ticksPerWaterUndergroundCreatureSpawns); + } + +@@ -1705,11 +1727,13 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setTicksPerAmbientSpawns(int ticksPerAmbientSpawns) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setTicksPerSpawns(SpawnCategory.AMBIENT, ticksPerAmbientSpawns); + } + + @Override + public void setTicksPerSpawns(SpawnCategory spawnCategory, int ticksPerCategorySpawn) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); + Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); + +@@ -1726,21 +1750,25 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setMetadata(String metadataKey, MetadataValue newMetadataValue) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify metadata off of the global region"); // Folia - region threading + this.server.getWorldMetadata().setMetadata(this, metadataKey, newMetadataValue); + } + + @Override + public List getMetadata(String metadataKey) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot retrieve metadata off of the global region"); // Folia - region threading + return this.server.getWorldMetadata().getMetadata(this, metadataKey); + } + + @Override + public boolean hasMetadata(String metadataKey) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot retrieve metadata off of the global region"); // Folia - region threading + return this.server.getWorldMetadata().hasMetadata(this, metadataKey); + } + + @Override + public void removeMetadata(String metadataKey, Plugin owningPlugin) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify metadata off of the global region"); // Folia - region threading + this.server.getWorldMetadata().removeMetadata(this, metadataKey, owningPlugin); + } + +@@ -1753,6 +1781,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setMonsterSpawnLimit(int limit) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setSpawnLimit(SpawnCategory.MONSTER, limit); + } + +@@ -1765,6 +1794,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setAnimalSpawnLimit(int limit) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setSpawnLimit(SpawnCategory.ANIMAL, limit); + } + +@@ -1777,6 +1807,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setWaterAnimalSpawnLimit(int limit) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setSpawnLimit(SpawnCategory.WATER_ANIMAL, limit); + } + +@@ -1789,6 +1820,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setWaterAmbientSpawnLimit(int limit) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setSpawnLimit(SpawnCategory.WATER_AMBIENT, limit); + } + +@@ -1801,6 +1833,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setWaterUndergroundCreatureSpawnLimit(int limit) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setSpawnLimit(SpawnCategory.WATER_UNDERGROUND_CREATURE, limit); + } + +@@ -1813,6 +1846,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + @Override + @Deprecated + public void setAmbientSpawnLimit(int limit) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + this.setSpawnLimit(SpawnCategory.AMBIENT, limit); + } + +@@ -1835,6 +1869,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void setSpawnLimit(SpawnCategory spawnCategory, int limit) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + Preconditions.checkArgument(spawnCategory != null, "SpawnCategory cannot be null"); + Preconditions.checkArgument(CraftSpawnCategory.isValidForLimits(spawnCategory), "SpawnCategory.%s are not supported", spawnCategory); + +@@ -1917,7 +1952,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; + + ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(CraftSound.bukkitToMinecraftHolder(sound), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); +- ChunkMap.TrackedEntity entityTracker = this.getHandle().getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); ++ ChunkMap.TrackedEntity entityTracker = ((CraftEntity) entity).getHandle().moonrise$getTrackedEntity(); // Folia - region threading + if (entityTracker != null) { + entityTracker.broadcastAndSend(packet); + } +@@ -1938,7 +1973,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + if (!(entity instanceof CraftEntity craftEntity) || entity.getWorld() != this || sound == null || category == null) return; + + ClientboundSoundEntityPacket packet = new ClientboundSoundEntityPacket(Holder.direct(SoundEvent.createVariableRangeEvent(ResourceLocation.parse(sound))), net.minecraft.sounds.SoundSource.valueOf(category.name()), craftEntity.getHandle(), volume, pitch, seed); +- ChunkMap.TrackedEntity entityTracker = this.getHandle().getChunkSource().chunkMap.entityMap.get(entity.getEntityId()); ++ ChunkMap.TrackedEntity entityTracker = ((CraftEntity)entity).getHandle().moonrise$getTrackedEntity(); // Folia - region threading + if (entityTracker != null) { + entityTracker.broadcastAndSend(packet); + } +@@ -2021,6 +2056,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean setGameRuleValue(String rule, String value) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + // No null values allowed + if (rule == null || value == null) return false; + +@@ -2063,6 +2099,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public boolean setGameRule(GameRule rule, T newValue) { ++ io.papermc.paper.threadedregions.RegionizedServer.ensureGlobalTickThread("Cannot modify server settings off of the global region"); // Folia - region threading + Preconditions.checkArgument(rule != null, "GameRule cannot be null"); + Preconditions.checkArgument(newValue != null, "GameRule value cannot be null"); + +@@ -2290,6 +2327,12 @@ public class CraftWorld extends CraftRegionAccessor implements World { + + @Override + public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) { ++ // Folia start - region threading ++ if (sourceEntity != null && !Bukkit.isOwnedByCurrentRegion(sourceEntity)) { ++ throw new IllegalStateException("Cannot send game event asynchronously"); ++ } ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); ++ // Folia end - region threading + getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position)); + } + // Paper end +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +index 5cb69d0b822e11a99a96aef4f59986d083b079f4..a2f35f6d057b098a016a40094d84c54cb5e174fd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +@@ -75,6 +75,11 @@ public class CraftBlock implements Block { + } + + public net.minecraft.world.level.block.state.BlockState getNMS() { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + return this.world.getBlockState(this.position); + } + +@@ -157,6 +162,11 @@ public class CraftBlock implements Block { + } + + private void setData(final byte data, int flag) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag); + } + +@@ -198,6 +208,11 @@ public class CraftBlock implements Block { + } + + public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) { ++ // Folia start - region threading ++ if (world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); ++ } ++ // Folia end - region threading + // SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup + if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes + // SPIGOT-4612: faster - just clear tile +@@ -343,18 +358,33 @@ public class CraftBlock implements Block { + + @Override + public Biome getBiome() { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ()); + } + + // Paper start + @Override + public Biome getComputedBiome() { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ()); + } + // Paper end + + @Override + public void setBiome(Biome bio) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio); + } + +@@ -402,6 +432,11 @@ public class CraftBlock implements Block { + + @Override + public boolean isBlockFaceIndirectlyPowered(BlockFace face) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face)); + + Block relative = this.getRelative(face); +@@ -414,6 +449,11 @@ public class CraftBlock implements Block { + + @Override + public int getBlockPower(BlockFace face) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + int power = 0; + net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); + int x = this.getX(); +@@ -500,6 +540,11 @@ public class CraftBlock implements Block { + + @Override + public boolean breakNaturally(ItemStack item, boolean triggerEffect, boolean dropExperience) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + // Paper end + // Order matters here, need to drop before setting to air so skulls can get their data + net.minecraft.world.level.block.state.BlockState iblockdata = this.getNMS(); +@@ -543,21 +588,27 @@ public class CraftBlock implements Block { + + @Override + public boolean applyBoneMeal(BlockFace face) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + Direction direction = CraftBlock.blockFaceToNotch(face); + BlockFertilizeEvent event = null; + ServerLevel world = this.getCraftWorld().getHandle(); + UseOnContext context = new UseOnContext(world, null, InteractionHand.MAIN_HAND, Items.BONE_MEAL.getDefaultInstance(), new BlockHitResult(Vec3.ZERO, direction, this.getPosition(), false)); + ++ io.papermc.paper.threadedregions.RegionizedWorldData worldData = world.getCurrentWorldData(); // Folia - region threading + // SPIGOT-6895: Call StructureGrowEvent and BlockFertilizeEvent +- world.captureTreeGeneration = true; ++ worldData.captureTreeGeneration = true; // Folia - region threading + InteractionResult result = BoneMealItem.applyBonemeal(context); +- world.captureTreeGeneration = false; ++ worldData.captureTreeGeneration = false; // Folia - region threading + +- if (world.capturedBlockStates.size() > 0) { +- TreeType treeType = SaplingBlock.treeType; +- SaplingBlock.treeType = null; +- List blocks = new ArrayList<>(world.capturedBlockStates.values()); +- world.capturedBlockStates.clear(); ++ if (worldData.capturedBlockStates.size() > 0) { // Folia - region threading ++ TreeType treeType = SaplingBlock.treeTypeRT.get(); // Folia - region threading ++ SaplingBlock.treeTypeRT.set(null); // Folia - region threading ++ List blocks = new ArrayList<>(worldData.capturedBlockStates.values()); // Folia - region threading ++ worldData.capturedBlockStates.clear(); // Folia - region threading + StructureGrowEvent structureEvent = null; + + if (treeType != null) { +@@ -644,6 +695,11 @@ public class CraftBlock implements Block { + + @Override + public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + Preconditions.checkArgument(start != null, "Location start cannot be null"); + Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world"); + start.checkFinite(); +@@ -685,6 +741,11 @@ public class CraftBlock implements Block { + + @Override + public boolean canPlace(BlockData data) { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + Preconditions.checkArgument(data != null, "BlockData cannot be null"); + net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState(); + net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); +@@ -719,18 +780,32 @@ public class CraftBlock implements Block { + + @Override + public void tick() { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + final ServerLevel level = this.world.getMinecraftWorld(); + this.getNMS().tick(level, this.position, level.random); + } + +- + @Override + public void fluidTick() { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + this.getNMSFluid().tick(this.world.getMinecraftWorld(), this.position, this.getNMS()); + } + + @Override + public void randomTick() { ++ // Folia start - region threading ++ if (this.world instanceof ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, this.position, "Cannot read world asynchronously"); ++ } ++ // Folia end - region threading + final ServerLevel level = this.world.getMinecraftWorld(); + this.getNMS().randomTick(level, this.position, level.random); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +index 04ae258a2f8e98421340d29d5cceedec045171b7..698a87ac30cc9efabeef3344ee254bcace1256c9 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +@@ -25,7 +25,7 @@ public abstract class CraftBlockEntityState extends Craft + private final T tileEntity; + private final T snapshot; + public boolean snapshotDisabled; // Paper +- public static boolean DISABLE_SNAPSHOT = false; // Paper ++ public static final ThreadLocal DISABLE_SNAPSHOT = ThreadLocal.withInitial(() -> Boolean.FALSE); // Paper // Folia - region threading + + public CraftBlockEntityState(World world, T tileEntity) { + super(world, tileEntity.getBlockPos(), tileEntity.getBlockState()); +@@ -34,8 +34,8 @@ public abstract class CraftBlockEntityState extends Craft + + try { // Paper - Show blockstate location if we failed to read it + // Paper start +- this.snapshotDisabled = DISABLE_SNAPSHOT; +- if (DISABLE_SNAPSHOT) { ++ this.snapshotDisabled = DISABLE_SNAPSHOT.get().booleanValue(); // Folia - region threading ++ if (this.snapshotDisabled) { // Folia - region threading + this.snapshot = this.tileEntity; + } else { + this.snapshot = this.createSnapshot(tileEntity); +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..def7749e6dc4ae8351b72deefc75936629c33d7f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +@@ -215,6 +215,12 @@ public class CraftBlockState implements BlockState { + LevelAccessor access = this.getWorldHandle(); + CraftBlock block = this.getBlock(); + ++ // Folia start - region threading ++ if (access instanceof net.minecraft.server.level.ServerLevel serverWorld) { ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); ++ } ++ // Folia end - region threading ++ + if (block.getType() != this.getType()) { + if (!force) { + return false; +@@ -350,6 +356,9 @@ public class CraftBlockState implements BlockState { + + @Override + public java.util.Collection getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) { ++ // Folia start - region threading ++ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); ++ // Folia end - region threading + this.requirePlaced(); + net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item); + +diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..69e8a170a80c2fde79bc015cd54879896c110d9d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java ++++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +@@ -249,8 +249,8 @@ public final class CraftBlockStates { + net.minecraft.world.level.block.state.BlockState blockData = craftBlock.getNMS(); + BlockEntity tileEntity = craftBlock.getHandle().getBlockEntity(blockPosition); + // Paper start - block state snapshots +- boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT; +- CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot; ++ boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT.get().booleanValue(); // Folia - region threading ++ CraftBlockEntityState.DISABLE_SNAPSHOT.set(Boolean.valueOf(!useSnapshot)); // Folia - region threading + try { + // Paper end + CraftBlockState blockState = CraftBlockStates.getBlockState(world, blockPosition, blockData, tileEntity); +@@ -258,7 +258,7 @@ public final class CraftBlockStates { + return blockState; + // Paper start + } finally { +- CraftBlockEntityState.DISABLE_SNAPSHOT = prev; ++ CraftBlockEntityState.DISABLE_SNAPSHOT.set(Boolean.valueOf(prev)); // Folia - region threading + } + // Paper end + } +diff --git a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java +index a45e658996e483e9a21cfd8178153ddb7b87ae69..25303f144422469350fdc6f84320b16bcc9f6e0c 100644 +--- a/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java ++++ b/src/main/java/org/bukkit/craftbukkit/command/ConsoleCommandCompleter.java +@@ -50,7 +50,7 @@ public class ConsoleCommandCompleter implements Completer { + return syncEvent.callEvent() ? syncEvent.getCompletions() : com.google.common.collect.ImmutableList.of(); + } + }; +- server.getServer().processQueue.add(syncCompletions); ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(syncCompletions); // Folia - region threading + try { + final List legacyCompletions = syncCompletions.get(); + completions.removeIf(it -> !legacyCompletions.contains(it.suggestion())); // remove any suggestions that were removed +@@ -98,7 +98,7 @@ public class ConsoleCommandCompleter implements Completer { + return tabEvent.isCancelled() ? Collections.EMPTY_LIST : tabEvent.getCompletions(); + } + }; +- server.getServer().processQueue.add(waitable); // Paper - Remove "this." ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(waitable); // Folia - region threading + try { + List offers = waitable.get(); + if (offers == null) { +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +index 4562bee2e2795801862bae03d783799fc076b73e..e0ed7e9501bcf95c9bf7480f766738ed694295b0 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +@@ -82,6 +82,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + return this.apiScheduler; + }; + // Paper end - Folia schedulers ++ // Folia start - region threading ++ public boolean isPurged() { ++ return this.taskScheduler.isRetired(); ++ } ++ // Folia end - region threading + + public CraftEntity(final CraftServer server, final Entity entity) { + this.server = server; +@@ -239,6 +244,11 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + + @Override + public boolean teleport(Location location, TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { ++ // Folia start - region threading ++ if (true) { ++ throw new UnsupportedOperationException("Must use teleportAsync while in region threading"); ++ } ++ // Folia end - region threading + // Paper end + Preconditions.checkArgument(location != null, "location cannot be null"); + location.checkFinite(); +@@ -722,7 +732,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + ImmutableSet.Builder players = ImmutableSet.builder(); + + ServerLevel world = ((CraftWorld) this.getWorld()).getHandle(); +- ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId()); ++ ChunkMap.TrackedEntity entityTracker = this.getHandle().moonrise$getTrackedEntity(); // Folia - region threading + + if (entityTracker != null) { + for (ServerPlayerConnection connection : entityTracker.seenBy) { +@@ -1026,7 +1036,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + + ServerLevel world = ((CraftWorld) this.getWorld()).getHandle(); +- ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId()); ++ ChunkMap.TrackedEntity entityTracker = this.getHandle().moonrise$getTrackedEntity(); // Folia - region threading + + if (entityTracker == null) { + return; +@@ -1045,7 +1055,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + } + + ServerLevel world = ((CraftWorld) this.getWorld()).getHandle(); +- ChunkMap.TrackedEntity entityTracker = world.getChunkSource().chunkMap.entityMap.get(this.getEntityId()); ++ ChunkMap.TrackedEntity entityTracker = this.entity.moonrise$getTrackedEntity(); // Folia - region threading + + if (entityTracker == null) { + return; +@@ -1079,29 +1089,43 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + location.checkFinite(); + Location locationClone = location.clone(); // clone so we don't need to worry about mutations after this call. + +- net.minecraft.server.level.ServerLevel world = ((CraftWorld)locationClone.getWorld()).getHandle(); ++ // Folia start - region threading + java.util.concurrent.CompletableFuture ret = new java.util.concurrent.CompletableFuture<>(); +- +- world.loadChunksForMoveAsync(getHandle().getBoundingBoxAt(locationClone.getX(), locationClone.getY(), locationClone.getZ()), +- this instanceof CraftPlayer ? ca.spottedleaf.concurrentutil.util.Priority.HIGHER : ca.spottedleaf.concurrentutil.util.Priority.NORMAL, (list) -> { +- net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> { +- final net.minecraft.server.level.ServerChunkCache chunkCache = world.getChunkSource(); +- for (final net.minecraft.world.level.chunk.ChunkAccess chunk : list) { +- chunkCache.addTicketAtLevel(net.minecraft.server.level.TicketType.POST_TELEPORT, chunk.getPos(), 33, CraftEntity.this.getEntityId()); +- } +- try { +- ret.complete(CraftEntity.this.teleport(locationClone, cause, teleportFlags) ? Boolean.TRUE : Boolean.FALSE); +- } catch (Throwable throwable) { +- if (throwable instanceof ThreadDeath) { +- throw (ThreadDeath)throwable; +- } +- net.minecraft.server.MinecraftServer.LOGGER.error("Failed to teleport entity " + CraftEntity.this, throwable); +- ret.completeExceptionally(throwable); +- } +- }); +- }); ++ java.util.function.Consumer run = (Entity nmsEntity) -> { ++ boolean success = nmsEntity.teleportAsync( ++ ((CraftWorld)locationClone.getWorld()).getHandle(), ++ new net.minecraft.world.phys.Vec3(locationClone.getX(), locationClone.getY(), locationClone.getZ()), ++ locationClone.getYaw(), locationClone.getPitch(), net.minecraft.world.phys.Vec3.ZERO, ++ cause == null ? TeleportCause.UNKNOWN : cause, ++ Entity.TELEPORT_FLAG_LOAD_CHUNK | Entity.TELEPORT_FLAG_TELEPORT_PASSENGERS, // preserve behavior with old API: dismount the entity so it can teleport ++ (Entity entityTp) -> { ++ ret.complete(Boolean.TRUE); ++ } ++ ); ++ if (!success) { ++ ret.complete(Boolean.FALSE); ++ } ++ }; ++ if (org.bukkit.Bukkit.isOwnedByCurrentRegion(this)) { ++ run.accept(this.getHandle()); ++ return ret; ++ } ++ boolean scheduled = this.taskScheduler.schedule( ++ // success ++ run, ++ // retired ++ (Entity nmsEntity) -> { ++ ret.complete(Boolean.FALSE); ++ }, ++ 1L ++ ); ++ ++ if (!scheduled) { ++ ret.complete(Boolean.FALSE); ++ } + + return ret; ++ // Folia end - region threading + } + // Paper end - more teleport API / async chunk API + +@@ -1214,8 +1238,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { + // Paper start - tracked players API + @Override + public Set getTrackedPlayers() { +- ServerLevel world = (net.minecraft.server.level.ServerLevel)this.entity.level(); +- ChunkMap.TrackedEntity tracker = world == null ? null : world.getChunkSource().chunkMap.entityMap.get(this.entity.getId()); ++ ChunkMap.TrackedEntity tracker = this.entity.moonrise$getTrackedEntity(); // Folia - region threading + if (tracker == null) { + return java.util.Collections.emptySet(); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +index 98fc89cc7a715d35b62e13f8ecbe56c05605ca64..89633d88be288e8caba846c49c6267e45fcadc06 100644 +--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java ++++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +@@ -666,7 +666,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public void kickPlayer(String message) { +- org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot ++ //org.spigotmc.AsyncCatcher.catchOp("player kick"); // Spigot // Folia - thread-safe now, as it will simply delay the kick + this.getHandle().transferCookieConnection.kickPlayer(CraftChatMessage.fromStringOrEmpty(message, true), org.bukkit.event.player.PlayerKickEvent.Cause.PLUGIN); // Paper - kick event cause + } + +@@ -1403,6 +1403,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + + @Override + public boolean teleport(Location location, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause, io.papermc.paper.entity.TeleportFlag... flags) { ++ // Folia start - region threading ++ if (true) { ++ throw new UnsupportedOperationException("Must use teleportAsync while in region threading"); ++ } ++ // Folia end - region threading + Set relativeArguments; + Set allFlags; + if (flags.length == 0) { +@@ -2067,7 +2072,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + private void unregisterEntity(Entity other) { + // Paper end + ChunkMap tracker = ((ServerLevel) this.getHandle().level()).getChunkSource().chunkMap; +- ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId()); ++ ChunkMap.TrackedEntity entry = other.moonrise$getTrackedEntity(); // Folia - region threading + if (entry != null) { + entry.removePlayer(this.getHandle()); + } +@@ -2164,7 +2169,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + if (original != null) otherPlayer.setUUID(original); // Paper - uuid override + } + +- ChunkMap.TrackedEntity entry = tracker.entityMap.get(other.getId()); ++ ChunkMap.TrackedEntity entry = other.moonrise$getTrackedEntity(); // Folia - region threading + if (entry != null && !entry.seenBy.contains(this.getHandle().connection)) { + entry.updatePlayer(this.getHandle()); + } +@@ -3345,7 +3350,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { + { + if ( CraftPlayer.this.getHealth() <= 0 && CraftPlayer.this.isOnline() ) + { +- CraftPlayer.this.server.getServer().getPlayerList().respawn( CraftPlayer.this.getHandle(), false, Entity.RemovalReason.KILLED, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.PLUGIN ); ++ CraftPlayer.this.getHandle().respawn(null, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.PLUGIN); // Folia - region threading + } + } + +diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +index e37aaf77f94b97b736cc20ef070cefdff0400188..ebbe224d81f6a96f3b05e3379cd0c5b5ab50fcbd 100644 +--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java ++++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +@@ -951,7 +951,7 @@ public class CraftEventFactory { + return CraftEventFactory.handleBlockSpreadEvent(world, source, target, block, 2); + } + +- public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. ++ public static final ThreadLocal sourceBlockOverrideRT = new ThreadLocal<>(); // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. // Folia - region threading + + public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) { + // Suppress during worldgen +@@ -963,7 +963,7 @@ public class CraftEventFactory { + CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag); + state.setData(block); + +- BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), state); ++ BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverrideRT.get() != null ? CraftEventFactory.sourceBlockOverrideRT.get() : source), state); // Folia - region threading + Bukkit.getPluginManager().callEvent(event); + + if (!event.isCancelled()) { +@@ -2229,7 +2229,7 @@ public class CraftEventFactory { + CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1)); + + org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to)); +- if (!net.minecraft.world.level.block.DispenserBlock.eventFired) { ++ if (!net.minecraft.world.level.block.DispenserBlock.eventFired.get().booleanValue()) { // Folia - region threading + if (!event.callEvent()) { + return itemStack; + } +diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +index 1354ccfbf525e5e64483ac5f443cc2325ba63850..fad85bea8643a3a88ec5c4194de7a5060e81c136 100644 +--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java ++++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +@@ -514,6 +514,7 @@ public class CraftScheduler implements BukkitScheduler { + } + + protected CraftTask handle(final CraftTask task, final long delay) { // Paper ++ if (true) throw new UnsupportedOperationException(); // Folia - region threading + // Paper start + if (!this.isAsyncScheduler && !task.isSync()) { + this.asyncScheduler.handle(task, delay); +diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +index 32750451421fc559e9be1d98e6e328ede0049263..53817969cce8eed9e821c38a8b932f14dbb7ba8b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java +@@ -384,6 +384,12 @@ public final class CraftMagicNumbers implements UnsafeValues { + throw new InvalidPluginException("Unsupported API version " + pdf.getAPIVersion()); + } + ++ // Folia start - block plugins not marked as supported ++ if (!pdf.isFoliaSupported()) { ++ throw new InvalidPluginException("Plugin " + pdf.getFullName() + " is not marked as supporting regionised multithreading"); ++ } ++ // Folia end - block plugins not marked as supported ++ + if (toCheck.isOlderThan(minimumVersion)) { + // Older than supported + throw new InvalidPluginException("Plugin API version " + pdf.getAPIVersion() + " is lower than the minimum allowed version. Please update or replace it."); +diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +index 09e87552159e24603aa9a4f658ab4449d7eaeb0a..698c8b061649fa84761f278ff7a2e9c88bb5fb87 100644 +--- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java ++++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +@@ -66,6 +66,13 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { + this.handle = worldAccess; + } + ++ // Folia start - region threading ++ @Override ++ public net.minecraft.world.level.StructureManager structureManager() { ++ return this.handle.structureManager(); ++ } ++ // Folia end - region threading ++ + public WorldGenLevel getHandle() { + return this.handle; + } +diff --git a/src/main/java/org/spigotmc/SpigotCommand.java b/src/main/java/org/spigotmc/SpigotCommand.java +index 1b60abf5f5951288f6d54f522621472673eada6e..4ea06cb7a9e9db0d7feb0981de90015320c092d4 100644 +--- a/src/main/java/org/spigotmc/SpigotCommand.java ++++ b/src/main/java/org/spigotmc/SpigotCommand.java +@@ -35,6 +35,7 @@ public class SpigotCommand extends Command { + .build() + ); + ++ io.papermc.paper.threadedregions.RegionizedServer.getInstance().addTask(() -> { // Folia - region threading + MinecraftServer console = MinecraftServer.getServer(); + org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); + for (ServerLevel world : console.getAllLevels()) { +@@ -43,6 +44,7 @@ public class SpigotCommand extends Command { + console.server.reloadCount++; + + Command.broadcastCommandMessage(sender, text("Reload complete.", NamedTextColor.GREEN)); ++ }); // Folia - region threading + } + + return true; +diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java +index e0d4222a99f22d7130d95cf29b034a98f2f3b76e..48432a7c9df33bae8aa72991843ed61545c64814 100644 +--- a/src/main/java/org/spigotmc/SpigotConfig.java ++++ b/src/main/java/org/spigotmc/SpigotConfig.java +@@ -182,7 +182,7 @@ public class SpigotConfig { + SpigotConfig.restartOnCrash = SpigotConfig.getBoolean("settings.restart-on-crash", SpigotConfig.restartOnCrash); + SpigotConfig.restartScript = SpigotConfig.getString("settings.restart-script", SpigotConfig.restartScript); + SpigotConfig.restartMessage = SpigotConfig.transform(SpigotConfig.getString("messages.restart", "Server is restarting")); +- SpigotConfig.commands.put("restart", new RestartCommand("restart")); ++ //SpigotConfig.commands.put("restart", new RestartCommand("restart")); // Folia - region threading + } + + public static boolean bungee; +@@ -228,7 +228,7 @@ public class SpigotConfig { + } + + private static void tpsCommand() { +- SpigotConfig.commands.put("tps", new TicksPerSecondCommand("tps")); ++ //SpigotConfig.commands.put("tps", new TicksPerSecondCommand("tps")); // Folia - region threading + } + + public static int playerSample; +diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java +index 89e2adbc1e1a0709d03e151e3ffcdbff10a44098..3476d639141c15ddb96fe0da1f11569e1e4b5bec 100644 +--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java ++++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java +@@ -401,7 +401,7 @@ public class SpigotWorldConfig { + this.otherMultiplier = (float) this.getDouble("hunger.other-multiplier", 0.0); + } + +- public int currentPrimedTnt = 0; ++ //public int currentPrimedTnt = 0; // Folia - region threading - moved to regionised world data + public int maxTntTicksPerTick; + private void maxTntPerTick() { + if (SpigotConfig.version < 7) { diff --git a/patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch b/folia-server/paper-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch similarity index 97% rename from patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch rename to folia-server/paper-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch index 3f68ca4..5e7304c 100644 --- a/patches/server/0006-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch +++ b/folia-server/paper-patches/features/0004-Make-CraftEntity-getHandle-and-overrides-perform-thr.patch @@ -28,44 +28,8 @@ index 41bf71d116ffc5431586ce54abba7f8def6c1dcf..1cf9a7677449ab8f03fb23d835e3fadc return (AbstractSchoolingFish) super.getHandle(); } -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 35ff983cd84cb610b70e193220a97a3a5406252f..94f2610e1f2cce41d998bb9c92abbb38d9811f56 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3244,6 +3244,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - if (!force && (!this.canRide(entity) || !entity.canAddPassenger(this))) { - return false; - } else { -+ if (this.valid) { // Folia - region threading - suppress entire event logic during worldgen - // CraftBukkit start - if (entity.getBukkitEntity() instanceof Vehicle && this.getBukkitEntity() instanceof LivingEntity) { - VehicleEnterEvent event = new VehicleEnterEvent((Vehicle) entity.getBukkitEntity(), this.getBukkitEntity()); -@@ -3265,6 +3266,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return false; - } - // CraftBukkit end -+ } // Folia - region threading - suppress entire event logic during worldgen - if (this.isPassenger()) { - this.stopRiding(); - } -@@ -3348,6 +3350,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - throw new IllegalStateException("Use x.stopRiding(y), not y.removePassenger(x)"); - } else { - // CraftBukkit start -+ if (this.valid) { // Folia - region threading - suppress entire event logic during worldgen - CraftEntity craft = (CraftEntity) entity.getBukkitEntity().getVehicle(); - Entity orig = craft == null ? null : craft.getHandle(); - if (this.getBukkitEntity() instanceof Vehicle && entity.getBukkitEntity() instanceof LivingEntity) { -@@ -3375,6 +3378,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess - return false; - } - // CraftBukkit end -+ } // Folia - region threading - suppress entire event logic during worldgen - if (this.passengers.size() == 1 && this.passengers.get(0) == entity) { - this.passengers = ImmutableList.of(); - } else { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java -index 591af9d0d2fdc9953415979fc97a4a00afd85885..4a0fd1e3203342b7a5ffde579947057fe84a0d80 100644 +index e8d82054d17ef1859eb57f3871043b3fe3de22b9..6fae4697512e6e1ded15938d4cdce93e7e2eef39 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/AbstractProjectile.java @@ -1,5 +1,6 @@ @@ -88,7 +52,7 @@ index 591af9d0d2fdc9953415979fc97a4a00afd85885..4a0fd1e3203342b7a5ffde579947057f + @Override public boolean canHitEntity(org.bukkit.entity.Entity entity) { - return this.getHandle().canHitEntity(((CraftEntity) entity).getHandle()); + return this.getHandle().canHitEntityPublic(((CraftEntity) entity).getHandle()); @@ -55,6 +63,7 @@ public abstract class AbstractProjectile extends CraftEntity implements Projecti @Override @@ -98,7 +62,7 @@ index 591af9d0d2fdc9953415979fc97a4a00afd85885..4a0fd1e3203342b7a5ffde579947057f } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java -index d0c30fd12aa9866900fe72b97d10c257479cf010..46d8cbe8d09cf43b489d0358498e937454d96e7b 100644 +index af2c1ad8cd878f0048f326699ac4462b86e7a4be..866456bda1bebb75ee4be77466d02f951060b693 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java @@ -133,6 +133,7 @@ public class CraftAbstractArrow extends AbstractProjectile implements AbstractAr @@ -895,7 +859,7 @@ index 676dd5331bec75407a74aea2a89e78ab72d69724..4f876511b116dd6e7704f1f047af6fab } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java -index 7b7b89e67d53ed70efae714192c5fa32977f3d9c..747907123b9a9b2b7cae4a20f77455ea48bc04e9 100644 +index 1ef0ec7ed3b13c25d76c03c7013c8e2eaba4d66a..9f37334ba0e2358f583df5a6d3e347909cfe681e 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEnderDragon.java @@ -30,8 +30,16 @@ public class CraftEnderDragon extends CraftMob implements EnderDragon, CraftEnem @@ -1021,10 +985,10 @@ index d657fd2c507a5b215aeab0a5f3e9c2ee892a27c8..399ef60ab5f1bf02b638c8c46a72d297 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 5168cf0d58013aecfd80d37fb698014f38f8e08d..982778c4828e79bc7a55745418beb04f9c56cc78 100644 +index e0ed7e9501bcf95c9bf7480f766738ed694295b0..fd6449e015289a0079e363ec6ca605cd0c8d7c27 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -514,6 +514,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { +@@ -538,6 +538,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { } public Entity getHandle() { @@ -1474,10 +1438,10 @@ index 9b6ff0f64966c78a3233860bb0840182b52f01bc..fb34651a9e4ed0cb05721d15524a26f8 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -index e345cdbfab44a0f5da80d738798dbb4424b7ab5c..2a4ed66335e4fd88aefabb063ec04fe803bc728e 100644 +index a1f42f860f080227a2223ec48d218e91d8f65977..9ce7dba9cfae9c34185a4edcfc2e3c1cc215ccea 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftHumanEntity.java -@@ -298,8 +298,16 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { +@@ -303,8 +303,16 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity { this.mode = mode; } @@ -1579,7 +1543,7 @@ index 63cae1a2e95d8da17c45c4404a8dd0ca6a413c39..e417ff87b047dcffa6121835af6f4e71 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java -index 30d62ee4d5cd2ddacb8783b5bbbf475d592b3e02..3985b6bea750341f5336babb237aab8874a4cbd9 100644 +index 7a3d982b133f8cdaeb936cf40f92565f0f7f6dd0..9216543d8f9c25221abb510b35c6bd504e2ccfeb 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftItem.java @@ -18,8 +18,16 @@ public class CraftItem extends CraftEntity implements Item { @@ -2078,7 +2042,7 @@ index ecdac2cf74e99f0d69e053dece11ab891973dc2b..fa365c38c9e0f671df1481c8b36bc993 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java -index b1b139b773b37e6ec2afea85c500387d6ba9800e..38c1eb97de420cd7dea6a9f76ef644ecdf8c30b8 100644 +index bcac1359c667ef1ee46384f9c7a5adf4010d2b08..e740abd53d99f549acb5048d748241560dfeddd1 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPainting.java @@ -50,8 +50,16 @@ public class CraftPainting extends CraftHanging implements Painting { @@ -2141,7 +2105,7 @@ index 04d6cf6a1f3ae8316e3b2862c2d1b04e84a3b20a..4ed79610b50be635a7a7c8a8f7d7af8f } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java -index 83e77c6d287d8e239d2f55f3e9f19ef74946be7c..10e385066d29834eb3d8c9d539bb8655407cabb5 100644 +index 429200b0b06cc0f71db03924228240b8b5f22a55..634a95a5d89821d3464e2ae8bd86b3b574f0ef17 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPhantom.java @@ -9,8 +9,16 @@ public class CraftPhantom extends CraftFlying implements Phantom, CraftEnemy { @@ -2162,7 +2126,7 @@ index 83e77c6d287d8e239d2f55f3e9f19ef74946be7c..10e385066d29834eb3d8c9d539bb8655 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java -index 8016c810aeaf6ee953bca549bc1e7f9a85f860fc..e96e58fa4fb2a73e3e44c5213c73f332df4daa97 100644 +index fd4f13e8ea000eb38efd77bfb197855db8816744..7f049e504cf7af7c5c5ee247bccb4f6e01b80121 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPig.java @@ -55,8 +55,16 @@ public class CraftPig extends CraftAnimals implements Pig { @@ -2288,10 +2252,10 @@ index 2638c341bc02f201f7ab17fdebcdbdf3a7ec05bf..074b2919be2b5544b0a46e6cd32f6c57 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index f2a847e590c72eee91a053cecdc691c53751ca3a..b0e93050839ce00b057e3a9bf3bdf8dd5e0662cf 100644 +index 89633d88be288e8caba846c49c6267e45fcadc06..5aa9fcb697a758da10a9e1f839dd5502a446c076 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -683,7 +683,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -684,7 +684,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @Override public void kick(net.kyori.adventure.text.Component message, org.bukkit.event.player.PlayerKickEvent.Cause cause) { @@ -2300,7 +2264,7 @@ index f2a847e590c72eee91a053cecdc691c53751ca3a..b0e93050839ce00b057e3a9bf3bdf8dd final ServerGamePacketListenerImpl connection = this.getHandle().connection; if (connection != null) { connection.disconnect(message == null ? net.kyori.adventure.text.Component.empty() : message, cause); -@@ -2336,9 +2336,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2318,9 +2318,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player { return this; } @@ -2803,7 +2767,7 @@ index 067a95ea50418601acfb8b9453d1291161bb706a..3a41ef5fdecee262f3e8899deec360c3 } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftStrider.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftStrider.java -index 9472a6f9c9584048abf1f8d11ab6254b7c7a287d..de8f656818192f35cca228724db3d17ede40b556 100644 +index 74fac97231d4d89d1b941a1b5295afc2dafc6007..27992471bb7727a17f5fee61046cc0718994403a 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftStrider.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftStrider.java @@ -65,8 +65,16 @@ public class CraftStrider extends CraftAnimals implements Strider { diff --git a/patches/server/0007-Throw-UnsupportedOperationException-for-broken-APIs.patch b/folia-server/paper-patches/features/0005-Throw-UnsupportedOperationException-for-broken-APIs.patch similarity index 96% rename from patches/server/0007-Throw-UnsupportedOperationException-for-broken-APIs.patch rename to folia-server/paper-patches/features/0005-Throw-UnsupportedOperationException-for-broken-APIs.patch index c18ada1..aeab88d 100644 --- a/patches/server/0007-Throw-UnsupportedOperationException-for-broken-APIs.patch +++ b/folia-server/paper-patches/features/0005-Throw-UnsupportedOperationException-for-broken-APIs.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Throw UnsupportedOperationException() for broken APIs diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 26e1584557c8ba7b6bdf4a5ca7fc801d2f33fbdf..567e12e24ece2cd823b73e7337b10eb89995da21 100644 +index 82e4b25fbfb27d4a2a96a0785daf2168c60584aa..62a9bb77078522c3a98806083a4995251e036138 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -1320,6 +1320,7 @@ public final class CraftServer implements Server { @@ -16,7 +16,7 @@ index 26e1584557c8ba7b6bdf4a5ca7fc801d2f33fbdf..567e12e24ece2cd823b73e7337b10eb8 Preconditions.checkState(this.console.getAllLevels().iterator().hasNext(), "Cannot create additional worlds on STARTUP"); //Preconditions.checkState(!this.console.isIteratingOverLevels, "Cannot create a world while worlds are being ticked"); // Paper - Cat - Temp disable. We'll see how this goes. Preconditions.checkArgument(creator != null, "WorldCreator cannot be null"); -@@ -1498,6 +1499,7 @@ public final class CraftServer implements Server { +@@ -1517,6 +1518,7 @@ public final class CraftServer implements Server { @Override public boolean unloadWorld(World world, boolean save) { diff --git a/patches/server/0008-Fix-tests-by-removing-them.patch b/folia-server/paper-patches/features/0006-Fix-tests-by-removing-them.patch similarity index 100% rename from patches/server/0008-Fix-tests-by-removing-them.patch rename to folia-server/paper-patches/features/0006-Fix-tests-by-removing-them.patch diff --git a/patches/server/0009-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch b/folia-server/paper-patches/features/0007-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch similarity index 100% rename from patches/server/0009-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch rename to folia-server/paper-patches/features/0007-Require-plugins-to-be-explicitly-marked-as-Folia-sup.patch diff --git a/patches/server/0014-Synchronize-PaperPermissionManager.patch b/folia-server/paper-patches/features/0008-Synchronize-PaperPermissionManager.patch similarity index 100% rename from patches/server/0014-Synchronize-PaperPermissionManager.patch rename to folia-server/paper-patches/features/0008-Synchronize-PaperPermissionManager.patch diff --git a/patches/server/0018-Disable-spark-profiler.patch b/folia-server/paper-patches/features/0009-Disable-spark-profiler.patch similarity index 100% rename from patches/server/0018-Disable-spark-profiler.patch rename to folia-server/paper-patches/features/0009-Disable-spark-profiler.patch diff --git a/folia-server/paper-patches/features/0010-Region-profiler.patch b/folia-server/paper-patches/features/0010-Region-profiler.patch new file mode 100644 index 0000000..2ed989f --- /dev/null +++ b/folia-server/paper-patches/features/0010-Region-profiler.patch @@ -0,0 +1,90 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Tue, 3 Oct 2023 06:03:34 -0700 +Subject: [PATCH] Region profiler + +Profiling for a region starts with the /profiler command. +The usage for /profiler: +/profiler