mirror of
https://github.com/SparklyPower/SparklyPaper.git
synced 2025-12-19 15:09:27 +00:00
Update to Paper 1.21.4 (post hard fork™️ edition)
This commit is contained in:
2
.github/workflows/build-without-pwt.yml
vendored
2
.github/workflows/build-without-pwt.yml
vendored
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- name: Grant execute permission for gradlew
|
- name: Grant execute permission for gradlew
|
||||||
run: chmod +x gradlew
|
run: chmod +x gradlew
|
||||||
- name: Delete Parallel world ticking patch
|
- name: Delete Parallel world ticking patch
|
||||||
run: rm patches/server/*-Parallel-world-ticking.patch
|
run: rm sparklypaper-server/minecraft-patches/features/*-Parallel-world-ticking.patch sparklypaper-server/paper-patches/features/*-Parallel-world-ticking.patch
|
||||||
- name: Apply Patches
|
- name: Apply Patches
|
||||||
run: ./gradlew -PsparklypaperImplementationVersionSuffix=without-pwt applyPatches
|
run: ./gradlew -PsparklypaperImplementationVersionSuffix=without-pwt applyPatches
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
26
.gitignore
vendored
26
.gitignore
vendored
@@ -13,13 +13,6 @@ build/
|
|||||||
nbproject/
|
nbproject/
|
||||||
nbactions.xml
|
nbactions.xml
|
||||||
|
|
||||||
# we use maven!
|
|
||||||
build.xml
|
|
||||||
|
|
||||||
# maven
|
|
||||||
target/
|
|
||||||
dependency-reduced-pom.xml
|
|
||||||
|
|
||||||
# vim
|
# vim
|
||||||
.*.sw[a-p]
|
.*.sw[a-p]
|
||||||
|
|
||||||
@@ -46,7 +39,22 @@ out/
|
|||||||
# other stuff
|
# other stuff
|
||||||
run/
|
run/
|
||||||
|
|
||||||
forktest-server
|
# Ignore Gradle project-specific cache directory
|
||||||
forktest-api
|
.gradle
|
||||||
|
|
||||||
|
# Ignore Gradle build output directory
|
||||||
|
build
|
||||||
|
|
||||||
|
/run
|
||||||
|
|
||||||
|
/sparklypaper-server/build.gradle.kts
|
||||||
|
/sparklypaper-server/src/minecraft
|
||||||
|
/sparklypaper-server/build
|
||||||
|
/paper-server
|
||||||
|
/sparklypaper-api/build
|
||||||
|
/sparklypaper-api/build.gradle.kts
|
||||||
|
/paper-api
|
||||||
|
/paper-api-generator
|
||||||
|
|
||||||
|
|
||||||
!gradle/wrapper/gradle-wrapper.jar
|
!gradle/wrapper/gradle-wrapper.jar
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<h1 align="center">✨ SparklyPaper ✨</h1>
|
<h1 align="center">✨ SparklyPaper ✨</h1>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
 
|
 
|
||||||
|
|
||||||
SparklyPower's Paper fork, making large servers snappier with high-performance optimizations and improvements! Focused on performance improvements for Survival servers with high player counts.
|
SparklyPower's Paper fork, making large servers snappier with high-performance optimizations and improvements! Focused on performance improvements for Survival servers with high player counts.
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,7 @@
|
|||||||
# To import classes from the vanilla Minecraft jar use `minecraft` as the artifactId:
|
# 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.LevelEntityGetterAdapter
|
||||||
# minecraft net/minecraft/world/level/entity/LevelEntityGetter.java
|
# minecraft net/minecraft/world/level/entity/LevelEntityGetter.java
|
||||||
net.minecraft.world.level.block.entity.TickingBlockEntity
|
# To import minecraft data files, like the default chat type, use `mc_data` as the prefix:
|
||||||
minecraft net.minecraft.world.level.block.Blocks
|
# mc_data chat_type/chat.json
|
||||||
minecraft net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket
|
# mc_data dimension_type/overworld.json
|
||||||
minecraft net.minecraft.network.protocol.game.ClientboundRotateHeadPacket
|
#
|
||||||
minecraft net.minecraft.network.protocol.game.ClientboundAddEntityPacket
|
|
||||||
|
|||||||
2
build-data/fork.at
Normal file
2
build-data/fork.at
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# This file is auto generated, any changes may be overridden!
|
||||||
|
# See CONTRIBUTING.md on how to add access transformers.
|
||||||
@@ -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
|
|
||||||
150
build.gradle.kts
150
build.gradle.kts
@@ -1,41 +1,64 @@
|
|||||||
|
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
|
||||||
|
import org.gradle.api.tasks.testing.logging.TestLogEvent
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
java
|
java // TODO java launcher tasks
|
||||||
`maven-publish`
|
id("io.papermc.paperweight.patcher") version "2.0.0-beta.13"
|
||||||
|
|
||||||
// In general, keep this version in sync with upstream. Sometimes a newer version than upstream might work, but an older version is extremely likely to break.
|
|
||||||
id("io.papermc.paperweight.patcher") version "1.7.5"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
paperweight {
|
||||||
|
upstreams.paper {
|
||||||
|
ref = providers.gradleProperty("paperRef")
|
||||||
|
|
||||||
repositories {
|
patchFile {
|
||||||
mavenCentral()
|
path = "paper-server/build.gradle.kts"
|
||||||
maven(paperMavenPublicUrl) {
|
outputFile = file("sparklypaper-server/build.gradle.kts")
|
||||||
content { onlyForConfigurations(configurations.paperclip.name) }
|
patchFile = file("sparklypaper-server/build.gradle.kts.patch")
|
||||||
}
|
}
|
||||||
}
|
patchFile {
|
||||||
|
path = "paper-api/build.gradle.kts"
|
||||||
dependencies {
|
outputFile = file("sparklypaper-api/build.gradle.kts")
|
||||||
remapper("net.fabricmc:tiny-remapper:0.10.3:fat") // Must be kept in sync with upstream
|
patchFile = file("sparklypaper-api/build.gradle.kts.patch")
|
||||||
decompiler("org.vineflower:vineflower:1.10.1") // Must be kept in sync with upstream
|
}
|
||||||
paperclip("io.papermc:paperclip:3.0.3") // You probably want this to be kept in sync with upstream
|
patchDir("paperApi") {
|
||||||
}
|
upstreamPath = "paper-api"
|
||||||
|
excludes = setOf("build.gradle.kts")
|
||||||
allprojects {
|
patchesDir = file("sparklypaper-api/paper-patches")
|
||||||
apply(plugin = "java")
|
outputDir = file("paper-api")
|
||||||
apply(plugin = "maven-publish")
|
}
|
||||||
|
patchDir("paperApiGenerator") {
|
||||||
java {
|
upstreamPath = "paper-api-generator"
|
||||||
toolchain {
|
patchesDir = file("sparklypaper-api-generator/paper-patches")
|
||||||
languageVersion.set(JavaLanguageVersion.of(21))
|
outputDir = file("paper-api-generator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/"
|
||||||
|
|
||||||
subprojects {
|
subprojects {
|
||||||
|
apply(plugin = "java-library")
|
||||||
|
apply(plugin = "maven-publish")
|
||||||
|
|
||||||
|
extensions.configure<JavaPluginExtension> {
|
||||||
|
toolchain {
|
||||||
|
languageVersion = JavaLanguageVersion.of(21)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven(paperMavenPublicUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.withType<AbstractArchiveTask>().configureEach {
|
||||||
|
isPreserveFileTimestamps = false
|
||||||
|
isReproducibleFileOrder = true
|
||||||
|
}
|
||||||
tasks.withType<JavaCompile> {
|
tasks.withType<JavaCompile> {
|
||||||
options.encoding = Charsets.UTF_8.name()
|
options.encoding = Charsets.UTF_8.name()
|
||||||
options.release.set(21)
|
options.release = 21
|
||||||
|
options.isFork = true
|
||||||
}
|
}
|
||||||
tasks.withType<Javadoc> {
|
tasks.withType<Javadoc> {
|
||||||
options.encoding = Charsets.UTF_8.name()
|
options.encoding = Charsets.UTF_8.name()
|
||||||
@@ -43,75 +66,22 @@ subprojects {
|
|||||||
tasks.withType<ProcessResources> {
|
tasks.withType<ProcessResources> {
|
||||||
filteringCharset = Charsets.UTF_8.name()
|
filteringCharset = Charsets.UTF_8.name()
|
||||||
}
|
}
|
||||||
|
tasks.withType<Test> {
|
||||||
repositories {
|
testLogging {
|
||||||
mavenCentral()
|
showStackTraces = true
|
||||||
maven(paperMavenPublicUrl)
|
exceptionFormat = TestExceptionFormat.FULL
|
||||||
}
|
events(TestLogEvent.STANDARD_OUT)
|
||||||
}
|
|
||||||
|
|
||||||
paperweight {
|
|
||||||
serverProject.set(project(":sparklypaper-server"))
|
|
||||||
|
|
||||||
remapRepo.set(paperMavenPublicUrl)
|
|
||||||
decompileRepo.set(paperMavenPublicUrl)
|
|
||||||
|
|
||||||
usePaperUpstream(providers.gradleProperty("paperRef")) {
|
|
||||||
withPaperPatcher {
|
|
||||||
apiPatchDir.set(layout.projectDirectory.dir("patches/api"))
|
|
||||||
apiOutputDir.set(layout.projectDirectory.dir("sparklypaper-api"))
|
|
||||||
|
|
||||||
serverPatchDir.set(layout.projectDirectory.dir("patches/server"))
|
|
||||||
serverOutputDir.set(layout.projectDirectory.dir("sparklypaper-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")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//
|
extensions.configure<PublishingExtension> {
|
||||||
// Everything below here is optional if you don't care about publishing API or dev bundles to your repository
|
|
||||||
//
|
|
||||||
|
|
||||||
tasks.generateDevelopmentBundle {
|
|
||||||
apiCoordinates.set("net.sparklypower.sparklypaper:sparklypaper-api")
|
|
||||||
libraryRepositories.set(
|
|
||||||
listOf(
|
|
||||||
"https://repo.maven.apache.org/maven2/",
|
|
||||||
paperMavenPublicUrl,
|
|
||||||
// "https://my.repo/", // This should be a repo hosting your API (in this example, 'net.sparklypower.sparklypaper:sparklypaper-api')
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
allprojects {
|
|
||||||
// Publishing API:
|
|
||||||
// ./gradlew :SparklyPaper-API:publish[ToMavenLocal]
|
|
||||||
publishing {
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
/*
|
||||||
name = "PerfectDreams"
|
maven("https://repo.papermc.io/repository/maven-snapshots/") {
|
||||||
url = uri("https://repo.perfectdreams.net/")
|
name = "paperSnapshots"
|
||||||
// See Gradle docs for how to provide credentials to PasswordCredentials
|
|
||||||
// https://docs.gradle.org/current/samples/sample_publishing_credentials.html
|
|
||||||
credentials(PasswordCredentials::class)
|
credentials(PasswordCredentials::class)
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
publishing {
|
|
||||||
// Publishing dev bundle:
|
|
||||||
// ./gradlew publishDevBundlePublicationTo(MavenLocal|MyRepoSnapshotsRepository) -PpublishDevBundle
|
|
||||||
if (project.hasProperty("publishDevBundle")) {
|
|
||||||
publications.create<MavenPublication>("devBundle") {
|
|
||||||
artifact(tasks.generateDevelopmentBundle) {
|
|
||||||
artifactId = "dev-bundle"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
group=net.sparklypower.sparklypaper
|
group=net.sparklypower.sparklypaper
|
||||||
version=1.21.3-R0.1-SNAPSHOT
|
version=1.21.4-R0.1-SNAPSHOT
|
||||||
|
mcVersion=1.21.4
|
||||||
mcVersion=1.21.3
|
paperRef=d69981b611c8afc67e55aa9955a749e3af119a77
|
||||||
paperRef=da7138233f6392e791d790d1c3407414c855f9c2
|
|
||||||
|
|
||||||
|
org.gradle.configuration-cache=true
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.vfs.watch=false
|
org.gradle.vfs.watch=false
|
||||||
|
|||||||
2
gradle/libs.versions.toml
Normal file
2
gradle/libs.versions.toml
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
# This file was generated by the Gradle 'init' task.
|
||||||
|
# https://docs.gradle.org/current/userguide/platforms.html#sub::toml-dependencies-format
|
||||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
6
gradlew
vendored
6
gradlew
vendored
@@ -15,6 +15,8 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
#
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
#
|
#
|
||||||
@@ -55,7 +57,7 @@
|
|||||||
# Darwin, MinGW, and NonStop.
|
# Darwin, MinGW, and NonStop.
|
||||||
#
|
#
|
||||||
# (3) This script is generated from the Groovy template
|
# (3) This script is generated from the Groovy template
|
||||||
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||||
# within the Gradle project.
|
# within the Gradle project.
|
||||||
#
|
#
|
||||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||||
@@ -84,7 +86,7 @@ done
|
|||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
APP_BASE_NAME=${0##*/}
|
APP_BASE_NAME=${0##*/}
|
||||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||||
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
|
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||||
|
|
||||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||||
MAX_FD=maximum
|
MAX_FD=maximum
|
||||||
|
|||||||
22
gradlew.bat
vendored
22
gradlew.bat
vendored
@@ -13,6 +13,8 @@
|
|||||||
@rem See the License for the specific language governing permissions and
|
@rem See the License for the specific language governing permissions and
|
||||||
@rem limitations under the License.
|
@rem limitations under the License.
|
||||||
@rem
|
@rem
|
||||||
|
@rem SPDX-License-Identifier: Apache-2.0
|
||||||
|
@rem
|
||||||
|
|
||||||
@if "%DEBUG%"=="" @echo off
|
@if "%DEBUG%"=="" @echo off
|
||||||
@rem ##########################################################################
|
@rem ##########################################################################
|
||||||
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
|
|||||||
%JAVA_EXE% -version >NUL 2>&1
|
%JAVA_EXE% -version >NUL 2>&1
|
||||||
if %ERRORLEVEL% equ 0 goto execute
|
if %ERRORLEVEL% equ 0 goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
|
|||||||
|
|
||||||
if exist "%JAVA_EXE%" goto execute
|
if exist "%JAVA_EXE%" goto execute
|
||||||
|
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
|
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
|
||||||
echo.
|
echo. 1>&2
|
||||||
echo Please set the JAVA_HOME variable in your environment to match the
|
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
|
||||||
echo location of your Java installation.
|
echo location of your Java installation. 1>&2
|
||||||
|
|
||||||
goto fail
|
goto fail
|
||||||
|
|
||||||
|
|||||||
@@ -1,91 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Mon, 10 Jun 2024 12:27:08 -0300
|
|
||||||
Subject: [PATCH] Add ClientboundPacketPreDispatchEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/event/packet/ClientboundPacketPreDispatchEvent.java b/src/main/java/net/sparklypower/sparklypaper/event/packet/ClientboundPacketPreDispatchEvent.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..9a279ad0b0f9b63f5f3a37977076e0bb805cd56d
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/event/packet/ClientboundPacketPreDispatchEvent.java
|
|
||||||
@@ -0,0 +1,79 @@
|
|
||||||
+package net.sparklypower.sparklypaper.event.packet;
|
|
||||||
+
|
|
||||||
+import org.bukkit.entity.Player;
|
|
||||||
+import org.bukkit.event.Cancellable;
|
|
||||||
+import org.bukkit.event.Event;
|
|
||||||
+import org.bukkit.event.HandlerList;
|
|
||||||
+import org.jetbrains.annotations.NotNull;
|
|
||||||
+import org.jetbrains.annotations.Nullable;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Called before a packet is dispatched to a connection.
|
|
||||||
+ * <p>
|
|
||||||
+ * Compared to other solutions like ProtocolLib, this has the advantage that this is called eariler on the packet sending cycle, before the packet is added to the packet queue, allowing for
|
|
||||||
+ * main thread access of resources without worrying about race conditions.
|
|
||||||
+ * <p>
|
|
||||||
+ * The asynchronously state of this event is undefined, the event may be called on an async or on a sync thread, depending on where the packet was sent.
|
|
||||||
+ */
|
|
||||||
+public class ClientboundPacketPreDispatchEvent extends Event implements Cancellable {
|
|
||||||
+ private static final HandlerList handlers = new HandlerList();
|
|
||||||
+ private boolean isCancelled = false;
|
|
||||||
+ private final Player player;
|
|
||||||
+ private Object packet;
|
|
||||||
+
|
|
||||||
+ public ClientboundPacketPreDispatchEvent(boolean isAsync, @Nullable Player player, @NotNull Object packet) {
|
|
||||||
+ super(isAsync);
|
|
||||||
+ this.player = player;
|
|
||||||
+ this.packet = packet;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the player associated with this packet.
|
|
||||||
+ * <p>
|
|
||||||
+ * Depending on which phase the packet is from, the player may be null
|
|
||||||
+ *
|
|
||||||
+ * @return the player associated with this packet
|
|
||||||
+ */
|
|
||||||
+ @Nullable
|
|
||||||
+ public Player getPlayer() {
|
|
||||||
+ return player;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the packet associated with this event.
|
|
||||||
+ *
|
|
||||||
+ * @return the packet associated with this event
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public Object getPacket() {
|
|
||||||
+ return packet;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets the packet associated with this event.
|
|
||||||
+ */
|
|
||||||
+ public void setPacket(@NotNull Object packet) {
|
|
||||||
+ this.packet = packet;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ @Override
|
|
||||||
+ public HandlerList getHandlers() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ public static HandlerList getHandlerList() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean isCancelled() {
|
|
||||||
+ return isCancelled;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void setCancelled(boolean cancel) {
|
|
||||||
+ this.isCancelled = cancel;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Mon, 10 Jun 2024 14:38:59 -0300
|
|
||||||
Subject: [PATCH] Add PlayerBlockDestroySpeedEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/event/block/PlayerBlockDestroySpeedEvent.java b/src/main/java/net/sparklypower/sparklypaper/event/block/PlayerBlockDestroySpeedEvent.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..d5e097dad04ed62088aade42ba59866029369326
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/event/block/PlayerBlockDestroySpeedEvent.java
|
|
||||||
@@ -0,0 +1,64 @@
|
|
||||||
+package net.sparklypower.sparklypaper.event.block;
|
|
||||||
+
|
|
||||||
+import org.bukkit.block.Block;
|
|
||||||
+import org.bukkit.entity.Player;
|
|
||||||
+import org.bukkit.event.Event;
|
|
||||||
+import org.bukkit.event.HandlerList;
|
|
||||||
+import org.bukkit.event.block.BlockEvent;
|
|
||||||
+import org.jetbrains.annotations.NotNull;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Called when the block destroy speed is calculated for a block that a player is breaking.
|
|
||||||
+ * <p>
|
|
||||||
+ * Useful for custom blocks to override a server side block destroy speed to fix desynchronization issues between the server and the client. (Example: Chiseled bookshelves on the server side that are overriden by target blocks on the client side)
|
|
||||||
+ * <p>
|
|
||||||
+ * Keep in mind that you should use this event to synchronize the block destroy speed between the server and the client! Not keeping both destroy speeds in sync will cause desync issues!
|
|
||||||
+ */
|
|
||||||
+public class PlayerBlockDestroySpeedEvent extends BlockEvent {
|
|
||||||
+ private static final HandlerList handlers = new HandlerList();
|
|
||||||
+ private final Player player;
|
|
||||||
+ private float destroySpeed;
|
|
||||||
+
|
|
||||||
+ public PlayerBlockDestroySpeedEvent(@NotNull Player player, @NotNull Block block, float destroySpeed) {
|
|
||||||
+ super(block);
|
|
||||||
+ this.player = player;
|
|
||||||
+ this.destroySpeed = destroySpeed;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ @Override
|
|
||||||
+ public HandlerList getHandlers() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ public static HandlerList getHandlerList() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the Player that is breaking the block involved in this event.
|
|
||||||
+ *
|
|
||||||
+ * @return The Player that is breaking the block involved in this event
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public Player getPlayer() {
|
|
||||||
+ return player;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the block destroy speed of the block involved in this event.
|
|
||||||
+ *
|
|
||||||
+ * @return the block destroy speed of the block involved in this event.
|
|
||||||
+ */
|
|
||||||
+ public float getDestroySpeed() {
|
|
||||||
+ return destroySpeed;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets the block destroy speed of the block involved in this event.
|
|
||||||
+ */
|
|
||||||
+ public void setDestroySpeed(float destroySpeed) {
|
|
||||||
+ this.destroySpeed = destroySpeed;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
@@ -1,83 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Tue, 25 Jun 2024 02:54:47 -0300
|
|
||||||
Subject: [PATCH] Add CraftItemRecipeEvent
|
|
||||||
|
|
||||||
Used when a player OR a crafter block crafts an item, as an alternative to PrepareItemCraftEvent and CraftItemEvent, because both events are not triggered when a item is crafted from a crafter
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/event/inventory/CraftItemRecipeEvent.java b/src/main/java/net/sparklypower/sparklypaper/event/inventory/CraftItemRecipeEvent.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..129e5244fd0928fc21d9aa7d4bc28e89c1408be0
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/event/inventory/CraftItemRecipeEvent.java
|
|
||||||
@@ -0,0 +1,70 @@
|
|
||||||
+package net.sparklypower.sparklypaper.event.inventory;
|
|
||||||
+
|
|
||||||
+import org.bukkit.event.Cancellable;
|
|
||||||
+import org.bukkit.event.Event;
|
|
||||||
+import org.bukkit.event.HandlerList;
|
|
||||||
+import org.bukkit.inventory.*;
|
|
||||||
+import org.jetbrains.annotations.NotNull;
|
|
||||||
+import org.jetbrains.annotations.Nullable;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Called when the recipe of an Item is completed inside a crafting matrix.
|
|
||||||
+ *
|
|
||||||
+ * This is an alternate version of [org.bukkit.event.inventory.CraftItemEvent], where this one is called for player crafting items and crafters.
|
|
||||||
+ */
|
|
||||||
+public class CraftItemRecipeEvent extends Event implements Cancellable {
|
|
||||||
+ private static final HandlerList handlers = new HandlerList();
|
|
||||||
+ private final Recipe recipe;
|
|
||||||
+ private final ItemStack @Nullable [] matrix;
|
|
||||||
+ private ItemStack result;
|
|
||||||
+ private boolean isCancelled = false;
|
|
||||||
+
|
|
||||||
+ public CraftItemRecipeEvent(@NotNull ItemStack @Nullable [] matrix, @NotNull Recipe recipe, @Nullable ItemStack result) {
|
|
||||||
+ this.matrix = matrix;
|
|
||||||
+ this.recipe = recipe;
|
|
||||||
+ this.result = result;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public void setResult(@Nullable ItemStack result) {
|
|
||||||
+ this.result = result;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Nullable
|
|
||||||
+ public ItemStack getResult() {
|
|
||||||
+ return result;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * @return A copy of the current recipe on the crafting matrix.
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public Recipe getRecipe() {
|
|
||||||
+ return recipe;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public @Nullable ItemStack[] getCraftingMatrix() {
|
|
||||||
+ return matrix;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean isCancelled() {
|
|
||||||
+ return isCancelled;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void setCancelled(boolean cancel) {
|
|
||||||
+ this.isCancelled = cancel;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ @Override
|
|
||||||
+ public HandlerList getHandlers() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ public static HandlerList getHandlerList() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
+
|
|
||||||
@@ -1,141 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sat, 4 Jan 2025 23:58:34 -0300
|
|
||||||
Subject: [PATCH] Add PlayerMoveControllableVehicleEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerMoveControllableVehicleEvent.java b/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerMoveControllableVehicleEvent.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..a646251feb6b8bf7ff07e6b4b84bb5751ee4b90b
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerMoveControllableVehicleEvent.java
|
|
||||||
@@ -0,0 +1,129 @@
|
|
||||||
+package net.sparklypower.sparklypaper.event.player;
|
|
||||||
+
|
|
||||||
+import com.google.common.base.Preconditions;
|
|
||||||
+import org.bukkit.Location;
|
|
||||||
+import org.bukkit.entity.Entity;
|
|
||||||
+import org.bukkit.entity.Player;
|
|
||||||
+import org.bukkit.entity.Vehicle;
|
|
||||||
+import org.bukkit.event.Cancellable;
|
|
||||||
+import org.bukkit.event.HandlerList;
|
|
||||||
+import org.bukkit.event.player.PlayerEvent;
|
|
||||||
+import org.jetbrains.annotations.NotNull;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Raised when a player moves a controllable vehicle. Controllable vehicles are vehicles that the client can control, such as boats, horses, striders, pigs, etc.
|
|
||||||
+ * <p>
|
|
||||||
+ * Minecarts are NOT affected by this event!
|
|
||||||
+ */
|
|
||||||
+public class PlayerMoveControllableVehicleEvent extends PlayerEvent implements Cancellable {
|
|
||||||
+ private static final HandlerList handlers = new HandlerList();
|
|
||||||
+ private boolean cancel = false;
|
|
||||||
+ private final Vehicle vehicle;
|
|
||||||
+ private Location from;
|
|
||||||
+ private Location to;
|
|
||||||
+
|
|
||||||
+ public PlayerMoveControllableVehicleEvent(@NotNull final Player player, @NotNull final Vehicle vehicle, @NotNull final Location from, @NotNull final Location to) {
|
|
||||||
+ super(player);
|
|
||||||
+
|
|
||||||
+ this.vehicle = vehicle;
|
|
||||||
+ this.from = from;
|
|
||||||
+ this.to = to;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Get the previous position.
|
|
||||||
+ *
|
|
||||||
+ * @return Old position.
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public Location getFrom() {
|
|
||||||
+ return from.clone(); // Paper - clone to avoid changes
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets the location to mark as where the player moved from
|
|
||||||
+ *
|
|
||||||
+ * @param from New location to mark as the players previous location
|
|
||||||
+ */
|
|
||||||
+ public void setFrom(@NotNull Location from) {
|
|
||||||
+ validateLocation(from, this.from);
|
|
||||||
+ this.from = from;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Get the next position.
|
|
||||||
+ *
|
|
||||||
+ * @return New position.
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public Location getTo() {
|
|
||||||
+ return to.clone(); // Paper - clone to avoid changes
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets the location that this player will move to
|
|
||||||
+ *
|
|
||||||
+ * @param to New Location this player will move to
|
|
||||||
+ */
|
|
||||||
+ public void setTo(@NotNull Location to) {
|
|
||||||
+ validateLocation(to, this.to);
|
|
||||||
+ this.to = to;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Get the vehicle.
|
|
||||||
+ *
|
|
||||||
+ * @return the vehicle
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public final Entity getVehicle() {
|
|
||||||
+ return vehicle;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the cancellation state of this event. A cancelled event will not
|
|
||||||
+ * be executed in the server, but will still pass to other plugins
|
|
||||||
+ * <p>
|
|
||||||
+ * If a move or teleport event is cancelled, the vehicle and player will be moved or
|
|
||||||
+ * teleported back to the Location as defined by getFrom(). This will not
|
|
||||||
+ * fire an event
|
|
||||||
+ *
|
|
||||||
+ * @return true if this event is cancelled
|
|
||||||
+ */
|
|
||||||
+ @Override
|
|
||||||
+ public boolean isCancelled() {
|
|
||||||
+ return cancel;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets the cancellation state of this event. A cancelled event will not
|
|
||||||
+ * be executed in the server, but will still pass to other plugins
|
|
||||||
+ * <p>
|
|
||||||
+ * If a move or teleport event is cancelled, the vehicle and player will be moved or
|
|
||||||
+ * teleported back to the Location as defined by getFrom(). This will not
|
|
||||||
+ * fire an event
|
|
||||||
+ *
|
|
||||||
+ * @param cancel true if you wish to cancel this event
|
|
||||||
+ */
|
|
||||||
+ @Override
|
|
||||||
+ public void setCancelled(boolean cancel) {
|
|
||||||
+ this.cancel = cancel;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ @Override
|
|
||||||
+ public HandlerList getHandlers() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ public static HandlerList getHandlerList() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private void validateLocation(@NotNull Location loc, @NotNull Location originalLoc) {
|
|
||||||
+ Preconditions.checkArgument(loc != null, "Cannot use null location!");
|
|
||||||
+ Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!");
|
|
||||||
+ Preconditions.checkArgument(loc.getWorld() != originalLoc, "New location should be in the original world!");
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Wed, 8 Jan 2025 22:49:00 -0300
|
|
||||||
Subject: [PATCH] Add PlayerPreMoveEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerPreMoveEvent.java b/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerPreMoveEvent.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..de57542c3a0ff3e093611f8362c60560a7ded964
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/event/player/PlayerPreMoveEvent.java
|
|
||||||
@@ -0,0 +1,167 @@
|
|
||||||
+package net.sparklypower.sparklypaper.event.player;
|
|
||||||
+
|
|
||||||
+import org.bukkit.Location;
|
|
||||||
+import org.bukkit.entity.Player;
|
|
||||||
+import org.bukkit.event.HandlerList;
|
|
||||||
+import org.bukkit.event.player.PlayerEvent;
|
|
||||||
+import org.jetbrains.annotations.NotNull;
|
|
||||||
+import org.jetbrains.annotations.Nullable;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Called after the server attempts to move the player, but before the PlayerMoveEvent is called.
|
|
||||||
+ * <p>
|
|
||||||
+ * In contrast to PlayerMoveEvent, this event happens on every movement instead of being throttled like PlayerMoveEvent,
|
|
||||||
+ * and this event exposes the player's onGround/horizontalCollision status, allowing plugins to manipulate it.
|
|
||||||
+ */
|
|
||||||
+public class PlayerPreMoveEvent extends PlayerEvent {
|
|
||||||
+ private static final HandlerList handlers = new HandlerList();
|
|
||||||
+ private final Location from;
|
|
||||||
+ private final Location to;
|
|
||||||
+ private boolean onGround;
|
|
||||||
+ private boolean horizontalCollision;
|
|
||||||
+ private boolean resetFallDistance;
|
|
||||||
+
|
|
||||||
+ public PlayerPreMoveEvent(@NotNull final Player player, @NotNull final Location from, @Nullable final Location to, boolean onGround, boolean horizontalCollision, boolean resetFallDistance) {
|
|
||||||
+ super(player);
|
|
||||||
+ this.from = from;
|
|
||||||
+ this.to = to;
|
|
||||||
+ this.onGround = onGround;
|
|
||||||
+ this.horizontalCollision = horizontalCollision;
|
|
||||||
+ this.resetFallDistance = resetFallDistance;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the location this player moved from
|
|
||||||
+ *
|
|
||||||
+ * @return Location the player moved from
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public Location getFrom() {
|
|
||||||
+ return from;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the location this player moved to
|
|
||||||
+ *
|
|
||||||
+ * @return Location the player moved to
|
|
||||||
+ */
|
|
||||||
+ @NotNull // Paper
|
|
||||||
+ public Location getTo() {
|
|
||||||
+ return to;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // Paper start - PlayerMoveEvent improvements
|
|
||||||
+ /**
|
|
||||||
+ * Check if the player has changed position (even within the same block) in the event
|
|
||||||
+ *
|
|
||||||
+ * @return whether the player has changed position or not
|
|
||||||
+ */
|
|
||||||
+ public boolean hasChangedPosition() {
|
|
||||||
+ return hasExplicitlyChangedPosition() || !from.getWorld().equals(to.getWorld());
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Check if the player has changed position (even within the same block) in the event, disregarding a possible world change
|
|
||||||
+ *
|
|
||||||
+ * @return whether the player has changed position or not
|
|
||||||
+ */
|
|
||||||
+ public boolean hasExplicitlyChangedPosition() {
|
|
||||||
+ return from.getX() != to.getX() || from.getY() != to.getY() || from.getZ() != to.getZ();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Check if the player has moved to a new block in the event
|
|
||||||
+ *
|
|
||||||
+ * @return whether the player has moved to a new block or not
|
|
||||||
+ */
|
|
||||||
+ public boolean hasChangedBlock() {
|
|
||||||
+ return hasExplicitlyChangedBlock() || !from.getWorld().equals(to.getWorld());
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Check if the player has moved to a new block in the event, disregarding a possible world change
|
|
||||||
+ *
|
|
||||||
+ * @return whether the player has moved to a new block or not
|
|
||||||
+ */
|
|
||||||
+ public boolean hasExplicitlyChangedBlock() {
|
|
||||||
+ return from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY() || from.getBlockZ() != to.getBlockZ();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Check if the player has changed orientation in the event
|
|
||||||
+ *
|
|
||||||
+ * @return whether the player has changed orientation or not
|
|
||||||
+ */
|
|
||||||
+ public boolean hasChangedOrientation() {
|
|
||||||
+ return from.getPitch() != to.getPitch() || from.getYaw() != to.getYaw();
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets if the client said that they are on ground, keep in mind that this value is controlled by the client, so it can
|
|
||||||
+ * be spoofed by malicious clients or be out of sync.
|
|
||||||
+ *
|
|
||||||
+ * @return if the client said that the is on ground
|
|
||||||
+ */
|
|
||||||
+ public boolean isOnGround() {
|
|
||||||
+ return onGround;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets if the player should be on ground.
|
|
||||||
+ *
|
|
||||||
+ * @param onGround true if the player should be on ground
|
|
||||||
+ */
|
|
||||||
+ public void setOnGround(boolean onGround) {
|
|
||||||
+ this.onGround = onGround;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets if the client said that they are horizontally colliding, keep in mind that this value is controlled by the client, so it can
|
|
||||||
+ * be spoofed by malicious clients or be out of sync.
|
|
||||||
+ *
|
|
||||||
+ * @return if the player is horizontally colliding on a block
|
|
||||||
+ */
|
|
||||||
+ public boolean isHorizontalCollision() {
|
|
||||||
+ return horizontalCollision;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets if the player should be horizontally colliding on a block.
|
|
||||||
+ *
|
|
||||||
+ * @param horizontalCollision true if the player should be colliding horizontally be on ground
|
|
||||||
+ */
|
|
||||||
+ public void setHorizontalCollision(boolean horizontalCollision) {
|
|
||||||
+ this.horizontalCollision = horizontalCollision;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets if the player's fall distance should be reset. By default, the fall distance is reset every time the player moves upwards on the y axis.
|
|
||||||
+ *
|
|
||||||
+ * @return if the fall distance should be reset
|
|
||||||
+ */
|
|
||||||
+ public boolean isResetFallDistance() {
|
|
||||||
+ return resetFallDistance;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Sets if the player's fall distance should be reset.
|
|
||||||
+ *
|
|
||||||
+ * @param resetFallDistance true if the player fall distance should be reset
|
|
||||||
+ */
|
|
||||||
+ public void setResetFallDistance(boolean resetFallDistance) {
|
|
||||||
+ this.resetFallDistance = resetFallDistance;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ @Override
|
|
||||||
+ public HandlerList getHandlers() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ public static HandlerList getHandlerList() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+}
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sun, 12 Jan 2025 23:27:00 -0300
|
|
||||||
Subject: [PATCH] Add PreEntityShootBowEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/event/entity/PreEntityShootBowEvent.java b/src/main/java/net/sparklypower/sparklypaper/event/entity/PreEntityShootBowEvent.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..1438ad2444db2b19fd84f5147f0b68b5df7f13dc
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/event/entity/PreEntityShootBowEvent.java
|
|
||||||
@@ -0,0 +1,82 @@
|
|
||||||
+package net.sparklypower.sparklypaper.event.entity;
|
|
||||||
+
|
|
||||||
+import org.bukkit.entity.HumanEntity;
|
|
||||||
+import org.bukkit.event.Cancellable;
|
|
||||||
+import org.bukkit.event.HandlerList;
|
|
||||||
+import org.bukkit.event.entity.EntityEvent;
|
|
||||||
+import org.bukkit.inventory.EquipmentSlot;
|
|
||||||
+import org.bukkit.inventory.ItemStack;
|
|
||||||
+import org.jetbrains.annotations.NotNull;
|
|
||||||
+import org.jetbrains.annotations.Nullable;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * Called when a entity releases a bow, before the projectile is spawned
|
|
||||||
+ * <p>
|
|
||||||
+ * Compared to EntityShootBowEvent, this event is called before the projectile is spawned, before the force check is done, and before the bow release sound is played.
|
|
||||||
+ * <p>
|
|
||||||
+ * Currently this event is only called for players! To be more specific, it is only called for HumanEntity!!
|
|
||||||
+ */
|
|
||||||
+public class PreEntityShootBowEvent extends EntityEvent implements Cancellable {
|
|
||||||
+ private static final HandlerList handlers = new HandlerList();
|
|
||||||
+ private final ItemStack bow;
|
|
||||||
+ private final EquipmentSlot hand;
|
|
||||||
+ private final float force;
|
|
||||||
+ private boolean cancelled;
|
|
||||||
+
|
|
||||||
+ public PreEntityShootBowEvent(@NotNull final HumanEntity shooter, @Nullable final ItemStack bow, @NotNull final EquipmentSlot hand, final float force) {
|
|
||||||
+ super(shooter);
|
|
||||||
+ this.bow = bow;
|
|
||||||
+ this.hand = hand;
|
|
||||||
+ this.force = force;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the bow ItemStack used to fire the arrow.
|
|
||||||
+ *
|
|
||||||
+ * @return the bow involved in this event
|
|
||||||
+ */
|
|
||||||
+ @Nullable
|
|
||||||
+ public ItemStack getBow() {
|
|
||||||
+ return bow;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Get the hand from which the bow was shot.
|
|
||||||
+ *
|
|
||||||
+ * @return the hand
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ public EquipmentSlot getHand() {
|
|
||||||
+ return hand;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the force the arrow was launched with
|
|
||||||
+ *
|
|
||||||
+ * @return bow shooting force, up to 1.0
|
|
||||||
+ */
|
|
||||||
+ public float getForce() {
|
|
||||||
+ return force;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean isCancelled() {
|
|
||||||
+ return cancelled;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public void setCancelled(boolean cancel) {
|
|
||||||
+ cancelled = cancel;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ @Override
|
|
||||||
+ public HandlerList getHandlers() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @NotNull
|
|
||||||
+ public static HandlerList getHandlerList() {
|
|
||||||
+ return handlers;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Fri, 13 Dec 2024 16:35:03 -0300
|
|
||||||
Subject: [PATCH] Extend AsyncPlayerPreLoginEvent to allow plugins to send
|
|
||||||
Login Plugin Requests to the client
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/PendingConnection.java b/src/main/java/net/sparklypower/sparklypaper/PendingConnection.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..11d64d825c15c122192359b86561808d0d7f5fbb
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/PendingConnection.java
|
|
||||||
@@ -0,0 +1,41 @@
|
|
||||||
+package net.sparklypower.sparklypaper;
|
|
||||||
+
|
|
||||||
+import org.bukkit.NamespacedKey;
|
|
||||||
+import org.jetbrains.annotations.NotNull;
|
|
||||||
+
|
|
||||||
+import java.util.concurrent.CompletableFuture;
|
|
||||||
+
|
|
||||||
+public interface PendingConnection {
|
|
||||||
+ /**
|
|
||||||
+ * Sends a login plugin request to the client, the client must reply with a login plugin response.
|
|
||||||
+ * <br>
|
|
||||||
+ * The vanilla client always replies with "not acknowledged", however mods, and proxies, can change
|
|
||||||
+ * the response.
|
|
||||||
+ *
|
|
||||||
+ * @param transactionId the ID of the transaction, must be unique for each connection
|
|
||||||
+ * @param channel the chanenl where the data will be sent
|
|
||||||
+ * @param data the data that will be sent
|
|
||||||
+ * @return a {@link CompletableFuture} that will be completed when the
|
|
||||||
+ * login plugin response is received or otherwise available.
|
|
||||||
+ */
|
|
||||||
+ @NotNull
|
|
||||||
+ CompletableFuture<PendingConnection.LoginPluginResponse> sendLoginPluginRequest(int transactionId, @NotNull NamespacedKey channel, byte @NotNull [] data);
|
|
||||||
+
|
|
||||||
+ class LoginPluginResponse {
|
|
||||||
+ final boolean acknowledged;
|
|
||||||
+ final byte[] response;
|
|
||||||
+
|
|
||||||
+ public LoginPluginResponse(boolean acknowledged, byte[] response) {
|
|
||||||
+ this.acknowledged = acknowledged;
|
|
||||||
+ this.response = response;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public boolean isAcknowledged() {
|
|
||||||
+ return acknowledged;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public byte[] getResponse() {
|
|
||||||
+ return response;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
diff --git a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java
|
|
||||||
index ff5cca4a7e75274b4b278a48ae1544ff42a9836a..2ace8261a836dbdf44b35cdedb53c4b5b2986f0f 100644
|
|
||||||
--- a/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java
|
|
||||||
+++ b/src/main/java/org/bukkit/event/player/AsyncPlayerPreLoginEvent.java
|
|
||||||
@@ -27,6 +27,7 @@ public class AsyncPlayerPreLoginEvent extends Event {
|
|
||||||
private final InetAddress rawAddress; // Paper
|
|
||||||
private final String hostname; // Paper
|
|
||||||
private final boolean transferred;
|
|
||||||
+ private net.sparklypower.sparklypaper.PendingConnection pendingConnection; // SparklyPaper - Add support for login plugin requests
|
|
||||||
|
|
||||||
@Deprecated(since = "1.7.5")
|
|
||||||
public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress) {
|
|
||||||
@@ -53,8 +54,15 @@ public class AsyncPlayerPreLoginEvent extends Event {
|
|
||||||
this(name, ipAddress, rawAddress, uniqueId, transferred, profile, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Add support for login plugin requests
|
|
||||||
@org.jetbrains.annotations.ApiStatus.Internal
|
|
||||||
public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @NotNull String hostname) {
|
|
||||||
+ this(name, ipAddress, rawAddress, uniqueId, transferred, profile, hostname, null);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @org.jetbrains.annotations.ApiStatus.Internal
|
|
||||||
+ public AsyncPlayerPreLoginEvent(@NotNull final String name, @NotNull final InetAddress ipAddress, @NotNull final InetAddress rawAddress, @NotNull final UUID uniqueId, boolean transferred, @NotNull com.destroystokyo.paper.profile.PlayerProfile profile, @NotNull String hostname, @NotNull net.sparklypower.sparklypaper.PendingConnection pendingConnection) {
|
|
||||||
+ // SparklyPaper end
|
|
||||||
// Paper end
|
|
||||||
super(true);
|
|
||||||
this.result = Result.ALLOWED;
|
|
||||||
@@ -64,6 +72,7 @@ public class AsyncPlayerPreLoginEvent extends Event {
|
|
||||||
this.rawAddress = rawAddress; // Paper
|
|
||||||
this.hostname = hostname; // Paper
|
|
||||||
this.transferred = transferred;
|
|
||||||
+ this.pendingConnection = pendingConnection; // SparklyPaper - Add support for login plugin requests
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
@@ -297,6 +306,18 @@ public class AsyncPlayerPreLoginEvent extends Event {
|
|
||||||
return transferred;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Add support for login plugin requests
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Gets the pending connection associated with this event.
|
|
||||||
+ *
|
|
||||||
+ * @return The pending connection
|
|
||||||
+ */
|
|
||||||
+ public net.sparklypower.sparklypaper.PendingConnection getPendingConnection() {
|
|
||||||
+ return this.pendingConnection;
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
@NotNull
|
|
||||||
@Override
|
|
||||||
public HandlerList getHandlers() {
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Kevin Raneri <kevin.raneri@gmail.com>
|
|
||||||
Date: Tue, 9 Nov 2021 14:33:16 -0500
|
|
||||||
Subject: [PATCH] Optimize entity coordinate key
|
|
||||||
|
|
||||||
When executing getCoordinateKey for entities (a hotpath), the JVM is
|
|
||||||
required to repeatedly cast doubles to longs. The performance impact of
|
|
||||||
this depends on the CPU architecture, but generally switching between
|
|
||||||
FPU and ALU incurs a significant performance hit. The casted/rounded
|
|
||||||
data is already available in the blockPosition struct, so we use that
|
|
||||||
instead of re-doing the casting.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java
|
|
||||||
index 1d6b3fe2ce240af4ede61588795456b046eee6c9..cdcb1bff7913bfe86fed008271016a3175b6df90 100644
|
|
||||||
--- a/src/main/java/io/papermc/paper/util/MCUtil.java
|
|
||||||
+++ b/src/main/java/io/papermc/paper/util/MCUtil.java
|
|
||||||
@@ -215,7 +215,7 @@ public final class MCUtil {
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getCoordinateKey(final Entity entity) {
|
|
||||||
- return ((long)(MCUtil.fastFloor(entity.getZ()) >> 4) << 32) | ((MCUtil.fastFloor(entity.getX()) >> 4) & 0xFFFFFFFFL);
|
|
||||||
+ return ((long)(entity.blockPosition.getZ() >> 4) << 32) | ((entity.blockPosition.getX() >> 4) & 0xFFFFFFFFL); // Pufferfish - eliminate double->long cast in hotpath
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long getCoordinateKey(final ChunkPos pair) {
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
||||||
index 4ee843dfd826772c9157ca421d8fe1f36f814b51..41ce41e92f3722e7ffb3423c90663d7a677bf277 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/entity/Entity.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/Entity.java
|
|
||||||
@@ -311,7 +311,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
|
||||||
public double yo;
|
|
||||||
public double zo;
|
|
||||||
private Vec3 position;
|
|
||||||
- private BlockPos blockPosition;
|
|
||||||
+ public BlockPos blockPosition; // Pufferfish - private->public
|
|
||||||
private ChunkPos chunkPosition;
|
|
||||||
private Vec3 deltaMovement;
|
|
||||||
private float yRot;
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sat, 18 Nov 2023 21:04:53 -0300
|
|
||||||
Subject: [PATCH] Avoid unnecessary ItemFrame#getItem() calls
|
|
||||||
|
|
||||||
When ticking a item frame, on each tick, it checks if the item on the item frame is a map and, if it is, it adds the map to be carried by the entity player
|
|
||||||
|
|
||||||
However, the "getItem()" call is a bit expensive, especially because this is only really used if the item in the item frame is a map
|
|
||||||
|
|
||||||
We can avoid this call by checking if the "cachedMapId" is not null
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
index aedf24ba0d64de855a59869052cbc2704e7dc134..f49585cfd485eed504e91887599ff25c3238c8fd 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
@@ -115,13 +115,14 @@ public class ServerEntity {
|
|
||||||
ItemFrame entityitemframe = (ItemFrame) entity;
|
|
||||||
|
|
||||||
if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block
|
|
||||||
- ItemStack itemstack = entityitemframe.getItem();
|
|
||||||
-
|
|
||||||
- if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable
|
|
||||||
+ if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && entityitemframe.cachedMapId != null) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable // SparklyPaper - avoid unnecessary ItemFrame#getItem() calls
|
|
||||||
Integer integer = entityitemframe.cachedMapId; // Paper
|
|
||||||
MapItemSavedData worldmap = MapItem.getSavedData(integer, this.level);
|
|
||||||
|
|
||||||
if (worldmap != null) {
|
|
||||||
+ // SparklyPaper start - avoid unnecessary ItemFrame#getItem() calls
|
|
||||||
+ ItemStack itemstack = entityitemframe.getItem();
|
|
||||||
+ if (itemstack.getItem() instanceof MapItem) { // fail-safe, what if the cached map ID is present but the item isn't a MapItem? (this should NEVER happen but, who knows)
|
|
||||||
Iterator<ServerPlayerConnection> iterator = this.trackedPlayers.iterator(); // CraftBukkit
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
@@ -134,6 +135,7 @@ public class ServerEntity {
|
|
||||||
entityplayer.connection.send(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ } // SparklyPaper end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 759ecd79534a7706f7d4a63eb9dacbefcfe54674..07739c3d74074b2668466250f944dfbe22d4dc86 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
||||||
@@ -50,7 +50,8 @@ public class ItemFrame extends HangingEntity {
|
|
||||||
public static final int NUM_ROTATIONS = 8;
|
|
||||||
public float dropChance;
|
|
||||||
public boolean fixed;
|
|
||||||
- public Integer cachedMapId; // Paper
|
|
||||||
+ @Nullable // SparklyPaper - avoid unnecessary ItemFrame#getItem() calls
|
|
||||||
+ public Integer cachedMapId = null; // Paper // SparklyPaper - avoid unnecessary ItemFrame#getItem() calls
|
|
||||||
|
|
||||||
public ItemFrame(EntityType<? extends ItemFrame> type, Level world) {
|
|
||||||
super(type, world);
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sun, 22 Oct 2023 12:27:26 -0300
|
|
||||||
Subject: [PATCH] Only check thundering once per world instead for every chunk
|
|
||||||
|
|
||||||
For some reason the isThundering check is consuming ~3% of CPU time when profiled so, instead of checking the thunder every chunk, we can cache the result and reuse on the same chunk tick
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
index c02ffd419236980cd063741612e99d739d97ec94..daa5948cc7b86a719a313ea595f135cd00b6a3cc 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
@@ -599,6 +599,7 @@ public class ServerChunkCache extends ChunkSource {
|
|
||||||
}
|
|
||||||
// Paper end - optimise chunk tick iteration
|
|
||||||
|
|
||||||
+ this.level.isCurrentlyThundering = this.level.isThundering_old(); // SparklyPaper - Only check thundering once per world instead for every chunk
|
|
||||||
int chunksTicked = 0; // Paper
|
|
||||||
// Paper start - optimise chunk tick iteration
|
|
||||||
io.papermc.paper.util.player.NearbyPlayers nearbyPlayers = this.chunkMap.getNearbyPlayers(); // Paper - optimise chunk tick iteration
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
index 9388dd9b34bb8148ce8b5f7e24122fa4bd1bafa8..0210226d2185803a18c0020d7985c1fccb798953 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
@@ -184,6 +184,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
||||||
private int tileTickPosition;
|
|
||||||
public final Map<Explosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
|
|
||||||
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here
|
|
||||||
+ public boolean isCurrentlyThundering; // SparklyPaper - Only check if the world is currently thundering once instead for every chunk
|
|
||||||
|
|
||||||
// Paper start - fix and optimise world upgrading
|
|
||||||
// copied from below
|
|
||||||
@@ -1614,7 +1615,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
||||||
this.rainLevel = f1;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Only check thundering once per world instead for every chunk
|
|
||||||
public boolean isThundering() {
|
|
||||||
+ return isCurrentlyThundering;
|
|
||||||
+ }
|
|
||||||
+ public boolean isThundering_old() {
|
|
||||||
+ // SparklyPaper end
|
|
||||||
return this.dimensionType().hasSkyLight() && !this.dimensionType().hasCeiling() ? (double) this.getThunderLevel(1.0F) > 0.9D : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sat, 28 Oct 2023 19:02:12 -0300
|
|
||||||
Subject: [PATCH] Optimize heavy EntityLookup.ArrayIterable.<init>() calls on
|
|
||||||
tickChunks
|
|
||||||
|
|
||||||
For some reason, on SparklyPower allocating an ArrayIterable is expensive, taking around ~2.5% of tick time (I have no idea why tho), because tickChunks() only uses this for the NaturalSpawner, let's avoid the array allocation by passing thru the raw array data + size
|
|
||||||
|
|
||||||
diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
|
|
||||||
index 15ee41452992714108efe53b708b5a4e1da7c1ff..f5a5796dda9e0e05ed9afc069c241dedd9aaffa0 100644
|
|
||||||
--- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
|
|
||||||
+++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java
|
|
||||||
@@ -198,6 +198,12 @@ public final class EntityLookup implements LevelEntityGetter<Entity> {
|
|
||||||
return Arrays.copyOf(this.accessibleEntities.getRawData(), this.accessibleEntities.size(), Entity[].class);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Optimize heavy EntityLookup$ArrayIterable.<init>() calls on tickChunks
|
|
||||||
+ public EntityList getAccessibleEntities() {
|
|
||||||
+ return this.accessibleEntities;
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
@Override
|
|
||||||
public <U extends Entity> void get(final EntityTypeTest<Entity, U> filter, final AbortableIterationConsumer<U> action) {
|
|
||||||
final Int2ReferenceOpenHashMap<Entity> entityCopy;
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
index f8270b78ab0d561e55301e989d80fe7b4118337a..e51d06140153e7f9a6e41b20addf02ec94e0f72c 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
|
||||||
@@ -545,9 +545,9 @@ public class ServerChunkCache extends ChunkSource {
|
|
||||||
}
|
|
||||||
// Paper end - per player mob spawning backoff
|
|
||||||
}
|
|
||||||
- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true);
|
|
||||||
+ spawnercreature_d = NaturalSpawner.createState(l, this.level.getEntityLookup().getAccessibleEntities().getRawData(), this.level.getEntityLookup().getAccessibleEntities().size(), this::getFullChunk, null, true); // SparklyPaper - Optimize heavy EntityLookup$ArrayIterable.<init>() calls on tickChunks
|
|
||||||
} else {
|
|
||||||
- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
|
|
||||||
+ spawnercreature_d = NaturalSpawner.createState(l, this.level.getEntityLookup().getAccessibleEntities().getRawData(), this.level.getEntityLookup().getAccessibleEntities().size(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); // SparklyPaper - Optimize heavy EntityLookup$ArrayIterable.<init>() calls on tickChunks
|
|
||||||
}
|
|
||||||
// Paper end
|
|
||||||
this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
||||||
index 9c2d62feff1816f5729060c6192269a5b2d34153..78bcb0af0735fe0ccf68ed06d8dc78d6e8c37064 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
|
|
||||||
@@ -74,7 +74,60 @@ public final class NaturalSpawner {
|
|
||||||
return createState(spawningChunkCount, entities, chunkSource, densityCapper, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Optimize heavy EntityLookup$ArrayIterable.<init>() calls on tickChunks
|
|
||||||
+ public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Entity[] entities, int count, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper, boolean countMobs) {
|
|
||||||
+ PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator();
|
|
||||||
+ Object2IntOpenHashMap<MobCategory> object2intopenhashmap = new Object2IntOpenHashMap();
|
|
||||||
+
|
|
||||||
+ for (int index = 0; count > index; index++) {
|
|
||||||
+ Entity entity = entities[index];
|
|
||||||
+
|
|
||||||
+ if (entity instanceof Mob) {
|
|
||||||
+ Mob entityinsentient = (Mob) entity;
|
|
||||||
+
|
|
||||||
+ if (entityinsentient.isPersistenceRequired() || entityinsentient.requiresCustomPersistence()) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ MobCategory enumcreaturetype = entity.getType().getCategory();
|
|
||||||
+
|
|
||||||
+ if (enumcreaturetype != MobCategory.MISC) {
|
|
||||||
+ // Paper start - Only count natural spawns
|
|
||||||
+ if (!entity.level().paperConfig().entities.spawning.countAllMobsForSpawning &&
|
|
||||||
+ !(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
|
|
||||||
+ entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
+ BlockPos blockposition = entity.blockPosition();
|
|
||||||
+
|
|
||||||
+ chunkSource.query(ChunkPos.asLong(blockposition), (chunk) -> {
|
|
||||||
+ MobSpawnSettings.MobSpawnCost biomesettingsmobs_b = NaturalSpawner.getRoughBiome(blockposition, chunk).getMobSettings().getMobSpawnCost(entity.getType());
|
|
||||||
+
|
|
||||||
+ if (biomesettingsmobs_b != null) {
|
|
||||||
+ spawnercreatureprobabilities.addCharge(entity.blockPosition(), biomesettingsmobs_b.charge());
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (densityCapper != null && entity instanceof Mob) { // Paper
|
|
||||||
+ densityCapper.addMob(chunk.getPos(), enumcreaturetype);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ object2intopenhashmap.addTo(enumcreaturetype, 1);
|
|
||||||
+ // Paper start
|
|
||||||
+ if (countMobs) {
|
|
||||||
+ chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
+ });
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return new NaturalSpawner.SpawnState(spawningChunkCount, object2intopenhashmap, spawnercreatureprobabilities, densityCapper);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper, boolean countMobs) {
|
|
||||||
+ // SparklyPaper end
|
|
||||||
// Paper end
|
|
||||||
PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator();
|
|
||||||
Object2IntOpenHashMap<MobCategory> object2intopenhashmap = new Object2IntOpenHashMap();
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Fri, 24 Nov 2023 23:37:24 -0300
|
|
||||||
Subject: [PATCH] BlockEntityTickersList optimization tests
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
index 94eac6837c06e6fd192c108632f1e365a008d6ad..3588657da9969b4207bbeb8109bc101384c03398 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
@@ -1274,8 +1274,8 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
||||||
// Iterator iterator = this.blockEntityTickers.iterator();
|
|
||||||
int tilesThisCycle = 0;
|
|
||||||
// SparklyPaper start - optimize tickBlockEntities
|
|
||||||
- // var toRemove = new it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet<TickingBlockEntity>(net.minecraft.Util.identityStrategy()); // Paper - use removeAll
|
|
||||||
- // toRemove.add(null);
|
|
||||||
+ var toRemoveOld = new it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet<TickingBlockEntity>(net.minecraft.Util.identityStrategy()); // Paper - use removeAll
|
|
||||||
+ toRemoveOld.add(null);
|
|
||||||
var toRemove = new java.util.HashSet<Integer>(); // For some reason, Java's HashSet seems to be faster than fastutil's only if we are removing HUGE amounts of tile entities, idk why
|
|
||||||
var startSearchFromIndex = -1;
|
|
||||||
var shouldTickBlocksAtLastResult = -1; // -1 = undefined
|
|
||||||
@@ -1301,13 +1301,13 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
||||||
// Spigot start
|
|
||||||
tilesThisCycle--;
|
|
||||||
// SparklyPaper start - optimize tickBlockEntities
|
|
||||||
- // toRemove.add(tickingblockentity); // Paper - use removeAll
|
|
||||||
+ toRemoveOld.add(tickingblockentity); // Paper - use removeAll
|
|
||||||
toRemove.add(tileTickPosition);
|
|
||||||
if (startSearchFromIndex == -1)
|
|
||||||
startSearchFromIndex = tileTickPosition;
|
|
||||||
// SparklyPaper end
|
|
||||||
// Spigot end
|
|
||||||
- // } else if (this.shouldTickBlocksAt(tickingblockentity.getPos())) { // SparklyPaper start - optimize tickBlockEntities
|
|
||||||
+ // } else if (this.shouldTickBlocksAt(tickingblockentity.getPos())) { // SparklyPaper start - optimize tickBlockEntities
|
|
||||||
} else {
|
|
||||||
long chunkPos = tickingblockentity.getChunkCoordinateKey();
|
|
||||||
boolean shouldTick;
|
|
||||||
@@ -1319,18 +1319,47 @@ public abstract class Level implements LevelAccessor, AutoCloseable {
|
|
||||||
shouldTickBlocksAtChunkPos = chunkPos;
|
|
||||||
}
|
|
||||||
if (shouldTick) {
|
|
||||||
- tickingblockentity.tick();
|
|
||||||
- // Paper start - execute chunk tasks during tick
|
|
||||||
- if ((this.tileTickPosition & 7) == 0) {
|
|
||||||
- // MinecraftServer.getServer().executeMidTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
|
||||||
- }
|
|
||||||
- // Paper end - execute chunk tasks during tick
|
|
||||||
+ tickingblockentity.tick();
|
|
||||||
+ // Paper start - execute chunk tasks during tick
|
|
||||||
+ if ((this.tileTickPosition & 7) == 0) {
|
|
||||||
+ // MinecraftServer.getServer().executeMidTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
|
||||||
+ }
|
|
||||||
+ // Paper end - execute chunk tasks during tick
|
|
||||||
} // SparklyPaper end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// SparklyPaper start - optimize tickBlockEntities
|
|
||||||
- // this.blockEntityTickers.removeAll(toRemove);
|
|
||||||
- this.blockEntityTickers.removeAllByIndex(startSearchFromIndex, toRemove); // We don't need to care about if the startSearchFromIndex can be -1 here, since if it is -1, then the toRemove list is empty and the call will fast fail
|
|
||||||
+ java.util.ArrayList<TickingBlockEntity> oldList = new java.util.ArrayList<>(this.blockEntityTickers);
|
|
||||||
+ long diffOld = 0;
|
|
||||||
+ long diffNew = 0;
|
|
||||||
+ if (toRemoveOld.size() != 1) { // the old one always have null as the first element
|
|
||||||
+ var startOld = System.nanoTime();
|
|
||||||
+ oldList.removeAll(toRemoveOld);
|
|
||||||
+ var endOld = System.nanoTime();
|
|
||||||
+ diffOld = endOld - startOld;
|
|
||||||
+ System.out.println("Old version deleted " + toRemoveOld.size() + " elements, took " + diffOld + "ns");
|
|
||||||
+ }
|
|
||||||
+ if (startSearchFromIndex != -1) {
|
|
||||||
+ var start = System.nanoTime();
|
|
||||||
+ this.blockEntityTickers.removeAllByIndex(startSearchFromIndex, toRemove); // We don't need to care about if the startSearchFromIndex can be -1 here, since if it is -1, then the toRemove list is empty and the call will fast fail
|
|
||||||
+ var end = System.nanoTime();
|
|
||||||
+ System.out.println("(current tick: " + this.getServer().getTickCount() + ") startSearchFromIndex: " + startSearchFromIndex + " - toRemove: " + toRemove);
|
|
||||||
+ diffNew = end - start;
|
|
||||||
+ System.out.println("New version deleted " + toRemove.size() + " elements, took " + diffNew + "ns");
|
|
||||||
+ }
|
|
||||||
+ if (toRemove.size() != 0) {
|
|
||||||
+ System.out.println("Equals? " + oldList.equals(this.blockEntityTickers));
|
|
||||||
+ String winner = "Unknown";
|
|
||||||
+ long perfIncrease = 0;
|
|
||||||
+ if (diffOld > diffNew) {
|
|
||||||
+ winner = "New Version";
|
|
||||||
+ perfIncrease = diffOld - diffNew;
|
|
||||||
+ } else {
|
|
||||||
+ winner = "Old Version";
|
|
||||||
+ perfIncrease = diffNew - diffOld;
|
|
||||||
+ }
|
|
||||||
+ System.out.println("Who won? " + winner + ", by " + perfIncrease + "ns");
|
|
||||||
+ }
|
|
||||||
// SparklyPaper end
|
|
||||||
this.timings.tileEntityTick.stopTiming(); // Spigot
|
|
||||||
this.tickingBlockEntities = false;
|
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Fri, 13 Dec 2024 16:35:12 -0300
|
|
||||||
Subject: [PATCH] Extend AsyncPlayerPreLoginEvent to allow plugins to send
|
|
||||||
Login Plugin Requests to the client
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
||||||
index 033755682c61c889723c3669b5cff4de147f637e..8809a4ee30d0701dab85556c54e29a5c315790bc 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
|
||||||
@@ -92,6 +92,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
|
||||||
private ServerPlayer player; // CraftBukkit
|
|
||||||
public boolean iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation = false; // Paper - username validation overriding
|
|
||||||
private int velocityLoginMessageId = -1; // Paper - Add Velocity IP Forwarding Support
|
|
||||||
+ private net.sparklypower.sparklypaper.CraftPendingConnection pendingConnection = new net.sparklypower.sparklypaper.CraftPendingConnection(this);
|
|
||||||
|
|
||||||
public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) {
|
|
||||||
this.state = ServerLoginPacketListenerImpl.State.HELLO;
|
|
||||||
@@ -368,7 +369,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
|
||||||
// Paper start - Add more fields to AsyncPlayerPreLoginEvent
|
|
||||||
final InetAddress rawAddress = ((InetSocketAddress) this.connection.channel.remoteAddress()).getAddress();
|
|
||||||
com.destroystokyo.paper.profile.PlayerProfile profile = com.destroystokyo.paper.profile.CraftPlayerProfile.asBukkitMirror(gameprofile); // Paper - setPlayerProfileAPI
|
|
||||||
- AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, this.transferred, profile, this.connection.hostname);
|
|
||||||
+ AsyncPlayerPreLoginEvent asyncEvent = new AsyncPlayerPreLoginEvent(playerName, address, rawAddress, uniqueId, this.transferred, profile, this.connection.hostname, this.pendingConnection); // SparklyPaper - Add support for login plugin requests
|
|
||||||
server.getPluginManager().callEvent(asyncEvent);
|
|
||||||
profile = asyncEvent.getPlayerProfile();
|
|
||||||
profile.complete(true); // Paper - setPlayerProfileAPI
|
|
||||||
@@ -450,6 +451,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Paper end - Add Velocity IP Forwarding Support
|
|
||||||
+ // SparklyPaper - Add support for login plugin requests
|
|
||||||
+ if (pendingConnection.handleLoginPluginResponse(packet)) {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
this.disconnect(ServerCommonPacketListenerImpl.DISCONNECT_UNEXPECTED_QUERY);
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/CraftPendingConnection.kt b/src/main/kotlin/net/sparklypower/sparklypaper/CraftPendingConnection.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..59570030537f5ffedd199e2c74c11f9510bc4147
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/CraftPendingConnection.kt
|
|
||||||
@@ -0,0 +1,68 @@
|
|
||||||
+package net.sparklypower.sparklypaper
|
|
||||||
+
|
|
||||||
+import com.google.common.base.Preconditions
|
|
||||||
+import io.netty.buffer.Unpooled
|
|
||||||
+import net.minecraft.network.FriendlyByteBuf
|
|
||||||
+import net.minecraft.network.protocol.login.ClientboundCustomQueryPacket
|
|
||||||
+import net.minecraft.network.protocol.login.ServerboundCustomQueryAnswerPacket
|
|
||||||
+import net.minecraft.server.network.ServerLoginPacketListenerImpl
|
|
||||||
+import org.bukkit.NamespacedKey
|
|
||||||
+import org.bukkit.craftbukkit.util.CraftNamespacedKey
|
|
||||||
+import java.util.*
|
|
||||||
+import java.util.concurrent.CompletableFuture
|
|
||||||
+
|
|
||||||
+class CraftPendingConnection(val manager: ServerLoginPacketListenerImpl) : PendingConnection {
|
|
||||||
+ private val requestedLoginData: Queue<LoginDataFuture> = LinkedList()
|
|
||||||
+
|
|
||||||
+ override fun sendLoginPluginRequest(
|
|
||||||
+ transactionId: Int,
|
|
||||||
+ channel: NamespacedKey,
|
|
||||||
+ data: ByteArray
|
|
||||||
+ ): CompletableFuture<PendingConnection.LoginPluginResponse> {
|
|
||||||
+ val future = CompletableFuture<PendingConnection.LoginPluginResponse>()
|
|
||||||
+
|
|
||||||
+ this.requestedLoginData.add(LoginDataFuture(transactionId, future))
|
|
||||||
+ manager.sendPacket(
|
|
||||||
+ ClientboundCustomQueryPacket(
|
|
||||||
+ transactionId,
|
|
||||||
+ ClientboundCustomQueryPacket.PlayerInfoChannelPayload(
|
|
||||||
+ CraftNamespacedKey.toMinecraft(channel),
|
|
||||||
+ FriendlyByteBuf(Unpooled.wrappedBuffer(data))
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ return future
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fun handleLoginPluginResponse(response: ServerboundCustomQueryAnswerPacket): Boolean {
|
|
||||||
+ val future = this.requestedLoginData.peek()
|
|
||||||
+ if (future != null) {
|
|
||||||
+ if (future.transactionId == response.transactionId) {
|
|
||||||
+ Preconditions.checkState(future === this.requestedLoginData.poll(), "requestedLoginData queue mismatch")
|
|
||||||
+ if (response.payload == null) {
|
|
||||||
+ future.future.complete(PendingConnection.LoginPluginResponse(false, null))
|
|
||||||
+ return true
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ val payload = response.payload as ServerboundCustomQueryAnswerPacket.QueryAnswerPayload
|
|
||||||
+
|
|
||||||
+ // Ensure the reader index and writer index are not modified
|
|
||||||
+ val readableBytes: Int = payload.buffer.readableBytes()
|
|
||||||
+ val byteArray = ByteArray(readableBytes)
|
|
||||||
+
|
|
||||||
+ // Copy the readable bytes into the byte array
|
|
||||||
+ payload.buffer.getBytes(payload.buffer.readerIndex(), byteArray)
|
|
||||||
+
|
|
||||||
+ future.future.complete(PendingConnection.LoginPluginResponse(true, byteArray))
|
|
||||||
+
|
|
||||||
+ return true
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return false
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @JvmRecord
|
|
||||||
+ data class LoginDataFuture(val transactionId: Int, val future: CompletableFuture<PendingConnection.LoginPluginResponse>)
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sat, 12 Jun 2021 16:40:34 +0200
|
|
||||||
Subject: [PATCH] new fork who dis - Rebrand to SparklyPaper and Build Changes
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/build.gradle.kts b/build.gradle.kts
|
|
||||||
index faf3e3fd72e8c915e7a4803dacbe1bb576c6663e..144c7a15a51f0d22f3c35412fa7aa395d092bebc 100644
|
|
||||||
--- a/build.gradle.kts
|
|
||||||
+++ b/build.gradle.kts
|
|
||||||
@@ -3,6 +3,8 @@ import java.time.Instant
|
|
||||||
|
|
||||||
plugins {
|
|
||||||
java
|
|
||||||
+ kotlin("jvm") version "2.0.0"
|
|
||||||
+ kotlin("plugin.serialization") version "2.0.0"
|
|
||||||
`maven-publish`
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -25,7 +27,12 @@ abstract class MockitoAgentProvider : CommandLineArgumentProvider {
|
|
||||||
// Paper end - configure mockito agent that is needed in newer java versions
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
- implementation(project(":paper-api"))
|
|
||||||
+ // SparklyPaper start
|
|
||||||
+ implementation(project(":sparklypaper-api"))
|
|
||||||
+ implementation(kotlin("reflect"))
|
|
||||||
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
|
||||||
+ implementation("com.charleskorn.kaml:kaml:0.55.0")
|
|
||||||
+ // SparklyPaper end
|
|
||||||
// Paper start
|
|
||||||
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
|
|
||||||
@@ -94,7 +101,12 @@ tasks.jar {
|
|
||||||
val mcVersion = rootProject.providers.gradleProperty("mcVersion").get()
|
|
||||||
val build = System.getenv("BUILD_NUMBER") ?: null
|
|
||||||
val gitHash = git("rev-parse", "--short=7", "HEAD").getText().trim()
|
|
||||||
- val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
|
||||||
+ // SparklyPaper start
|
|
||||||
+ var implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
|
||||||
+ if (project.hasProperty("sparklypaperImplementationVersionSuffix")) {
|
|
||||||
+ implementationVersion += "/${project.property("sparklypaperImplementationVersionSuffix")}"
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
val date = git("show", "-s", "--format=%ci", gitHash).getText().trim() // Paper
|
|
||||||
val gitBranch = git("rev-parse", "--abbrev-ref", "HEAD").getText().trim() // Paper
|
|
||||||
attributes(
|
|
||||||
@@ -105,8 +117,8 @@ tasks.jar {
|
|
||||||
"Specification-Title" to "Paper",
|
|
||||||
"Specification-Version" to project.version,
|
|
||||||
"Specification-Vendor" to "Paper Team",
|
|
||||||
- "Brand-Id" to "papermc:paper",
|
|
||||||
- "Brand-Name" to "Paper",
|
|
||||||
+ "Brand-Id" to "sparklypower:sparklypaper", // SparklyPaper
|
|
||||||
+ "Brand-Name" to "SparklyPaper", // SparklyPaper
|
|
||||||
"Build-Number" to (build ?: ""),
|
|
||||||
"Build-Time" to Instant.now().toString(),
|
|
||||||
"Git-Branch" to gitBranch, // Paper
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
|
||||||
index 774556a62eb240da42e84db4502e2ed43495be17..9bc7b99b5b39a8ffe4118b8d86f5b8065c4fe460 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/net.sparklypower.sparklypaper/sparklypaper-api/pom.properties"); // SparklyPaper
|
|
||||||
Properties properties = new Properties();
|
|
||||||
|
|
||||||
if (stream != null) {
|
|
||||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
||||||
index f7a4fee9bb25ff256dc2e5ea26bfbceca6a49167..e7321e56c6ba3c601641c6466857331e9fe5f4bb 100644
|
|
||||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
|
||||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
|
||||||
@@ -155,14 +155,14 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
|
||||||
if (isLongTimeout) {
|
|
||||||
// Paper end
|
|
||||||
log.log( Level.SEVERE, "------------------------------" );
|
|
||||||
- log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug." ); // Paper
|
|
||||||
+ log.log( Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug. This could be a SparklyPaper bug and, in that case, MrPowerGamerBR probably made a fucky wucky!" ); // SparklyPaper - branding changes // Paper
|
|
||||||
log.log( Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author" );
|
|
||||||
log.log( Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring" );
|
|
||||||
log.log( Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once" );
|
|
||||||
log.log( Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes" );
|
|
||||||
- log.log( Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues" );
|
|
||||||
+ log.log( Level.SEVERE, "If you are unsure or still think this is a SparklyPaper bug, please report this to https://github.com/SparklyPower/SparklyPaper/issues - and if you think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues" );
|
|
||||||
log.log( Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports" );
|
|
||||||
- log.log( Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion() );
|
|
||||||
+ log.log( Level.SEVERE, "SparklyPaper version: " + Bukkit.getServer().getVersion() ); // SparklyPaper - branding changes
|
|
||||||
//
|
|
||||||
if ( net.minecraft.world.level.Level.lastPhysicsProblem != null )
|
|
||||||
{
|
|
||||||
@@ -189,7 +189,7 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
|
||||||
}
|
|
||||||
// Paper end - Different message for short timeout
|
|
||||||
log.log( Level.SEVERE, "------------------------------" );
|
|
||||||
- log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):" ); // Paper
|
|
||||||
+ log.log( Level.SEVERE, "Server thread dump (Look for plugins here before reporting to SparklyPaper!):" ); // SparklyPaper - branding changes // Paper
|
|
||||||
ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - rewrite chunk system
|
|
||||||
this.dumpTickingInfo(); // Paper - log detailed tick information
|
|
||||||
WatchdogThread.dumpThread( ManagementFactory.getThreadMXBean().getThreadInfo( MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE ), log );
|
|
||||||
@@ -1,444 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sun, 22 Oct 2023 09:35:07 -0300
|
|
||||||
Subject: [PATCH] SparklyPaper config files
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
||||||
index 17a158ff6ce6520b69a5a0032ba4c05449dd0cf8..bb8975cd3d3b1c57f313ad31b5e767fa93ad8e13 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
||||||
@@ -235,6 +235,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
||||||
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
|
||||||
this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
|
|
||||||
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
|
|
||||||
+ // SparklyPaper start
|
|
||||||
+ try {
|
|
||||||
+ net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((java.io.File) options.valueOf("sparklypaper-settings"));
|
|
||||||
+ } catch (Exception e) {
|
|
||||||
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+ net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
|
||||||
+ // SparklyPaper end
|
|
||||||
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
|
||||||
|
|
||||||
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
index 2cc264f577fdd81d02783e0d6146bea9728789c7..8433caa61a973d81a5eedc44428926e999c21a03 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
@@ -174,6 +174,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
// Paper end - add paper world config
|
|
||||||
|
|
||||||
public final com.destroystokyo.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
|
||||||
+ public net.sparklypower.sparklypaper.configs.SparklyPaperConfig.SparklyPaperWorldConfig sparklyPaperConfig; // SparklyPaper
|
|
||||||
public static BlockPos lastPhysicsProblem; // Spigot
|
|
||||||
private org.spigotmc.TickLimiter entityLimiter;
|
|
||||||
private org.spigotmc.TickLimiter tileLimiter;
|
|
||||||
@@ -842,6 +843,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
// Paper end - getblock optimisations - cache world height/sections
|
|
||||||
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // Spigot
|
|
||||||
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
|
||||||
+ this.sparklyPaperConfig = net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getWorldSettings(((net.minecraft.world.level.storage.PrimaryLevelData) worlddatamutable).getLevelName()); // SparklyPaper
|
|
||||||
this.generator = gen;
|
|
||||||
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/commands/SparklyPaperCommand.java b/src/main/java/net/sparklypower/sparklypaper/commands/SparklyPaperCommand.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..bc0ec96f91f7c9ab9f9a865a50f69707fab8fd27
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/commands/SparklyPaperCommand.java
|
|
||||||
@@ -0,0 +1,65 @@
|
|
||||||
+package net.sparklypower.sparklypaper.commands;
|
|
||||||
+
|
|
||||||
+import net.minecraft.server.MinecraftServer;
|
|
||||||
+import net.minecraft.server.level.ServerLevel;
|
|
||||||
+import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils;
|
|
||||||
+import org.bukkit.ChatColor;
|
|
||||||
+import org.bukkit.Location;
|
|
||||||
+import org.bukkit.command.Command;
|
|
||||||
+import org.bukkit.command.CommandSender;
|
|
||||||
+
|
|
||||||
+import java.io.File;
|
|
||||||
+import java.util.Collections;
|
|
||||||
+import java.util.List;
|
|
||||||
+import java.util.stream.Collectors;
|
|
||||||
+import java.util.stream.Stream;
|
|
||||||
+
|
|
||||||
+public class SparklyPaperCommand extends Command {
|
|
||||||
+ public SparklyPaperCommand(String name) {
|
|
||||||
+ super(name);
|
|
||||||
+ this.description = "SparklyPaper related commands";
|
|
||||||
+ this.usageMessage = "/sparklypaper [reload | version]";
|
|
||||||
+ this.setPermission("bukkit.command.sparklypaper");
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
|
|
||||||
+ if (args.length == 1) {
|
|
||||||
+ return Stream.of("reload", "version")
|
|
||||||
+ .filter(arg -> arg.startsWith(args[0].toLowerCase()))
|
|
||||||
+ .collect(Collectors.toList());
|
|
||||||
+ }
|
|
||||||
+ return Collections.emptyList();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Override
|
|
||||||
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
|
||||||
+ if (!testPermission(sender)) return true;
|
|
||||||
+
|
|
||||||
+ if (args.length != 1) {
|
|
||||||
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
|
||||||
+ return false;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (args[0].equalsIgnoreCase("reload")) {
|
|
||||||
+ 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.");
|
|
||||||
+
|
|
||||||
+ MinecraftServer console = MinecraftServer.getServer();
|
|
||||||
+ SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings"));
|
|
||||||
+ for (ServerLevel level : console.getAllLevels()) {
|
|
||||||
+ level.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(level.serverLevelData.getLevelName());
|
|
||||||
+ }
|
|
||||||
+ console.server.reloadCount++;
|
|
||||||
+
|
|
||||||
+ Command.broadcastCommandMessage(sender, ChatColor.GREEN + "SparklyPaper config reload complete.");
|
|
||||||
+ } else if (args[0].equalsIgnoreCase("version")) {
|
|
||||||
+ Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
|
|
||||||
+ if (verCmd != null) {
|
|
||||||
+ return verCmd.execute(sender, commandLabel, new String[0]);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return true;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
||||||
index ac8af406180bc680d46e8edc3da0fc2e5211345a..29f01accd1cf8de9f97de8533a3a6299dfc80417 100644
|
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
|
||||||
@@ -111,6 +111,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage;
|
|
||||||
import net.minecraft.world.level.storage.PrimaryLevelData;
|
|
||||||
import net.minecraft.world.level.validation.ContentValidationException;
|
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
+import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils;
|
|
||||||
import org.bukkit.BanList;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
@@ -1086,6 +1087,7 @@ public final class CraftServer implements Server {
|
|
||||||
|
|
||||||
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
|
|
||||||
this.console.paperConfigurations.reloadConfigs(this.console);
|
|
||||||
+ net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings")); // SparklyPaper
|
|
||||||
for (ServerLevel world : this.console.getAllLevels()) {
|
|
||||||
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
|
||||||
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
|
||||||
@@ -1101,6 +1103,7 @@ public final class CraftServer implements Server {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
world.spigotConfig.init(); // Spigot
|
|
||||||
+ world.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(world.serverLevelData.getLevelName()); // SparklyPaper
|
|
||||||
}
|
|
||||||
|
|
||||||
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
|
||||||
@@ -1118,6 +1121,7 @@ public final class CraftServer implements Server {
|
|
||||||
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
|
||||||
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
|
|
||||||
this.spark.registerCommandBeforePlugins(this); // Paper - spark
|
|
||||||
+ net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this.console); // SparklyPaper
|
|
||||||
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
|
||||||
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
|
||||||
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
||||||
index be0d38544395a9b3befb898bb961f34e32fe9509..522efbfaedb20fe3650c6ebe3c1678ee5c0f236a 100644
|
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
|
||||||
@@ -176,6 +176,14 @@ public class Main {
|
|
||||||
.describedAs("Jar file");
|
|
||||||
// Paper end
|
|
||||||
|
|
||||||
+ // SparklyPaper Start
|
|
||||||
+ acceptsAll(asList("sparklypaper", "sparklypaper-settings"), "File for SparklyPaper settings")
|
|
||||||
+ .withRequiredArg()
|
|
||||||
+ .ofType(File.class)
|
|
||||||
+ .defaultsTo(new File("sparklypaper.yml"))
|
|
||||||
+ .describedAs("Yml file");
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
// Paper start
|
|
||||||
acceptsAll(asList("server-name"), "Name of the server")
|
|
||||||
.withRequiredArg()
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/SparklyPaperCommands.kt b/src/main/kotlin/net/sparklypower/sparklypaper/SparklyPaperCommands.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..614e64ce6bf5bb7fab5758250927a0d3949d0917
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/SparklyPaperCommands.kt
|
|
||||||
@@ -0,0 +1,22 @@
|
|
||||||
+package net.sparklypower.sparklypaper
|
|
||||||
+
|
|
||||||
+import net.minecraft.server.MinecraftServer
|
|
||||||
+import net.sparklypower.sparklypaper.commands.SparklyPaperCommand
|
|
||||||
+import org.bukkit.command.Command
|
|
||||||
+import org.checkerframework.checker.nullness.qual.NonNull
|
|
||||||
+import org.checkerframework.framework.qual.DefaultQualifier
|
|
||||||
+
|
|
||||||
+@DefaultQualifier(NonNull::class)
|
|
||||||
+object SparklyPaperCommands {
|
|
||||||
+ private val COMMANDS = mapOf(
|
|
||||||
+ "sparklypaper" to SparklyPaperCommand("sparklypaper")
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ fun registerCommands(server: MinecraftServer) {
|
|
||||||
+ COMMANDS.forEach { (s: String, command: Command) ->
|
|
||||||
+ server.server.commandMap.register(
|
|
||||||
+ s, "SparklyPaper", command
|
|
||||||
+ )
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfig.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfig.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..f633fe54c176c4e6ec46e54078f8485efadf0fce
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfig.kt
|
|
||||||
@@ -0,0 +1,50 @@
|
|
||||||
+package net.sparklypower.sparklypaper.configs
|
|
||||||
+
|
|
||||||
+import kotlinx.serialization.SerialName
|
|
||||||
+import kotlinx.serialization.Serializable
|
|
||||||
+
|
|
||||||
+@Serializable
|
|
||||||
+class SparklyPaperConfig(
|
|
||||||
+ @SerialName("config-version")
|
|
||||||
+ override val configVersion: Int,
|
|
||||||
+ @SerialName("parallel-world-ticking")
|
|
||||||
+ val parallelWorldTicking: ParallelWorldTicking,
|
|
||||||
+ @SerialName("world-settings")
|
|
||||||
+ val worldSettings: Map<String, SparklyPaperWorldConfig>
|
|
||||||
+) : UpgradeableConfig {
|
|
||||||
+ override fun isNewest() = true
|
|
||||||
+
|
|
||||||
+ override fun upgradeToNext() = error("This config is already the newest version!")
|
|
||||||
+
|
|
||||||
+ @Serializable
|
|
||||||
+ class ParallelWorldTicking(
|
|
||||||
+ val threads: Int
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ @Serializable
|
|
||||||
+ class SparklyPaperWorldConfig(
|
|
||||||
+ @SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
|
||||||
+ val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
|
||||||
+ @SerialName("blazingly-simple-farm-checks")
|
|
||||||
+ val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks,
|
|
||||||
+ @SerialName("ticks-per")
|
|
||||||
+ val ticksPer: TicksPer,
|
|
||||||
+ ) {
|
|
||||||
+ @Serializable
|
|
||||||
+ data class BlazinglySimpleFarmChecks(
|
|
||||||
+ val enabled: Boolean,
|
|
||||||
+ @SerialName("default-growth-speed")
|
|
||||||
+ val defaultGrowthSpeed: Float,
|
|
||||||
+ @SerialName("moist-growth-speed")
|
|
||||||
+ val moistGrowthSpeed: Float,
|
|
||||||
+ @SerialName("skip-middle-aging-stages-for-crops")
|
|
||||||
+ val skipMiddleAgingStagesForCrops: Boolean
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ @Serializable
|
|
||||||
+ data class TicksPer(
|
|
||||||
+ @SerialName("hopper-cooldown-when-target-container-is-full")
|
|
||||||
+ val hopperCooldownWhenTargetContainerIsFull: Int
|
|
||||||
+ )
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..072b5811acf9ecc58e3bba7f74dc0dcf8556e848
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/SparklyPaperConfigUtils.kt
|
|
||||||
@@ -0,0 +1,93 @@
|
|
||||||
+package net.sparklypower.sparklypaper.configs
|
|
||||||
+
|
|
||||||
+import com.charleskorn.kaml.*
|
|
||||||
+import com.google.common.base.Throwables
|
|
||||||
+import kotlinx.serialization.SerializationException
|
|
||||||
+import kotlinx.serialization.decodeFromString
|
|
||||||
+import kotlinx.serialization.encodeToString
|
|
||||||
+import net.sparklypower.sparklypaper.configs.previous.SparklyPaperConfigV1
|
|
||||||
+import org.bukkit.Bukkit
|
|
||||||
+import java.io.File
|
|
||||||
+import java.util.logging.Level
|
|
||||||
+
|
|
||||||
+object SparklyPaperConfigUtils {
|
|
||||||
+ private const val CURRENT_CONFIG_VERSION = 2
|
|
||||||
+ val yaml = Yaml(
|
|
||||||
+ configuration = YamlConfiguration(
|
|
||||||
+ strictMode = false
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ val deserializationStrategiesForVersions = mapOf(
|
|
||||||
+ 1 to SparklyPaperConfigV1.serializer(),
|
|
||||||
+ CURRENT_CONFIG_VERSION to SparklyPaperConfig.serializer()
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ lateinit var config: SparklyPaperConfig
|
|
||||||
+
|
|
||||||
+ fun init(configFile: File) {
|
|
||||||
+ // Write default config if the file doesn't exist
|
|
||||||
+ if (!configFile.exists()) {
|
|
||||||
+ configFile.writeText(
|
|
||||||
+ yaml.encodeToString(
|
|
||||||
+ SparklyPaperConfig(
|
|
||||||
+ CURRENT_CONFIG_VERSION,
|
|
||||||
+ SparklyPaperConfig.ParallelWorldTicking(
|
|
||||||
+ threads = 8
|
|
||||||
+ ),
|
|
||||||
+ mapOf(
|
|
||||||
+ "default" to SparklyPaperConfig.SparklyPaperWorldConfig(
|
|
||||||
+ skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer = true,
|
|
||||||
+ blazinglySimpleFarmChecks = SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
|
||||||
+ enabled = false,
|
|
||||||
+ defaultGrowthSpeed = 1.0f,
|
|
||||||
+ moistGrowthSpeed = 5.0f,
|
|
||||||
+ skipMiddleAgingStagesForCrops = true
|
|
||||||
+ ),
|
|
||||||
+ SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
|
||||||
+ hopperCooldownWhenTargetContainerIsFull = 0
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ val loadedConfig = try {
|
|
||||||
+ // Read the version file from the config before attempting to parse
|
|
||||||
+ val yamlNode = yaml.parseToYamlNode(configFile.readText())
|
|
||||||
+ var configVersion = yamlNode.yamlMap.getScalar("config-version")?.toInt() ?: 1 // The first config version didn't have the "config-version" key
|
|
||||||
+
|
|
||||||
+ if (configVersion != CURRENT_CONFIG_VERSION) {
|
|
||||||
+ var upgradedVersion: UpgradeableConfig? = null
|
|
||||||
+
|
|
||||||
+ while (configVersion != CURRENT_CONFIG_VERSION) {
|
|
||||||
+ Bukkit.getLogger().log(Level.INFO, "Attempting to upgrade SparklyPaper Config from version $configVersion to the next version...")
|
|
||||||
+
|
|
||||||
+ val upgradeableConfig = yaml.decodeFromYamlNode(deserializationStrategiesForVersions[configVersion]!!, yamlNode)
|
|
||||||
+ if (!upgradeableConfig.isNewest()) {
|
|
||||||
+ upgradedVersion = upgradeableConfig.upgradeToNext()
|
|
||||||
+
|
|
||||||
+ Bukkit.getLogger().log(Level.INFO, "Upgraded SparklyPaper Config from version $configVersion to ${upgradedVersion.configVersion}")
|
|
||||||
+ configVersion = upgradedVersion.configVersion
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ upgradedVersion as SparklyPaperConfig
|
|
||||||
+ } else {
|
|
||||||
+ yaml.decodeFromYamlNode(SparklyPaperConfig.serializer(), yamlNode)
|
|
||||||
+ }
|
|
||||||
+ } catch (e: SerializationException) {
|
|
||||||
+ Bukkit.getLogger().log(Level.SEVERE, "Could not load sparklypaper.yml, please correct your syntax errors", e)
|
|
||||||
+ throw Throwables.propagate(e)
|
|
||||||
+ }
|
|
||||||
+ // Rewrite the config file to remove old fields and stuff
|
|
||||||
+ // TODO: Maybe handle this in another way? This feels kinda bad
|
|
||||||
+ configFile.writeText(yaml.encodeToString(loadedConfig))
|
|
||||||
+ config = loadedConfig
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fun getWorldSettings(levelName: String): SparklyPaperConfig.SparklyPaperWorldConfig {
|
|
||||||
+ return config.worldSettings[levelName] ?: config.worldSettings["default"] ?: error("Missing default world-settings in sparklypaper.yml!")
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/UpgradeableConfig.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/UpgradeableConfig.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..e6de89ef69bd492a9e9facaa189e260678e2c6e6
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/UpgradeableConfig.kt
|
|
||||||
@@ -0,0 +1,7 @@
|
|
||||||
+package net.sparklypower.sparklypaper.configs
|
|
||||||
+
|
|
||||||
+interface UpgradeableConfig {
|
|
||||||
+ abstract val configVersion: Int
|
|
||||||
+ fun isNewest(): Boolean
|
|
||||||
+ fun upgradeToNext(): UpgradeableConfig
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/configs/previous/SparklyPaperConfigV1.kt b/src/main/kotlin/net/sparklypower/sparklypaper/configs/previous/SparklyPaperConfigV1.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..fe86a557388cea29dfad8ba5e3990e3272cf0c55
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/configs/previous/SparklyPaperConfigV1.kt
|
|
||||||
@@ -0,0 +1,65 @@
|
|
||||||
+package net.sparklypower.sparklypaper.configs.previous
|
|
||||||
+
|
|
||||||
+import kotlinx.serialization.SerialName
|
|
||||||
+import kotlinx.serialization.Serializable
|
|
||||||
+import net.sparklypower.sparklypaper.configs.SparklyPaperConfig
|
|
||||||
+import net.sparklypower.sparklypaper.configs.UpgradeableConfig
|
|
||||||
+
|
|
||||||
+@Serializable
|
|
||||||
+class SparklyPaperConfigV1(
|
|
||||||
+ @SerialName("parallel-world-ticking")
|
|
||||||
+ val parallelWorldTicking: ParallelWorldTicking,
|
|
||||||
+ @SerialName("world-settings")
|
|
||||||
+ val worldSettings: Map<String, SparklyPaperWorldConfig>
|
|
||||||
+) : UpgradeableConfig {
|
|
||||||
+ override val configVersion = 1
|
|
||||||
+
|
|
||||||
+ override fun isNewest() = false
|
|
||||||
+
|
|
||||||
+ override fun upgradeToNext(): UpgradeableConfig {
|
|
||||||
+ return SparklyPaperConfig(
|
|
||||||
+ 2,
|
|
||||||
+ SparklyPaperConfig.ParallelWorldTicking(
|
|
||||||
+ this.parallelWorldTicking.threads
|
|
||||||
+ ),
|
|
||||||
+ worldSettings.mapValues {
|
|
||||||
+ SparklyPaperConfig.SparklyPaperWorldConfig(
|
|
||||||
+ it.value.skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer,
|
|
||||||
+ SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
|
||||||
+ it.value.blazinglySimpleFarmChecks.enabled,
|
|
||||||
+ it.value.blazinglySimpleFarmChecks.defaultGrowthSpeed,
|
|
||||||
+ it.value.blazinglySimpleFarmChecks.moistGrowthSpeed,
|
|
||||||
+ it.value.blazinglySimpleFarmChecks.skipMiddleAgingStagesForCrops,
|
|
||||||
+ ),
|
|
||||||
+ SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
|
||||||
+ 0
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ }
|
|
||||||
+ )
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ @Serializable
|
|
||||||
+ class ParallelWorldTicking(
|
|
||||||
+ val threads: Int
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ @Serializable
|
|
||||||
+ class SparklyPaperWorldConfig(
|
|
||||||
+ @SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
|
||||||
+ val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
|
||||||
+ @SerialName("blazingly-simple-farm-checks")
|
|
||||||
+ val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks
|
|
||||||
+ ) {
|
|
||||||
+ @Serializable
|
|
||||||
+ data class BlazinglySimpleFarmChecks(
|
|
||||||
+ val enabled: Boolean,
|
|
||||||
+ @SerialName("default-growth-speed")
|
|
||||||
+ val defaultGrowthSpeed: Float,
|
|
||||||
+ @SerialName("moist-growth-speed")
|
|
||||||
+ val moistGrowthSpeed: Float,
|
|
||||||
+ @SerialName("skip-middle-aging-stages-for-crops")
|
|
||||||
+ val skipMiddleAgingStagesForCrops: Boolean
|
|
||||||
+ )
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
@@ -1,297 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Warrior <50800980+Warriorrrr@users.noreply.github.com>
|
|
||||||
Date: Mon, 14 Aug 2023 17:34:53 +0200
|
|
||||||
Subject: [PATCH] Rewrite framed map tracker ticking
|
|
||||||
|
|
||||||
Rewrites the tracking code for framed maps to remove the use of the tickCarriedBy method and the HoldingPlayer class.
|
|
||||||
The tickCarriedBy method contained a lot of code that did not apply to framed maps at all, and by moving the parts
|
|
||||||
that did elsewhere, we can essentially skip it. The only logic that's ran inside the ServerEntity#sendChanges for maps
|
|
||||||
now is just updating dirty map/decoration data.
|
|
||||||
|
|
||||||
When no bukkit renderers are added to the map, we also re-use the same packet for all players who are tracking it which avoids a lot of work.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
index 90eb4927fa51ce3df86aa7b6c71f49150a03e337..9938d359de5b179ff486390288d481d6ece1ecf3 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
@@ -128,27 +128,40 @@ public class ServerEntity {
|
|
||||||
|
|
||||||
Entity entity = this.entity;
|
|
||||||
|
|
||||||
- if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame entityitemframe) { // Paper - Perf: Only tick item frames if players can see it
|
|
||||||
+ if (!this.trackedPlayers.isEmpty() && entity instanceof ItemFrame entityitemframe && entityitemframe.cachedMapId != null) { // Paper - Perf: Only tick item frames if players can see it // Paper
|
|
||||||
if (true || this.tickCount % 10 == 0) { // CraftBukkit - Moved below, should always enter this block
|
|
||||||
- ItemStack itemstack = entityitemframe.getItem();
|
|
||||||
+ //ItemStack itemstack = entityitemframe.getItem(); // Paper - skip redundant getItem
|
|
||||||
|
|
||||||
- if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 && itemstack.getItem() instanceof MapItem) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable
|
|
||||||
+ if (this.level.paperConfig().maps.itemFrameCursorUpdateInterval > 0 && this.tickCount % this.level.paperConfig().maps.itemFrameCursorUpdateInterval == 0 /*&& itemstack.getItem() instanceof MapItem*/) { // CraftBukkit - Moved this.tickCounter % 10 logic here so item frames do not enter the other blocks // Paper - Make item frame map cursor update interval configurable // Paper - skip redundant getItem
|
|
||||||
MapId mapid = entityitemframe.cachedMapId; // Paper - Perf: Cache map ids on item frames
|
|
||||||
MapItemSavedData worldmap = MapItem.getSavedData(mapid, this.level);
|
|
||||||
|
|
||||||
if (worldmap != null) {
|
|
||||||
+ // Paper start - re-use the same update packet when possible
|
|
||||||
+ if (!worldmap.hasContextualRenderer) {
|
|
||||||
+ // Pass in a "random" player when a non-contextual plugin renderer is added to make sure its called
|
|
||||||
+ final Packet<?> updatePacket = worldmap.framedUpdatePacket(mapid, worldmap.hasPluginRenderer ? com.google.common.collect.Iterables.getFirst(this.trackedPlayers, null).getPlayer() : null);
|
|
||||||
+
|
|
||||||
+ if (updatePacket != null) {
|
|
||||||
+ for (ServerPlayerConnection connection : this.trackedPlayers) {
|
|
||||||
+ connection.send(updatePacket);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ } else {
|
|
||||||
+ // Paper end
|
|
||||||
Iterator<ServerPlayerConnection> iterator = this.trackedPlayers.iterator(); // CraftBukkit
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
ServerPlayer entityplayer = iterator.next().getPlayer(); // CraftBukkit
|
|
||||||
|
|
||||||
- worldmap.tickCarriedBy(entityplayer, itemstack);
|
|
||||||
- Packet<?> packet = worldmap.getUpdatePacket(mapid, entityplayer);
|
|
||||||
+ //worldmap.tickCarriedBy(entityplayer, itemstack); // Paper
|
|
||||||
+ Packet<?> packet = worldmap.framedUpdatePacket(mapid, entityplayer); // Paper
|
|
||||||
|
|
||||||
if (packet != null) {
|
|
||||||
entityplayer.connection.send(packet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ } // Paper
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -421,6 +434,19 @@ public class ServerEntity {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Paper start - send full map when tracked
|
|
||||||
+ if (this.entity instanceof ItemFrame frame && frame.cachedMapId != null) {
|
|
||||||
+ MapItemSavedData mapData = MapItem.getSavedData(frame.cachedMapId, this.level);
|
|
||||||
+
|
|
||||||
+ if (mapData != null) {
|
|
||||||
+ mapData.addFrameDecoration(frame);
|
|
||||||
+
|
|
||||||
+ final Packet<?> mapPacket = mapData.fullUpdatePacket(frame.cachedMapId, mapData.hasPluginRenderer ? player : null);
|
|
||||||
+ if (mapPacket != null)
|
|
||||||
+ sender.accept((Packet<ClientGamePacketListener>) mapPacket);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
}
|
|
||||||
|
|
||||||
public Vec3 getPositionBase() {
|
|
||||||
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 bbdaaa1cc0b4aed28bc39385508d221055b99d4d..7562147721fc8c6aa6c435f027a1757cf5b61818 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/decoration/ItemFrame.java
|
|
||||||
@@ -175,6 +175,16 @@ public class ItemFrame extends HangingEntity {
|
|
||||||
this.setItem(ItemStack.fromBukkitCopy(event.getItemStack()), false);
|
|
||||||
}
|
|
||||||
// Paper end - Add PlayerItemFrameChangeEvent
|
|
||||||
+ // Paper start - add decoration and mark everything dirty for other players who are already tracking this frame
|
|
||||||
+ final ItemStack item = this.getItem();
|
|
||||||
+ if (item.is(Items.FILLED_MAP)) {
|
|
||||||
+ final MapItemSavedData data = MapItem.getSavedData(item, this.level());
|
|
||||||
+ if (data != null) {
|
|
||||||
+ data.addFrameDecoration(this);
|
|
||||||
+ data.markAllDirty();
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
this.dropItem(world, source.getEntity(), false);
|
|
||||||
this.gameEvent(GameEvent.BLOCK_CHANGE, source.getEntity());
|
|
||||||
this.playSound(this.getRemoveItemSound(), 1.0F, 1.0F);
|
|
||||||
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..3515ce1e69b35cc8072b833e4f95632c7aa53bc1 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
|
|
||||||
@@ -81,6 +81,16 @@ public class MapItemSavedData extends SavedData {
|
|
||||||
private final Map<String, MapFrame> frameMarkers = Maps.newHashMap();
|
|
||||||
private int trackedDecorationCount;
|
|
||||||
private org.bukkit.craftbukkit.map.RenderData vanillaRender = new org.bukkit.craftbukkit.map.RenderData(); // Paper
|
|
||||||
+ // Paper start - shared between all players tracking this map inside an item frame
|
|
||||||
+ public boolean dirtyColorData;
|
|
||||||
+ public int minDirtyX;
|
|
||||||
+ public int minDirtyY;
|
|
||||||
+ public int maxDirtyX;
|
|
||||||
+ public int maxDirtyY;
|
|
||||||
+ public boolean dirtyFrameDecorations;
|
|
||||||
+ public boolean hasPluginRenderer;
|
|
||||||
+ public boolean hasContextualRenderer;
|
|
||||||
+ // Paper end
|
|
||||||
|
|
||||||
// CraftBukkit start
|
|
||||||
public final CraftMapView mapView;
|
|
||||||
@@ -370,7 +380,7 @@ public class MapItemSavedData extends SavedData {
|
|
||||||
--this.trackedDecorationCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (mapicon != null) this.setDecorationsDirty(); // Paper - only mark dirty if a change occurs
|
|
||||||
+ if (mapicon != null && mapicon.renderOnFrame()) this.dirtyFrameDecorations = true; // Paper
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void addTargetDecoration(ItemStack stack, BlockPos pos, String id, Holder<MapDecorationType> decorationType) {
|
|
||||||
@@ -407,6 +417,7 @@ public class MapItemSavedData extends SavedData {
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setDecorationsDirty();
|
|
||||||
+ if (mapicon.renderOnFrame()) this.dirtyFrameDecorations = true; // Paper
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -478,6 +489,20 @@ public class MapItemSavedData extends SavedData {
|
|
||||||
|
|
||||||
public void setColorsDirty(int x, int z) {
|
|
||||||
this.setDirty();
|
|
||||||
+ // Paper start
|
|
||||||
+ if (this.dirtyColorData) {
|
|
||||||
+ this.minDirtyX = Math.min(this.minDirtyX, x);
|
|
||||||
+ this.minDirtyY = Math.min(this.minDirtyY, z);
|
|
||||||
+ this.maxDirtyX = Math.max(this.maxDirtyX, x);
|
|
||||||
+ this.maxDirtyY = Math.max(this.maxDirtyY, z);
|
|
||||||
+ } else {
|
|
||||||
+ this.dirtyColorData = true;
|
|
||||||
+ this.minDirtyX = x;
|
|
||||||
+ this.minDirtyY = z;
|
|
||||||
+ this.maxDirtyX = x;
|
|
||||||
+ this.maxDirtyY = z;
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
Iterator iterator = this.carriedBy.iterator();
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
@@ -561,6 +586,7 @@ public class MapItemSavedData extends SavedData {
|
|
||||||
this.removeDecoration(MapItemSavedData.getFrameKey(id));
|
|
||||||
this.frameMarkers.remove(MapFrame.frameId(pos));
|
|
||||||
this.setDirty();
|
|
||||||
+ this.dirtyFrameDecorations = true; // Paper
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean updateColor(int x, int z, byte color) {
|
|
||||||
@@ -622,6 +648,93 @@ public class MapItemSavedData extends SavedData {
|
|
||||||
return "frame-" + id;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // Paper start
|
|
||||||
+ public final @Nullable Packet<?> framedUpdatePacket(MapId id, @Nullable Player player) {
|
|
||||||
+ return createUpdatePacket(id, player, false);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public final @Nullable Packet<?> fullUpdatePacket(MapId id, @Nullable Player player) {
|
|
||||||
+ return createUpdatePacket(id, player, true);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public final @Nullable Packet<?> createUpdatePacket(MapId id, @Nullable Player player, boolean full) {
|
|
||||||
+ if (!dirtyColorData && !dirtyFrameDecorations && (player == null || server.getCurrentTick() % 5 != 0) && !full) // Periodically send update packets if a renderer is added
|
|
||||||
+ return null;
|
|
||||||
+
|
|
||||||
+ final org.bukkit.craftbukkit.map.RenderData render = player != null ? this.mapView.render((org.bukkit.craftbukkit.entity.CraftPlayer) player.getBukkitEntity()) : this.vanillaRender;
|
|
||||||
+
|
|
||||||
+ final MapPatch patch;
|
|
||||||
+ if (full) {
|
|
||||||
+ patch = createPatch(render.buffer, 0, 0, 127, 127);
|
|
||||||
+ } else if (dirtyColorData) {
|
|
||||||
+ dirtyColorData = false;
|
|
||||||
+ patch = createPatch(render.buffer, this.minDirtyX, this.minDirtyY, this.maxDirtyX, this.maxDirtyY);
|
|
||||||
+ } else {
|
|
||||||
+ patch = null;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ Collection<MapDecoration> decorations = null;
|
|
||||||
+ if (dirtyFrameDecorations || full || hasPluginRenderer) { // Always add decorations when a plugin renderer is added
|
|
||||||
+ dirtyFrameDecorations = false;
|
|
||||||
+ decorations = new java.util.ArrayList<>();
|
|
||||||
+
|
|
||||||
+ if (player == null) {
|
|
||||||
+ // We're using the vanilla renderer, add in vanilla decorations
|
|
||||||
+ for (MapDecoration decoration : this.decorations.values()) {
|
|
||||||
+ // Skip sending decorations that aren't rendered, i.e. player decorations.
|
|
||||||
+ // Skipping player decorations also allows us to send the same update packet to all tracking players, the only caveat
|
|
||||||
+ // being that it causes a slight flicker of the player decoration for anyone holding & looking at the map.
|
|
||||||
+ if (decoration.renderOnFrame()) {
|
|
||||||
+ decorations.add(decoration);
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ for (final org.bukkit.map.MapCursor cursor : render.cursors) {
|
|
||||||
+ if (cursor.isVisible()) {
|
|
||||||
+ decorations.add(new MapDecoration(CraftMapCursor.CraftType.bukkitToMinecraftHolder(cursor.getType()), cursor.getX(), cursor.getY(), cursor.getDirection(), Optional.ofNullable(PaperAdventure.asVanilla(cursor.caption())))); // Paper - Adventure
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return new ClientboundMapItemDataPacket(id, this.scale, this.locked, decorations, patch);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private MapPatch createPatch(byte[] buffer, int minDirtyX, int minDirtyY, int maxDirtyX, int maxDirtyY) {
|
|
||||||
+ int i = minDirtyX;
|
|
||||||
+ int j = minDirtyY;
|
|
||||||
+ int k = maxDirtyX + 1 - minDirtyX;
|
|
||||||
+ int l = maxDirtyY + 1 - minDirtyY;
|
|
||||||
+ byte[] abyte = new byte[k * l];
|
|
||||||
+
|
|
||||||
+ for (int i1 = 0; i1 < k; ++i1) {
|
|
||||||
+ for (int j1 = 0; j1 < l; ++j1) {
|
|
||||||
+ abyte[i1 + j1 * k] = buffer[i + i1 + (j + j1) * 128];
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ return new MapItemSavedData.MapPatch(i, j, k, l, abyte);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public void addFrameDecoration(net.minecraft.world.entity.decoration.ItemFrame frame) {
|
|
||||||
+ if (this.trackedDecorationCount >= frame.level().paperConfig().maps.itemFrameCursorLimit || this.frameMarkers.containsKey(MapFrame.frameId(frame.getPos())))
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ MapFrame mapFrame = new MapFrame(frame.getPos(), frame.getDirection().get2DDataValue() * 90, frame.getId());
|
|
||||||
+ this.addDecoration(MapDecorationTypes.FRAME, frame.level(), "frame-" + frame.getId(), frame.getPos().getX(), frame.getPos().getZ(), mapFrame.getRotation(), (Component) null);
|
|
||||||
+ this.frameMarkers.put(mapFrame.getId(), mapFrame);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public void markAllDirty() {
|
|
||||||
+ this.dirtyColorData = true;
|
|
||||||
+ this.minDirtyX = 0;
|
|
||||||
+ this.minDirtyY = 0;
|
|
||||||
+ this.maxDirtyX = 127;
|
|
||||||
+ this.maxDirtyY = 127;
|
|
||||||
+ this.dirtyFrameDecorations = true;
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
+
|
|
||||||
public class HoldingPlayer {
|
|
||||||
|
|
||||||
// Paper start
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
|
|
||||||
index a15cdf64575841edfe30f2b2c522f8fdfe2caae3..ce20060e48226cc1cbe476a404ef6e1f6bdb9137 100644
|
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
|
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/map/CraftMapView.java
|
|
||||||
@@ -101,6 +101,10 @@ public final class CraftMapView implements MapView {
|
|
||||||
this.renderers.add(renderer);
|
|
||||||
this.canvases.put(renderer, new HashMap<CraftPlayer, CraftMapCanvas>());
|
|
||||||
renderer.initialize(this);
|
|
||||||
+ // Paper start
|
|
||||||
+ this.worldMap.hasPluginRenderer |= !(renderer instanceof CraftMapRenderer);
|
|
||||||
+ this.worldMap.hasContextualRenderer |= renderer.isContextual();
|
|
||||||
+ // Paper end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -116,6 +120,17 @@ public final class CraftMapView implements MapView {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.canvases.remove(renderer);
|
|
||||||
+ // Paper start
|
|
||||||
+ this.worldMap.hasPluginRenderer = !(this.renderers.size() == 1 && this.renderers.get(0) instanceof CraftMapRenderer);
|
|
||||||
+ if (renderer.isContextual()) {
|
|
||||||
+ // Re-check all renderers
|
|
||||||
+ boolean contextualFound = false;
|
|
||||||
+ for (final MapRenderer mapRenderer : this.renderers) {
|
|
||||||
+ contextualFound |= mapRenderer.isContextual();
|
|
||||||
+ }
|
|
||||||
+ this.worldMap.hasContextualRenderer = contextualFound;
|
|
||||||
+ }
|
|
||||||
+ // Paper end
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Wed, 15 Nov 2023 23:39:36 -0300
|
|
||||||
Subject: [PATCH] Skip "distanceToSqr" call in "ServerEntity#sendChanges" if
|
|
||||||
the delta movement hasn't changed
|
|
||||||
|
|
||||||
The "distanceToSqr" call is a bit expensive, so avoiding it is pretty nice, around ~15% calls are skipped with this check
|
|
||||||
|
|
||||||
We could also check if the x,y,z coordinates are equal, but for now, let's just keep the identity check, which also helps us since Minecraft's code does reuse the original delta movement Vec3 object
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
index 9938d359de5b179ff486390288d481d6ece1ecf3..ff5bf212e194dd0914c06e636a8268e8e8f6fff8 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java
|
|
||||||
@@ -243,6 +243,7 @@ public class ServerEntity {
|
|
||||||
|
|
||||||
if ((this.trackDelta || this.entity.hasImpulse || this.entity instanceof LivingEntity && ((LivingEntity) this.entity).isFallFlying()) && this.tickCount > 0) {
|
|
||||||
Vec3 vec3d1 = this.entity.getDeltaMovement();
|
|
||||||
+ if (vec3d1 != this.lastSentMovement) { // SparklyPaper start - skip distanceToSqr call in ServerEntity#sendChanges if the delta movement hasn't changed
|
|
||||||
double d0 = vec3d1.distanceToSqr(this.lastSentMovement);
|
|
||||||
|
|
||||||
if (d0 > 1.0E-7D || d0 > 0.0D && vec3d1.lengthSqr() == 0.0D) {
|
|
||||||
@@ -257,6 +258,7 @@ public class ServerEntity {
|
|
||||||
this.broadcast.accept(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+ } // SparklyPaper end
|
|
||||||
}
|
|
||||||
|
|
||||||
if (packet1 != null) {
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Fri, 17 Nov 2023 14:22:41 -0300
|
|
||||||
Subject: [PATCH] Skip "MapItem#update()" if the map does not have the
|
|
||||||
CraftMapRenderer present
|
|
||||||
|
|
||||||
Optimizes "image in map" maps, without requiring the map to be locked, which some old map plugins may not do
|
|
||||||
|
|
||||||
This has the disadvantage that the vanilla map data will never be updated while the CraftMapRenderer is not present, but that's not a huuuge problem for us
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/item/MapItem.java b/src/main/java/net/minecraft/world/item/MapItem.java
|
|
||||||
index 571f2540a1e9422025efe651167e26b44b437daa..70dd7d49807d8290b3a306550c2e1999c7e3553e 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/item/MapItem.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/item/MapItem.java
|
|
||||||
@@ -275,7 +275,7 @@ public class MapItem extends Item {
|
|
||||||
mapItemSavedData.tickCarriedBy(player, stack);
|
|
||||||
}
|
|
||||||
|
|
||||||
- if (!mapItemSavedData.locked && (selected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) {
|
|
||||||
+ if (!mapItemSavedData.locked && (!world.sparklyPaperConfig.getSkipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer() || mapItemSavedData.mapView.getRenderers().stream().anyMatch(mapRenderer -> mapRenderer.getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class)) && (selected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) { // SparklyPaper - don't update maps if they don't have the CraftMapRenderer in the render list
|
|
||||||
this.update(world, entity, mapItemSavedData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Wed, 22 Nov 2023 14:40:36 -0300
|
|
||||||
Subject: [PATCH] Skip dirty stats copy when requesting player stats
|
|
||||||
|
|
||||||
There's literally only one getDirty call. Because the map was only retrieved once, we don't actually need to create a copy of the map just to iterate it, we can just access it directly and clear it manually after use.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/stats/ServerStatsCounter.java b/src/main/java/net/minecraft/stats/ServerStatsCounter.java
|
|
||||||
index fb7342f7a5008a283c3400c6313c637de8210dfa..1f9b3cacb276c144ecbef104e5d598b78dc0c025 100644
|
|
||||||
--- a/src/main/java/net/minecraft/stats/ServerStatsCounter.java
|
|
||||||
+++ b/src/main/java/net/minecraft/stats/ServerStatsCounter.java
|
|
||||||
@@ -90,12 +90,16 @@ public class ServerStatsCounter extends StatsCounter {
|
|
||||||
this.dirty.add(stat);
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Skip dirty stats copy when requesting player stats
|
|
||||||
+ /*
|
|
||||||
private Set<Stat<?>> getDirty() {
|
|
||||||
Set<Stat<?>> set = Sets.newHashSet(this.dirty);
|
|
||||||
|
|
||||||
this.dirty.clear();
|
|
||||||
return set;
|
|
||||||
}
|
|
||||||
+ */
|
|
||||||
+ // SparklyPaper end
|
|
||||||
|
|
||||||
public void parseLocal(DataFixer dataFixer, String json) {
|
|
||||||
try {
|
|
||||||
@@ -243,7 +247,7 @@ public class ServerStatsCounter extends StatsCounter {
|
|
||||||
|
|
||||||
public void sendStats(ServerPlayer player) {
|
|
||||||
Object2IntMap<Stat<?>> object2intmap = new Object2IntOpenHashMap();
|
|
||||||
- Iterator iterator = this.getDirty().iterator();
|
|
||||||
+ Iterator iterator = this.dirty.iterator(); // SparklyPaper - Skip dirty stats copy when requesting player stats
|
|
||||||
|
|
||||||
while (iterator.hasNext()) {
|
|
||||||
Stat<?> statistic = (Stat) iterator.next();
|
|
||||||
@@ -251,6 +255,8 @@ public class ServerStatsCounter extends StatsCounter {
|
|
||||||
object2intmap.put(statistic, this.getValue(statistic));
|
|
||||||
}
|
|
||||||
|
|
||||||
+ this.dirty.clear(); // SparklyPaper - Skip dirty stats copy when requesting player stats
|
|
||||||
+
|
|
||||||
player.connection.send(new ClientboundAwardStatsPacket(object2intmap));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,209 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Tue, 21 Nov 2023 16:50:04 -0300
|
|
||||||
Subject: [PATCH] Spooky month optimizations
|
|
||||||
|
|
||||||
The quintessential patch that other performance forks also have for... some reason??? I thought that this optimization was too funny to not do it in SparklyPaper.
|
|
||||||
|
|
||||||
Caches when Bat's spooky season starts and ends, and when Skeleton and Zombies halloween starts and ends. The epoch is updated every 90 days. If your server is running for 90+ days straight without restarts, congratulations!
|
|
||||||
|
|
||||||
Avoids unnecessary date checks, even tho that this shouldn't really improve performance that much... unless you have a lot of bats/zombies/skeletons spawning.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
index 114b379bb3a56099dbd4e4bf11f6a1b7ddc488f7..c037913feea3b9302e31a6c3760db24ca7c819af 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
@@ -334,7 +334,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
||||||
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
|
||||||
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
|
|
||||||
public final Set<Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
|
||||||
-
|
|
||||||
+ public net.sparklypower.sparklypaper.HalloweenManager halloweenManager = new net.sparklypower.sparklypaper.HalloweenManager(); // SparklyPaper - Spooky month optimizations
|
|
||||||
+
|
|
||||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
|
||||||
AtomicReference<S> atomicreference = new AtomicReference();
|
|
||||||
Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> { // Paper - rewrite chunk system
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
||||||
index bb8975cd3d3b1c57f313ad31b5e767fa93ad8e13..e49e8e98ebbd3c8ba8a784f1626132699209b4e3 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
|
|
||||||
@@ -244,6 +244,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
||||||
}
|
|
||||||
net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
|
||||||
// SparklyPaper end
|
|
||||||
+ // SparklyPaper start - Spooky month optimizations
|
|
||||||
+ halloweenManager.startHalloweenEpochTask();
|
|
||||||
+ halloweenManager.waitUntilEpochHasBeenUpdated();
|
|
||||||
+ // SparklyPaper end
|
|
||||||
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
|
||||||
|
|
||||||
this.setPvpAllowed(dedicatedserverproperties.pvp);
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
|
|
||||||
index 60c2868f255d372226e0c1389caaa5477bbef41e..64b601a5275374ae8038eaa63f2dddfbb09f593a 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java
|
|
||||||
@@ -232,7 +232,7 @@ public class Bat extends AmbientCreature {
|
|
||||||
int i = world.getMaxLocalRawBrightness(pos);
|
|
||||||
byte b0 = 4;
|
|
||||||
|
|
||||||
- if (Bat.isHalloween()) {
|
|
||||||
+ if (world.getServer().halloweenManager.isSpookySeason()) { // SparklyPaper - Spooky month optimizations
|
|
||||||
b0 = 7;
|
|
||||||
} else if (random.nextBoolean()) {
|
|
||||||
return false;
|
|
||||||
@@ -242,6 +242,8 @@ public class Bat extends AmbientCreature {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper - Spooky month optimizations
|
|
||||||
+ /*
|
|
||||||
private static boolean isHalloween() {
|
|
||||||
LocalDate localdate = LocalDate.now();
|
|
||||||
int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
||||||
@@ -249,6 +251,7 @@ public class Bat extends AmbientCreature {
|
|
||||||
|
|
||||||
return j == 10 && i >= 20 || j == 11 && i <= 3;
|
|
||||||
}
|
|
||||||
+ */
|
|
||||||
|
|
||||||
private void setupAnimationStates() {
|
|
||||||
if (this.isResting()) {
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
|
||||||
index 32670a3cb4b54b66d655197e3fde834d2b2b6d34..68818edaf2762c0610377814aa6cb065fe72d290 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
|
||||||
@@ -159,10 +159,12 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
|
||||||
this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot
|
|
||||||
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
|
||||||
LocalDate localdate = LocalDate.now();
|
|
||||||
- int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
||||||
- int j = localdate.get(ChronoField.MONTH_OF_YEAR);
|
|
||||||
+ // SparklyPaper start - Spooky month optimizations
|
|
||||||
+ // int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
||||||
+ // int j = localdate.get(ChronoField.MONTH_OF_YEAR);
|
|
||||||
|
|
||||||
- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) {
|
|
||||||
+ if (this.getServer().halloweenManager.isHalloween() /* j == 10 && i == 31 */&& randomsource.nextFloat() < 0.25F) {
|
|
||||||
+ // SparklyPaper end
|
|
||||||
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
|
||||||
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
|
||||||
}
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
|
||||||
index a12461907278cfbfa3b1c0aa74b9f07a31768b8a..558f885fc0d9d1da54bcb9cfc65efb6ceba77fde 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java
|
|
||||||
@@ -563,10 +563,11 @@ public class Zombie extends Monster {
|
|
||||||
|
|
||||||
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
|
||||||
LocalDate localdate = LocalDate.now();
|
|
||||||
- int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
||||||
- int j = localdate.get(ChronoField.MONTH_OF_YEAR);
|
|
||||||
+ // SparklyPaper start - Spooky month optimizations
|
|
||||||
+ // int i = localdate.get(ChronoField.DAY_OF_MONTH);
|
|
||||||
+ // int j = localdate.get(ChronoField.MONTH_OF_YEAR);
|
|
||||||
|
|
||||||
- if (j == 10 && i == 31 && randomsource.nextFloat() < 0.25F) {
|
|
||||||
+ if (this.getServer().halloweenManager.isHalloween() /* j == 10 && i == 31 */&& randomsource.nextFloat() < 0.25F) {
|
|
||||||
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(randomsource.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
|
||||||
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
|
||||||
}
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/HalloweenManager.kt b/src/main/kotlin/net/sparklypower/sparklypaper/HalloweenManager.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..8dd82e727872c0d6c4d0827ac63d5fecb9218c61
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/HalloweenManager.kt
|
|
||||||
@@ -0,0 +1,93 @@
|
|
||||||
+package net.sparklypower.sparklypaper
|
|
||||||
+
|
|
||||||
+import com.mojang.logging.LogUtils
|
|
||||||
+import java.time.LocalDateTime
|
|
||||||
+import java.time.Month
|
|
||||||
+import java.time.ZoneOffset
|
|
||||||
+import java.util.concurrent.*
|
|
||||||
+
|
|
||||||
+class HalloweenManager {
|
|
||||||
+ companion object {
|
|
||||||
+ private val LOGGER = LogUtils.getLogger()
|
|
||||||
+ }
|
|
||||||
+ private var spookySeasonStartEpoch = 0L
|
|
||||||
+ private var spookySeasonEndEpoch = 0L
|
|
||||||
+ private var halloweenStartEpoch = 0L
|
|
||||||
+ private var halloweenEndEpoch = 0L
|
|
||||||
+ private var executor = Executors.newSingleThreadScheduledExecutor(object: ThreadFactory {
|
|
||||||
+ override fun newThread(p0: Runnable): Thread {
|
|
||||||
+ val thread = Thread(p0)
|
|
||||||
+ thread.name = "halloween-timer-updater"
|
|
||||||
+ thread.priority = 1 // Minimum priority
|
|
||||||
+ return thread
|
|
||||||
+ }
|
|
||||||
+ })
|
|
||||||
+ private var latch = CountDownLatch(1)
|
|
||||||
+
|
|
||||||
+ fun startHalloweenEpochTask() {
|
|
||||||
+ var isFirst = true
|
|
||||||
+ executor.scheduleAtFixedRate({
|
|
||||||
+ updateEpoch()
|
|
||||||
+ if (isFirst)
|
|
||||||
+ latch.countDown()
|
|
||||||
+ isFirst = false
|
|
||||||
+ }, 0L, 90L, TimeUnit.DAYS) // Every 90 days
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fun waitUntilEpochHasBeenUpdated() {
|
|
||||||
+ latch.await()
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fun updateEpoch() {
|
|
||||||
+ LOGGER.info("Updating Spooky Season and Halloween Time")
|
|
||||||
+ this.spookySeasonStartEpoch = getEpochMillisAtDate(20, Month.OCTOBER, false)
|
|
||||||
+ this.spookySeasonEndEpoch = getEpochMillisAtDate(3, Month.NOVEMBER, true)
|
|
||||||
+ this.halloweenStartEpoch = getEpochMillisAtDate(31, Month.OCTOBER, false)
|
|
||||||
+ this.halloweenEndEpoch = getEpochMillisAtDate(31, Month.OCTOBER, true)
|
|
||||||
+ LOGGER.info("Updated Spooky Season and Halloween Time!")
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ fun isSpookySeason() = System.currentTimeMillis() in spookySeasonStartEpoch until spookySeasonEndEpoch
|
|
||||||
+ fun isHalloween() = System.currentTimeMillis() in halloweenStartEpoch until halloweenEndEpoch
|
|
||||||
+
|
|
||||||
+ private fun getEpochMillisAtDate(dayOfMonth: Int, month: Month, isEnd: Boolean): Long {
|
|
||||||
+ // Get the current year
|
|
||||||
+ val currentYear = LocalDateTime.now().year
|
|
||||||
+
|
|
||||||
+ // Define the target date (20/10/CurrentYear at midnight)
|
|
||||||
+ val targetDate = LocalDateTime.of(
|
|
||||||
+ currentYear,
|
|
||||||
+ month,
|
|
||||||
+ dayOfMonth,
|
|
||||||
+ if (isEnd)
|
|
||||||
+ 23
|
|
||||||
+ else
|
|
||||||
+ 0,
|
|
||||||
+ if (isEnd)
|
|
||||||
+ 59
|
|
||||||
+ else
|
|
||||||
+ 0,
|
|
||||||
+ if (isEnd)
|
|
||||||
+ 59
|
|
||||||
+ else
|
|
||||||
+ 0,
|
|
||||||
+ if (isEnd)
|
|
||||||
+ 999_999_999
|
|
||||||
+ else
|
|
||||||
+ 0,
|
|
||||||
+ )
|
|
||||||
+
|
|
||||||
+ // Check if the target date is in the past
|
|
||||||
+ val now = LocalDateTime.now()
|
|
||||||
+ val adjustedDate = if (now.isAfter(targetDate)) {
|
|
||||||
+ // If in the past, adjust to the same date in the next year
|
|
||||||
+ targetDate.plusYears(1)
|
|
||||||
+ } else {
|
|
||||||
+ // If in the future or today, use the original target date
|
|
||||||
+ targetDate
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // Convert the adjusted date to epoch time in milliseconds
|
|
||||||
+ return adjustedDate.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli()
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sun, 18 Feb 2024 14:22:37 -0300
|
|
||||||
Subject: [PATCH] Revert "Fix MC-117075: Block entity unload lag spike"
|
|
||||||
|
|
||||||
This reverts commit f3453b204569ea865cc1d1302edb6d125e7f0cb3.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
index 8433caa61a973d81a5eedc44428926e999c21a03..db9eb10c33848ca5b342bf00e4a05738210d26b0 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
@@ -1458,8 +1458,6 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
int tickedEntities = 0; // Paper - rewrite chunk system
|
|
||||||
|
|
||||||
int tilesThisCycle = 0;
|
|
||||||
- var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<TickingBlockEntity>(); // 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);
|
|
||||||
@@ -1468,7 +1466,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
if (tickingblockentity.isRemoved()) {
|
|
||||||
// Spigot start
|
|
||||||
tilesThisCycle--;
|
|
||||||
- toRemove.add(tickingblockentity); // Paper - Fix MC-117075; use removeAll
|
|
||||||
+ this.blockEntityTickers.remove(this.tileTickPosition--);
|
|
||||||
// Spigot end
|
|
||||||
} else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) {
|
|
||||||
tickingblockentity.tick();
|
|
||||||
@@ -1479,7 +1477,6 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
// Paper end - rewrite chunk system
|
|
||||||
}
|
|
||||||
}
|
|
||||||
- this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
|
|
||||||
|
|
||||||
this.tickingBlockEntities = false;
|
|
||||||
gameprofilerfiller.pop();
|
|
||||||
@@ -1,146 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sun, 26 Nov 2023 13:02:16 -0300
|
|
||||||
Subject: [PATCH] Fix MC-117075: TE Unload Lag Spike
|
|
||||||
|
|
||||||
We replaced the `blockEntityTickers` list with a custom list based on fastutil's `ObjectArrayList` with a small yet huge change for us: A method that allows us to remove a list of indexes from the list.
|
|
||||||
|
|
||||||
This is WAY FASTER than using `removeAll` with a list of entries to be removed, because we don't need to calculate the identity of each block entity to be removed, and we can jump directly to where the search should begin, giving a performance boost for small removals (because we don't need to loop thru the entire list to find what element should be removed) and a performance boost for big removals (no need to calculate the identity of each block entity).
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
index db9eb10c33848ca5b342bf00e4a05738210d26b0..1e20c525cd0c75079fe971ae830120c69fee362e 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
@@ -118,7 +118,7 @@ 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;
|
|
||||||
- public final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList(); // Paper - public
|
|
||||||
+ public final net.sparklypower.sparklypaper.BlockEntityTickersList blockEntityTickers = new net.sparklypower.sparklypaper.BlockEntityTickersList(); // Paper - public // SparklyPaper - optimize block entity removals
|
|
||||||
protected final NeighborUpdater neighborUpdater;
|
|
||||||
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
|
||||||
private boolean tickingBlockEntities;
|
|
||||||
@@ -1466,7 +1466,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
if (tickingblockentity.isRemoved()) {
|
|
||||||
// Spigot start
|
|
||||||
tilesThisCycle--;
|
|
||||||
- this.blockEntityTickers.remove(this.tileTickPosition--);
|
|
||||||
+ this.blockEntityTickers.markAsRemoved(this.tileTickPosition); // this.blockEntityTickers.remove(this.tileTickPosition--); // SparklyPaper - optimize block entity removals
|
|
||||||
// Spigot end
|
|
||||||
} else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) {
|
|
||||||
tickingblockentity.tick();
|
|
||||||
@@ -1477,7 +1477,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
// Paper end - rewrite chunk system
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-
|
|
||||||
+ this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals
|
|
||||||
this.tickingBlockEntities = false;
|
|
||||||
gameprofilerfiller.pop();
|
|
||||||
this.spigotConfig.currentPrimedTnt = 0; // Spigot
|
|
||||||
diff --git a/src/main/java/net/sparklypower/sparklypaper/BlockEntityTickersList.java b/src/main/java/net/sparklypower/sparklypaper/BlockEntityTickersList.java
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..7affec7e343c39a83390ae13ce23f3bfa0db1eb6
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/java/net/sparklypower/sparklypaper/BlockEntityTickersList.java
|
|
||||||
@@ -0,0 +1,100 @@
|
|
||||||
+package net.sparklypower.sparklypaper;
|
|
||||||
+
|
|
||||||
+import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
|
||||||
+import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
|
||||||
+import net.minecraft.world.level.block.entity.TickingBlockEntity;
|
|
||||||
+
|
|
||||||
+import java.util.Arrays;
|
|
||||||
+import java.util.Collection;
|
|
||||||
+import java.util.HashSet;
|
|
||||||
+import java.util.Set;
|
|
||||||
+
|
|
||||||
+/**
|
|
||||||
+ * A list for ServerLevel's blockEntityTickers
|
|
||||||
+ *
|
|
||||||
+ * This list is behaves identically to ObjectArrayList, but it has an additional method, `removeAllByIndex`, that allows a list of integers to be passed indicating what
|
|
||||||
+ * indexes should be deleted from the list
|
|
||||||
+ *
|
|
||||||
+ * This is faster than using removeAll, since we don't need to compare the identity of each block entity, and faster than looping thru each index manually and deleting with remove,
|
|
||||||
+ * since we don't need to resize the array every single remove.
|
|
||||||
+ */
|
|
||||||
+public final class BlockEntityTickersList extends ObjectArrayList<TickingBlockEntity> {
|
|
||||||
+ private final IntOpenHashSet toRemove = new IntOpenHashSet();
|
|
||||||
+ private int startSearchFromIndex = -1;
|
|
||||||
+
|
|
||||||
+ /** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. */
|
|
||||||
+ public BlockEntityTickersList() {
|
|
||||||
+ super();
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Creates a new array list and fills it with a given collection.
|
|
||||||
+ *
|
|
||||||
+ * @param c a collection that will be used to fill the array list.
|
|
||||||
+ */
|
|
||||||
+ public BlockEntityTickersList(final Collection<? extends TickingBlockEntity> c) {
|
|
||||||
+ super(c);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Marks an entry as removed
|
|
||||||
+ *
|
|
||||||
+ * @param index the index of the item on the list to be marked as removed
|
|
||||||
+ */
|
|
||||||
+ public void markAsRemoved(final int index) {
|
|
||||||
+ // The block entities list always loop starting from 0, so we only need to check if the startSearchFromIndex is -1 and that's it
|
|
||||||
+ if (this.startSearchFromIndex == -1)
|
|
||||||
+ this.startSearchFromIndex = index;
|
|
||||||
+ this.toRemove.add(index);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Removes elements that have been marked as removed.
|
|
||||||
+ */
|
|
||||||
+ public void removeMarkedEntries() {
|
|
||||||
+ if (this.startSearchFromIndex == -1) // No entries in the list, skip
|
|
||||||
+ return;
|
|
||||||
+
|
|
||||||
+ removeAllByIndex(startSearchFromIndex, toRemove);
|
|
||||||
+ toRemove.clear();
|
|
||||||
+ this.startSearchFromIndex = -1; // Reset the start search index
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ /**
|
|
||||||
+ * Removes elements by their index.
|
|
||||||
+ */
|
|
||||||
+ private void removeAllByIndex(final int startSearchFromIndex, final IntOpenHashSet c) { // can't use Set<Integer> because we want to avoid autoboxing when using contains
|
|
||||||
+ final int requiredMatches = c.size();
|
|
||||||
+ if (requiredMatches == 0)
|
|
||||||
+ return; // exit early, we don't need to do anything
|
|
||||||
+
|
|
||||||
+ final Object[] a = this.a;
|
|
||||||
+ int j = startSearchFromIndex;
|
|
||||||
+ int matches = 0;
|
|
||||||
+ for (int i = startSearchFromIndex; i < size; i++) { // If the user knows the first index to be removed, we can skip a lot of unnecessary comparsions
|
|
||||||
+ if (!c.contains(i)) {
|
|
||||||
+ // TODO: It can be possible to optimize this loop by tracking the start/finish and then using arraycopy to "skip" the elements,
|
|
||||||
+ // this would optimize cases where the index to be removed are far apart, HOWEVER it does have a big performance impact if you are doing
|
|
||||||
+ // "arraycopy" for each element
|
|
||||||
+ a[j++] = a[i];
|
|
||||||
+ } else {
|
|
||||||
+ matches++;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ if (matches == requiredMatches) { // Exit the loop if we already removed everything, we don't need to check anything else
|
|
||||||
+ // We need to update the final size here, because we know that we already found everything!
|
|
||||||
+ // Because we know that the size must be currentSize - requiredMatches (because we have matched everything), let's update the value
|
|
||||||
+ // However, we need to copy the rest of the stuff over
|
|
||||||
+ if (i != (size - 1)) { // If it isn't the last index...
|
|
||||||
+ // i + 1 because we want to copy the *next* element over
|
|
||||||
+ // and the size - i - 1 is because we want to get the current size, minus the current index (which is i), and then - 1 because we want to copy -1 ahead (remember, we are adding +1 to copy the *next* element)
|
|
||||||
+ System.arraycopy(a, i + 1, a, j, size - i - 1);
|
|
||||||
+ }
|
|
||||||
+ j = size - requiredMatches;
|
|
||||||
+ break;
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ Arrays.fill(a, j, size, null);
|
|
||||||
+ size = j;
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
@@ -1,134 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sun, 26 Nov 2023 13:11:10 -0300
|
|
||||||
Subject: [PATCH] Optimize tickBlockEntities
|
|
||||||
|
|
||||||
We cache the last `shouldTickBlocksAt` result, because the `shouldTickBlocksAt` is expensive because it requires pulling chunk holder info from an map for each block entity (even if the block entities are on the same chunk!) every single time. So, if the last chunk position is the same as our cached value, we use the last cached `shouldTickBlocksAt` result!
|
|
||||||
|
|
||||||
We could use a map for caching, but here's why this is way better than using a map: The block entity ticking list is sorted by chunks! Well, sort of... It is sorted by chunk when the chunk has been loaded, newly placed blocks will be appended to the end of the list until the chunk unloads and loads again. Most block entities are things that players placed to be there for a long time anyway (like hoppers, etc)
|
|
||||||
|
|
||||||
But here's the thing: We don't care if we have a small performance penalty if the players have placed new block entities, the small performance hit of when a player placed new block entities is so small ('tis just a long comparsion after all), that the performance boost from already placed block entities is bigger, this helps a lot if your server has a lot of chunks with multiple block entities, and the block entities will be automatically sorted after the chunk is unloaded and loaded again, so it ain't that bad.
|
|
||||||
|
|
||||||
And finally, we also cache the chunk's coordinate key when creating the block entity, which is actually "free" because we just reuse the already cached chunk coordinate key from the chunk!
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
index 1e20c525cd0c75079fe971ae830120c69fee362e..97b31dffbaf965e86ad706a1bba7586cd3514ead 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/Level.java
|
|
||||||
@@ -1458,6 +1458,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
int tickedEntities = 0; // Paper - rewrite chunk system
|
|
||||||
|
|
||||||
int tilesThisCycle = 0;
|
|
||||||
+ // SparklyPaper start - optimize tickBlockEntities
|
|
||||||
+ int shouldTickBlocksAtLastResult = -1; // -1 = undefined
|
|
||||||
+ long shouldTickBlocksAtChunkPos = 0L;
|
|
||||||
+ // SparklyPaper end
|
|
||||||
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);
|
|
||||||
@@ -1468,13 +1472,25 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
|
||||||
tilesThisCycle--;
|
|
||||||
this.blockEntityTickers.markAsRemoved(this.tileTickPosition); // this.blockEntityTickers.remove(this.tileTickPosition--); // SparklyPaper - optimize block entity removals
|
|
||||||
// Spigot end
|
|
||||||
- } else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) {
|
|
||||||
+ // } else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) { // SparklyPaper start - optimize tickBlockEntities
|
|
||||||
+ } else if (flag) {
|
|
||||||
+ long chunkPos = tickingblockentity.getChunkCoordinateKey();
|
|
||||||
+ boolean shouldTick;
|
|
||||||
+ if (shouldTickBlocksAtChunkPos == chunkPos && shouldTickBlocksAtLastResult != -1) {
|
|
||||||
+ shouldTick = shouldTickBlocksAtLastResult == 1;
|
|
||||||
+ } else {
|
|
||||||
+ shouldTick = this.shouldTickBlocksAt(chunkPos);
|
|
||||||
+ shouldTickBlocksAtLastResult = shouldTick ? 1 : 0;
|
|
||||||
+ shouldTickBlocksAtChunkPos = chunkPos;
|
|
||||||
+ }
|
|
||||||
+ if (shouldTick) {
|
|
||||||
tickingblockentity.tick();
|
|
||||||
// Paper start - rewrite chunk system
|
|
||||||
if ((++tickedEntities & 7) == 0) {
|
|
||||||
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
|
|
||||||
}
|
|
||||||
// Paper end - rewrite chunk system
|
|
||||||
+ } // SparklyPaper end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals
|
|
||||||
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
|
|
||||||
index 28e3b73507b988f7234cbf29c4024c88180d0aef..427cf73383155c52bca8fb4b32f43029ff619833 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
|
|
||||||
@@ -10,4 +10,6 @@ public interface TickingBlockEntity {
|
|
||||||
BlockPos getPos();
|
|
||||||
|
|
||||||
String getType();
|
|
||||||
+
|
|
||||||
+ long getChunkCoordinateKey(); // SparklyPaper - optimize tickBlockEntities
|
|
||||||
}
|
|
||||||
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 4640baec5bed6c2d53cc0f8ca1d273cc115abe9b..b4c16fe7c9215b5610b7e7488c29b497b5357ecc 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
|
|
||||||
@@ -75,6 +75,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
||||||
public String getType() {
|
|
||||||
return "<null>";
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ // SparklyPaper start - optimize tickBlockEntities
|
|
||||||
+ @Override
|
|
||||||
+ public long getChunkCoordinateKey() {
|
|
||||||
+ return 0;
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
};
|
|
||||||
private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel;
|
|
||||||
public boolean loaded;
|
|
||||||
@@ -981,7 +988,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
||||||
}
|
|
||||||
|
|
||||||
private <T extends BlockEntity> TickingBlockEntity createTicker(T blockEntity, BlockEntityTicker<T> blockEntityTicker) {
|
|
||||||
- return new LevelChunk.BoundTickingBlockEntity<>(blockEntity, blockEntityTicker);
|
|
||||||
+ return new LevelChunk.BoundTickingBlockEntity<>(blockEntity, blockEntityTicker, this.coordinateKey); // SparklyPaper - optimize tickBlockEntities
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
@@ -1038,6 +1045,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
||||||
public String toString() {
|
|
||||||
return String.valueOf(this.ticker) + " <wrapped>";
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ // SparklyPaper start - optimize tickBlockEntities
|
|
||||||
+ @Override
|
|
||||||
+ public long getChunkCoordinateKey() {
|
|
||||||
+ return this.ticker.getChunkCoordinateKey();
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
}
|
|
||||||
|
|
||||||
private class BoundTickingBlockEntity<T extends BlockEntity> implements TickingBlockEntity {
|
|
||||||
@@ -1045,10 +1059,12 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
||||||
private final T blockEntity;
|
|
||||||
private final BlockEntityTicker<T> ticker;
|
|
||||||
private boolean loggedInvalidBlockState;
|
|
||||||
+ private final long chunkCoordinateKey; // SparklyPaper - optimize tickBlockEntities
|
|
||||||
|
|
||||||
- BoundTickingBlockEntity(final BlockEntity tileentity, final BlockEntityTicker blockentityticker) {
|
|
||||||
+ BoundTickingBlockEntity(final BlockEntity tileentity, final BlockEntityTicker blockentityticker, long chunkCoordinateKey) { // SparklyPaper - optimize tickBlockEntities
|
|
||||||
this.blockEntity = (T) tileentity; // CraftBukkit - decompile error
|
|
||||||
this.ticker = blockentityticker;
|
|
||||||
+ this.chunkCoordinateKey = chunkCoordinateKey; // SparklyPaper - optimize tickBlockEntities
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@@ -1112,5 +1128,12 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
|
||||||
|
|
||||||
return "Level ticker for " + s + "@" + String.valueOf(this.getPos());
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ // SparklyPaper start - optimize tickBlockEntities
|
|
||||||
+ @Override
|
|
||||||
+ public long getChunkCoordinateKey() {
|
|
||||||
+ return this.chunkCoordinateKey;
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,95 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Mon, 6 Nov 2023 21:54:33 -0300
|
|
||||||
Subject: [PATCH] Track how much MSPT each world used
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/io/papermc/paper/command/MSPTCommand.java b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
|
||||||
index 8b5293b0c696ef21d0101493ffa41b60bf0bc86b..601198a33adb29316b0617d5390d1620b7c1095c 100644
|
|
||||||
--- a/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
|
||||||
+++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
|
||||||
@@ -78,6 +78,46 @@ public final class MSPTCommand extends Command {
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
+
|
|
||||||
+ // SparklyPaper start - track world's MSPT
|
|
||||||
+ sender.sendMessage(text());
|
|
||||||
+ sender.sendMessage(text().content("World tick times ").color(GOLD)
|
|
||||||
+ .append(text().color(YELLOW)
|
|
||||||
+ .append(
|
|
||||||
+ text("("),
|
|
||||||
+ text("avg", GRAY),
|
|
||||||
+ text("/"),
|
|
||||||
+ text("min", GRAY),
|
|
||||||
+ text("/"),
|
|
||||||
+ text("max", GRAY),
|
|
||||||
+ text(")")
|
|
||||||
+ )
|
|
||||||
+ ).append(
|
|
||||||
+ text(" from last 5s"),
|
|
||||||
+ text(",", GRAY),
|
|
||||||
+ text(" 10s"),
|
|
||||||
+ text(",", GRAY),
|
|
||||||
+ text(" 1m"),
|
|
||||||
+ text(":", YELLOW)
|
|
||||||
+ )
|
|
||||||
+ );
|
|
||||||
+ for (net.minecraft.server.level.ServerLevel serverLevel : server.getAllLevels()) {
|
|
||||||
+ List<Component> worldTimes = new ArrayList<>();
|
|
||||||
+ worldTimes.addAll(eval(serverLevel.tickTimes5s.getTimes()));
|
|
||||||
+ worldTimes.addAll(eval(serverLevel.tickTimes10s.getTimes()));
|
|
||||||
+ worldTimes.addAll(eval(serverLevel.tickTimes60s.getTimes()));
|
|
||||||
+
|
|
||||||
+ sender.sendMessage(text().content("◴ " + serverLevel.getWorld().getName() + ": ").color(GOLD)
|
|
||||||
+ .append(text().color(GRAY)
|
|
||||||
+ .append(
|
|
||||||
+ worldTimes.get(0), SLASH, worldTimes.get(1), SLASH, worldTimes.get(2), text(", ", YELLOW),
|
|
||||||
+ worldTimes.get(3), SLASH, worldTimes.get(4), SLASH, worldTimes.get(5), text(", ", YELLOW),
|
|
||||||
+ worldTimes.get(6), SLASH, worldTimes.get(7), SLASH, worldTimes.get(8)
|
|
||||||
+ )
|
|
||||||
+ )
|
|
||||||
+ );
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
index 9fd2bb0441b614d0a1abf8a8000eece14dcd6bbe..e168e5f433da40f3bdd5821451c3f3572b69a48c 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
@@ -1889,7 +1889,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
||||||
gameprofilerfiller.push("tick");
|
|
||||||
|
|
||||||
try {
|
|
||||||
+ long i = Util.getNanos(); // SparklyPaper - track world's MSPT
|
|
||||||
worldserver.tick(shouldKeepTicking);
|
|
||||||
+ // SparklyPaper start - track world's MSPT
|
|
||||||
+ long j = Util.getNanos() - i;
|
|
||||||
+
|
|
||||||
+ // These are from the "tickServer" function
|
|
||||||
+ worldserver.tickTimes5s.add(this.tickCount, j);
|
|
||||||
+ worldserver.tickTimes10s.add(this.tickCount, j);
|
|
||||||
+ worldserver.tickTimes60s.add(this.tickCount, j);
|
|
||||||
+ // SparklyPaper end
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
||||||
index 585e2b43a0326f0b81597fa1234d3c67c76af550..ba899bcf05b967db784b7435895d6ff7b72b40f2 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java
|
|
||||||
@@ -595,6 +595,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
|
||||||
}
|
|
||||||
// Paper end - lag compensation
|
|
||||||
|
|
||||||
+ // SparklyPaper start - track world's MSPT
|
|
||||||
+ public final MinecraftServer.TickTimes tickTimes5s = new MinecraftServer.TickTimes(100);
|
|
||||||
+ public final MinecraftServer.TickTimes tickTimes10s = new MinecraftServer.TickTimes(200);
|
|
||||||
+ public final MinecraftServer.TickTimes tickTimes60s = new MinecraftServer.TickTimes(1200);
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
// Add env and gen to constructor, IWorldDataServer -> WorldDataServer
|
|
||||||
public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey<Level> resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List<CustomSpawner> list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) {
|
|
||||||
super(iworlddataserver, resourcekey, minecraftserver.registryAccess(), worlddimension.type(), false, flag, i, minecraftserver.getMaxChainedNeighborUpdates(), gen, biomeProvider, env, spigotConfig -> minecraftserver.paperConfigurations.createWorldConfig(io.papermc.paper.configuration.PaperConfigurations.createWorldContextMap(convertable_conversionsession.levelDirectory.path(), iworlddataserver.getLevelName(), resourcekey.location(), spigotConfig, minecraftserver.registryAccess(), iworlddataserver.getGameRules())), executor); // Paper - create paper world configs; Async-Anti-Xray: Pass executor
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Wed, 5 Jun 2024 15:20:00 -0300
|
|
||||||
Subject: [PATCH] Reset dirty flag when loading maps from the disk
|
|
||||||
|
|
||||||
By default, the server will start rewriting all map datas to the disk after loading it, even if the map didn't have any changes
|
|
||||||
|
|
||||||
This also slows down world saving a lot if you have a lot of maps
|
|
||||||
|
|
||||||
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 6bcb565cd60b60be9255ef537591ee821caab7b5..83ca73240aae660f565e016565b147018f9f407f 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
|
|
||||||
@@ -218,6 +218,7 @@ public class MapItemSavedData extends SavedData {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
+ worldmap.setDirty(false); // SparklyPaper - reset dirty flag when loading maps from the disk
|
|
||||||
return worldmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Mon, 10 Jun 2024 12:22:15 -0300
|
|
||||||
Subject: [PATCH] Add ClientboundPacketPreDispatchEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java
|
|
||||||
index 3e550f8e7cd4f4e16f499a8a2a4b95420270f07a..3bcff05a99662c28cc490579162a1f05b55b1cda 100644
|
|
||||||
--- a/src/main/java/net/minecraft/network/Connection.java
|
|
||||||
+++ b/src/main/java/net/minecraft/network/Connection.java
|
|
||||||
@@ -450,6 +450,18 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Add ClientboundPacketPreDispatchEvent
|
|
||||||
+ net.minecraft.server.level.ServerPlayer serverPlayer = this.getPlayer();
|
|
||||||
+ org.bukkit.craftbukkit.entity.CraftPlayer craftPlayer = null;
|
|
||||||
+ if (serverPlayer != null)
|
|
||||||
+ craftPlayer = serverPlayer.getBukkitEntity();
|
|
||||||
+ net.sparklypower.sparklypaper.event.packet.ClientboundPacketPreDispatchEvent event = new net.sparklypower.sparklypaper.event.packet.ClientboundPacketPreDispatchEvent(!org.bukkit.Bukkit.isPrimaryThread(), craftPlayer, packet);
|
|
||||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
|
|
||||||
+ if (event.isCancelled())
|
|
||||||
+ return;
|
|
||||||
+ packet = (Packet<?>) event.getPacket();
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
packet.onPacketDispatch(this.getPlayer());
|
|
||||||
if (connected && (InnerUtil.canSendImmediate(this, packet)
|
|
||||||
|| (io.papermc.paper.util.MCUtil.isMainThread() && packet.isReady() && this.pendingActions.isEmpty()
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Mon, 10 Jun 2024 14:39:10 -0300
|
|
||||||
Subject: [PATCH] Add PlayerBlockDestroySpeedEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
|
||||||
index 99fd67a78539133adf78d65e2c520ff3dd260301..96640ae707c9babe1c4f4895f39d4d7cfc71a765 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/block/state/BlockBehaviour.java
|
|
||||||
@@ -336,6 +336,14 @@ public abstract class BlockBehaviour implements FeatureElement {
|
|
||||||
protected float getDestroyProgress(BlockState state, Player player, BlockGetter world, BlockPos pos) {
|
|
||||||
float f = state.getDestroySpeed(world, pos);
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Add PlayerBlockDestroySpeedEvent
|
|
||||||
+ // *Technically* it seems that all getDestroyProgress calls use a LevelAccessor, but anyway...
|
|
||||||
+ if (world instanceof LevelAccessor) {
|
|
||||||
+ net.sparklypower.sparklypaper.event.block.PlayerBlockDestroySpeedEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerBlockDestroySpeedEvent(player, (LevelAccessor) world, pos, f);
|
|
||||||
+ f = event.getDestroySpeed();
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
if (f == -1.0F) {
|
|
||||||
return 0.0F;
|
|
||||||
} else {
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
||||||
index e37aaf77f94b97b736cc20ef070cefdff0400188..a46f0c810ee2b9679c0530e5e6d3505b3d1f661c 100644
|
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
||||||
@@ -2271,4 +2271,13 @@ public class CraftEventFactory {
|
|
||||||
return event;
|
|
||||||
}
|
|
||||||
// Paper end - add EntityFertilizeEggEvent
|
|
||||||
+
|
|
||||||
+ // SparklyPaper start - add PlayerBlockDestroySpeedEvent
|
|
||||||
+ public static net.sparklypower.sparklypaper.event.block.PlayerBlockDestroySpeedEvent callPlayerBlockDestroySpeedEvent(net.minecraft.world.entity.player.Player player, LevelAccessor world, BlockPos blockPos, float destroySpeed) {
|
|
||||||
+ org.bukkit.block.Block block = CraftBlock.at(world, blockPos);
|
|
||||||
+ net.sparklypower.sparklypaper.event.block.PlayerBlockDestroySpeedEvent event = new net.sparklypower.sparklypaper.event.block.PlayerBlockDestroySpeedEvent((Player) player.getBukkitEntity(), block, destroySpeed);
|
|
||||||
+ event.callEvent();
|
|
||||||
+ return event;
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
}
|
|
||||||
@@ -1,80 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Tue, 25 Jun 2024 02:52:32 -0300
|
|
||||||
Subject: [PATCH] Add CraftItemRecipeEvent
|
|
||||||
|
|
||||||
Used when a player OR a crafter block crafts an item, as an alternative to PrepareItemCraftEvent and CraftItemEvent, because both events are not triggered when a item is crafted from a crafter
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
index b5d5dbc50a7b8c40739a15f164ffd08fdc534f9c..01a67fde6c823cac52a6b09720f09acc825d3f86 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
@@ -3218,6 +3218,21 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
||||||
} else {
|
|
||||||
event = new CraftItemEvent(recipe, inventory, type, packet.getSlotNum(), click, action);
|
|
||||||
}
|
|
||||||
+ // SparklyPaper start - add CraftItemRecipeEvent
|
|
||||||
+ // We will pigback a bit on the current implementation
|
|
||||||
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent craftItemRecipeEvent = new net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent(
|
|
||||||
+ ((CraftingInventory) top).getMatrix(), // We cannot use the top inventory directly because (it seems) that the first slot is the "result" slot
|
|
||||||
+ recipe,
|
|
||||||
+ event.getCurrentItem()
|
|
||||||
+ );
|
|
||||||
+ if (craftItemRecipeEvent.callEvent()) {
|
|
||||||
+ event.setCurrentItem(craftItemRecipeEvent.getResult());
|
|
||||||
+ } else {
|
|
||||||
+ event.setCancelled(true);
|
|
||||||
+ cancelled = true;
|
|
||||||
+ event.setCurrentItem(craftItemRecipeEvent.getResult());
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/block/CrafterBlock.java b/src/main/java/net/minecraft/world/level/block/CrafterBlock.java
|
|
||||||
index 0e609b1e3abd50b415d8376dc550375a8a0251b6..8dbac20e32b70879eeee1c3563948e36c2eae342 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/block/CrafterBlock.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/block/CrafterBlock.java
|
|
||||||
@@ -203,6 +203,13 @@ public class CrafterBlock extends BaseEntityBlock {
|
|
||||||
}
|
|
||||||
itemstack = CraftItemStack.asNMSCopy(event.getResult());
|
|
||||||
// CraftBukkit end
|
|
||||||
+ // SparklyPaper - add CraftItemRecipeEvent
|
|
||||||
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent sparklyEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callCraftItemRecipeEvent(crafterblockentity, recipeholder.toBukkitRecipe(), itemstack);
|
|
||||||
+ if (sparklyEvent.isCancelled()) {
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+ itemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(sparklyEvent.getResult());
|
|
||||||
+ // SparklyPaper end
|
|
||||||
if (itemstack.isEmpty()) {
|
|
||||||
world.levelEvent(1050, pos, 0);
|
|
||||||
} else {
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
||||||
index a46f0c810ee2b9679c0530e5e6d3505b3d1f661c..85926a55066ac793b2e4cfe3502f9ab201df91a3 100644
|
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
|
||||||
@@ -1471,6 +1471,24 @@ public class CraftEventFactory {
|
|
||||||
Bukkit.getPluginManager().callEvent(crafterCraftEvent);
|
|
||||||
return crafterCraftEvent;
|
|
||||||
}
|
|
||||||
+
|
|
||||||
+ // SparklyPaper start - add CraftItemRecipeEvent
|
|
||||||
+ public static net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent callCraftItemRecipeEvent(net.minecraft.world.inventory.CraftingContainer container, Recipe recipe, ItemStack result) {
|
|
||||||
+ org.bukkit.inventory.ItemStack[] matrix = new org.bukkit.inventory.ItemStack[container.getItems().size()];
|
|
||||||
+ int i = 0;
|
|
||||||
+ for (ItemStack item : container.getItems()) {
|
|
||||||
+ matrix[i] = CraftItemStack.asCraftMirror(item);
|
|
||||||
+ i++;
|
|
||||||
+ }
|
|
||||||
+ org.bukkit.inventory.ItemStack bukkitResult = CraftItemStack.asCraftMirror(result);
|
|
||||||
+
|
|
||||||
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent event = new net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent(matrix, recipe, bukkitResult);
|
|
||||||
+ Bukkit.getPluginManager().callEvent(event);
|
|
||||||
+
|
|
||||||
+ return event;
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
// Paper start
|
|
||||||
@Deprecated
|
|
||||||
public static com.destroystokyo.paper.event.entity.ProjectileCollideEvent callProjectileCollideEvent(Entity entity, EntityHitResult position) {
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Fri, 23 Aug 2024 16:20:45 -0300
|
|
||||||
Subject: [PATCH] Allow throttling hopper checks if the target container is
|
|
||||||
full
|
|
||||||
|
|
||||||
|
|
||||||
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 cab403efd471bb61835224eea4e99570d34dcaaa..f074e9b9fbd7faf9502a83c1ed347f028a81021c 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
|
|
||||||
@@ -441,6 +441,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
|
||||||
Direction enumdirection = blockEntity.facing.getOpposite();
|
|
||||||
|
|
||||||
if (HopperBlockEntity.isFullContainer(iinventory, enumdirection)) {
|
|
||||||
+ if (world.sparklyPaperConfig.getTicksPer().getHopperCooldownWhenTargetContainerIsFull() != 0) blockEntity.setCooldown(world.sparklyPaperConfig.getTicksPer().getHopperCooldownWhenTargetContainerIsFull()); // SparklyPaper - Allow throttling hopper checks if the target container is full
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
// Paper start - Perf: Optimize Hoppers
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sat, 4 Jan 2025 23:58:55 -0300
|
|
||||||
Subject: [PATCH] Add PlayerMoveControllableVehicleEvent
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
index af4bcc57a9ad361de5da8c62ef7928b728c033de..ac0af5da6646df1cfe66aead3f945a9f77efa5de 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
|
||||||
@@ -611,6 +611,31 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
||||||
ServerGamePacketListenerImpl.LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", new Object[]{entity.getName().getString(), this.player.getName().getString(), Math.sqrt(d10)});
|
|
||||||
}
|
|
||||||
|
|
||||||
+ // SparklyPaper start - Add PlayerMoveControllableVehicleEvent
|
|
||||||
+ Player craftPlayer = this.getCraftPlayer();
|
|
||||||
+ org.bukkit.entity.Entity bukkitVehicle = entity.getBukkitEntity();
|
|
||||||
+ if (bukkitVehicle instanceof org.bukkit.entity.Vehicle) {
|
|
||||||
+ net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent playerMoveControllableVehicleEvent = new net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent(
|
|
||||||
+ craftPlayer,
|
|
||||||
+ (org.bukkit.entity.Vehicle) bukkitVehicle,
|
|
||||||
+ new org.bukkit.Location(craftPlayer.getWorld(), d0, d1, d2, f, f1),
|
|
||||||
+ new org.bukkit.Location(craftPlayer.getWorld(), d3, d4, d5, f, f1)
|
|
||||||
+ );
|
|
||||||
+ if (!playerMoveControllableVehicleEvent.callEvent()) {
|
|
||||||
+ // Cancelled, move back!
|
|
||||||
+ entity.absMoveTo(d0, d1, d2, f, f1);
|
|
||||||
+ this.player.absMoveTo(d0, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
|
||||||
+ this.send(new ClientboundMoveVehiclePacket(entity));
|
|
||||||
+ return;
|
|
||||||
+ }
|
|
||||||
+ d3 = playerMoveControllableVehicleEvent.getTo().x();
|
|
||||||
+ d4 = playerMoveControllableVehicleEvent.getTo().y();
|
|
||||||
+ d5 = playerMoveControllableVehicleEvent.getTo().z();
|
|
||||||
+ f = playerMoveControllableVehicleEvent.getTo().getYaw();
|
|
||||||
+ f1 = playerMoveControllableVehicleEvent.getTo().getPitch();
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
+
|
|
||||||
entity.absMoveTo(d3, d4, d5, f, f1);
|
|
||||||
this.player.absMoveTo(d3, d4, d5, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,129 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Sat, 1 Jun 2024 01:22:41 -0300
|
|
||||||
Subject: [PATCH] SPARKLYPOWER Remap SparklyPower hacky legacy NBT tags
|
|
||||||
|
|
||||||
This is only useful for us in SparklyPower, but yeah...
|
|
||||||
|
|
||||||
diff --git a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
|
||||||
index 2d29d89cc45866822189a62bffbe1a8fe57c477b..f54dd842ed40f2a2854c232b17009f932a1926a8 100644
|
|
||||||
--- a/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
|
||||||
+++ b/src/main/java/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
|
||||||
@@ -9,6 +9,7 @@ import ca.spottedleaf.dataconverter.types.ObjectType;
|
|
||||||
import ca.spottedleaf.dataconverter.types.TypeUtil;
|
|
||||||
import ca.spottedleaf.dataconverter.util.NamespaceUtil;
|
|
||||||
import net.minecraft.util.Mth;
|
|
||||||
+
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
@@ -1221,6 +1222,7 @@ public final class ConverterItemStackToDataComponents {
|
|
||||||
ret.setString("id", this.id);
|
|
||||||
ret.setInt("count", this.count);
|
|
||||||
if (!this.tag.isEmpty()) {
|
|
||||||
+ net.sparklypower.sparklypaper.LegacyNBTRemapper.INSTANCE.remap(this.tag); // SparklyPaper - Remap SparklyPower hacky legacy NBT tags
|
|
||||||
this.components.setMap("minecraft:custom_data", this.tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
diff --git a/src/main/kotlin/net/sparklypower/sparklypaper/LegacyNBTRemapper.kt b/src/main/kotlin/net/sparklypower/sparklypaper/LegacyNBTRemapper.kt
|
|
||||||
new file mode 100644
|
|
||||||
index 0000000000000000000000000000000000000000..399225fb883b9771084689d00723d944a89b0902
|
|
||||||
--- /dev/null
|
|
||||||
+++ b/src/main/kotlin/net/sparklypower/sparklypaper/LegacyNBTRemapper.kt
|
|
||||||
@@ -0,0 +1,95 @@
|
|
||||||
+package net.sparklypower.sparklypaper
|
|
||||||
+
|
|
||||||
+import ca.spottedleaf.dataconverter.types.MapType
|
|
||||||
+
|
|
||||||
+object LegacyNBTRemapper {
|
|
||||||
+ /**
|
|
||||||
+ * Remaps hacky direct NBT storage used in SparklyPower to proper PersistentDataContainer data
|
|
||||||
+ */
|
|
||||||
+ fun remap(tag: MapType<String>) {
|
|
||||||
+ val perfectDreamsMap = tag.getMap<String>("PerfectDreams")
|
|
||||||
+
|
|
||||||
+ if (perfectDreamsMap != null) {
|
|
||||||
+ val publicBukkitValuesMap = tag.getOrCreateMap<String>("PublicBukkitValues")
|
|
||||||
+
|
|
||||||
+ // The "setBoolean" functions do set bytes behind the scenes, just like how we do the things in SparklyPower
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("isJetpack")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_jetpack", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("disallowCrafting")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:disallow_crafting", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("poop")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_poop", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("renamedBySeuZe")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_renamed_by_seu_ze", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("isMonsterPickaxe")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_monster_tool", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("itemOwner")?.let {
|
|
||||||
+ publicBukkitValuesMap.setString("sparklypower:item_owner", it)
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("DreamFusca")?.let {
|
|
||||||
+ publicBukkitValuesMap.setString("sparklypower:fusca_info", it)
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("isFusca")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_fusca", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("fancyLeatherArmor")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_fancy_leather_armor", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("caixaSecretaLevel")?.let {
|
|
||||||
+ publicBukkitValuesMap.setInt("sparklypower:caixa_secreta_level", it.toInt())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("caixaSecretaWorld")?.let {
|
|
||||||
+ publicBukkitValuesMap.setString("sparklypower:caixa_secreta_world", it)
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("isMoveSpawners")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_move_spawners_tool", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("spawnerType")?.let {
|
|
||||||
+ publicBukkitValuesMap.setString("sparklypower:spawner_type", it)
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("isMochila")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_mochila", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("mochilaId")?.let {
|
|
||||||
+ publicBukkitValuesMap.setLong("sparklypower:mochila_id", it.toLong())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("customMapOwner")?.let {
|
|
||||||
+ publicBukkitValuesMap.setString("sparklypower:map_custom_owner", it)
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ perfectDreamsMap.getStringAndRemove("quickTeleport")?.let {
|
|
||||||
+ publicBukkitValuesMap.setBoolean("sparklypower:is_quick_resources_teleport", it.toBoolean())
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ // If it is empty, then it means that we have migrated everything and we can remove the old PerfectDreams tag, yay!
|
|
||||||
+ if (perfectDreamsMap.isEmpty)
|
|
||||||
+ tag.remove("PerfectDreams")
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ private fun MapType<String>.getStringAndRemove(key: String): String? {
|
|
||||||
+ val v = getString(key)
|
|
||||||
+ remove(key)
|
|
||||||
+ return v
|
|
||||||
+ }
|
|
||||||
+}
|
|
||||||
\ No newline at end of file
|
|
||||||
@@ -1,82 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
|
||||||
Date: Wed, 12 Jun 2024 11:53:09 -0300
|
|
||||||
Subject: [PATCH] SPARKLYPOWER Add custom blocks
|
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/block/Blocks.java b/src/main/java/net/minecraft/world/level/block/Blocks.java
|
|
||||||
index 66a07f7cbf1c1d6ecbe055cbf4f63eb07d93e90c..2738ccd47cbb7d26a6c92c2d86b1735003df9e2e 100644
|
|
||||||
--- a/src/main/java/net/minecraft/world/level/block/Blocks.java
|
|
||||||
+++ b/src/main/java/net/minecraft/world/level/block/Blocks.java
|
|
||||||
@@ -6725,10 +6725,55 @@ public class Blocks {
|
|
||||||
.pushReaction(PushReaction.DESTROY)
|
|
||||||
.requiredFeatures(FeatureFlags.WINTER_DROP)
|
|
||||||
);
|
|
||||||
+ // SparklyPaper start - SparklyPower Survival custom blocks
|
|
||||||
+ // Blocks' strength should be synced with the replaced block on the client side!
|
|
||||||
+ public static final Block SPARKLYPOWER_RAINBOW_WOOL = register(
|
|
||||||
+ "sparklypower_rainbow_wool",
|
|
||||||
+ Block::new,
|
|
||||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
|
||||||
+ );
|
|
||||||
+ public static final Block SPARKLYPOWER_RAINBOW_CONCRETE = register(
|
|
||||||
+ "sparklypower_rainbow_concrete",
|
|
||||||
+ Block::new,
|
|
||||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
|
||||||
+ );
|
|
||||||
+ public static final Block SPARKLYPOWER_RAINBOW_TERRACOTTA = register(
|
|
||||||
+ "sparklypower_rainbow_terracotta",
|
|
||||||
+ Block::new,
|
|
||||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
|
||||||
+ );
|
|
||||||
+ public static final Block SPARKLYPOWER_ASPHALT_SERVER = register(
|
|
||||||
+ "sparklypower_asphalt_server",
|
|
||||||
+ Block::new,
|
|
||||||
+ BlockBehaviour.Properties.of()
|
|
||||||
+ .mapColor(MapColor.COLOR_BLACK)
|
|
||||||
+ .instrument(NoteBlockInstrument.BASEDRUM)
|
|
||||||
+ .requiresCorrectToolForDrops()
|
|
||||||
+ .strength(1.5F, 6.0F)
|
|
||||||
+ );
|
|
||||||
+ public static final Block SPARKLYPOWER_ASPHALT_SERVER_SLAB = register(
|
|
||||||
+ "sparklypower_asphalt_server_slab",
|
|
||||||
+ SlabBlock::new,
|
|
||||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(2.0F, 6.0F)
|
|
||||||
+ );
|
|
||||||
+ public static final Block SPARKLYPOWER_ASPHALT_PLAYER = register(
|
|
||||||
+ "sparklypower_asphalt_player",
|
|
||||||
+ Block::new,
|
|
||||||
+ BlockBehaviour.Properties.of()
|
|
||||||
+ .mapColor(MapColor.COLOR_BLACK)
|
|
||||||
+ .instrument(NoteBlockInstrument.BASEDRUM)
|
|
||||||
+ .requiresCorrectToolForDrops()
|
|
||||||
+ .strength(1.5F, 6.0F)
|
|
||||||
+ );
|
|
||||||
+ public static final Block SPARKLYPOWER_ASPHALT_PLAYER_SLAB = register(
|
|
||||||
+ "sparklypower_asphalt_player_slab",
|
|
||||||
+ SlabBlock::new,
|
|
||||||
+ BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(2.0F, 6.0F)
|
|
||||||
+ );
|
|
||||||
+ // SparklyPaper end
|
|
||||||
|
|
||||||
private static ToIntFunction<BlockState> litBlockEmission(int litLevel) {
|
|
||||||
- return state -> state.getValue(BlockStateProperties.LIT) ? litLevel : 0;
|
|
||||||
- }
|
|
||||||
+ return state -> state.getValue(BlockStateProperties.LIT) ? litLevel : 0; }
|
|
||||||
|
|
||||||
private static Function<BlockState, MapColor> waterloggedMapColor(MapColor mapColor) {
|
|
||||||
return state -> state.getValue(BlockStateProperties.WATERLOGGED) ? MapColor.WATER : mapColor;
|
|
||||||
diff --git a/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
|
||||||
index 91926be355af20bba86be4c569cf7f972c79fbb5..26aa9cf0288055d5c8d9165ddc2ad3707b950ea4 100644
|
|
||||||
--- a/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
|
||||||
+++ b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
|
||||||
@@ -132,6 +132,9 @@ public class LegacyTest {
|
|
||||||
Material.CREAKING_SPAWN_EGG, Material.PALE_HANGING_MOSS, Material.PALE_MOSS_BLOCK, Material.PALE_MOSS_CARPET, Material.PALE_OAK_BOAT, Material.PALE_OAK_BUTTON, Material.PALE_OAK_CHEST_BOAT, Material.PALE_OAK_DOOR, Material.PALE_OAK_FENCE,
|
|
||||||
Material.PALE_OAK_FENCE_GATE, Material.PALE_OAK_HANGING_SIGN, Material.PALE_OAK_LEAVES, Material.PALE_OAK_LOG, Material.PALE_OAK_PLANKS, Material.PALE_OAK_PRESSURE_PLATE, Material.PALE_OAK_SAPLING, Material.PALE_OAK_SIGN, Material.PALE_OAK_SLAB,
|
|
||||||
Material.PALE_OAK_STAIRS, Material.PALE_OAK_TRAPDOOR, Material.PALE_OAK_WALL_SIGN, Material.PALE_OAK_WALL_HANGING_SIGN, Material.PALE_OAK_WOOD, Material.POTTED_PALE_OAK_SAPLING, Material.STRIPPED_PALE_OAK_LOG, Material.STRIPPED_PALE_OAK_WOOD,
|
|
||||||
+ // SparklyPower custom blocks
|
|
||||||
+ Material.SPARKLYPOWER_RAINBOW_WOOL, Material.SPARKLYPOWER_RAINBOW_CONCRETE, Material.SPARKLYPOWER_RAINBOW_TERRACOTTA, Material.SPARKLYPOWER_ASPHALT_PLAYER, Material.SPARKLYPOWER_ASPHALT_SERVER, Material.SPARKLYPOWER_ASPHALT_PLAYER_SLAB,
|
|
||||||
+ Material.SPARKLYPOWER_ASPHALT_SERVER_SLAB,
|
|
||||||
//
|
|
||||||
Material.LEGACY_AIR, Material.LEGACY_DEAD_BUSH, Material.LEGACY_BURNING_FURNACE, Material.LEGACY_WALL_SIGN, Material.LEGACY_REDSTONE_TORCH_OFF, Material.LEGACY_SKULL, Material.LEGACY_REDSTONE_COMPARATOR_ON, Material.LEGACY_WALL_BANNER, Material.LEGACY_MONSTER_EGG));
|
|
||||||
|
|
||||||
@@ -1,14 +1,16 @@
|
|||||||
pluginManagement {
|
pluginManagement {
|
||||||
repositories {
|
repositories {
|
||||||
gradlePluginPortal()
|
gradlePluginPortal()
|
||||||
|
mavenLocal()
|
||||||
maven("https://repo.papermc.io/repository/maven-public/")
|
maven("https://repo.papermc.io/repository/maven-public/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.7.0"
|
id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
|
||||||
}
|
}
|
||||||
|
|
||||||
rootProject.name = "SparklyPaper"
|
rootProject.name = "sparklypaper"
|
||||||
|
|
||||||
include("sparklypaper-api", "sparklypaper-server")
|
include("sparklypaper-api")
|
||||||
|
include("sparklypaper-server")
|
||||||
|
|||||||
44
sparklypaper-api/build.gradle.kts.patch
Normal file
44
sparklypaper-api/build.gradle.kts.patch
Normal file
@@ -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<Javadoc> {
|
||||||
|
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")
|
||||||
@@ -5,7 +5,7 @@ Subject: [PATCH] SPARKLYPOWER Add custom blocks
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/com/destroystokyo/paper/MaterialTags.java b/src/main/java/com/destroystokyo/paper/MaterialTags.java
|
diff --git a/src/main/java/com/destroystokyo/paper/MaterialTags.java b/src/main/java/com/destroystokyo/paper/MaterialTags.java
|
||||||
index 41eaa8159f8c028faa118300e95f6a0fb9cfe989..5b5ddb19b39d5201da422f9b10e2491ab9334925 100644
|
index 679f78e07a3a2de745fa237165d0a8db5e086f29..a083aac89cbe397545f34f0e9312fc8fb66dec85 100644
|
||||||
--- a/src/main/java/com/destroystokyo/paper/MaterialTags.java
|
--- a/src/main/java/com/destroystokyo/paper/MaterialTags.java
|
||||||
+++ b/src/main/java/com/destroystokyo/paper/MaterialTags.java
|
+++ b/src/main/java/com/destroystokyo/paper/MaterialTags.java
|
||||||
@@ -83,6 +83,7 @@ public class MaterialTags {
|
@@ -83,6 +83,7 @@ public class MaterialTags {
|
||||||
@@ -33,13 +33,13 @@ index 41eaa8159f8c028faa118300e95f6a0fb9cfe989..5b5ddb19b39d5201da422f9b10e2491a
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java
|
diff --git a/src/main/java/org/bukkit/Material.java b/src/main/java/org/bukkit/Material.java
|
||||||
index 028ac35df6c4d044d07b3869751736d418c1eb0e..dd9795e0725275b0fe5a3f4ecfd4d587a23f963f 100644
|
index 9afafc00e457c721a1b20b05c6a5d330caa40dfb..34049b57f5e481e3e8a3eb22cc73dcfda39c6116 100644
|
||||||
--- a/src/main/java/org/bukkit/Material.java
|
--- a/src/main/java/org/bukkit/Material.java
|
||||||
+++ b/src/main/java/org/bukkit/Material.java
|
+++ b/src/main/java/org/bukkit/Material.java
|
||||||
@@ -3843,6 +3843,22 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla
|
@@ -3814,6 +3814,22 @@ public enum Material implements Keyed, Translatable, net.kyori.adventure.transla
|
||||||
BIG_DRIPLEAF_STEM(13167, Dripleaf.class),
|
|
||||||
POTTED_AZALEA_BUSH(20430),
|
|
||||||
POTTED_FLOWERING_AZALEA_BUSH(10609),
|
POTTED_FLOWERING_AZALEA_BUSH(10609),
|
||||||
|
POTTED_OPEN_EYEBLOSSOM(24999),
|
||||||
|
POTTED_CLOSED_EYEBLOSSOM(16694),
|
||||||
+ // SparklyPaper start - SparklyPower Survival custom blocks
|
+ // SparklyPaper start - SparklyPower Survival custom blocks
|
||||||
+ // The IDs themselves doesn't have any correlation with anything, Spigot invented that for backwards compatibility
|
+ // The IDs themselves doesn't have any correlation with anything, Spigot invented that for backwards compatibility
|
||||||
+ SPARKLYPOWER_RAINBOW_WOOL(13003),
|
+ SPARKLYPOWER_RAINBOW_WOOL(13003),
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
--- a/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/advancement/AdvancementDisplay.java
|
||||||
|
@@ -27,7 +_,7 @@
|
||||||
|
*
|
||||||
|
* @return the frame type
|
||||||
|
*/
|
||||||
|
- Frame frame();
|
||||||
|
+ Frame frame(); // patch
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the advancement title.
|
||||||
2
sparklypaper-api/src/main/java/ForkFile.java
Normal file
2
sparklypaper-api/src/main/java/ForkFile.java
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
public class ForkFile {
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package net.sparklypower.sparklypaper.event.entity;
|
||||||
|
|
||||||
|
import org.bukkit.entity.HumanEntity;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.entity.EntityEvent;
|
||||||
|
import org.bukkit.inventory.EquipmentSlot;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a entity releases a bow, before the projectile is spawned
|
||||||
|
* <p>
|
||||||
|
* Compared to EntityShootBowEvent, this event is called before the projectile is spawned, before the force check is done, and before the bow release sound is played.
|
||||||
|
* <p>
|
||||||
|
* Currently this event is only called for players! To be more specific, it is only called for HumanEntity!!
|
||||||
|
*/
|
||||||
|
public class PreEntityShootBowEvent extends EntityEvent implements Cancellable {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private final ItemStack bow;
|
||||||
|
private final EquipmentSlot hand;
|
||||||
|
private final float force;
|
||||||
|
private boolean cancelled;
|
||||||
|
|
||||||
|
public PreEntityShootBowEvent(@NotNull final HumanEntity shooter, @Nullable final ItemStack bow, @NotNull final EquipmentSlot hand, final float force) {
|
||||||
|
super(shooter);
|
||||||
|
this.bow = bow;
|
||||||
|
this.hand = hand;
|
||||||
|
this.force = force;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bow ItemStack used to fire the arrow.
|
||||||
|
*
|
||||||
|
* @return the bow involved in this event
|
||||||
|
*/
|
||||||
|
@Nullable
|
||||||
|
public ItemStack getBow() {
|
||||||
|
return bow;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the hand from which the bow was shot.
|
||||||
|
*
|
||||||
|
* @return the hand
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public EquipmentSlot getHand() {
|
||||||
|
return hand;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the force the arrow was launched with
|
||||||
|
*
|
||||||
|
* @return bow shooting force, up to 1.0
|
||||||
|
*/
|
||||||
|
public float getForce() {
|
||||||
|
return force;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancel) {
|
||||||
|
cancelled = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package net.sparklypower.sparklypaper.event.inventory;
|
||||||
|
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.inventory.*;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the recipe of an Item is completed inside a crafting matrix.
|
||||||
|
*
|
||||||
|
* This is an alternate version of [org.bukkit.event.inventory.CraftItemEvent], where this one is called for player crafting items and crafters.
|
||||||
|
*/
|
||||||
|
public class CraftItemRecipeEvent extends Event implements Cancellable {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private final Recipe recipe;
|
||||||
|
private final ItemStack @Nullable [] matrix;
|
||||||
|
private ItemStack result;
|
||||||
|
private boolean isCancelled = false;
|
||||||
|
|
||||||
|
public CraftItemRecipeEvent(@NotNull ItemStack @Nullable [] matrix, @NotNull Recipe recipe, @Nullable ItemStack result) {
|
||||||
|
this.matrix = matrix;
|
||||||
|
this.recipe = recipe;
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setResult(@Nullable ItemStack result) {
|
||||||
|
this.result = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public ItemStack getResult() {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return A copy of the current recipe on the crafting matrix.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Recipe getRecipe() {
|
||||||
|
return recipe;
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nullable ItemStack[] getCraftingMatrix() {
|
||||||
|
return matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return isCancelled;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancel) {
|
||||||
|
this.isCancelled = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,129 @@
|
|||||||
|
package net.sparklypower.sparklypaper.event.player;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.entity.Vehicle;
|
||||||
|
import org.bukkit.event.Cancellable;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.player.PlayerEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raised when a player moves a controllable vehicle. Controllable vehicles are vehicles that the client can control, such as boats, horses, striders, pigs, etc.
|
||||||
|
* <p>
|
||||||
|
* Minecarts are NOT affected by this event!
|
||||||
|
*/
|
||||||
|
public class PlayerMoveControllableVehicleEvent extends PlayerEvent implements Cancellable {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private boolean cancel = false;
|
||||||
|
private final Vehicle vehicle;
|
||||||
|
private Location from;
|
||||||
|
private Location to;
|
||||||
|
|
||||||
|
public PlayerMoveControllableVehicleEvent(@NotNull final Player player, @NotNull final Vehicle vehicle, @NotNull final Location from, @NotNull final Location to) {
|
||||||
|
super(player);
|
||||||
|
|
||||||
|
this.vehicle = vehicle;
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the previous position.
|
||||||
|
*
|
||||||
|
* @return Old position.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Location getFrom() {
|
||||||
|
return from.clone(); // Paper - clone to avoid changes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the location to mark as where the player moved from
|
||||||
|
*
|
||||||
|
* @param from New location to mark as the players previous location
|
||||||
|
*/
|
||||||
|
public void setFrom(@NotNull Location from) {
|
||||||
|
validateLocation(from, this.from);
|
||||||
|
this.from = from;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the next position.
|
||||||
|
*
|
||||||
|
* @return New position.
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Location getTo() {
|
||||||
|
return to.clone(); // Paper - clone to avoid changes
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the location that this player will move to
|
||||||
|
*
|
||||||
|
* @param to New Location this player will move to
|
||||||
|
*/
|
||||||
|
public void setTo(@NotNull Location to) {
|
||||||
|
validateLocation(to, this.to);
|
||||||
|
this.to = to;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the vehicle.
|
||||||
|
*
|
||||||
|
* @return the vehicle
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public final Entity getVehicle() {
|
||||||
|
return vehicle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cancellation state of this event. A cancelled event will not
|
||||||
|
* be executed in the server, but will still pass to other plugins
|
||||||
|
* <p>
|
||||||
|
* If a move or teleport event is cancelled, the vehicle and player will be moved or
|
||||||
|
* teleported back to the Location as defined by getFrom(). This will not
|
||||||
|
* fire an event
|
||||||
|
*
|
||||||
|
* @return true if this event is cancelled
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isCancelled() {
|
||||||
|
return cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cancellation state of this event. A cancelled event will not
|
||||||
|
* be executed in the server, but will still pass to other plugins
|
||||||
|
* <p>
|
||||||
|
* If a move or teleport event is cancelled, the vehicle and player will be moved or
|
||||||
|
* teleported back to the Location as defined by getFrom(). This will not
|
||||||
|
* fire an event
|
||||||
|
*
|
||||||
|
* @param cancel true if you wish to cancel this event
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setCancelled(boolean cancel) {
|
||||||
|
this.cancel = cancel;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateLocation(@NotNull Location loc, @NotNull Location originalLoc) {
|
||||||
|
Preconditions.checkArgument(loc != null, "Cannot use null location!");
|
||||||
|
Preconditions.checkArgument(loc.getWorld() != null, "Cannot use null location with null world!");
|
||||||
|
Preconditions.checkArgument(loc.getWorld() != originalLoc, "New location should be in the original world!");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
package net.sparklypower.sparklypaper.event.player;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.HandlerList;
|
||||||
|
import org.bukkit.event.player.PlayerEvent;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called after the server attempts to move the player, but before the PlayerMoveEvent is called.
|
||||||
|
* <p>
|
||||||
|
* In contrast to PlayerMoveEvent, this event happens on every movement instead of being throttled like PlayerMoveEvent,
|
||||||
|
* and this event exposes the player's onGround/horizontalCollision status, allowing plugins to manipulate it.
|
||||||
|
*/
|
||||||
|
public class PlayerPreMoveEvent extends PlayerEvent {
|
||||||
|
private static final HandlerList handlers = new HandlerList();
|
||||||
|
private final Location from;
|
||||||
|
private final Location to;
|
||||||
|
private boolean onGround;
|
||||||
|
private boolean horizontalCollision;
|
||||||
|
private boolean resetFallDistance;
|
||||||
|
|
||||||
|
public PlayerPreMoveEvent(@NotNull final Player player, @NotNull final Location from, @Nullable final Location to, boolean onGround, boolean horizontalCollision, boolean resetFallDistance) {
|
||||||
|
super(player);
|
||||||
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
|
this.onGround = onGround;
|
||||||
|
this.horizontalCollision = horizontalCollision;
|
||||||
|
this.resetFallDistance = resetFallDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location this player moved from
|
||||||
|
*
|
||||||
|
* @return Location the player moved from
|
||||||
|
*/
|
||||||
|
@NotNull
|
||||||
|
public Location getFrom() {
|
||||||
|
return from;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the location this player moved to
|
||||||
|
*
|
||||||
|
* @return Location the player moved to
|
||||||
|
*/
|
||||||
|
@NotNull // Paper
|
||||||
|
public Location getTo() {
|
||||||
|
return to;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start - PlayerMoveEvent improvements
|
||||||
|
/**
|
||||||
|
* Check if the player has changed position (even within the same block) in the event
|
||||||
|
*
|
||||||
|
* @return whether the player has changed position or not
|
||||||
|
*/
|
||||||
|
public boolean hasChangedPosition() {
|
||||||
|
return hasExplicitlyChangedPosition() || !from.getWorld().equals(to.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the player has changed position (even within the same block) in the event, disregarding a possible world change
|
||||||
|
*
|
||||||
|
* @return whether the player has changed position or not
|
||||||
|
*/
|
||||||
|
public boolean hasExplicitlyChangedPosition() {
|
||||||
|
return from.getX() != to.getX() || from.getY() != to.getY() || from.getZ() != to.getZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the player has moved to a new block in the event
|
||||||
|
*
|
||||||
|
* @return whether the player has moved to a new block or not
|
||||||
|
*/
|
||||||
|
public boolean hasChangedBlock() {
|
||||||
|
return hasExplicitlyChangedBlock() || !from.getWorld().equals(to.getWorld());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the player has moved to a new block in the event, disregarding a possible world change
|
||||||
|
*
|
||||||
|
* @return whether the player has moved to a new block or not
|
||||||
|
*/
|
||||||
|
public boolean hasExplicitlyChangedBlock() {
|
||||||
|
return from.getBlockX() != to.getBlockX() || from.getBlockY() != to.getBlockY() || from.getBlockZ() != to.getBlockZ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the player has changed orientation in the event
|
||||||
|
*
|
||||||
|
* @return whether the player has changed orientation or not
|
||||||
|
*/
|
||||||
|
public boolean hasChangedOrientation() {
|
||||||
|
return from.getPitch() != to.getPitch() || from.getYaw() != to.getYaw();
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the client said that they are on ground, keep in mind that this value is controlled by the client, so it can
|
||||||
|
* be spoofed by malicious clients or be out of sync.
|
||||||
|
*
|
||||||
|
* @return if the client said that the is on ground
|
||||||
|
*/
|
||||||
|
public boolean isOnGround() {
|
||||||
|
return onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the player should be on ground.
|
||||||
|
*
|
||||||
|
* @param onGround true if the player should be on ground
|
||||||
|
*/
|
||||||
|
public void setOnGround(boolean onGround) {
|
||||||
|
this.onGround = onGround;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the client said that they are horizontally colliding, keep in mind that this value is controlled by the client, so it can
|
||||||
|
* be spoofed by malicious clients or be out of sync.
|
||||||
|
*
|
||||||
|
* @return if the player is horizontally colliding on a block
|
||||||
|
*/
|
||||||
|
public boolean isHorizontalCollision() {
|
||||||
|
return horizontalCollision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the player should be horizontally colliding on a block.
|
||||||
|
*
|
||||||
|
* @param horizontalCollision true if the player should be colliding horizontally be on ground
|
||||||
|
*/
|
||||||
|
public void setHorizontalCollision(boolean horizontalCollision) {
|
||||||
|
this.horizontalCollision = horizontalCollision;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets if the player's fall distance should be reset. By default, the fall distance is reset every time the player moves upwards on the y axis.
|
||||||
|
*
|
||||||
|
* @return if the fall distance should be reset
|
||||||
|
*/
|
||||||
|
public boolean isResetFallDistance() {
|
||||||
|
return resetFallDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets if the player's fall distance should be reset.
|
||||||
|
*
|
||||||
|
* @param resetFallDistance true if the player fall distance should be reset
|
||||||
|
*/
|
||||||
|
public void setResetFallDistance(boolean resetFallDistance) {
|
||||||
|
this.resetFallDistance = resetFallDistance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
@Override
|
||||||
|
public HandlerList getHandlers() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public static HandlerList getHandlerList() {
|
||||||
|
return handlers;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
94
sparklypaper-server/build.gradle.kts.patch
Normal file
94
sparklypaper-server/build.gradle.kts.patch
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
--- a/paper-server/build.gradle.kts
|
||||||
|
+++ b/paper-server/build.gradle.kts
|
||||||
|
@@ -4,6 +_,8 @@
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
`java-library`
|
||||||
|
+ kotlin("jvm") version "2.0.0"
|
||||||
|
+ kotlin("plugin.serialization") version "2.0.0"
|
||||||
|
`maven-publish`
|
||||||
|
id("io.papermc.paperweight.core")
|
||||||
|
}
|
||||||
|
@@ -21,6 +_,21 @@
|
||||||
|
// macheOldPath = file("F:\\Projects\\PaperTooling\\mache\\versions\\1.21.4\\src\\main\\java")
|
||||||
|
// gitFilePatches = true
|
||||||
|
|
||||||
|
+ val fork = forks.register("sparklypaper") {
|
||||||
|
+ upstream.patchDir("paperServer") {
|
||||||
|
+ upstreamPath = "paper-server"
|
||||||
|
+ excludes = setOf("src/minecraft", "patches", "build.gradle.kts")
|
||||||
|
+ patchesDir = rootDirectory.dir("sparklypaper-server/paper-patches")
|
||||||
|
+ outputDir = rootDirectory.dir("paper-server")
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ activeFork = fork
|
||||||
|
+
|
||||||
|
+ paper {
|
||||||
|
+ paperServerDir = upstreamsDirectory().map { it.dir("paper/paper-server") }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
spigot {
|
||||||
|
buildDataRef = "3edaf46ec1eed4115ce1b18d2846cded42577e42"
|
||||||
|
packageVersion = "v1_21_R3" // also needs to be updated in MappingEnvironment
|
||||||
|
@@ -101,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())
|
||||||
|
}
|
||||||
|
@@ -119,7 +_,12 @@
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
- implementation(project(":paper-api"))
|
||||||
|
+ // SparklyPaper start
|
||||||
|
+ implementation(project(":sparklypaper-api"))
|
||||||
|
+ implementation(kotlin("reflect"))
|
||||||
|
+ implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
|
||||||
|
+ implementation("com.charleskorn.kaml:kaml:0.55.0")
|
||||||
|
+ // SparklyPaper end
|
||||||
|
implementation("ca.spottedleaf:concurrentutil:0.0.3")
|
||||||
|
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
|
||||||
|
@@ -183,7 +_,12 @@
|
||||||
|
val build = System.getenv("BUILD_NUMBER") ?: null
|
||||||
|
val buildTime = if (build != null) Instant.now() else Instant.EPOCH
|
||||||
|
val gitHash = git.exec(providers, "rev-parse", "--short=7", "HEAD").get().trim()
|
||||||
|
- val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
||||||
|
+ // SparklyPaper start
|
||||||
|
+ var implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
|
||||||
|
+ if (project.hasProperty("sparklypaperImplementationVersionSuffix")) {
|
||||||
|
+ implementationVersion += "/${project.property("sparklypaperImplementationVersionSuffix")}"
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
val date = git.exec(providers, "show", "-s", "--format=%ci", gitHash).get().trim()
|
||||||
|
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
|
||||||
|
attributes(
|
||||||
|
@@ -194,8 +_,8 @@
|
||||||
|
"Specification-Title" to "Paper",
|
||||||
|
"Specification-Version" to project.version,
|
||||||
|
"Specification-Vendor" to "Paper Team",
|
||||||
|
- "Brand-Id" to "papermc:paper",
|
||||||
|
- "Brand-Name" to "Paper",
|
||||||
|
+ "Brand-Id" to "sparklypower:sparklypaper", // SparklyPaper
|
||||||
|
+ "Brand-Name" to "SparklyPaper", // SparklyPaper
|
||||||
|
"Build-Number" to (build ?: ""),
|
||||||
|
"Build-Time" to buildTime.toString(),
|
||||||
|
"Git-Branch" to gitBranch,
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 13 Jan 2025 13:20:31 -0300
|
||||||
|
Subject: [PATCH] SparklyPaper config files
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
index 97a294d2f5c1ddf0af7ffec3e1425eb329c5751b..4c420e17d936132bb4569776911757fd959e93d6 100644
|
||||||
|
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
@@ -224,6 +224,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||||
|
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
||||||
|
this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
|
||||||
|
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
|
||||||
|
+ // SparklyPaper start
|
||||||
|
+ try {
|
||||||
|
+ net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((java.io.File) options.valueOf("sparklypaper-settings"));
|
||||||
|
+ } catch (Exception e) {
|
||||||
|
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
||||||
|
+ // SparklyPaper end
|
||||||
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||||
|
|
||||||
|
this.setPvpAllowed(properties.pvp);
|
||||||
|
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||||
|
index 2bbebb4335d927f240abcac67a5b423e38dc33d7..27c2ea4a387ee5f7d078a42cb57f146cb748501d 100644
|
||||||
|
--- a/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/net/minecraft/world/level/Level.java
|
||||||
|
@@ -170,6 +170,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
// Paper end - add paper world config
|
||||||
|
|
||||||
|
public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
||||||
|
+ public net.sparklypower.sparklypaper.configs.SparklyPaperConfig.SparklyPaperWorldConfig sparklyPaperConfig; // SparklyPaper
|
||||||
|
public static BlockPos lastPhysicsProblem; // Spigot
|
||||||
|
private org.spigotmc.TickLimiter entityLimiter;
|
||||||
|
private org.spigotmc.TickLimiter tileLimiter;
|
||||||
|
@@ -853,6 +854,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
// Paper end - getblock optimisations - cache world height/sections
|
||||||
|
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
|
||||||
|
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
||||||
|
+ this.sparklyPaperConfig = net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getWorldSettings(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // SparklyPaper
|
||||||
|
this.generator = gen;
|
||||||
|
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);
|
||||||
|
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 13 Jan 2025 14:19:31 -0300
|
||||||
|
Subject: [PATCH] Skip "distanceToSqr" call in "ServerEntity#sendChanges" if
|
||||||
|
the delta movement hasn't changed
|
||||||
|
|
||||||
|
The "distanceToSqr" call is a bit expensive, so avoiding it is pretty nice, around ~15% calls are skipped with this check
|
||||||
|
|
||||||
|
We could also check if the x,y,z coordinates are equal, but for now, let's just keep the identity check, which also helps us since Minecraft's code does reuse the original delta movement Vec3 object
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||||
|
index 0fb253aa55a24b56b17f524b3261c5b75c7d7e59..8d0c259efc31de7de0ca5b900376677552e81f81 100644
|
||||||
|
--- a/net/minecraft/server/level/ServerEntity.java
|
||||||
|
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||||
|
@@ -195,6 +195,7 @@ public class ServerEntity {
|
||||||
|
|
||||||
|
if (this.entity.hasImpulse || this.trackDelta || this.entity instanceof LivingEntity && ((LivingEntity)this.entity).isFallFlying()) {
|
||||||
|
Vec3 deltaMovement = this.entity.getDeltaMovement();
|
||||||
|
+ if (deltaMovement != this.lastSentMovement) { // SparklyPaper start - skip distanceToSqr call in ServerEntity#sendChanges if the delta movement hasn't changed
|
||||||
|
double d = deltaMovement.distanceToSqr(this.lastSentMovement);
|
||||||
|
if (d > 1.0E-7 || d > 0.0 && deltaMovement.lengthSqr() == 0.0) {
|
||||||
|
this.lastSentMovement = deltaMovement;
|
||||||
|
@@ -212,6 +213,7 @@ public class ServerEntity {
|
||||||
|
this.broadcast.accept(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
+ } // SparklyPaper end
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packet != null) {
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Fri, 17 Nov 2023 14:22:41 -0300
|
||||||
|
Subject: [PATCH] Skip "MapItem#update()" if the map does not have the
|
||||||
|
CraftMapRenderer present
|
||||||
|
|
||||||
|
Optimizes "image in map" maps, without requiring the map to be locked, which some old map plugins may not do
|
||||||
|
|
||||||
|
This has the disadvantage that the vanilla map data will never be updated while the CraftMapRenderer is not present, but that's not a huuuge problem for us
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/item/MapItem.java b/net/minecraft/world/item/MapItem.java
|
||||||
|
index 8795d54cff569c911e0a535f38a0ec4130f7b4d5..31960e54bf5ed4aa31cd12b60ab0fa263902ce2c 100644
|
||||||
|
--- a/net/minecraft/world/item/MapItem.java
|
||||||
|
+++ b/net/minecraft/world/item/MapItem.java
|
||||||
|
@@ -277,7 +277,7 @@ public class MapItem extends Item {
|
||||||
|
savedData.tickCarriedBy(player, stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (!savedData.locked && (isSelected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) {
|
||||||
|
+ if (!savedData.locked && (!level.sparklyPaperConfig.getSkipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer() || savedData.mapView.getRenderers().stream().anyMatch(mapRenderer -> mapRenderer.getClass() == org.bukkit.craftbukkit.map.CraftMapRenderer.class)) && (isSelected || entity instanceof Player && ((Player)entity).getOffhandItem() == stack)) { // SparklyPaper - don't update maps if they don't have the CraftMapRenderer in the render list
|
||||||
|
this.update(level, entity, savedData);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 13 Jan 2025 14:32:08 -0300
|
||||||
|
Subject: [PATCH] Skip dirty stats copy when requesting player stats
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/stats/ServerStatsCounter.java b/net/minecraft/stats/ServerStatsCounter.java
|
||||||
|
index 6c5205fe1dc6387a77b1edbdcab748d39e775d7f..c6e4a7668ed923d93bd7f67d19af82d5d84a0dc0 100644
|
||||||
|
--- a/net/minecraft/stats/ServerStatsCounter.java
|
||||||
|
+++ b/net/minecraft/stats/ServerStatsCounter.java
|
||||||
|
@@ -81,11 +81,15 @@ public class ServerStatsCounter extends StatsCounter {
|
||||||
|
this.dirty.add(stat);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // SparklyPaper start - Skip dirty stats copy when requesting player stats
|
||||||
|
+ /*
|
||||||
|
private Set<Stat<?>> getDirty() {
|
||||||
|
Set<Stat<?>> set = Sets.newHashSet(this.dirty);
|
||||||
|
this.dirty.clear();
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
+ */
|
||||||
|
+ // SparklyPaper end
|
||||||
|
|
||||||
|
public void parseLocal(DataFixer fixerUpper, String json) {
|
||||||
|
try {
|
||||||
|
@@ -190,10 +194,12 @@ public class ServerStatsCounter extends StatsCounter {
|
||||||
|
public void sendStats(ServerPlayer player) {
|
||||||
|
Object2IntMap<Stat<?>> map = new Object2IntOpenHashMap<>();
|
||||||
|
|
||||||
|
- for (Stat<?> stat : this.getDirty()) {
|
||||||
|
+ for (Stat<?> stat : this.dirty) { // SparklyPaper - Skip dirty stats copy when requesting player stats
|
||||||
|
map.put(stat, this.getValue(stat));
|
||||||
|
}
|
||||||
|
|
||||||
|
+ this.dirty.clear(); // SparklyPaper - Skip dirty stats copy when requesting player stats
|
||||||
|
+
|
||||||
|
player.connection.send(new ClientboundAwardStatsPacket(map));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Sun, 19 Nov 2023 12:35:16 -0300
|
||||||
|
Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
|
||||||
|
tasks to be run
|
||||||
|
|
||||||
|
On each tick, Paper runs EntityScheduler's executeTick of each entity. This is a bit expensive, due to ArrayDeque's size() call because it ain't a simple "get the current queue size" function, due to the thread checks, and because it needs to iterate all entities in all worlds.
|
||||||
|
|
||||||
|
To avoid the hefty ArrayDeque's size() call, we check if we *really* need to execute the executeTick, by adding all entities with scheduled tasks to a global set.
|
||||||
|
|
||||||
|
Most entities won't have any scheduled tasks, so this is a nice performance bonus. These optimizations, however, wouldn't work in a Folia environment, but because in SparklyPaper executeTick is always executed on the main thread, it ain't an issue for us (yay).
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||||
|
index ae220a732c78ab076261f20b5a54c71d7fceb407..6ad6bfe60026be304aa2178d5f04a79531cc66a6 100644
|
||||||
|
--- a/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -303,6 +303,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
public boolean isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||||
|
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
|
||||||
|
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||||
|
+ public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
||||||
|
|
||||||
|
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||||
|
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||||
|
@@ -1659,6 +1660,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
|
||||||
|
// Paper start - Folia scheduler API
|
||||||
|
((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick();
|
||||||
|
+ // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||||
|
+ for (final net.minecraft.world.entity.Entity entity : entitiesWithScheduledTasks) {
|
||||||
|
+ if (entity.isRemoved()) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();
|
||||||
|
+ if (bukkit != null) {
|
||||||
|
+ bukkit.taskScheduler.executeTick();
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ /*
|
||||||
|
getAllLevels().forEach(level -> {
|
||||||
|
for (final net.minecraft.world.entity.Entity entity : level.getEntities().getAll()) {
|
||||||
|
if (entity.isRemoved()) {
|
||||||
|
@@ -1670,6 +1683,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
+ */
|
||||||
|
+ // SparklyPaper end
|
||||||
|
// Paper end - Folia scheduler API
|
||||||
|
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
|
||||||
|
profilerFiller.push("commandFunctions");
|
||||||
@@ -1,189 +1,180 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
Date: Mon, 20 Nov 2023 20:17:56 -0300
|
Date: Mon, 13 Jan 2025 14:50:47 -0300
|
||||||
Subject: [PATCH] Blazingly Simple Farm Checks
|
Subject: [PATCH] Blazingly Simple Farm Checks
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/block/CropBlock.java b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
diff --git a/net/minecraft/world/level/block/CropBlock.java b/net/minecraft/world/level/block/CropBlock.java
|
||||||
index 1ada5ed825501666addacf527a513ab7bd4a3a58..1ce3d73753b72a62272c3a9b8d7642bd4ffdf378 100644
|
index bc0969f40814094e42a860a72314fccd1a66fabe..c14de811ae7cead820a00a87b9d2ce8cfb241d92 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
--- a/net/minecraft/world/level/block/CropBlock.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/block/CropBlock.java
|
+++ b/net/minecraft/world/level/block/CropBlock.java
|
||||||
@@ -81,6 +81,57 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
@@ -87,6 +87,57 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
||||||
int i = this.getAge(state);
|
if (level.getRawBrightness(pos, 0) >= 9) {
|
||||||
|
int age = this.getAge(state);
|
||||||
if (i < this.getMaxAge()) {
|
if (age < this.getMaxAge()) {
|
||||||
+ // SparklyPaper start - Blazingly simple farm checks
|
+ // SparklyPaper start - Blazingly simple farm checks
|
||||||
+ if (world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
||||||
+ // These checks are similar to getGrowthSpeed, but we have "inlined" them because we want to access stuff like the farm block data later on
|
+ // These checks are similar to getGrowthSpeed, but we have "inlined" them because we want to access stuff like the farm block data later on
|
||||||
+ // Is the block below us moisturised?
|
+ // Is the block below us moisturised?
|
||||||
+ BlockPos farmlandBelowTheCurrentBlock = pos.below();
|
+ BlockPos farmlandBelowTheCurrentBlock = pos.below();
|
||||||
+ BlockState farmlandBelowTheCurrentBlockData = world.getBlockState(farmlandBelowTheCurrentBlock);
|
+ BlockState farmlandBelowTheCurrentBlockData = level.getBlockState(farmlandBelowTheCurrentBlock);
|
||||||
+ float f = world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getDefaultGrowthSpeed();
|
+ float f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getDefaultGrowthSpeed();
|
||||||
+ boolean isCurrentFarmlandStateMoist = false;
|
+ boolean isCurrentFarmlandStateMoist = false;
|
||||||
+ if (farmlandBelowTheCurrentBlockData.is(Blocks.FARMLAND)) {
|
+ if (farmlandBelowTheCurrentBlockData.is(Blocks.FARMLAND)) {
|
||||||
+ if ((Integer) farmlandBelowTheCurrentBlockData.getValue(FarmBlock.MOISTURE) > 0) {
|
+ if ((Integer) farmlandBelowTheCurrentBlockData.getValue(FarmBlock.MOISTURE) > 0) {
|
||||||
+ // If we are currently moist, increase the speed!
|
+ // If we are currently moist, increase the speed!
|
||||||
+ f = world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
+ f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
||||||
+ isCurrentFarmlandStateMoist = true;
|
+ isCurrentFarmlandStateMoist = true;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ // If we are skipping the middle aging stages, we need to change the growth speed and the next stage accordingly
|
+ // If we are skipping the middle aging stages, we need to change the growth speed and the next stage accordingly
|
||||||
+ if (world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getSkipMiddleAgingStagesForCrops()) {
|
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getSkipMiddleAgingStagesForCrops()) {
|
||||||
+ f = f / getMaxAge();
|
+ f = f / getMaxAge();
|
||||||
+ i = getMaxAge() - 1;
|
+ age = getMaxAge() - 1;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ // Spigot start
|
+ // Spigot start
|
||||||
+ int modifier;
|
+ int modifier;
|
||||||
+ if (this == Blocks.BEETROOTS) {
|
+ if (this == Blocks.BEETROOTS) {
|
||||||
+ modifier = world.spigotConfig.beetrootModifier;
|
+ modifier = level.spigotConfig.beetrootModifier;
|
||||||
+ } else if (this == Blocks.CARROTS) {
|
+ } else if (this == Blocks.CARROTS) {
|
||||||
+ modifier = world.spigotConfig.carrotModifier;
|
+ modifier = level.spigotConfig.carrotModifier;
|
||||||
+ } else if (this == Blocks.POTATOES) {
|
+ } else if (this == Blocks.POTATOES) {
|
||||||
+ modifier = world.spigotConfig.potatoModifier;
|
+ modifier = level.spigotConfig.potatoModifier;
|
||||||
+ // Paper start
|
+ // Paper start
|
||||||
+ } else if (this == Blocks.TORCHFLOWER_CROP) {
|
+ } else if (this == Blocks.TORCHFLOWER_CROP) {
|
||||||
+ modifier = world.spigotConfig.torchFlowerModifier;
|
+ modifier = level.spigotConfig.torchFlowerModifier;
|
||||||
+ // Paper end
|
+ // Paper end
|
||||||
+ } else {
|
+ } else {
|
||||||
+ modifier = world.spigotConfig.wheatModifier;
|
+ modifier = level.spigotConfig.wheatModifier;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (random.nextFloat() < (modifier / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
+ if (random.nextFloat() < (modifier / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||||
+ // Spigot end
|
+ // Spigot end
|
||||||
+ if (!CraftEventFactory.handleBlockGrowEvent(world, pos, this.getStateForAge(i + 1), 2)) {
|
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, this.getStateForAge(age + 1), 2)) {
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ // Now that we know that the crop will grow... is the next stage the crop's max age? If yes, we are going to check if the farm land is moist!
|
+ // Now that we know that the crop will grow... is the next stage the crop's max age? If yes, we are going to check if the farm land is moist!
|
||||||
+ if (i + 1 == getMaxAge() && isCurrentFarmlandStateMoist && !FarmBlock.isNearWater(world, farmlandBelowTheCurrentBlock)) {
|
+ if (age + 1 == getMaxAge() && isCurrentFarmlandStateMoist && !FarmBlock.isNearWater(level, farmlandBelowTheCurrentBlock)) {
|
||||||
+ // Whoops, farm land ain't moist!
|
+ // Whoops, farm land ain't moist!
|
||||||
+ // From FarmBlock, set the moisture to 0
|
+ // From FarmBlock, set the moisture to 0
|
||||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(world, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
float f = CropBlock.getGrowthSpeed(this, world, pos);
|
float growthSpeed = getGrowthSpeed(this, level, pos);
|
||||||
|
|
||||||
// Spigot start
|
// Spigot start
|
||||||
@@ -103,6 +154,8 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
int modifier = 100;
|
||||||
|
@@ -108,6 +159,8 @@ public class CropBlock extends BushBlock implements BonemealableBlock {
|
||||||
// Spigot end
|
// Spigot end
|
||||||
CraftEventFactory.handleBlockGrowEvent(world, pos, this.getStateForAge(i + 1), 2); // CraftBukkit
|
org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, this.getStateForAge(age + 1), 2); // CraftBukkit
|
||||||
}
|
}
|
||||||
+ }
|
+ }
|
||||||
+ // SparklyPaper end
|
+ // SparklyPaper end
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/block/FarmBlock.java b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
diff --git a/net/minecraft/world/level/block/FarmBlock.java b/net/minecraft/world/level/block/FarmBlock.java
|
||||||
index c3dba0c2c94f3804338f86621dc42405e380a6b3..bfa98fe6df8e61512d913f98710d369d18467fed 100644
|
index 47c9b32c89e7e6f84a279c2f6098ada77dc58b6b..06a33e6f6118c2f2dce567efc2e23cbf877b7a9c 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
--- a/net/minecraft/world/level/block/FarmBlock.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/block/FarmBlock.java
|
+++ b/net/minecraft/world/level/block/FarmBlock.java
|
||||||
@@ -93,6 +93,19 @@ public class FarmBlock extends Block {
|
@@ -95,6 +95,19 @@ public class FarmBlock extends Block {
|
||||||
@Override
|
@Override
|
||||||
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||||
int i = (Integer) state.getValue(FarmBlock.MOISTURE);
|
int moistureValue = state.getValue(MOISTURE);
|
||||||
+ // SparklyPaper start - Blazingly simple farm checks
|
+ // SparklyPaper start - Blazingly simple farm checks
|
||||||
+ if (world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
||||||
+ if (i == 0) { // We only care about non-moisturised farm blocks
|
+ if (moistureValue == 0) { // We only care about non-moisturised farm blocks
|
||||||
+ if (FarmBlock.isNearWater(world, pos)) {
|
+ if (FarmBlock.isNearWater(level, pos)) {
|
||||||
+ // Make it MOIST!
|
+ // Make it MOIST!
|
||||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(world, pos, (BlockState) state.setValue(FarmBlock.MOISTURE, 7), 2); // CraftBukkit
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, pos, (BlockState) state.setValue(FarmBlock.MOISTURE, 7), 2); // CraftBukkit
|
||||||
+ } else if (!FarmBlock.shouldMaintainFarmland(world, pos)) {
|
+ } else if (!FarmBlock.shouldMaintainFarmland(level, pos)) {
|
||||||
+ FarmBlock.turnToDirt((Entity) null, state, world, pos);
|
+ FarmBlock.turnToDirt((Entity) null, state, level, pos);
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+ // SparklyPaper end
|
+ // SparklyPaper end
|
||||||
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 (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 (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 (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 (!isNearWater(level, pos) && !level.isRainingAt(pos.above())) {
|
||||||
@@ -153,7 +166,7 @@ public class FarmBlock extends Block {
|
@@ -154,7 +167,7 @@ public class FarmBlock extends Block {
|
||||||
return world.getBlockState(pos.above()).is(BlockTags.MAINTAINS_FARMLAND);
|
return level.getBlockState(pos.above()).is(BlockTags.MAINTAINS_FARMLAND);
|
||||||
}
|
}
|
||||||
|
|
||||||
- private static boolean isNearWater(LevelReader world, BlockPos pos) {
|
- private static boolean isNearWater(LevelReader level, BlockPos pos) {
|
||||||
+ public static boolean isNearWater(LevelReader world, BlockPos pos) { // SparklyPaper - make public for the Blazingly simple farm checks
|
+ public static boolean isNearWater(LevelReader level, BlockPos pos) { // SparklyPaper - make public for the Blazingly simple farm checks
|
||||||
// Paper start - Perf: remove abstract block iteration
|
// Paper start - Perf: remove abstract block iteration
|
||||||
int xOff = pos.getX();
|
int xOff = pos.getX();
|
||||||
int yOff = pos.getY();
|
int yOff = pos.getY();
|
||||||
diff --git a/src/main/java/net/minecraft/world/level/block/StemBlock.java b/src/main/java/net/minecraft/world/level/block/StemBlock.java
|
diff --git a/net/minecraft/world/level/block/StemBlock.java b/net/minecraft/world/level/block/StemBlock.java
|
||||||
index 76109aceb24a4719d49c1a55e3621cf2a63bbe16..ad2a81ca11d5e6fcf5899051c5b0af9b5398f1ac 100644
|
index 3dca57dd0c00dc64724cbc7f5a71963da9d12fd5..9839821365484bac93023b1aa542619dae4c88cf 100644
|
||||||
--- a/src/main/java/net/minecraft/world/level/block/StemBlock.java
|
--- a/net/minecraft/world/level/block/StemBlock.java
|
||||||
+++ b/src/main/java/net/minecraft/world/level/block/StemBlock.java
|
+++ b/net/minecraft/world/level/block/StemBlock.java
|
||||||
@@ -7,6 +7,7 @@ import java.util.Optional;
|
@@ -79,6 +79,56 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.core.Registry;
|
|
||||||
+import net.minecraft.core.registries.BuiltInRegistries;
|
|
||||||
import net.minecraft.core.registries.Registries;
|
|
||||||
import net.minecraft.resources.ResourceKey;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
@@ -73,6 +74,56 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
|
||||||
@Override
|
@Override
|
||||||
protected void randomTick(BlockState state, ServerLevel world, BlockPos pos, RandomSource random) {
|
protected void randomTick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||||
if (world.getRawBrightness(pos, 0) >= 9) {
|
if (level.getRawBrightness(pos, 0) >= 9) {
|
||||||
+ // SparklyPaper start - Blazingly simple farm checks
|
+ // SparklyPaper start - Blazingly simple farm checks
|
||||||
+ if (world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
+ if (level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getEnabled()) {
|
||||||
+ // These checks are similar to getGrowthSpeed, but we have "inlined" them because we want to access stuff like the farm block data later on
|
+ // These checks are similar to getGrowthSpeed, but we have "inlined" them because we want to access stuff like the farm block data later on
|
||||||
+ // Is the block below us moisturised?
|
+ // Is the block below us moisturised?
|
||||||
+ BlockPos farmlandBelowTheCurrentBlock = pos.below();
|
+ BlockPos farmlandBelowTheCurrentBlock = pos.below();
|
||||||
+ BlockState farmlandBelowTheCurrentBlockData = world.getBlockState(farmlandBelowTheCurrentBlock);
|
+ BlockState farmlandBelowTheCurrentBlockData = level.getBlockState(farmlandBelowTheCurrentBlock);
|
||||||
+ float f = world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getDefaultGrowthSpeed();
|
+ float f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getDefaultGrowthSpeed();
|
||||||
+ boolean isCurrentFarmlandStateMoist = false;
|
+ boolean isCurrentFarmlandStateMoist = false;
|
||||||
+ if (farmlandBelowTheCurrentBlockData.is(Blocks.FARMLAND)) {
|
+ if (farmlandBelowTheCurrentBlockData.is(Blocks.FARMLAND)) {
|
||||||
+ if ((Integer) farmlandBelowTheCurrentBlockData.getValue(FarmBlock.MOISTURE) > 0) {
|
+ if ((Integer) farmlandBelowTheCurrentBlockData.getValue(FarmBlock.MOISTURE) > 0) {
|
||||||
+ // If we are currently moist, increase the speed!
|
+ // If we are currently moist, increase the speed!
|
||||||
+ f = world.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
+ f = level.sparklyPaperConfig.getBlazinglySimpleFarmChecks().getMoistGrowthSpeed();
|
||||||
+ isCurrentFarmlandStateMoist = true;
|
+ isCurrentFarmlandStateMoist = true;
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? world.spigotConfig.pumpkinModifier : world.spigotConfig.melonModifier) / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
+ if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? level.spigotConfig.pumpkinModifier : level.spigotConfig.melonModifier) / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||||
+ int i = (Integer) state.getValue(StemBlock.AGE);
|
+ int i = (Integer) state.getValue(StemBlock.AGE);
|
||||||
+
|
+
|
||||||
+ if (i < 7) {
|
+ if (i < 7) {
|
||||||
+ state = (BlockState) state.setValue(StemBlock.AGE, i + 1);
|
+ state = (BlockState) state.setValue(StemBlock.AGE, i + 1);
|
||||||
+ CraftEventFactory.handleBlockGrowEvent(world, pos, state, 2); // CraftBukkit
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, pos, state, 2); // CraftBukkit
|
||||||
+ } else {
|
+ } else {
|
||||||
+ Direction enumdirection = Direction.Plane.HORIZONTAL.getRandomDirection(random);
|
+ Direction enumdirection = Direction.Plane.HORIZONTAL.getRandomDirection(random);
|
||||||
+ BlockPos blockposition1 = pos.relative(enumdirection);
|
+ BlockPos blockposition1 = pos.relative(enumdirection);
|
||||||
+ BlockState iblockdata1 = world.getBlockState(blockposition1.below());
|
+ BlockState iblockdata1 = level.getBlockState(blockposition1.below());
|
||||||
+
|
+
|
||||||
+ if (world.getBlockState(blockposition1).isAir() && (iblockdata1.is(Blocks.FARMLAND) || iblockdata1.is(BlockTags.DIRT))) {
|
+ if (level.getBlockState(blockposition1).isAir() && (iblockdata1.is(Blocks.FARMLAND) || iblockdata1.is(BlockTags.DIRT))) {
|
||||||
+ Registry<Block> iregistry = BuiltInRegistries.BLOCK;
|
+ Registry<Block> iregistry = net.minecraft.core.registries.BuiltInRegistries.BLOCK;
|
||||||
+ Optional<Block> optional = iregistry.getOptional(this.fruit);
|
+ Optional<Block> optional = iregistry.getOptional(this.fruit);
|
||||||
+ Optional<Block> optional1 = iregistry.getOptional(this.attachedStem);
|
+ Optional<Block> optional1 = iregistry.getOptional(this.attachedStem);
|
||||||
+
|
+
|
||||||
+ if (optional.isPresent() && optional1.isPresent()) {
|
+ if (optional.isPresent() && optional1.isPresent()) {
|
||||||
+ // CraftBukkit start
|
+ // CraftBukkit start
|
||||||
+ if (!CraftEventFactory.handleBlockGrowEvent(world, blockposition1, ((Block) optional.get()).defaultBlockState())) {
|
+ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockGrowEvent(level, blockposition1, ((Block) optional.get()).defaultBlockState())) {
|
||||||
+ return;
|
+ return;
|
||||||
+ }
|
+ }
|
||||||
+ // CraftBukkit end
|
+ // CraftBukkit end
|
||||||
+ // Now that we know that the crop will grow... is the next stage the crop's max age? If yes, we are going to check if the farm land is moist!
|
+ // Now that we know that the crop will grow... is the next stage the crop's max age? If yes, we are going to check if the farm land is moist!
|
||||||
+ if (isCurrentFarmlandStateMoist && !FarmBlock.isNearWater(world, farmlandBelowTheCurrentBlock)) {
|
+ if (isCurrentFarmlandStateMoist && !FarmBlock.isNearWater(level, farmlandBelowTheCurrentBlock)) {
|
||||||
+ // Whoops, farm land ain't moist!
|
+ // Whoops, farm land ain't moist!
|
||||||
+ // From FarmBlock, set the moisture to 0
|
+ // From FarmBlock, set the moisture to 0
|
||||||
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(world, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
+ org.bukkit.craftbukkit.event.CraftEventFactory.handleMoistureChangeEvent(level, farmlandBelowTheCurrentBlock, (BlockState) farmlandBelowTheCurrentBlockData.setValue(FarmBlock.MOISTURE, 0), 2); // CraftBukkit
|
||||||
+ }
|
+ }
|
||||||
+ world.setBlockAndUpdate(pos, (BlockState) ((Block) optional1.get()).defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, enumdirection));
|
+ level.setBlockAndUpdate(pos, (BlockState) ((Block) optional1.get()).defaultBlockState().setValue(HorizontalDirectionalBlock.FACING, enumdirection));
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ } else {
|
+ } else {
|
||||||
float f = CropBlock.getGrowthSpeed(this, world, pos);
|
float growthSpeed = CropBlock.getGrowthSpeed(this, level, pos);
|
||||||
|
if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? level.spigotConfig.pumpkinModifier : level.spigotConfig.melonModifier) / (100.0f * (Math.floor((25.0F / growthSpeed) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
||||||
if (random.nextFloat() < ((this == Blocks.PUMPKIN_STEM ? world.spigotConfig.pumpkinModifier : world.spigotConfig.melonModifier) / (100.0f * (Math.floor((25.0F / f) + 1))))) { // Spigot - SPIGOT-7159: Better modifier resolution
|
int ageValue = state.getValue(AGE);
|
||||||
@@ -102,7 +153,8 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
@@ -105,6 +155,8 @@ public class StemBlock extends BushBlock implements BonemealableBlock {
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-
|
|
||||||
+ }
|
|
||||||
+ // SparklyPaper end
|
|
||||||
}
|
}
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Tue, 21 Nov 2023 16:50:04 -0300
|
||||||
|
Subject: [PATCH] Spooky month optimizations
|
||||||
|
|
||||||
|
The quintessential patch that other performance forks also have for... some reason??? I thought that this optimization was too funny to not do it in SparklyPaper.
|
||||||
|
|
||||||
|
Caches when Bat's spooky season starts and ends, and when Skeleton and Zombies halloween starts and ends. The epoch is updated every 90 days. If your server is running for 90+ days straight without restarts, congratulations!
|
||||||
|
|
||||||
|
Avoids unnecessary date checks, even tho that this shouldn't really improve performance that much... unless you have a lot of bats/zombies/skeletons spawning.
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 6ad6bfe60026be304aa2178d5f04a79531cc66a6..4dbf2d9aa52029122f4816ca3504fa330b28a29b 100644
|
||||||
|
--- a/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -304,6 +304,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
|
||||||
|
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||||
|
public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
||||||
|
+ public net.sparklypower.sparklypaper.HalloweenManager halloweenManager = new net.sparklypower.sparklypaper.HalloweenManager(); // SparklyPaper - Spooky month optimizations
|
||||||
|
|
||||||
|
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||||
|
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||||
|
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
index 4c420e17d936132bb4569776911757fd959e93d6..6ac73610f6039290c4ef3dde2206b6863d2b5067 100644
|
||||||
|
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
@@ -233,6 +233,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||||
|
}
|
||||||
|
net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
||||||
|
// SparklyPaper end
|
||||||
|
+ // SparklyPaper start - Spooky month optimizations
|
||||||
|
+ halloweenManager.startHalloweenEpochTask();
|
||||||
|
+ halloweenManager.waitUntilEpochHasBeenUpdated();
|
||||||
|
+ // SparklyPaper end
|
||||||
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||||
|
|
||||||
|
this.setPvpAllowed(properties.pvp);
|
||||||
|
diff --git a/net/minecraft/world/entity/ambient/Bat.java b/net/minecraft/world/entity/ambient/Bat.java
|
||||||
|
index 5ebe7b1dce367d5c5e1136b97b2b9f6737595201..b003fa86fab9a6106c9875205d73e49e46904498 100644
|
||||||
|
--- a/net/minecraft/world/entity/ambient/Bat.java
|
||||||
|
+++ b/net/minecraft/world/entity/ambient/Bat.java
|
||||||
|
@@ -231,7 +231,7 @@ public class Bat extends AmbientCreature {
|
||||||
|
} else {
|
||||||
|
int maxLocalRawBrightness = level.getMaxLocalRawBrightness(pos);
|
||||||
|
int i = 4;
|
||||||
|
- if (isHalloween()) {
|
||||||
|
+ if (level.getServer().halloweenManager.isSpookySeason()) {
|
||||||
|
i = 7;
|
||||||
|
} else if (randomSource.nextBoolean()) {
|
||||||
|
return false;
|
||||||
|
@@ -243,12 +243,15 @@ public class Bat extends AmbientCreature {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // SparklyPaper - Spooky month optimizations
|
||||||
|
+ /*
|
||||||
|
private static boolean isHalloween() {
|
||||||
|
LocalDate localDate = LocalDate.now();
|
||||||
|
int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||||
|
int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||||
|
return i1 == 10 && i >= 20 || i1 == 11 && i <= 3;
|
||||||
|
}
|
||||||
|
+ */
|
||||||
|
|
||||||
|
private void setupAnimationStates() {
|
||||||
|
if (this.isResting()) {
|
||||||
|
diff --git a/net/minecraft/world/entity/monster/AbstractSkeleton.java b/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
||||||
|
index 37abc7769573e3cdda380166dd086551d5e7bd88..be623fd09ca573922297d3af3cd114160ec05061 100644
|
||||||
|
--- a/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
||||||
|
+++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java
|
||||||
|
@@ -158,10 +158,12 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo
|
||||||
|
this.reassessWeaponGoal();
|
||||||
|
this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || random.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot
|
||||||
|
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
||||||
|
- LocalDate localDate = LocalDate.now();
|
||||||
|
- int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||||
|
- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||||
|
- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) {
|
||||||
|
+ // SparklyPaper start - Spooky month optimizations
|
||||||
|
+ // LocalDate localDate = LocalDate.now();
|
||||||
|
+ // int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||||
|
+ // int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||||
|
+ if (this.getServer().halloweenManager.isHalloween() /* i1 == 10 && i == 31 */&& random.nextFloat() < 0.25F) {
|
||||||
|
+ // SparklyPaper end
|
||||||
|
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
||||||
|
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
|
||||||
|
index 637790ff833abaa0c52fdee204abba7077d12ccc..600b96d4b2645e26fd690ac70d3901d567b7bc24 100644
|
||||||
|
--- a/net/minecraft/world/entity/monster/Zombie.java
|
||||||
|
+++ b/net/minecraft/world/entity/monster/Zombie.java
|
||||||
|
@@ -550,10 +550,12 @@ public class Zombie extends Monster {
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
|
||||||
|
- LocalDate localDate = LocalDate.now();
|
||||||
|
- int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||||
|
- int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||||
|
- if (i1 == 10 && i == 31 && random.nextFloat() < 0.25F) {
|
||||||
|
+ // SparklyPaper start - Spooky month optimizations
|
||||||
|
+ // LocalDate localDate = LocalDate.now();
|
||||||
|
+ // int i = localDate.get(ChronoField.DAY_OF_MONTH);
|
||||||
|
+ // int i1 = localDate.get(ChronoField.MONTH_OF_YEAR);
|
||||||
|
+ if (this.getServer().halloweenManager.isHalloween() /* i1 == 10 && i == 31 */&& random.nextFloat() < 0.25F) {
|
||||||
|
+ // SparklyPaper end
|
||||||
|
this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN));
|
||||||
|
this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F;
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 13 Jan 2025 15:03:52 -0300
|
||||||
|
Subject: [PATCH] Optimize canSee checks
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index b3f498558614243cf633dcd71e3c49c2c55e6e0f..ad9ab7fe6df3880c730388a50741b7938b037ff2 100644
|
||||||
|
--- a/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -1232,7 +1232,7 @@ 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
|
||||||
|
// CraftBukkit start - respect vanish API
|
||||||
|
- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits
|
||||||
|
+ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // SparklyPaper - optimize canSee checks
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 13 Jan 2025 16:41:37 -0300
|
||||||
|
Subject: [PATCH] Fix MC-117075: TE Unload Lag Spike
|
||||||
|
|
||||||
|
We replaced the `blockEntityTickers` list with a custom list based on fastutil's `ObjectArrayList` with a small yet huge change for us: A method that allows us to remove a list of indexes from the list.
|
||||||
|
|
||||||
|
This is WAY FASTER than using `removeAll` with a list of entries to be removed, because we don't need to calculate the identity of each block entity to be removed, and we can jump directly to where the search should begin, giving a performance boost for small removals (because we don't need to loop thru the entire list to find what element should be removed) and a performance boost for big removals (no need to calculate the identity of each block entity).
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||||
|
index 27c2ea4a387ee5f7d078a42cb57f146cb748501d..644ab8b2c797f0675530a3efe23a878899689d66 100644
|
||||||
|
--- a/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/net/minecraft/world/level/Level.java
|
||||||
|
@@ -115,7 +115,7 @@ 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;
|
||||||
|
- public final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList(); // Paper - public
|
||||||
|
+ public final net.sparklypower.sparklypaper.BlockEntityTickersList blockEntityTickers = new net.sparklypower.sparklypaper.BlockEntityTickersList(); // Paper - public // SparklyPaper - optimize block entity removals
|
||||||
|
protected final NeighborUpdater neighborUpdater;
|
||||||
|
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
||||||
|
private boolean tickingBlockEntities;
|
||||||
|
@@ -1479,7 +1479,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition);
|
||||||
|
// Spigot end
|
||||||
|
if (tickingBlockEntity.isRemoved()) {
|
||||||
|
- toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll
|
||||||
|
+ this.blockEntityTickers.markAsRemoved(this.tileTickPosition); // toRemove.add(tickingBlockEntity); // SparklyPaper - optimize block entity removals // Paper - Fix MC-117075; use removeAll
|
||||||
|
} else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) {
|
||||||
|
tickingBlockEntity.tick();
|
||||||
|
// Paper start - rewrite chunk system
|
||||||
|
@@ -1491,6 +1491,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
}
|
||||||
|
this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
|
||||||
|
|
||||||
|
+ this.blockEntityTickers.removeMarkedEntries(); // SparklyPaper - optimize block entity removals
|
||||||
|
this.tickingBlockEntities = false;
|
||||||
|
profilerFiller.pop();
|
||||||
|
this.spigotConfig.currentPrimedTnt = 0; // Spigot
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 6 Nov 2023 21:54:33 -0300
|
||||||
|
Subject: [PATCH] Track how much MSPT each world used
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||||
|
index 4dbf2d9aa52029122f4816ca3504fa330b28a29b..c15c11ab3feaca918ac0185383cd1653200cd186 100644
|
||||||
|
--- a/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -1737,7 +1737,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
profilerFiller.push("tick");
|
||||||
|
|
||||||
|
try {
|
||||||
|
+ long i = Util.getNanos(); // SparklyPaper - track world's MSPT
|
||||||
|
serverLevel.tick(hasTimeLeft);
|
||||||
|
+ // SparklyPaper start - track world's MSPT
|
||||||
|
+ long j = Util.getNanos() - i;
|
||||||
|
+
|
||||||
|
+ // These are from the "tickServer" function
|
||||||
|
+ serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||||
|
+ serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||||
|
+ serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||||
|
+ // SparklyPaper end
|
||||||
|
} catch (Throwable var7) {
|
||||||
|
CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
|
||||||
|
serverLevel.fillReportDetails(crashReport);
|
||||||
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index ebeeb63c3dca505a3ce8b88feaa5d2ca20ec24a2..59465ab6d7723d27b1597cc7094b5044a3f24250 100644
|
||||||
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -570,6 +570,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
}
|
||||||
|
// Paper end - chunk tick iteration
|
||||||
|
|
||||||
|
+ // SparklyPaper start - track world's MSPT
|
||||||
|
+ public final MinecraftServer.TickTimes tickTimes5s = new MinecraftServer.TickTimes(100);
|
||||||
|
+ public final MinecraftServer.TickTimes tickTimes10s = new MinecraftServer.TickTimes(200);
|
||||||
|
+ public final MinecraftServer.TickTimes tickTimes60s = new MinecraftServer.TickTimes(1200);
|
||||||
|
+ // SparklyPaper end
|
||||||
|
+
|
||||||
|
public ServerLevel(
|
||||||
|
MinecraftServer server,
|
||||||
|
Executor dispatcher,
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Wed, 5 Jun 2024 15:20:00 -0300
|
||||||
|
Subject: [PATCH] Reset dirty flag when loading maps from the disk
|
||||||
|
|
||||||
|
By default, the server will start rewriting all map datas to the disk after loading it, even if the map didn't have any changes
|
||||||
|
|
||||||
|
This also slows down world saving a lot if you have a lot of maps
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||||
|
index f5a131e870a4f1ad06ebfb1f360720cf19656fb5..2aed9d55ea1a93b323865141a69c9947759eae29 100644
|
||||||
|
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||||
|
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||||
|
@@ -197,6 +197,7 @@ public class MapItemSavedData extends SavedData {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ mapItemSavedData.setDirty(false); // SparklyPaper - reset dirty flag when loading maps from the disk (context for updates: this modification is at the end of the map "load" function)
|
||||||
|
return mapItemSavedData;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,10 +5,10 @@ Subject: [PATCH] Helpful NMS packet changes
|
|||||||
|
|
||||||
Some nice changes to the packet internals to make packet sending and manipulation easier for us to avoid Reflection and JVM internals (ooo theUnsafe spooky) usage
|
Some nice changes to the packet internals to make packet sending and manipulation easier for us to avoid Reflection and JVM internals (ooo theUnsafe spooky) usage
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
diff --git a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||||
index f66e40326c510aa3267542b1a24ed75d1ed6d3f1..797640c4f26abb32a480a611820bbcd72e43d1ac 100644
|
index 1373977b339405ef59bb3ea03d195285c96dd3fe..20a782d1bb7355bbdc0822a02204e1e05dc44145 100644
|
||||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
--- a/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
+++ b/net/minecraft/network/protocol/game/ClientboundAddEntityPacket.java
|
||||||
@@ -22,7 +22,7 @@ public class ClientboundAddEntityPacket implements Packet<ClientGamePacketListen
|
@@ -22,7 +22,7 @@ public class ClientboundAddEntityPacket implements Packet<ClientGamePacketListen
|
||||||
private static final double LIMIT = 3.9;
|
private static final double LIMIT = 3.9;
|
||||||
private final int id;
|
private final int id;
|
||||||
@@ -51,10 +51,10 @@ index f66e40326c510aa3267542b1a24ed75d1ed6d3f1..797640c4f26abb32a480a611820bbcd7
|
|||||||
public int getData() {
|
public int getData() {
|
||||||
return this.data;
|
return this.data;
|
||||||
}
|
}
|
||||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
diff --git a/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java b/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
||||||
index 1e8fad30c5f5be48501c7d8584caedcdc232f6c8..772848cf83a92a8ef8d734949b21f2f1d13e3fcb 100644
|
index 8fca836e63731c5cef95bbc07e6e1414c9f02bea..c412dcab882abe11ecae34700df3e62ece464b82 100644
|
||||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
--- a/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
||||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
+++ b/net/minecraft/network/protocol/game/ClientboundBlockUpdatePacket.java
|
||||||
@@ -19,7 +19,7 @@ public class ClientboundBlockUpdatePacket implements Packet<ClientGamePacketList
|
@@ -19,7 +19,7 @@ public class ClientboundBlockUpdatePacket implements Packet<ClientGamePacketList
|
||||||
ClientboundBlockUpdatePacket::new
|
ClientboundBlockUpdatePacket::new
|
||||||
);
|
);
|
||||||
@@ -62,12 +62,12 @@ index 1e8fad30c5f5be48501c7d8584caedcdc232f6c8..772848cf83a92a8ef8d734949b21f2f1
|
|||||||
- public final BlockState blockState;
|
- public final BlockState blockState;
|
||||||
+ public BlockState blockState; // SparklyPaper - Helpful NMS packet changes: remove final
|
+ public BlockState blockState; // SparklyPaper - Helpful NMS packet changes: remove final
|
||||||
|
|
||||||
public ClientboundBlockUpdatePacket(BlockPos pos, BlockState state) {
|
public ClientboundBlockUpdatePacket(BlockPos pos, BlockState blockState) {
|
||||||
this.pos = pos;
|
this.pos = pos;
|
||||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||||
index 0a8d07bf68b0ceabd13c70196d357fce79dcc2c3..0b5abaf11508fa6c6809b73f53d6854aa3b3247c 100644
|
index 9e321ef1c3d5803519b243685f4ee598dc0cf640..851931062c4401817aad14721ac7fb0362c3b418 100644
|
||||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||||
@@ -25,7 +25,7 @@ import net.minecraft.world.level.levelgen.Heightmap;
|
@@ -25,7 +25,7 @@ import net.minecraft.world.level.levelgen.Heightmap;
|
||||||
public class ClientboundLevelChunkPacketData {
|
public class ClientboundLevelChunkPacketData {
|
||||||
private static final int TWO_MEGABYTES = 2097152;
|
private static final int TWO_MEGABYTES = 2097152;
|
||||||
@@ -77,12 +77,12 @@ index 0a8d07bf68b0ceabd13c70196d357fce79dcc2c3..0b5abaf11508fa6c6809b73f53d6854a
|
|||||||
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
|
private final List<ClientboundLevelChunkPacketData.BlockEntityInfo> blockEntitiesData;
|
||||||
// Paper start - Handle oversized block entities in chunks
|
// Paper start - Handle oversized block entities in chunks
|
||||||
private final java.util.List<net.minecraft.network.protocol.Packet<?>> extraPackets = new java.util.ArrayList<>();
|
private final java.util.List<net.minecraft.network.protocol.Packet<?>> extraPackets = new java.util.ArrayList<>();
|
||||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
diff --git a/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java b/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
||||||
index ab44c24ce5f4570dee9d84b4216299bedfa800d8..99fbb958b82a3398564febb1e87e3ef4efca5b1a 100644
|
index 4bcbf4bff67d4d4958d56764a273cf4a66b9dd0c..fd621a5d02170f6aa297dbd6a08ba1fef60e54c9 100644
|
||||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
--- a/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
||||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
+++ b/net/minecraft/network/protocol/game/ClientboundRotateHeadPacket.java
|
||||||
@@ -20,6 +20,13 @@ public class ClientboundRotateHeadPacket implements Packet<ClientGamePacketListe
|
@@ -20,6 +20,13 @@ public class ClientboundRotateHeadPacket implements Packet<ClientGamePacketListe
|
||||||
this.yHeadRot = headYaw;
|
this.yHeadRot = yHeadRot;
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // SparklyPaper start - Helpful NMS packet changes: add entity ID constructor
|
+ // SparklyPaper start - Helpful NMS packet changes: add entity ID constructor
|
||||||
@@ -92,16 +92,16 @@ index ab44c24ce5f4570dee9d84b4216299bedfa800d8..99fbb958b82a3398564febb1e87e3ef4
|
|||||||
+ }
|
+ }
|
||||||
+ // SparklyPaper end
|
+ // SparklyPaper end
|
||||||
+
|
+
|
||||||
private ClientboundRotateHeadPacket(FriendlyByteBuf buf) {
|
private ClientboundRotateHeadPacket(FriendlyByteBuf buffer) {
|
||||||
this.entityId = buf.readVarInt();
|
this.entityId = buffer.readVarInt();
|
||||||
this.yHeadRot = buf.readByte();
|
this.yHeadRot = buffer.readByte();
|
||||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
diff --git a/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java b/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||||
index 1a37654aff9a9c86c9f7af10a1cf721371f0c5ec..e69ff4e6bb3919340a93ed4c68bdd6c4778669a9 100644
|
index 10b46c59d83d1274cf491f217df2355d13b594c1..de8767eb8a01e1fed06fbb9d8d5904a83fd19bf5 100644
|
||||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
--- a/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
+++ b/net/minecraft/network/protocol/game/ClientboundSectionBlocksUpdatePacket.java
|
||||||
@@ -17,9 +17,9 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet<ClientGamePa
|
@@ -17,9 +17,9 @@ public class ClientboundSectionBlocksUpdatePacket implements Packet<ClientGamePa
|
||||||
|
ClientboundSectionBlocksUpdatePacket::write, ClientboundSectionBlocksUpdatePacket::new
|
||||||
public static final StreamCodec<FriendlyByteBuf, ClientboundSectionBlocksUpdatePacket> STREAM_CODEC = Packet.codec(ClientboundSectionBlocksUpdatePacket::write, ClientboundSectionBlocksUpdatePacket::new);
|
);
|
||||||
private static final int POS_IN_SECTION_BITS = 12;
|
private static final int POS_IN_SECTION_BITS = 12;
|
||||||
- private final SectionPos sectionPos;
|
- private final SectionPos sectionPos;
|
||||||
- private final short[] positions;
|
- private final short[] positions;
|
||||||
@@ -112,12 +112,12 @@ index 1a37654aff9a9c86c9f7af10a1cf721371f0c5ec..e69ff4e6bb3919340a93ed4c68bdd6c4
|
|||||||
|
|
||||||
public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, ShortSet positions, LevelChunkSection section) {
|
public ClientboundSectionBlocksUpdatePacket(SectionPos sectionPos, ShortSet positions, LevelChunkSection section) {
|
||||||
this.sectionPos = sectionPos;
|
this.sectionPos = sectionPos;
|
||||||
diff --git a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
diff --git a/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java b/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
||||||
index 799f5a8c69f295216997d52fb4bc6c56d3a18115..633f10f17eebd43e8dc7c878b9101decf31190a9 100644
|
index 2545057c7f1f355f59f1e7da06ce08fd2d997b43..9920fe2d2f2f74f372731f1be5abaa4953344632 100644
|
||||||
--- a/src/main/java/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
--- a/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
||||||
+++ b/src/main/java/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
+++ b/net/minecraft/network/protocol/game/ClientboundSetCameraPacket.java
|
||||||
@@ -18,6 +18,12 @@ public class ClientboundSetCameraPacket implements Packet<ClientGamePacketListen
|
@@ -22,6 +22,12 @@ public class ClientboundSetCameraPacket implements Packet<ClientGamePacketListen
|
||||||
this.cameraId = entity.getId();
|
this.cameraId = buffer.readVarInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
+ // SparklyPaper - Helpful NMS packet changes: add direct entityId constructor
|
+ // SparklyPaper - Helpful NMS packet changes: add direct entityId constructor
|
||||||
@@ -126,14 +126,14 @@ index 799f5a8c69f295216997d52fb4bc6c56d3a18115..633f10f17eebd43e8dc7c878b9101dec
|
|||||||
+ }
|
+ }
|
||||||
+ // SparklyPaper end
|
+ // SparklyPaper end
|
||||||
+
|
+
|
||||||
private ClientboundSetCameraPacket(FriendlyByteBuf buf) {
|
private void write(FriendlyByteBuf buffer) {
|
||||||
this.cameraId = buf.readVarInt();
|
buffer.writeVarInt(this.cameraId);
|
||||||
}
|
}
|
||||||
diff --git a/src/main/java/net/minecraft/world/entity/Display.java b/src/main/java/net/minecraft/world/entity/Display.java
|
diff --git a/net/minecraft/world/entity/Display.java b/net/minecraft/world/entity/Display.java
|
||||||
index e6cbf4506c75046a89fad778e138b448fb4a29a9..3b705c75b840dbb0e741f46aaa3b98180a27ecf5 100644
|
index ff49fdcddb43ee479a377aa219eb18fcaefeffca..33a47487f79fdc5164ff6a6d639dfe5834deed0d 100644
|
||||||
--- a/src/main/java/net/minecraft/world/entity/Display.java
|
--- a/net/minecraft/world/entity/Display.java
|
||||||
+++ b/src/main/java/net/minecraft/world/entity/Display.java
|
+++ b/net/minecraft/world/entity/Display.java
|
||||||
@@ -802,7 +802,7 @@ public abstract class Display extends Entity {
|
@@ -800,7 +800,7 @@ public abstract class Display extends Entity {
|
||||||
public static final byte FLAG_ALIGN_RIGHT = 16;
|
public static final byte FLAG_ALIGN_RIGHT = 16;
|
||||||
private static final byte INITIAL_TEXT_OPACITY = -1;
|
private static final byte INITIAL_TEXT_OPACITY = -1;
|
||||||
public static final int INITIAL_BACKGROUND = 1073741824;
|
public static final int INITIAL_BACKGROUND = 1073741824;
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Tue, 25 Jun 2024 02:52:32 -0300
|
||||||
|
Subject: [PATCH] Add CraftItemRecipeEvent
|
||||||
|
|
||||||
|
Used when a player OR a crafter block crafts an item, as an alternative to PrepareItemCraftEvent and CraftItemEvent, because both events are not triggered when a item is crafted from a crafter
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
index 27ef385a85b13ceb58e8d149849983107c539b31..7f9ed94576c94161070fd1be1544aaed9aac0c6b 100644
|
||||||
|
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
@@ -3156,6 +3156,21 @@ public class ServerGamePacketListenerImpl
|
||||||
|
} else {
|
||||||
|
event = new CraftItemEvent(recipe, inventory, type, slotNum, click, action);
|
||||||
|
}
|
||||||
|
+ // SparklyPaper start - add CraftItemRecipeEvent
|
||||||
|
+ // We will pigback a bit on the current implementation
|
||||||
|
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent craftItemRecipeEvent = new net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent(
|
||||||
|
+ ((CraftingInventory) top).getMatrix(), // We cannot use the top inventory directly because (it seems) that the first slot is the "result" slot
|
||||||
|
+ recipe,
|
||||||
|
+ event.getCurrentItem()
|
||||||
|
+ );
|
||||||
|
+ if (craftItemRecipeEvent.callEvent()) {
|
||||||
|
+ event.setCurrentItem(craftItemRecipeEvent.getResult());
|
||||||
|
+ } else {
|
||||||
|
+ event.setCancelled(true);
|
||||||
|
+ cancelled = true;
|
||||||
|
+ event.setCurrentItem(craftItemRecipeEvent.getResult());
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
|
||||||
|
index 5f5966278faf86ed9b28955c80ba845c0cb75595..751969d28951f59f381aa6bf7ad42d55d3e84d57 100644
|
||||||
|
--- a/net/minecraft/world/level/block/CrafterBlock.java
|
||||||
|
+++ b/net/minecraft/world/level/block/CrafterBlock.java
|
||||||
|
@@ -167,6 +167,13 @@ public class CrafterBlock extends BaseEntityBlock {
|
||||||
|
}
|
||||||
|
itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getResult());
|
||||||
|
// CraftBukkit end
|
||||||
|
+ // SparklyPaper - add CraftItemRecipeEvent
|
||||||
|
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent sparklyEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callCraftItemRecipeEvent(crafterBlockEntity, recipeHolder.toBukkitRecipe(), itemStack);
|
||||||
|
+ if (sparklyEvent.isCancelled()) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(sparklyEvent.getResult());
|
||||||
|
+ // SparklyPaper end
|
||||||
|
if (itemStack.isEmpty()) {
|
||||||
|
level.levelEvent(1050, pos, 0);
|
||||||
|
} else {
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Fri, 23 Aug 2024 16:20:45 -0300
|
||||||
|
Subject: [PATCH] Allow throttling hopper checks if the target container is
|
||||||
|
full
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||||
|
index 5cd1326ad5d046c88b2b3449d610a78fa880b4cd..d512f44dcfc480b5608555aa319c93342ae5b208 100644
|
||||||
|
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||||
|
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||||
|
@@ -419,6 +419,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
|
||||||
|
} else {
|
||||||
|
Direction opposite = blockEntity.facing.getOpposite();
|
||||||
|
if (isFullContainer(attachedContainer, opposite)) {
|
||||||
|
+ if (level.sparklyPaperConfig.getTicksPer().getHopperCooldownWhenTargetContainerIsFull() != 0) blockEntity.setCooldown(level.sparklyPaperConfig.getTicksPer().getHopperCooldownWhenTargetContainerIsFull()); // SparklyPaper - Allow throttling hopper checks if the target container is full
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
// Paper start - Perf: Optimize Hoppers
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Sat, 4 Jan 2025 23:58:55 -0300
|
||||||
|
Subject: [PATCH] Add PlayerMoveControllableVehicleEvent
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
index 7f9ed94576c94161070fd1be1544aaed9aac0c6b..da190c2ab2080344dc11903aec51598af18d7556 100644
|
||||||
|
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
|
@@ -587,6 +587,31 @@ public class ServerGamePacketListenerImpl
|
||||||
|
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7));
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // SparklyPaper start - Add PlayerMoveControllableVehicleEvent
|
||||||
|
+ org.bukkit.entity.Player craftPlayer = this.getCraftPlayer();
|
||||||
|
+ org.bukkit.entity.Entity bukkitVehicle = rootVehicle.getBukkitEntity();
|
||||||
|
+ if (bukkitVehicle instanceof org.bukkit.entity.Vehicle) {
|
||||||
|
+ net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent playerMoveControllableVehicleEvent = new net.sparklypower.sparklypaper.event.player.PlayerMoveControllableVehicleEvent(
|
||||||
|
+ craftPlayer,
|
||||||
|
+ (org.bukkit.entity.Vehicle) bukkitVehicle,
|
||||||
|
+ new org.bukkit.Location(craftPlayer.getWorld(), x, y, z, f, f1),
|
||||||
|
+ new org.bukkit.Location(craftPlayer.getWorld(), d, d1, d2, f, f1)
|
||||||
|
+ );
|
||||||
|
+ if (!playerMoveControllableVehicleEvent.callEvent()) {
|
||||||
|
+ // Cancelled, move back!
|
||||||
|
+ rootVehicle.absMoveTo(x, y, z, f, f1);
|
||||||
|
+ this.player.absMoveTo(x, y, z, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||||
|
+ this.send(ClientboundMoveVehiclePacket.fromEntity(rootVehicle));
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ d = playerMoveControllableVehicleEvent.getTo().x();
|
||||||
|
+ d1 = playerMoveControllableVehicleEvent.getTo().y();
|
||||||
|
+ d2 = playerMoveControllableVehicleEvent.getTo().z();
|
||||||
|
+ f = playerMoveControllableVehicleEvent.getTo().getYaw();
|
||||||
|
+ f1 = playerMoveControllableVehicleEvent.getTo().getPitch();
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
+
|
||||||
|
rootVehicle.absMoveTo(d, d1, d2, f, f1);
|
||||||
|
this.player.absMoveTo(d, d1, d2, this.player.getYRot(), this.player.getXRot()); // CraftBukkit
|
||||||
|
// Paper start - optimise out extra getCubes
|
||||||
@@ -4,29 +4,29 @@ Date: Wed, 8 Jan 2025 22:48:04 -0300
|
|||||||
Subject: [PATCH] Add PlayerPreMoveEvent
|
Subject: [PATCH] Add PlayerPreMoveEvent
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
index ac0af5da6646df1cfe66aead3f945a9f77efa5de..3a74c35da37326ee52bc7ccee79791732cb2e092 100644
|
index da190c2ab2080344dc11903aec51598af18d7556..f637d2be3d67a928ed7f78eaa7aa80cbea85a3e6 100644
|
||||||
--- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||||
@@ -1462,7 +1462,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
@@ -1422,7 +1422,7 @@ public class ServerGamePacketListenerImpl
|
||||||
d6 = d0 - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
d3 = d - this.lastGoodX; // Paper - diff on change, used for checking large move vectors above
|
||||||
d7 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
d4 = d1 - this.lastGoodY; // Paper - diff on change, used for checking large move vectors above
|
||||||
d8 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
d5 = d2 - this.lastGoodZ; // Paper - diff on change, used for checking large move vectors above
|
||||||
- boolean flag1 = d7 > 0.0D;
|
- boolean flag = d4 > 0.0;
|
||||||
+ boolean flag1 = d7 > 0.0D; // SparklyPaper - diff on change, used to reset the fall distance, checks if d7 is > 0.0D (player is moving upwards)
|
+ boolean flag = d4 > 0.0; // SparklyPaper - diff on change, used to reset the fall distance, checks if d7 is > 0.0D (player is moving upwards)
|
||||||
|
if (this.player.onGround() && !packet.isOnGround() && flag) {
|
||||||
if (this.player.onGround() && !packet.isOnGround() && flag1) {
|
|
||||||
// Paper start - Add PlayerJumpEvent
|
// Paper start - Add PlayerJumpEvent
|
||||||
@@ -1498,7 +1498,37 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
org.bukkit.entity.Player player = this.getCraftPlayer();
|
||||||
boolean flag2 = this.player.verticalCollisionBelow;
|
@@ -1456,7 +1456,37 @@ public class ServerGamePacketListenerImpl
|
||||||
|
|
||||||
this.player.move(MoverType.PLAYER, new Vec3(d6, d7, d8));
|
boolean flag1 = this.player.verticalCollisionBelow;
|
||||||
|
this.player.move(MoverType.PLAYER, new Vec3(d3, d4, d5));
|
||||||
- this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
- this.player.onGround = packet.isOnGround(); // CraftBukkit - SPIGOT-5810, SPIGOT-5835, SPIGOT-6828: reset by this.player.move
|
||||||
+ // SparklyPaper start - Add PlayerPreMoveEvent event
|
+ // SparklyPaper start - Add PlayerPreMoveEvent event
|
||||||
+ boolean isOnGround = packet.isOnGround();
|
+ boolean isOnGround = packet.isOnGround();
|
||||||
+ boolean horizontalCollision = packet.horizontalCollision();
|
+ boolean horizontalCollision = packet.horizontalCollision();
|
||||||
+ if (net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent.getHandlerList().getRegisteredListeners().length != 0) {
|
+ if (net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent.getHandlerList().getRegisteredListeners().length != 0) {
|
||||||
+ Player player = this.getCraftPlayer();
|
+ org.bukkit.entity.Player player = this.getCraftPlayer();
|
||||||
+ Location from = new Location(player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch); // Get the Players previous Event location.
|
+ Location from = new Location(player.getWorld(), lastPosX, lastPosY, lastPosZ, lastYaw, lastPitch); // Get the Players previous Event location.
|
||||||
+ Location to = player.getLocation().clone(); // Start off the To location as the Players current location.
|
+ Location to = player.getLocation().clone(); // Start off the To location as the Players current location.
|
||||||
+
|
+
|
||||||
@@ -43,12 +43,12 @@ index ac0af5da6646df1cfe66aead3f945a9f77efa5de..3a74c35da37326ee52bc7ccee7979173
|
|||||||
+ to.setPitch(packet.xRot);
|
+ to.setPitch(packet.xRot);
|
||||||
+ }
|
+ }
|
||||||
+
|
+
|
||||||
+ net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent event = new net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent(player, from, to, packet.isOnGround(), packet.horizontalCollision(), flag1);
|
+ net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent event = new net.sparklypower.sparklypaper.event.player.PlayerPreMoveEvent(player, from, to, packet.isOnGround(), packet.horizontalCollision(), flag);
|
||||||
+
|
+
|
||||||
+ if (event.callEvent()) {
|
+ if (event.callEvent()) {
|
||||||
+ isOnGround = event.isOnGround();
|
+ isOnGround = event.isOnGround();
|
||||||
+ horizontalCollision = event.isHorizontalCollision();
|
+ horizontalCollision = event.isHorizontalCollision();
|
||||||
+ flag1 = event.isResetFallDistance();
|
+ flag = event.isResetFallDistance();
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
+ // SparklyPaper end
|
+ // SparklyPaper end
|
||||||
@@ -56,31 +56,31 @@ index ac0af5da6646df1cfe66aead3f945a9f77efa5de..3a74c35da37326ee52bc7ccee7979173
|
|||||||
boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
boolean didCollide = toX != this.player.getX() || toY != this.player.getY() || toZ != this.player.getZ(); // Paper - needed here as the difference in Y can be reset - also note: this is only a guess at whether collisions took place, floating point errors can make this true when it shouldn't be...
|
||||||
// Paper start - prevent position desync
|
// Paper start - prevent position desync
|
||||||
if (this.awaitingPositionFromClient != null) {
|
if (this.awaitingPositionFromClient != null) {
|
||||||
@@ -1551,7 +1581,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
@@ -1590,15 +1620,15 @@ public class ServerGamePacketListenerImpl
|
||||||
if (teleportBack) {
|
&& this.noBlocksAround(this.player);
|
||||||
// Paper end - Add fail move event
|
|
||||||
this.internalTeleport(d3, d4, d5, f, f1); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet.
|
|
||||||
- this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packet.isOnGround());
|
|
||||||
+ this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, isOnGround); // SparklyPaper - Add PlayerPreMoveEvent
|
|
||||||
} else {
|
|
||||||
// CraftBukkit start - fire PlayerMoveEvent
|
|
||||||
// Reset to old location first
|
|
||||||
@@ -1626,15 +1656,15 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl
|
|
||||||
this.player.serverLevel().getChunkSource().move(this.player);
|
this.player.serverLevel().getChunkSource().move(this.player);
|
||||||
Vec3 vec3d = new Vec3(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5);
|
Vec3 vec3 = new Vec3(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z);
|
||||||
|
- this.player.setOnGroundWithMovement(packet.isOnGround(), packet.horizontalCollision(), vec3);
|
||||||
- this.player.setOnGroundWithMovement(packet.isOnGround(), packet.horizontalCollision(), vec3d);
|
- this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, packet.isOnGround());
|
||||||
- this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, packet.isOnGround());
|
+ this.player.setOnGroundWithMovement(isOnGround, horizontalCollision, vec3); // SparklyPaper - Add PlayerPreMoveEvent
|
||||||
+ this.player.setOnGroundWithMovement(isOnGround, horizontalCollision, vec3d); // SparklyPaper - Add PlayerPreMoveEvent
|
+ this.player.doCheckFallDamage(vec3.x, vec3.y, vec3.z, isOnGround); // SparklyPaper - Add PlayerPreMoveEvent
|
||||||
+ this.player.doCheckFallDamage(this.player.getX() - d3, this.player.getY() - d4, this.player.getZ() - d5, isOnGround); // SparklyPaper - Add PlayerPreMoveEvent
|
this.player.recordMovementThroughBlocks(new Vec3(x, y, z), this.player.position());
|
||||||
this.player.recordMovementThroughBlocks(new Vec3(d3, d4, d5), this.player.position());
|
this.handlePlayerKnownMovement(vec3);
|
||||||
this.handlePlayerKnownMovement(vec3d);
|
if (flag) {
|
||||||
if (flag1) {
|
|
||||||
this.player.resetFallDistance();
|
this.player.resetFallDistance();
|
||||||
}
|
}
|
||||||
|
|
||||||
- if (packet.isOnGround() || this.player.hasLandedInLiquid() || this.player.onClimbable() || this.player.isSpectator() || flag || flag4) {
|
- if (packet.isOnGround()
|
||||||
+ if (isOnGround || this.player.hasLandedInLiquid() || this.player.onClimbable() || this.player.isSpectator() || flag || flag4) { // SparklyPaper - Add PlayerPreMoveEvent
|
+ if (isOnGround // SparklyPaper - Add PlayerPreMoveEvent
|
||||||
this.player.tryResetCurrentImpulseContext();
|
|| this.player.hasLandedInLiquid()
|
||||||
}
|
|| this.player.onClimbable()
|
||||||
|
|| this.player.isSpectator()
|
||||||
|
@@ -1613,7 +1643,7 @@ public class ServerGamePacketListenerImpl
|
||||||
|
this.lastGoodZ = this.player.getZ();
|
||||||
|
} else {
|
||||||
|
this.internalTeleport(x, y, z, f, f1); // CraftBukkit - SPIGOT-1807: Don't call teleport event, when the client thinks the player is falling, because the chunks are not loaded on the client yet.
|
||||||
|
- this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, packet.isOnGround());
|
||||||
|
+ this.player.doCheckFallDamage(this.player.getX() - x, this.player.getY() - y, this.player.getZ() - z, isOnGround); // SparklyPaper - Add PlayerPreMoveEvent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,19 +4,19 @@ Date: Sun, 12 Jan 2025 23:26:44 -0300
|
|||||||
Subject: [PATCH] Add PreEntityShootBowEvent
|
Subject: [PATCH] Add PreEntityShootBowEvent
|
||||||
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/world/item/BowItem.java b/src/main/java/net/minecraft/world/item/BowItem.java
|
diff --git a/net/minecraft/world/item/BowItem.java b/net/minecraft/world/item/BowItem.java
|
||||||
index bb593209c95c9cf1f9c5d52d52fab4a33ddbabcf..776c37284e9cff50fae6b937cb707e7ba7edc624 100644
|
index 57c933af200551162774f1d473437521e5a85833..9d8a6763efcdd2a57507e208c34faa3f180d5421 100644
|
||||||
--- a/src/main/java/net/minecraft/world/item/BowItem.java
|
--- a/net/minecraft/world/item/BowItem.java
|
||||||
+++ b/src/main/java/net/minecraft/world/item/BowItem.java
|
+++ b/net/minecraft/world/item/BowItem.java
|
||||||
@@ -33,6 +33,11 @@ public class BowItem extends ProjectileWeaponItem {
|
@@ -33,6 +33,11 @@ public class BowItem extends ProjectileWeaponItem {
|
||||||
} else {
|
} else {
|
||||||
int i = this.getUseDuration(stack, user) - remainingUseTicks;
|
int i = this.getUseDuration(stack, entity) - timeLeft;
|
||||||
float f = getPowerForTime(i);
|
float powerForTime = getPowerForTime(i);
|
||||||
+ // SparklyPaper start - Add PreEntityShootBowEvent
|
+ // SparklyPaper start - Add PreEntityShootBowEvent
|
||||||
+ net.sparklypower.sparklypaper.event.entity.PreEntityShootBowEvent event = new net.sparklypower.sparklypaper.event.entity.PreEntityShootBowEvent(player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), player.getUsedItemHand() == InteractionHand.MAIN_HAND ? org.bukkit.inventory.EquipmentSlot.HAND : org.bukkit.inventory.EquipmentSlot.OFF_HAND, f);
|
+ net.sparklypower.sparklypaper.event.entity.PreEntityShootBowEvent event = new net.sparklypower.sparklypaper.event.entity.PreEntityShootBowEvent(player.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack), player.getUsedItemHand() == InteractionHand.MAIN_HAND ? org.bukkit.inventory.EquipmentSlot.HAND : org.bukkit.inventory.EquipmentSlot.OFF_HAND, powerForTime);
|
||||||
+ if (!event.callEvent())
|
+ if (!event.callEvent())
|
||||||
+ return false;
|
+ return false;
|
||||||
+ // SparklyPaper end
|
+ // SparklyPaper end
|
||||||
if ((double)f < 0.1) {
|
if (powerForTime < 0.1) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
@@ -0,0 +1,967 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Tue, 7 Nov 2023 01:34:14 -0300
|
||||||
|
Subject: [PATCH] Parallel world ticking
|
||||||
|
|
||||||
|
"mom can we have folia?" "we already have folia at home" folia at home:
|
||||||
|
|
||||||
|
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||||
|
index b5817aa8f537593f6d9fc6b612c82ccccb250ac7..2dbbd33690265cbacd4c6516d24bc64890f50990 100644
|
||||||
|
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||||
|
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||||
|
@@ -1031,7 +1031,7 @@ public final class ChunkHolderManager {
|
||||||
|
if (changedFullStatus.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
- if (!TickThread.isTickThread()) {
|
||||||
|
+ if (!TickThread.isTickThreadFor(world)) { // SparklyPaper - parallel world ticking
|
||||||
|
this.taskScheduler.scheduleChunkTask(() -> {
|
||||||
|
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
|
||||||
|
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
||||||
|
@@ -1057,7 +1057,7 @@ public final class ChunkHolderManager {
|
||||||
|
|
||||||
|
// note: never call while inside the chunk system, this will absolutely break everything
|
||||||
|
public void processUnloads() {
|
||||||
|
- TickThread.ensureTickThread("Cannot unload chunks off-main");
|
||||||
|
+ TickThread.ensureTickThread(world, "Cannot unload chunks off-main"); // SparklyPaper - parallel world ticking
|
||||||
|
|
||||||
|
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
|
||||||
|
throw new IllegalStateException("Cannot unload chunks recursively");
|
||||||
|
@@ -1339,7 +1339,7 @@ public final class ChunkHolderManager {
|
||||||
|
|
||||||
|
List<NewChunkHolder> changedFullStatus = null;
|
||||||
|
|
||||||
|
- final boolean isTickThread = TickThread.isTickThread();
|
||||||
|
+ final boolean isTickThread = TickThread.isTickThreadFor(world);
|
||||||
|
|
||||||
|
boolean ret = false;
|
||||||
|
final boolean canProcessFullUpdates = processFullUpdates & isTickThread;
|
||||||
|
diff --git a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
|
||||||
|
index 4a881636ba21fae9e50950bbba2b4321b71d35ab..ef76ff3671d38b482ac9932560e574d0d8cd9318 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);
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
|
||||||
|
index bd5bbc7e55c6bea77991fe5a3c0c2580313d16c5..a231e08edba33bd55bed9a34129615f5e6dddb4d 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);
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/core/dispenser/DispenseItemBehavior.java b/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||||
|
index 717c84165d5e25cd384f56b7cb976abf6669b6f0..8771e808cdf90fa6590140654da4eab08e15e58f 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);
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -147,7 +147,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(0, 0, 0));
|
||||||
|
- if (!DispenserBlock.eventFired) {
|
||||||
|
+ if (!DispenserBlock.eventFired.get()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -201,7 +201,7 @@ public interface DispenseItemBehavior {
|
||||||
|
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
world.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -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()) { // SparklyPaper - parallel world ticking
|
||||||
|
world.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
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -510,8 +510,8 @@ public interface DispenseItemBehavior {
|
||||||
|
// 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;
|
||||||
|
+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||||
|
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null); // SparklyPaper - parallel world ticking
|
||||||
|
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, level.getWorld());
|
||||||
|
List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(level.capturedBlockStates.values());
|
||||||
|
level.capturedBlockStates.clear();
|
||||||
|
@@ -548,7 +548,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()) { // SparklyPaper - parallel world ticking
|
||||||
|
level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -591,7 +591,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()) { // SparklyPaper - parallel world ticking
|
||||||
|
level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -644,7 +644,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()) { // SparklyPaper - parallel world ticking
|
||||||
|
level.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -702,7 +702,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()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -783,7 +783,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()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
|
||||||
|
index 3595bbd05fb3e8fe57e38d4e2df5c6237046b726..2b02d7cbc7fbb916c240f2d16bab365dbc1b8e56 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()) { // SparklyPaper - parallel world ticking
|
||||||
|
world.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
|
||||||
|
index 116395b6c00a0814922516707544a9ff26d68835..672ebd0cfc144d9b7315dcebf1e8007912ad7412 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);
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
|
||||||
|
index 449d9b72ff4650961daa9d1bd25940f3914a6b12..df07b55924c1edca11eebd9debc75d9f184ede9d 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);
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
|
||||||
|
index 626e9feb6a6e7a2cbc7c63e30ba4fb6b923e85c7..6ac9a0fc92eb9801bed3bc296988ee224afffa14 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()) { // SparklyPaper - parallel world ticking
|
||||||
|
serverLevel.getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
|
||||||
|
index 5ab2c8333178335515e619b87ae420f948c83bd1..c98e3748ff467f75f0a0e5a429563feaf06105f3 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
|
||||||
|
|
||||||
|
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()) { // SparklyPaper - parallel world ticking
|
||||||
|
blockSource.level().getCraftServer().getPluginManager().callEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||||
|
index c15c11ab3feaca918ac0185383cd1653200cd186..1bc0e3397a1299bdbe37a69097ece7d7395421f7 100644
|
||||||
|
--- a/net/minecraft/server/MinecraftServer.java
|
||||||
|
+++ b/net/minecraft/server/MinecraftServer.java
|
||||||
|
@@ -305,6 +305,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||||
|
public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
||||||
|
public net.sparklypower.sparklypaper.HalloweenManager halloweenManager = new net.sparklypower.sparklypaper.HalloweenManager(); // SparklyPaper - Spooky month optimizations
|
||||||
|
+ public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // SparklyPaper - parallel world ticking
|
||||||
|
|
||||||
|
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||||
|
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||||
|
@@ -1720,6 +1721,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
}
|
||||||
|
|
||||||
|
this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ java.util.ArrayDeque<java.util.concurrent.Future<ServerLevel>> tasks = new java.util.ArrayDeque<>();
|
||||||
|
+ try {
|
||||||
|
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
|
||||||
|
@@ -1736,27 +1740,46 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
|
||||||
|
profilerFiller.push("tick");
|
||||||
|
|
||||||
|
- try {
|
||||||
|
- long i = Util.getNanos(); // SparklyPaper - track world's MSPT
|
||||||
|
- serverLevel.tick(hasTimeLeft);
|
||||||
|
- // SparklyPaper start - track world's MSPT
|
||||||
|
- long j = Util.getNanos() - i;
|
||||||
|
-
|
||||||
|
- // These are from the "tickServer" function
|
||||||
|
- serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||||
|
- serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||||
|
- serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||||
|
- // SparklyPaper end
|
||||||
|
- } catch (Throwable var7) {
|
||||||
|
- CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
|
||||||
|
- serverLevel.fillReportDetails(crashReport);
|
||||||
|
- throw new ReportedException(crashReport);
|
||||||
|
- }
|
||||||
|
+ serverLevelTickingSemaphore.acquire();
|
||||||
|
+ tasks.add(
|
||||||
|
+ serverLevel.tickExecutor.submit(() -> {
|
||||||
|
+ try {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread currentThread = (ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread) Thread.currentThread();
|
||||||
|
+ currentThread.currentlyTickingServerLevel = serverLevel;
|
||||||
|
+
|
||||||
|
+ long i = Util.getNanos(); // SparklyPaper - track world's MSPT
|
||||||
|
+ serverLevel.tick(hasTimeLeft);
|
||||||
|
+ // SparklyPaper start - track world's MSPT
|
||||||
|
+ long j = Util.getNanos() - i;
|
||||||
|
+
|
||||||
|
+ // These are from the "tickServer" function
|
||||||
|
+ serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||||
|
+ serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||||
|
+ serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||||
|
+ // SparklyPaper end
|
||||||
|
+ } catch (Throwable throwable) {
|
||||||
|
+ CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
|
||||||
|
+
|
||||||
|
+ serverLevel.fillReportDetails(crashreport);
|
||||||
|
+ throw new ReportedException(crashreport);
|
||||||
|
+ } finally {
|
||||||
|
+ serverLevelTickingSemaphore.release();
|
||||||
|
+ }
|
||||||
|
+ }, serverLevel)
|
||||||
|
+ );
|
||||||
|
|
||||||
|
profilerFiller.pop();
|
||||||
|
profilerFiller.pop();
|
||||||
|
serverLevel.explosionDensityCache.clear(); // Paper - Optimize explosions
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ while (!tasks.isEmpty()) {
|
||||||
|
+ tasks.pop().get();
|
||||||
|
+ }
|
||||||
|
+ } catch (java.lang.InterruptedException | java.util.concurrent.ExecutionException e) {
|
||||||
|
+ throw new RuntimeException(e); // Propagate exception
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||||
|
|
||||||
|
profilerFiller.popPush("connection");
|
||||||
|
@@ -1847,6 +1870,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||||
|
Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
|
||||||
|
Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
|
||||||
|
newLevels.remove(level.dimension());
|
||||||
|
+ level.tickExecutor.shutdown(); // SparklyPaper - parallel world ticking (We remove it in here instead of ServerLevel.close() because ServerLevel.close() is never called!)
|
||||||
|
this.levels = Collections.unmodifiableMap(newLevels);
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
index 6ac73610f6039290c4ef3dde2206b6863d2b5067..0c5dbfe1d7e17796c1a60bcb1f97673ddff4d94e 100644
|
||||||
|
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||||
|
@@ -233,6 +233,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||||
|
}
|
||||||
|
net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this);
|
||||||
|
// SparklyPaper end
|
||||||
|
+ serverLevelTickingSemaphore = new java.util.concurrent.Semaphore(net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getConfig().getParallelWorldTicking().getThreads()); // SparklyPaper - parallel world ticking
|
||||||
|
+ DedicatedServer.LOGGER.info("Using " + serverLevelTickingSemaphore.availablePermits() + " permits for parallel world ticking"); // SparklyPaper - parallel world ticking
|
||||||
|
// SparklyPaper start - Spooky month optimizations
|
||||||
|
halloweenManager.startHalloweenEpochTask();
|
||||||
|
halloweenManager.waitUntilEpochHasBeenUpdated();
|
||||||
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||||
|
index 59465ab6d7723d27b1597cc7094b5044a3f24250..7d0e5184289b37c6c9acc34341b8d84399ba653f 100644
|
||||||
|
--- a/net/minecraft/server/level/ServerLevel.java
|
||||||
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||||
|
@@ -184,7 +184,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
private final MinecraftServer server;
|
||||||
|
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
|
||||||
|
private int lastSpawnChunkRadius;
|
||||||
|
- final EntityTickList entityTickList = new EntityTickList();
|
||||||
|
+ final EntityTickList entityTickList = new EntityTickList(this); // SparklyPaper - parallel world ticking
|
||||||
|
// Paper - rewrite chunk system
|
||||||
|
private final GameEventDispatcher gameEventDispatcher;
|
||||||
|
public boolean noSave;
|
||||||
|
@@ -208,6 +208,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
private final StructureCheck structureCheck;
|
||||||
|
private final boolean tickTime;
|
||||||
|
private final RandomSequences randomSequences;
|
||||||
|
+ public java.util.concurrent.ExecutorService tickExecutor; // SparklyPaper - parallel world ticking
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
public final LevelStorageSource.LevelStorageAccess levelStorageAccess;
|
||||||
|
@@ -687,6 +688,7 @@ 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
|
||||||
|
+ this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new net.sparklypower.sparklypaper.ServerLevelTickExecutorThreadFactory(getWorld().getName())); // SparklyPaper - parallel world ticking
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start
|
||||||
|
@@ -1226,7 +1228,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
}
|
||||||
|
// Paper start - rewrite chunk system
|
||||||
|
if ((++this.tickedBlocksOrFluids & 7L) != 0L) {
|
||||||
|
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks();
|
||||||
|
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||||
|
}
|
||||||
|
// Paper end - rewrite chunk system
|
||||||
|
|
||||||
|
@@ -1239,7 +1241,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
}
|
||||||
|
// Paper start - rewrite chunk system
|
||||||
|
if ((++this.tickedBlocksOrFluids & 7L) != 0L) {
|
||||||
|
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks();
|
||||||
|
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||||
|
}
|
||||||
|
// Paper end - rewrite chunk system
|
||||||
|
|
||||||
|
@@ -1497,6 +1499,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPlayer(ServerPlayer player) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot add player off-main"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
Entity entity = this.getEntities().get(player.getUUID());
|
||||||
|
if (entity != null) {
|
||||||
|
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
|
||||||
|
@@ -1509,7 +1512,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
||||||
|
- org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot add entity off-main"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
entity.generation = false; // Paper - Don't fire sync event during generation; Reset flag if it was added during a ServerLevel generation process
|
||||||
|
// Paper start - extra debug info
|
||||||
|
if (entity.valid) {
|
||||||
|
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
index f347ff8d863f4bcef46604c757de112cb3fe445c..532df406e9fb41ab2ccfd59bcc7a614d6ada6548 100644
|
||||||
|
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||||
|
@@ -423,6 +423,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||||
|
return this.viewDistanceHolder;
|
||||||
|
}
|
||||||
|
// Paper end - rewrite chunk system
|
||||||
|
+ public boolean hasTickedAtLeastOnceInNewWorld = false; // SparklyPaper - parallel world ticking (fixes bug in DreamResourceReset where the inventory is opened AFTER the player has changed worlds, if you click with the quick tp torch in a chest, because the inventory is opened AFTER the player has teleported)
|
||||||
|
|
||||||
|
public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) {
|
||||||
|
super(level, level.getSharedSpawnPos(), level.getSharedSpawnAngle(), gameProfile);
|
||||||
|
@@ -792,6 +793,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
+ hasTickedAtLeastOnceInNewWorld = true; // SparklyPaper - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||||
|
// CraftBukkit start
|
||||||
|
if (this.joining) {
|
||||||
|
this.joining = false;
|
||||||
|
@@ -1415,6 +1417,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||||
|
return this;
|
||||||
|
} else {
|
||||||
|
// CraftBukkit start
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot change dimension of a player off-main, from world " + serverLevel().getWorld().getName() + " to world " + level.getWorld().getName()); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
/*
|
||||||
|
this.isChangingDimension = true;
|
||||||
|
LevelData levelData = level.getLevelData();
|
||||||
|
@@ -1768,6 +1771,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||||
|
return OptionalInt.empty();
|
||||||
|
} else {
|
||||||
|
// CraftBukkit start
|
||||||
|
+ // SparklyPaper start - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||||
|
+ if (!hasTickedAtLeastOnceInNewWorld) {
|
||||||
|
+ MinecraftServer.LOGGER.warn("Ignoring request to open container " + abstractContainerMenu + " because we haven't ticked in the current world yet!", new Throwable());
|
||||||
|
+ return OptionalInt.empty();
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
this.containerMenu = abstractContainerMenu; // Moved up
|
||||||
|
if (!this.isImmobile())
|
||||||
|
this.connection
|
||||||
|
@@ -1832,6 +1841,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking (debugging)
|
||||||
|
+ if (net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getLogContainerCreationStacktraces()) {
|
||||||
|
+ MinecraftServer.LOGGER.warn("Closing " + this.getBukkitEntity().getName() + " inventory that was created at", this.containerMenu.containerCreationStacktrace);
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
|
||||||
|
// Paper end - Inventory close reason
|
||||||
|
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
|
||||||
|
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||||
|
index 03feaf0adb8ee87e33744a4615dc2507a02f92d7..d6e13845fce443ae9b8f2c9a4ee5b00c4c5cc831 100644
|
||||||
|
--- a/net/minecraft/server/players/PlayerList.java
|
||||||
|
+++ b/net/minecraft/server/players/PlayerList.java
|
||||||
|
@@ -113,7 +113,7 @@ public abstract class PlayerList {
|
||||||
|
private static final SimpleDateFormat BAN_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
|
||||||
|
private final MinecraftServer server;
|
||||||
|
public final List<ServerPlayer> players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety
|
||||||
|
- private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap();
|
||||||
|
+ private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap(); // SparklyPaper - parallel world ticking (we don't need to replace the original map because we never iterate on top of this map)
|
||||||
|
private final UserBanList bans = new UserBanList(USERBANLIST_FILE);
|
||||||
|
private final IpBanList ipBans = new IpBanList(IPBANLIST_FILE);
|
||||||
|
private final ServerOpList ops = new ServerOpList(OPLIST_FILE);
|
||||||
|
@@ -134,7 +134,7 @@ public abstract class PlayerList {
|
||||||
|
|
||||||
|
// CraftBukkit start
|
||||||
|
private org.bukkit.craftbukkit.CraftServer cserver;
|
||||||
|
- private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>();
|
||||||
|
+ private final Map<String,ServerPlayer> playersByName = new java.util.HashMap<>(); // SparklyPaper - parallel world ticking (we don't need to replace the original map because we never iterate on top of this map)
|
||||||
|
public @Nullable String collideRuleTeamName; // Paper - Configurable player collision
|
||||||
|
|
||||||
|
public PlayerList(MinecraftServer server, LayeredRegistryAccess<RegistryLayer> registries, PlayerDataStorage playerIo, int maxPlayers) {
|
||||||
|
@@ -150,6 +150,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 cookie) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot place new player off-main"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
player.isRealPlayer = true; // Paper
|
||||||
|
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
|
||||||
|
GameProfile gameProfile = player.getGameProfile();
|
||||||
|
@@ -714,6 +715,13 @@ public abstract class PlayerList {
|
||||||
|
return this.respawn(player, keepInventory, reason, eventReason, null);
|
||||||
|
}
|
||||||
|
public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason eventReason, org.bukkit.Location location) {
|
||||||
|
+ System.out.println("respawning player - current player container is " + player.containerMenu + " but their inventory is " + player.inventoryMenu);
|
||||||
|
+ // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
+ if (location != null) // TODO: Is this really never null, or is IntelliJ IDEA tripping? Because I'm pretty sure that this can be null and there isn't any @NotNull annotations
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, from world " + player.serverLevel().getWorld().getName() + " to world " + location.getWorld().getName());
|
||||||
|
+ else
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, respawning in world " + player.serverLevel().getWorld().getName());
|
||||||
|
+ // SparklyPaper end
|
||||||
|
player.stopRiding(); // CraftBukkit
|
||||||
|
this.players.remove(player);
|
||||||
|
this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
|
||||||
|
@@ -724,6 +732,7 @@ public abstract class PlayerList {
|
||||||
|
ServerPlayer serverPlayer = player;
|
||||||
|
Level fromWorld = player.level();
|
||||||
|
player.wonGame = false;
|
||||||
|
+ serverPlayer.hasTickedAtLeastOnceInNewWorld = false; // SparklyPaper - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||||
|
// CraftBukkit end
|
||||||
|
serverPlayer.connection = player.connection;
|
||||||
|
serverPlayer.restoreFrom(player, keepInventory);
|
||||||
|
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||||
|
index 1d0151a042ed5de4e235ef0bdac1a0e8240e85e7..731aecb84f87b6de41029b88e0c5c7ce2bab20cb 100644
|
||||||
|
--- a/net/minecraft/world/entity/Entity.java
|
||||||
|
+++ b/net/minecraft/world/entity/Entity.java
|
||||||
|
@@ -822,7 +822,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||||
|
// CraftBukkit start
|
||||||
|
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
|
||||||
|
+ if (false && !(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities // SparklyPaper - parallel world ticking (see issue #9, this is executed in the server level tick for non-player entities)
|
||||||
|
this.handlePortal();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -3808,6 +3808,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||||
|
}
|
||||||
|
|
||||||
|
private Entity teleportCrossDimension(ServerLevel level, TeleportTransition teleportTransition) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(level, "Cannot teleport entity to another world off-main, from world " + this.level.getWorld().getName() + " to world " + level.getWorld().getName()); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
List<Entity> passengers = this.getPassengers();
|
||||||
|
List<Entity> list = new ArrayList<>(passengers.size());
|
||||||
|
this.ejectPassengers();
|
||||||
|
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||||
|
index 50af953a4698a3c6e16b840fab764dd733b3fbc9..27b6fcb12f1f6a36529fbf19f10ca6330280525a 100644
|
||||||
|
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||||
|
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
||||||
|
@@ -91,8 +91,14 @@ public abstract class AbstractContainerMenu {
|
||||||
|
}
|
||||||
|
public void startOpen() {}
|
||||||
|
// CraftBukkit end
|
||||||
|
+ public Throwable containerCreationStacktrace; // SparklyPaper - parallel world ticking (debugging)
|
||||||
|
|
||||||
|
protected AbstractContainerMenu(@Nullable MenuType<?> menuType, int containerId) {
|
||||||
|
+ // SparklyPaper - parallel world ticking (debugging)
|
||||||
|
+ if (net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.getLogContainerCreationStacktraces()) {
|
||||||
|
+ this.containerCreationStacktrace = new Throwable();
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
this.menuType = menuType;
|
||||||
|
this.containerId = containerId;
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
||||||
|
index 76f50437396f8f856381d0fbef52953ef7c263f6..199fec37b2c2b2ea6a55700cb8f4ec98aeb6504a 100644
|
||||||
|
--- a/net/minecraft/world/item/ItemStack.java
|
||||||
|
+++ b/net/minecraft/world/item/ItemStack.java
|
||||||
|
@@ -407,8 +407,8 @@ public final class ItemStack implements DataComponentHolder {
|
||||||
|
if (interactionResult.consumesAction() && serverLevel.captureTreeGeneration && !serverLevel.capturedBlockStates.isEmpty()) {
|
||||||
|
serverLevel.captureTreeGeneration = false;
|
||||||
|
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;
|
||||||
|
+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||||
|
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null);
|
||||||
|
List<org.bukkit.craftbukkit.block.CraftBlockState> blocks = new java.util.ArrayList<>(serverLevel.capturedBlockStates.values());
|
||||||
|
serverLevel.capturedBlockStates.clear();
|
||||||
|
org.bukkit.event.world.StructureGrowEvent structureEvent = null;
|
||||||
|
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||||
|
index 644ab8b2c797f0675530a3efe23a878899689d66..b43cc51c23da0228aafd99d56e2a6e5cc05496ed 100644
|
||||||
|
--- a/net/minecraft/world/level/Level.java
|
||||||
|
+++ b/net/minecraft/world/level/Level.java
|
||||||
|
@@ -171,6 +171,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
|
||||||
|
public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
|
||||||
|
public net.sparklypower.sparklypaper.configs.SparklyPaperConfig.SparklyPaperWorldConfig sparklyPaperConfig; // SparklyPaper
|
||||||
|
+ public io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo((net.minecraft.world.level.block.RedStoneWireBlock) net.minecraft.world.level.block.Blocks.REDSTONE_WIRE); // SparklyPaper - parallel world ticking (moved to world)
|
||||||
|
public static BlockPos lastPhysicsProblem; // Spigot
|
||||||
|
private org.spigotmc.TickLimiter entityLimiter;
|
||||||
|
private org.spigotmc.TickLimiter tileLimiter;
|
||||||
|
@@ -1100,6 +1101,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, pos, "Updating block asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
// CraftBukkit start - tree generation
|
||||||
|
if (this.captureTreeGeneration) {
|
||||||
|
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
|
||||||
|
@@ -1484,7 +1486,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
tickingBlockEntity.tick();
|
||||||
|
// Paper start - rewrite chunk system
|
||||||
|
if ((++tickedEntities & 7) == 0) {
|
||||||
|
- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
|
||||||
|
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks(); // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||||
|
}
|
||||||
|
// Paper end - rewrite chunk system
|
||||||
|
}
|
||||||
|
@@ -1508,7 +1510,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
|
||||||
|
// Paper end - Prevent block entity and entity crashes
|
||||||
|
}
|
||||||
|
- this.moonrise$midTickTasks(); // Paper - rewrite chunk system
|
||||||
|
+ // this.moonrise$midTickTasks(); // Paper - rewrite chunk system // SparklyPaper - parallel world ticking (only run mid-tick at the end of each tick / fixes concurrency bugs related to executeMidTickTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start - Option to prevent armor stands from doing entity lookups
|
||||||
|
@@ -1651,6 +1653,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public BlockEntity getBlockEntity(BlockPos pos, boolean validate) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThreadOrAsyncThread((ServerLevel) this, "Cannot read world asynchronously"); // SparklyPaper - parallel world ticking
|
||||||
|
// Paper start - Perf: Optimize capturedTileEntities lookup
|
||||||
|
net.minecraft.world.level.block.entity.BlockEntity blockEntity;
|
||||||
|
if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(pos)) != null) {
|
||||||
|
@@ -1668,6 +1671,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBlockEntity(BlockEntity blockEntity) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel) this, "Cannot modify world asynchronously"); // SparklyPaper - parallel world ticking
|
||||||
|
BlockPos blockPos = blockEntity.getBlockPos();
|
||||||
|
if (!this.isOutsideBuildHeight(blockPos)) {
|
||||||
|
// CraftBukkit start
|
||||||
|
@@ -1752,6 +1756,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Entity> getEntities(@Nullable Entity entity, AABB boundingBox, Predicate<? super Entity> predicate) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, boundingBox, "Cannot getEntities asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
Profiler.get().incrementCounter("getEntities");
|
||||||
|
List<Entity> list = Lists.newArrayList();
|
||||||
|
|
||||||
|
@@ -2064,8 +2069,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||||
|
public abstract RecipeAccess recipeAccess();
|
||||||
|
|
||||||
|
public BlockPos getBlockRandomPos(int x, int y, int z, int yMask) {
|
||||||
|
- this.randValue = this.randValue * 3 + 1013904223;
|
||||||
|
- int i = this.randValue >> 2;
|
||||||
|
+ int i = this.random.nextInt() >> 2; // SparklyPaper - parallel world ticking
|
||||||
|
return new BlockPos(x + (i & 15), y + (i >> 16 & yMask), z + (i >> 8 & 15));
|
||||||
|
}
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/block/DispenserBlock.java b/net/minecraft/world/level/block/DispenserBlock.java
|
||||||
|
index e0a4d41e5bcf144ea4c10d6f633c3a95ed2c5aec..ff99bff5b1986798ac8170def2809cc0c553e500 100644
|
||||||
|
--- a/net/minecraft/world/level/block/DispenserBlock.java
|
||||||
|
+++ b/net/minecraft/world/level/block/DispenserBlock.java
|
||||||
|
@@ -50,7 +50,8 @@ public class DispenserBlock extends BaseEntityBlock {
|
||||||
|
private static final DefaultDispenseItemBehavior DEFAULT_BEHAVIOR = new DefaultDispenseItemBehavior();
|
||||||
|
public static final Map<Item, DispenseItemBehavior> DISPENSER_REGISTRY = new IdentityHashMap<>();
|
||||||
|
private static final int TRIGGER_DURATION = 4;
|
||||||
|
- public static boolean eventFired = false; // CraftBukkit
|
||||||
|
+ // public static boolean eventFired = false; // CraftBukkit // SparklyPaper - parallel world ticking
|
||||||
|
+ public static ThreadLocal<Boolean> eventFired = ThreadLocal.withInitial(() -> Boolean.FALSE); // SparklyPaper - parallel world ticking
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<? extends DispenserBlock> codec() {
|
||||||
|
@@ -96,7 +97,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 // SparklyPaper - parallel world ticking
|
||||||
|
dispenserBlockEntity.setItem(randomSlot, dispenseMethod.dispense(blockSource, item));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/level/block/FungusBlock.java b/net/minecraft/world/level/block/FungusBlock.java
|
||||||
|
index 85f0eac75784565c658c5178c544f969db3d6f54..bfa0b1f72497cefecc112d9f484896edc9ec6f36 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 {
|
||||||
|
// CraftBukkit start
|
||||||
|
.map((value) -> {
|
||||||
|
if (this == Blocks.WARPED_FUNGUS) {
|
||||||
|
- SaplingBlock.treeType = org.bukkit.TreeType.WARPED_FUNGUS;
|
||||||
|
+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.WARPED_FUNGUS); // SparklyPaper - parallel world ticking
|
||||||
|
} else if (this == Blocks.CRIMSON_FUNGUS) {
|
||||||
|
- SaplingBlock.treeType = org.bukkit.TreeType.CRIMSON_FUNGUS;
|
||||||
|
+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.CRIMSON_FUNGUS); // SparklyPaper - parallel world ticking
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
})
|
||||||
|
diff --git a/net/minecraft/world/level/block/MushroomBlock.java b/net/minecraft/world/level/block/MushroomBlock.java
|
||||||
|
index 904369f4d7db41026183f2de7c96c2f0f4dc204d..1ef0cf368fe9de49c7ba0ba3b647108b5bbe3e48 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 {
|
||||||
|
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 // SparklyPaper - parallel world ticking
|
||||||
|
if (optional.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||||
|
index 12c9d60314c99fb65e640d255a2d0c6b7790ad4d..833b180741cd361562d86794b16e3cd6a25410d5 100644
|
||||||
|
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||||
|
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
|
||||||
|
@@ -292,7 +292,7 @@ public class RedStoneWireBlock extends Block {
|
||||||
|
|
||||||
|
// Paper start - Optimize redstone (Eigencraft)
|
||||||
|
// The bulk of the new functionality is found in RedstoneWireTurbo.java
|
||||||
|
- io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this);
|
||||||
|
+ // io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this); // SparklyPaper - parallel world ticking (moved to world)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Modified version of pre-existing updateSurroundingRedstone, which is called from
|
||||||
|
@@ -308,7 +308,7 @@ public class RedStoneWireBlock extends Block {
|
||||||
|
if (orientation != null) {
|
||||||
|
source = pos.relative(orientation.getFront().getOpposite());
|
||||||
|
}
|
||||||
|
- turbo.updateSurroundingRedstone(worldIn, pos, state, source);
|
||||||
|
+ worldIn.turbo.updateSurroundingRedstone(worldIn, pos, state, source); // SparklyPaper - parallel world ticking
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updatePowerStrength(worldIn, pos, state, orientation, blockAdded);
|
||||||
|
@@ -336,7 +336,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)) {
|
||||||
|
- turbo.updateNeighborShapes(level, pos, state);
|
||||||
|
+ level.turbo.updateNeighborShapes(level, pos, state); // SparklyPaper - parallel world ticking
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/level/block/SaplingBlock.java b/net/minecraft/world/level/block/SaplingBlock.java
|
||||||
|
index e014f052e9b0f5ca6b28044e2389782b7d0e0cb8..c9091b66f5ddf7bd7145becdfc5e252163b03300 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.0, 0.0, 2.0, 14.0, 12.0, 14.0);
|
||||||
|
protected final TreeGrower treeGrower;
|
||||||
|
- public static org.bukkit.TreeType treeType; // CraftBukkit
|
||||||
|
+ public static final ThreadLocal<org.bukkit.TreeType> treeTypeRT = new ThreadLocal<>(); // CraftBukkit // SparklyPaper - parallel world ticking (from Folia)
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MapCodec<? extends SaplingBlock> codec() {
|
||||||
|
@@ -63,8 +63,8 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock {
|
||||||
|
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;
|
||||||
|
+ org.bukkit.TreeType treeType = SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||||
|
+ SaplingBlock.treeTypeRT.set(null); // SparklyPaper - parallel world ticking
|
||||||
|
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level.getWorld());
|
||||||
|
java.util.List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(level.capturedBlockStates.values());
|
||||||
|
level.capturedBlockStates.clear();
|
||||||
|
diff --git a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||||
|
index 26db603ed681a6c302596627d4dd5bf8a9bafc4e..a2df3546922ea27b948ed89450428a27f65d93ed 100644
|
||||||
|
--- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||||
|
+++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
|
||||||
|
@@ -77,6 +77,12 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
|
||||||
|
return canUnlock(player, code, displayName, null);
|
||||||
|
}
|
||||||
|
public static boolean canUnlock(Player player, LockCode code, Component displayName, @Nullable BlockEntity blockEntity) {
|
||||||
|
+ // SparklyPaper - parallel world ticking (see: PARALLEL_NOTES.md - Opening an inventory after a world switch)
|
||||||
|
+ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != serverPlayer.serverLevel()) {
|
||||||
|
+ net.minecraft.server.MinecraftServer.LOGGER.warn("Player " + serverPlayer.getScoreboardName() + " (" + serverPlayer.getStringUUID() + ") attempted to open a BlockEntity @ " + blockEntity.getLevel().getWorld().getName() + " " + blockEntity.getBlockPos().getX() + ", " + blockEntity.getBlockPos().getY() + ", " + blockEntity.getBlockPos().getZ() + " while they were in a different world " + serverPlayer.level().getWorld().getName() + " than the block themselves!");
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != null && blockEntity.getLevel().getBlockEntity(blockEntity.getBlockPos()) == blockEntity) {
|
||||||
|
final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(blockEntity.getLevel(), blockEntity.getBlockPos());
|
||||||
|
net.kyori.adventure.text.Component lockedMessage = net.kyori.adventure.text.Component.translatable("container.isLocked", io.papermc.paper.adventure.PaperAdventure.asAdventure(displayName));
|
||||||
|
diff --git a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
|
||||||
|
index 1638eccef431fb68775af624110f1968f0c6dabd..a1096b17ddd4f02cdbe5615030803df88d200ed7 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 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(pos); // SparklyPaper - parallel world ticking // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
|
||||||
|
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); // SparklyPaper - parallel world ticking // CraftBukkit
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
diff --git a/net/minecraft/world/level/block/grower/TreeGrower.java b/net/minecraft/world/level/block/grower/TreeGrower.java
|
||||||
|
index cf7311c507de09a8f89934e430b2201e8bdffe51..2ad658fa8e42f26a37fed9faff421827cb72607b 100644
|
||||||
|
--- a/net/minecraft/world/level/block/grower/TreeGrower.java
|
||||||
|
+++ b/net/minecraft/world/level/block/grower/TreeGrower.java
|
||||||
|
@@ -204,55 +204,59 @@ public final class TreeGrower {
|
||||||
|
// CraftBukkit start
|
||||||
|
private void setTreeType(Holder<ConfiguredFeature<?, ?>> holder) {
|
||||||
|
ResourceKey<ConfiguredFeature<?, ?>> treeFeature = holder.unwrapKey().get();
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ org.bukkit.TreeType treeType;
|
||||||
|
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;
|
||||||
|
} 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;
|
||||||
|
} 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;
|
||||||
|
} else if (treeFeature == TreeFeatures.JUNGLE_TREE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.COCOA_TREE;
|
||||||
|
+ treeType = org.bukkit.TreeType.COCOA_TREE;
|
||||||
|
} 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;
|
||||||
|
} else if (treeFeature == TreeFeatures.PINE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_REDWOOD;
|
||||||
|
+ treeType = org.bukkit.TreeType.TALL_REDWOOD;
|
||||||
|
} else if (treeFeature == TreeFeatures.SPRUCE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.REDWOOD;
|
||||||
|
+ treeType = org.bukkit.TreeType.REDWOOD;
|
||||||
|
} else if (treeFeature == TreeFeatures.ACACIA) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.ACACIA;
|
||||||
|
+ treeType = org.bukkit.TreeType.ACACIA;
|
||||||
|
} 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;
|
||||||
|
} 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;
|
||||||
|
} else if (treeFeature == TreeFeatures.SWAMP_OAK) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.SWAMP;
|
||||||
|
+ treeType = org.bukkit.TreeType.SWAMP;
|
||||||
|
} 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;
|
||||||
|
} else if (treeFeature == TreeFeatures.JUNGLE_BUSH) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE_BUSH;
|
||||||
|
+ treeType = org.bukkit.TreeType.JUNGLE_BUSH;
|
||||||
|
} else if (treeFeature == TreeFeatures.DARK_OAK) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.DARK_OAK;
|
||||||
|
+ treeType = org.bukkit.TreeType.DARK_OAK;
|
||||||
|
} else if (treeFeature == TreeFeatures.MEGA_SPRUCE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_REDWOOD;
|
||||||
|
+ treeType = org.bukkit.TreeType.MEGA_REDWOOD;
|
||||||
|
} else if (treeFeature == TreeFeatures.MEGA_PINE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_PINE;
|
||||||
|
+ treeType = org.bukkit.TreeType.MEGA_PINE;
|
||||||
|
} else if (treeFeature == TreeFeatures.MEGA_JUNGLE_TREE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE;
|
||||||
|
+ treeType = org.bukkit.TreeType.JUNGLE;
|
||||||
|
} else if (treeFeature == TreeFeatures.AZALEA_TREE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.AZALEA;
|
||||||
|
+ treeType = org.bukkit.TreeType.AZALEA;
|
||||||
|
} else if (treeFeature == TreeFeatures.MANGROVE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MANGROVE;
|
||||||
|
+ treeType = org.bukkit.TreeType.MANGROVE;
|
||||||
|
} else if (treeFeature == TreeFeatures.TALL_MANGROVE) {
|
||||||
|
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_MANGROVE;
|
||||||
|
+ treeType = org.bukkit.TreeType.TALL_MANGROVE;
|
||||||
|
} 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;
|
||||||
|
} 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;
|
||||||
|
} 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;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown tree generator " + treeFeature);
|
||||||
|
}
|
||||||
|
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(treeType); // SparklyPaper - parallel world ticking
|
||||||
|
+ // SparklyPaper end
|
||||||
|
}
|
||||||
|
// CraftBukkit end
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
index 761fdcd4a4e18f45547afd8edff44f61c6eeacb4..17fb7161171cbe44d145cf0065826f49183880b0 100644
|
||||||
|
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||||
|
@@ -360,6 +360,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving, boolean doPlace) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, pos, "Updating block asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
// CraftBukkit end
|
||||||
|
int y = pos.getY();
|
||||||
|
LevelChunkSection section = this.getSection(this.getSectionIndex(y));
|
||||||
|
diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java
|
||||||
|
index 423779a2b690f387a4f0bd07b97b50e0baefda76..24f9632e73d73c2ad68ebf30eb0e4cca7befae2d 100644
|
||||||
|
--- a/net/minecraft/world/level/entity/EntityTickList.java
|
||||||
|
+++ b/net/minecraft/world/level/entity/EntityTickList.java
|
||||||
|
@@ -10,17 +10,26 @@ import net.minecraft.world.entity.Entity;
|
||||||
|
|
||||||
|
public class EntityTickList {
|
||||||
|
private final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ // Used to track async entity additions/removals/loops
|
||||||
|
+ private final net.minecraft.server.level.ServerLevel serverLevel;
|
||||||
|
+ public EntityTickList(net.minecraft.server.level.ServerLevel serverLevel) {
|
||||||
|
+ this.serverLevel = serverLevel;
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
|
||||||
|
private void ensureActiveIsNotIterated() {
|
||||||
|
// Paper - rewrite chunk system
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(Entity entity) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(entity, "Asynchronous entity ticklist addition"); // Paper // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
this.ensureActiveIsNotIterated();
|
||||||
|
this.entities.add(entity); // Paper - rewrite chunk system
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(Entity entity) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(entity, "Asynchronous entity ticklist removal"); // Paper // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
this.ensureActiveIsNotIterated();
|
||||||
|
this.entities.remove(entity); // Paper - rewrite chunk system
|
||||||
|
}
|
||||||
|
@@ -30,6 +39,7 @@ public class EntityTickList {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void forEach(Consumer<Entity> entity) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverLevel, "Asynchronous entity ticklist iteration"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
// Paper start - rewrite chunk system
|
||||||
|
// To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
|
||||||
|
// (by dfl iterator() is configured to not iterate over new entries)
|
||||||
|
diff --git a/net/minecraft/world/level/saveddata/maps/MapIndex.java b/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||||
|
index ffe604f8397a002800e6ecc2f878d0f6f1c98703..ee022449c1e00a106687496a1dfb98fc0d86fb72 100644
|
||||||
|
--- a/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||||
|
+++ b/net/minecraft/world/level/saveddata/maps/MapIndex.java
|
||||||
|
@@ -34,17 +34,20 @@ public class MapIndex extends SavedData {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) {
|
||||||
|
+ synchronized (this.usedAuxIds) { // SparklyPaper start - make map data thread-safe
|
||||||
|
for (Entry<String> entry : this.usedAuxIds.object2IntEntrySet()) {
|
||||||
|
tag.putInt(entry.getKey(), entry.getIntValue());
|
||||||
|
}
|
||||||
|
-
|
||||||
|
+ } // SparklyPaper end - make map data thread-safe
|
||||||
|
return tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapId getFreeAuxValueForMap() {
|
||||||
|
+ synchronized (this.usedAuxIds) { // SparklyPaper start - make map data thread-safe
|
||||||
|
int i = this.usedAuxIds.getInt("map") + 1;
|
||||||
|
this.usedAuxIds.put("map", i);
|
||||||
|
this.setDirty();
|
||||||
|
return new MapId(i);
|
||||||
|
+ } // SparklyPaper end - make map data thread-safe
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Sat, 1 Jun 2024 01:22:41 -0300
|
||||||
|
Subject: [PATCH] SPARKLYPOWER Remap SparklyPower hacky legacy NBT tags
|
||||||
|
|
||||||
|
This is only useful for us in SparklyPower, but yeah...
|
||||||
|
|
||||||
|
diff --git a/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java b/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
||||||
|
index 2d29d89cc45866822189a62bffbe1a8fe57c477b..688230454b42fd7da72833ca8fe631e6fba06eb9 100644
|
||||||
|
--- a/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
||||||
|
+++ b/ca/spottedleaf/dataconverter/minecraft/converters/itemstack/ConverterItemStackToDataComponents.java
|
||||||
|
@@ -1221,6 +1221,7 @@ public final class ConverterItemStackToDataComponents {
|
||||||
|
ret.setString("id", this.id);
|
||||||
|
ret.setInt("count", this.count);
|
||||||
|
if (!this.tag.isEmpty()) {
|
||||||
|
+ net.sparklypower.sparklypaper.LegacyNBTRemapper.INSTANCE.remap(this.tag); // SparklyPaper - Remap SparklyPower hacky legacy NBT tags
|
||||||
|
this.components.setMap("minecraft:custom_data", this.tag);
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Wed, 12 Jun 2024 11:53:09 -0300
|
||||||
|
Subject: [PATCH] SPARKLYPOWER Add custom blocks
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/world/level/block/Blocks.java b/net/minecraft/world/level/block/Blocks.java
|
||||||
|
index 0401a5e88fe7840ae667748409411ab73888799c..d83e8b92b77f6b8179b24f07eae528dda5f12ed2 100644
|
||||||
|
--- a/net/minecraft/world/level/block/Blocks.java
|
||||||
|
+++ b/net/minecraft/world/level/block/Blocks.java
|
||||||
|
@@ -6775,6 +6775,52 @@ public class Blocks {
|
||||||
|
public static final Block POTTED_CLOSED_EYEBLOSSOM = register(
|
||||||
|
"potted_closed_eyeblossom", properties -> new FlowerPotBlock(CLOSED_EYEBLOSSOM, properties), flowerPotProperties().randomTicks()
|
||||||
|
);
|
||||||
|
+ // SparklyPaper start - SparklyPower Survival custom blocks
|
||||||
|
+ // Blocks' strength should be synced with the replaced block on the client side!
|
||||||
|
+ public static final Block SPARKLYPOWER_RAINBOW_WOOL = register(
|
||||||
|
+ "sparklypower_rainbow_wool",
|
||||||
|
+ Block::new,
|
||||||
|
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
||||||
|
+ );
|
||||||
|
+ public static final Block SPARKLYPOWER_RAINBOW_CONCRETE = register(
|
||||||
|
+ "sparklypower_rainbow_concrete",
|
||||||
|
+ Block::new,
|
||||||
|
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
||||||
|
+ );
|
||||||
|
+ public static final Block SPARKLYPOWER_RAINBOW_TERRACOTTA = register(
|
||||||
|
+ "sparklypower_rainbow_terracotta",
|
||||||
|
+ Block::new,
|
||||||
|
+ BlockBehaviour.Properties.of().mapColor(MapColor.TERRACOTTA_RED).strength(0.5F).sound(SoundType.GRASS)
|
||||||
|
+ );
|
||||||
|
+ public static final Block SPARKLYPOWER_ASPHALT_SERVER = register(
|
||||||
|
+ "sparklypower_asphalt_server",
|
||||||
|
+ Block::new,
|
||||||
|
+ BlockBehaviour.Properties.of()
|
||||||
|
+ .mapColor(MapColor.COLOR_BLACK)
|
||||||
|
+ .instrument(NoteBlockInstrument.BASEDRUM)
|
||||||
|
+ .requiresCorrectToolForDrops()
|
||||||
|
+ .strength(1.5F, 6.0F)
|
||||||
|
+ );
|
||||||
|
+ public static final Block SPARKLYPOWER_ASPHALT_SERVER_SLAB = register(
|
||||||
|
+ "sparklypower_asphalt_server_slab",
|
||||||
|
+ SlabBlock::new,
|
||||||
|
+ BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(2.0F, 6.0F)
|
||||||
|
+ );
|
||||||
|
+ public static final Block SPARKLYPOWER_ASPHALT_PLAYER = register(
|
||||||
|
+ "sparklypower_asphalt_player",
|
||||||
|
+ Block::new,
|
||||||
|
+ BlockBehaviour.Properties.of()
|
||||||
|
+ .mapColor(MapColor.COLOR_BLACK)
|
||||||
|
+ .instrument(NoteBlockInstrument.BASEDRUM)
|
||||||
|
+ .requiresCorrectToolForDrops()
|
||||||
|
+ .strength(1.5F, 6.0F)
|
||||||
|
+ );
|
||||||
|
+ public static final Block SPARKLYPOWER_ASPHALT_PLAYER_SLAB = register(
|
||||||
|
+ "sparklypower_asphalt_player_slab",
|
||||||
|
+ SlabBlock::new,
|
||||||
|
+ BlockBehaviour.Properties.of().mapColor(MapColor.COLOR_BLACK).instrument(NoteBlockInstrument.BASEDRUM).requiresCorrectToolForDrops().strength(2.0F, 6.0F)
|
||||||
|
+ );
|
||||||
|
+ // SparklyPaper end
|
||||||
|
|
||||||
|
private static ToIntFunction<BlockState> litBlockEmission(int lightValue) {
|
||||||
|
return state -> state.getValue(BlockStateProperties.LIT) ? lightValue : 0;
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Sat, 12 Jun 2021 16:40:34 +0200
|
||||||
|
Subject: [PATCH] new fork who dis - Rebrand to SparklyPaper and Build Changes
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java
|
||||||
|
index 774556a62eb240da42e84db4502e2ed43495be17..9bc7b99b5b39a8ffe4118b8d86f5b8065c4fe460 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/net.sparklypower.sparklypaper/sparklypaper-api/pom.properties"); // SparklyPaper
|
||||||
|
Properties properties = new Properties();
|
||||||
|
|
||||||
|
if (stream != null) {
|
||||||
|
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
index a9339f59f81dff307317ae4afdff0dc296febcc9..2ce97bee092dd7a6d898836376c442b114d54003 100644
|
||||||
|
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||||
|
@@ -77,14 +77,14 @@ public class WatchdogThread extends Thread {
|
||||||
|
if (isLongTimeout) {
|
||||||
|
// Paper end
|
||||||
|
logger.log(Level.SEVERE, "------------------------------");
|
||||||
|
- logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug."); // Paper
|
||||||
|
+ logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Paper bug. This could be a SparklyPaper bug and, in that case, MrPowerGamerBR probably made a fucky wucky!"); // SparklyPaper - branding changes // Paper
|
||||||
|
logger.log(Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author");
|
||||||
|
logger.log(Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring");
|
||||||
|
logger.log(Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once");
|
||||||
|
logger.log(Level.SEVERE, "\t If this is the case, consider increasing timeout-time in spigot.yml but note that this will replace the crash with LARGE lag spikes");
|
||||||
|
- logger.log(Level.SEVERE, "If you are unsure or still think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues");
|
||||||
|
+ logger.log(Level.SEVERE, "If you are unsure or still think this is a SparklyPaper bug, please report this to https://github.com/SparklyPower/SparklyPaper/issues - and if you think this is a Paper bug, please report this to https://github.com/PaperMC/Paper/issues\""); // SparklyPaper - branding changes
|
||||||
|
logger.log(Level.SEVERE, "Be sure to include ALL relevant console errors and Minecraft crash reports");
|
||||||
|
- logger.log(Level.SEVERE, "Paper version: " + Bukkit.getServer().getVersion());
|
||||||
|
+ logger.log(Level.SEVERE, "SparklyPaper version: " + Bukkit.getServer().getVersion()); // SparklyPaper - branding changes
|
||||||
|
|
||||||
|
if (net.minecraft.world.level.Level.lastPhysicsProblem != null) {
|
||||||
|
logger.log(Level.SEVERE, "------------------------------");
|
||||||
|
@@ -109,7 +109,7 @@ public class WatchdogThread extends Thread {
|
||||||
|
}
|
||||||
|
// Paper end - Different message for short timeout
|
||||||
|
logger.log(Level.SEVERE, "------------------------------");
|
||||||
|
- logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Paper!):"); // Paper
|
||||||
|
+ logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to SparklyPaper!):"); // SparklyPaper - branding changes // Paper
|
||||||
|
FeatureHooks.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - log detailed tick information
|
||||||
|
WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE), logger);
|
||||||
|
logger.log(Level.SEVERE, "------------------------------");
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 13 Jan 2025 13:20:49 -0300
|
||||||
|
Subject: [PATCH] SparklyPaper config files
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
index d2de789967f8f1942e91d9e4c547113a5e31382b..6f3add0ee20978d84fba844955eefe5fdad71af8 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||||
|
@@ -111,6 +111,7 @@ import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||||
|
import net.minecraft.world.level.storage.PrimaryLevelData;
|
||||||
|
import net.minecraft.world.level.validation.ContentValidationException;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
+import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils;
|
||||||
|
import org.bukkit.BanList;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
@@ -1087,6 +1088,7 @@ public final class CraftServer implements Server {
|
||||||
|
|
||||||
|
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
|
||||||
|
this.console.paperConfigurations.reloadConfigs(this.console);
|
||||||
|
+ net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings")); // SparklyPaper
|
||||||
|
for (ServerLevel world : this.console.getAllLevels()) {
|
||||||
|
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
||||||
|
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
||||||
|
@@ -1102,6 +1104,7 @@ public final class CraftServer implements Server {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
world.spigotConfig.init(); // Spigot
|
||||||
|
+ world.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(world.serverLevelData.getLevelName()); // SparklyPaper
|
||||||
|
}
|
||||||
|
|
||||||
|
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
||||||
|
@@ -1119,6 +1122,7 @@ public final class CraftServer implements Server {
|
||||||
|
org.spigotmc.SpigotConfig.registerCommands(); // Spigot
|
||||||
|
io.papermc.paper.command.PaperCommands.registerCommands(this.console); // Paper
|
||||||
|
this.spark.registerCommandBeforePlugins(this); // Paper - spark
|
||||||
|
+ net.sparklypower.sparklypaper.SparklyPaperCommands.INSTANCE.registerCommands(this.console); // SparklyPaper
|
||||||
|
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
||||||
|
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
index ecb0fcd1f3b3f3d7751eded3cdf0977c1889c9ed..10f84fb104adc6e8cf57f12e9388398e32711f4a 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||||
|
@@ -176,6 +176,14 @@ public class Main {
|
||||||
|
.describedAs("Jar file");
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
+ // SparklyPaper Start
|
||||||
|
+ acceptsAll(asList("sparklypaper", "sparklypaper-settings"), "File for SparklyPaper settings")
|
||||||
|
+ .withRequiredArg()
|
||||||
|
+ .ofType(File.class)
|
||||||
|
+ .defaultsTo(new File("sparklypaper.yml"))
|
||||||
|
+ .describedAs("Yml file");
|
||||||
|
+ // SparklyPaper end
|
||||||
|
+
|
||||||
|
// Paper start
|
||||||
|
acceptsAll(asList("server-name"), "Name of the server")
|
||||||
|
.withRequiredArg()
|
||||||
@@ -1,10 +1,8 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
Date: Fri, 17 Nov 2023 19:08:08 -0300
|
Date: Mon, 13 Jan 2025 14:27:53 -0300
|
||||||
Subject: [PATCH] Fix concurrency issues when using "imageToBytes" in multiple
|
Subject: [PATCH] Fix concurrency issues when using imageToBytes
|
||||||
threads
|
|
||||||
|
|
||||||
Useful if one of your plugins is parallelizng map creation on server startup
|
|
||||||
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java
|
diff --git a/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java b/src/main/java/org/bukkit/craftbukkit/map/CraftMapColorCache.java
|
||||||
index 8149b9c51b78eb5c689b7218a2ca3aab60e73bcf..c983d8d7e79d55c9757add8ac1093a0a9d98e5b3 100644
|
index 8149b9c51b78eb5c689b7218a2ca3aab60e73bcf..c983d8d7e79d55c9757add8ac1093a0a9d98e5b3 100644
|
||||||
@@ -72,53 +72,11 @@ index c03608fec96b51e1867f43d8f42e5aefb1520e46..15b21fa3907db1b77ed5b5d1050a37f4
|
|||||||
if (this.tickCount == RETIRED_TICK_COUNT) {
|
if (this.tickCount == RETIRED_TICK_COUNT) {
|
||||||
throw new IllegalStateException("Ticking retired scheduler");
|
throw new IllegalStateException("Ticking retired scheduler");
|
||||||
}
|
}
|
||||||
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
index 4158473fd553a16fec23bcbcf9a278d413120600..8cc953b72a7132a92390ab1f5e62b267d08e706a 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
||||||
@@ -333,7 +333,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
||||||
public volatile boolean abnormalExit = false; // Paper
|
|
||||||
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
|
||||||
private final Set<String> pluginsBlockingSleep = new java.util.HashSet<>(); // Paper - API to allow/disallow tick sleeping
|
|
||||||
-
|
|
||||||
+ public final Set<Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run (concurrent because plugins may schedule tasks async)
|
|
||||||
+
|
|
||||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
|
|
||||||
AtomicReference<S> atomicreference = new AtomicReference();
|
|
||||||
Thread thread = new ca.spottedleaf.moonrise.common.util.TickThread(() -> { // Paper - rewrite chunk system
|
|
||||||
@@ -1804,6 +1805,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
||||||
this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
|
|
||||||
// Paper start - Folia scheduler API
|
|
||||||
((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) Bukkit.getGlobalRegionScheduler()).tick();
|
|
||||||
+ // SparklyPaper - skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
|
||||||
+ for (final Entity entity : entitiesWithScheduledTasks) {
|
|
||||||
+ if (entity.isRemoved()) {
|
|
||||||
+ continue;
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();
|
|
||||||
+ if (bukkit != null) {
|
|
||||||
+ bukkit.taskScheduler.executeTick();
|
|
||||||
+ }
|
|
||||||
+ }
|
|
||||||
+ /*
|
|
||||||
getAllLevels().forEach(level -> {
|
|
||||||
for (final Entity entity : level.getEntities().getAll()) {
|
|
||||||
if (entity.isRemoved()) {
|
|
||||||
@@ -1815,6 +1828,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
+ */
|
|
||||||
+ // SparklyPaper end
|
|
||||||
// Paper end - Folia scheduler API
|
|
||||||
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
|
|
||||||
gameprofilerfiller.push("commandFunctions");
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
index ddabaed899c755925ad8618b78c33dacaf2126ac..ae74ce4954cbe5004654f447e4c083196cc1be55 100644
|
index 4562bee2e2795801862bae03d783799fc076b73e..7107acb0a4ad4c84f78185bb8da2db8506c352d1 100644
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||||
@@ -72,7 +72,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
@@ -74,7 +74,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||||
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY);
|
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY);
|
||||||
protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
|
||||||
// Paper start - Folia shedulers
|
// Paper start - Folia shedulers
|
||||||
@@ -127,7 +85,7 @@ index ddabaed899c755925ad8618b78c33dacaf2126ac..ae74ce4954cbe5004654f447e4c08319
|
|||||||
private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this);
|
private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,6 +85,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
@@ -87,6 +87,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
this.entityType = CraftEntityType.minecraftToBukkit(entity.getType());
|
this.entityType = CraftEntityType.minecraftToBukkit(entity.getType());
|
||||||
@@ -1,36 +1,14 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
Date: Thu, 23 Nov 2023 14:36:47 -0300
|
Date: Mon, 13 Jan 2025 15:04:15 -0300
|
||||||
Subject: [PATCH] Optimize "canSee" checks
|
Subject: [PATCH] Optimize canSee checks
|
||||||
|
|
||||||
The "canSee" checks is in a hot path, invoked by each entity for each player on the server if they are in tracking range, so optimizing it is pretty nice
|
|
||||||
|
|
||||||
First, we change the original "HashMap" to fastutil's "Object2ObjectOpenHashMap", because the containsKey throughput is better
|
|
||||||
|
|
||||||
Then, we add a "isEmpty()" check before attempting to check if the map contains something
|
|
||||||
|
|
||||||
This seems stupid, but it does seem that it improves the performance a bit, and it makes sense, "containsKey(...)" does not attempt to check the map size before attempting to check if the map contains the key
|
|
||||||
|
|
||||||
We also create a "canSee" method tailored for "ChunkMap#updatePlayer()", a method without the equals check (the "updatePlayer()" already checks if the entity is the same entity) because the CraftPlayer's `equals()` check is a *bit* expensive compared to only checking the object's identity, and because the identity has already been check, we don't need to check it twice.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
||||||
index 52a6a4badace15a983f0acb431036bd704d9cebd..7c19a4d11546bbcbf144feddee72733915bd3abd 100644
|
|
||||||
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
||||||
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
|
|
||||||
@@ -1289,7 +1289,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
|
||||||
// Paper end - Configurable entity tracking range by Y
|
|
||||||
|
|
||||||
// CraftBukkit start - respect vanish API
|
|
||||||
- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits
|
|
||||||
+ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // SparklyPaper - optimize canSee checks
|
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
// CraftBukkit end
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
index 554714e449d1d2439b05d7e15f72afccd17d4df5..405a65b52f5b4cd9a9a19e3e6369d98c39f306bc 100644
|
index 98fc89cc7a715d35b62e13f8ecbe56c05605ca64..330e68e79f2201a5107c007d96ebd845bfa3caed 100644
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||||
@@ -205,7 +205,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
@@ -207,7 +207,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
private boolean hasPlayedBefore = false;
|
private boolean hasPlayedBefore = false;
|
||||||
private final ConversationTracker conversationTracker = new ConversationTracker();
|
private final ConversationTracker conversationTracker = new ConversationTracker();
|
||||||
private final Set<String> channels = new HashSet<String>();
|
private final Set<String> channels = new HashSet<String>();
|
||||||
@@ -39,7 +17,7 @@ index 554714e449d1d2439b05d7e15f72afccd17d4df5..405a65b52f5b4cd9a9a19e3e6369d98c
|
|||||||
private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player
|
private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player
|
||||||
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
|
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
|
||||||
private int hash = 0;
|
private int hash = 0;
|
||||||
@@ -2264,9 +2264,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
@@ -2255,9 +2255,16 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canSee(org.bukkit.entity.Entity entity) {
|
public boolean canSee(org.bukkit.entity.Entity entity) {
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Mon, 6 Nov 2023 21:54:33 -0300
|
||||||
|
Subject: [PATCH] Track how much MSPT each world used
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/main/java/io/papermc/paper/command/MSPTCommand.java b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||||
|
index 8b5293b0c696ef21d0101493ffa41b60bf0bc86b..601198a33adb29316b0617d5390d1620b7c1095c 100644
|
||||||
|
--- a/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||||
|
+++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java
|
||||||
|
@@ -78,6 +78,46 @@ public final class MSPTCommand extends Command {
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
+
|
||||||
|
+ // SparklyPaper start - track world's MSPT
|
||||||
|
+ sender.sendMessage(text());
|
||||||
|
+ sender.sendMessage(text().content("World tick times ").color(GOLD)
|
||||||
|
+ .append(text().color(YELLOW)
|
||||||
|
+ .append(
|
||||||
|
+ text("("),
|
||||||
|
+ text("avg", GRAY),
|
||||||
|
+ text("/"),
|
||||||
|
+ text("min", GRAY),
|
||||||
|
+ text("/"),
|
||||||
|
+ text("max", GRAY),
|
||||||
|
+ text(")")
|
||||||
|
+ )
|
||||||
|
+ ).append(
|
||||||
|
+ text(" from last 5s"),
|
||||||
|
+ text(",", GRAY),
|
||||||
|
+ text(" 10s"),
|
||||||
|
+ text(",", GRAY),
|
||||||
|
+ text(" 1m"),
|
||||||
|
+ text(":", YELLOW)
|
||||||
|
+ )
|
||||||
|
+ );
|
||||||
|
+ for (net.minecraft.server.level.ServerLevel serverLevel : server.getAllLevels()) {
|
||||||
|
+ List<Component> worldTimes = new ArrayList<>();
|
||||||
|
+ worldTimes.addAll(eval(serverLevel.tickTimes5s.getTimes()));
|
||||||
|
+ worldTimes.addAll(eval(serverLevel.tickTimes10s.getTimes()));
|
||||||
|
+ worldTimes.addAll(eval(serverLevel.tickTimes60s.getTimes()));
|
||||||
|
+
|
||||||
|
+ sender.sendMessage(text().content("◴ " + serverLevel.getWorld().getName() + ": ").color(GOLD)
|
||||||
|
+ .append(text().color(GRAY)
|
||||||
|
+ .append(
|
||||||
|
+ worldTimes.get(0), SLASH, worldTimes.get(1), SLASH, worldTimes.get(2), text(", ", YELLOW),
|
||||||
|
+ worldTimes.get(3), SLASH, worldTimes.get(4), SLASH, worldTimes.get(5), text(", ", YELLOW),
|
||||||
|
+ worldTimes.get(6), SLASH, worldTimes.get(7), SLASH, worldTimes.get(8)
|
||||||
|
+ )
|
||||||
|
+ )
|
||||||
|
+ );
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Tue, 25 Jun 2024 02:52:32 -0300
|
||||||
|
Subject: [PATCH] Add CraftItemRecipeEvent
|
||||||
|
|
||||||
|
Used when a player OR a crafter block crafts an item, as an alternative to PrepareItemCraftEvent and CraftItemEvent, because both events are not triggered when a item is crafted from a crafter
|
||||||
|
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||||
|
index d7a52220e9525502163f5ee6afbadf2baaae6190..bbd000e3a3e9112e10a09e5d3ef6851b28e900fa 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||||
|
@@ -1472,6 +1472,24 @@ public class CraftEventFactory {
|
||||||
|
Bukkit.getPluginManager().callEvent(crafterCraftEvent);
|
||||||
|
return crafterCraftEvent;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // SparklyPaper start - add CraftItemRecipeEvent
|
||||||
|
+ public static net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent callCraftItemRecipeEvent(net.minecraft.world.inventory.CraftingContainer container, Recipe recipe, ItemStack result) {
|
||||||
|
+ org.bukkit.inventory.ItemStack[] matrix = new org.bukkit.inventory.ItemStack[container.getItems().size()];
|
||||||
|
+ int i = 0;
|
||||||
|
+ for (ItemStack item : container.getItems()) {
|
||||||
|
+ matrix[i] = CraftItemStack.asCraftMirror(item);
|
||||||
|
+ i++;
|
||||||
|
+ }
|
||||||
|
+ org.bukkit.inventory.ItemStack bukkitResult = CraftItemStack.asCraftMirror(result);
|
||||||
|
+
|
||||||
|
+ net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent event = new net.sparklypower.sparklypaper.event.inventory.CraftItemRecipeEvent(matrix, recipe, bukkitResult);
|
||||||
|
+ Bukkit.getPluginManager().callEvent(event);
|
||||||
|
+
|
||||||
|
+ return event;
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end
|
||||||
|
+
|
||||||
|
// Paper start
|
||||||
|
@Deprecated
|
||||||
|
public static com.destroystokyo.paper.event.entity.ProjectileCollideEvent callProjectileCollideEvent(Entity entity, EntityHitResult position) {
|
||||||
@@ -6,10 +6,10 @@ Subject: [PATCH] Allow item version downgrades
|
|||||||
The server WON'T convert the item data from a newer version to an older version, so proceed with caution
|
The server WON'T convert the item data from a newer version to an older version, so proceed with caution
|
||||||
|
|
||||||
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
diff --git a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||||
index 507f908916cbeb592496f963b46e4c2121a7b5e3..d9361a5bb576da7f9ea47236620746f21119ab4d 100644
|
index bd8005cd3a52532f4cb2e123da473f1490b59dbb..2d23110b61024847c8ed554ac5652982a35dd74b 100644
|
||||||
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
--- a/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||||
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
+++ b/src/main/java/org/bukkit/craftbukkit/util/CraftMagicNumbers.java
|
||||||
@@ -76,6 +76,7 @@ import org.bukkit.potion.PotionType;
|
@@ -85,6 +85,7 @@ import org.bukkit.potion.PotionType;
|
||||||
public final class CraftMagicNumbers implements UnsafeValues {
|
public final class CraftMagicNumbers implements UnsafeValues {
|
||||||
public static final CraftMagicNumbers INSTANCE = new CraftMagicNumbers();
|
public static final CraftMagicNumbers INSTANCE = new CraftMagicNumbers();
|
||||||
public static final boolean DISABLE_OLD_API_SUPPORT = Boolean.getBoolean("paper.disableOldApiSupport"); // Paper
|
public static final boolean DISABLE_OLD_API_SUPPORT = Boolean.getBoolean("paper.disableOldApiSupport"); // Paper
|
||||||
@@ -17,7 +17,7 @@ index 507f908916cbeb592496f963b46e4c2121a7b5e3..d9361a5bb576da7f9ea47236620746f2
|
|||||||
|
|
||||||
private final Commodore commodore = new Commodore();
|
private final Commodore commodore = new Commodore();
|
||||||
|
|
||||||
@@ -237,7 +238,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
@@ -246,7 +247,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||||
@Override
|
@Override
|
||||||
public Material getMaterial(String material, int version) {
|
public Material getMaterial(String material, int version) {
|
||||||
Preconditions.checkArgument(material != null, "material == null");
|
Preconditions.checkArgument(material != null, "material == null");
|
||||||
@@ -26,7 +26,7 @@ index 507f908916cbeb592496f963b46e4c2121a7b5e3..d9361a5bb576da7f9ea47236620746f2
|
|||||||
|
|
||||||
// Fastpath up to date materials
|
// Fastpath up to date materials
|
||||||
if (version == this.getDataVersion()) {
|
if (version == this.getDataVersion()) {
|
||||||
@@ -610,7 +611,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
@@ -676,7 +677,7 @@ public final class CraftMagicNumbers implements UnsafeValues {
|
||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
int dataVersion = compound.getInt("DataVersion");
|
int dataVersion = compound.getInt("DataVersion");
|
||||||
@@ -0,0 +1,627 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Tue, 7 Nov 2023 01:34:14 -0300
|
||||||
|
Subject: [PATCH] Parallel world ticking
|
||||||
|
|
||||||
|
"mom can we have folia?" "we already have folia at home" folia at home:
|
||||||
|
|
||||||
|
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..f47b49b02f664725d310887e65477deb07414bde 100644
|
||||||
|
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||||
|
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||||
|
@@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
public class TickThread extends Thread {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(TickThread.class);
|
||||||
|
+ public static final boolean HARD_THROW = !Boolean.getBoolean("sparklypaper.disableHardThrow"); // SparklyPaper - parallel world ticking - THIS SHOULD NOT BE DISABLED SINCE IT CAN CAUSE DATA CORRUPTION!!! Anyhow, for production servers, if you want to make a test run to see if the server could crash, you can test it with this disabled
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
@@ -22,14 +23,15 @@ public class TickThread extends Thread {
|
||||||
|
public static void ensureTickThread(final String reason) {
|
||||||
|
if (!isTickThread()) {
|
||||||
|
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
||||||
|
- throw new IllegalStateException(reason);
|
||||||
|
+ if (HARD_THROW)
|
||||||
|
+ throw new IllegalStateException(reason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ensureTickThread(final Level world, final BlockPos pos, final String reason) {
|
||||||
|
if (!isTickThreadFor(world, pos)) {
|
||||||
|
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||||
|
- reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos;
|
||||||
|
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + " - " + getTickThreadInformation(world.getServer());
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
@@ -38,7 +40,7 @@ public class TickThread extends Thread {
|
||||||
|
public static void ensureTickThread(final Level world, final BlockPos pos, final int blockRadius, final String reason) {
|
||||||
|
if (!isTickThreadFor(world, pos, blockRadius)) {
|
||||||
|
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||||
|
- reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius;
|
||||||
|
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius + " - " + getTickThreadInformation(world.getServer());
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
@@ -56,7 +58,7 @@ public class TickThread extends Thread {
|
||||||
|
public static void ensureTickThread(final Level world, final int chunkX, final int chunkZ, final String reason) {
|
||||||
|
if (!isTickThreadFor(world, chunkX, chunkZ)) {
|
||||||
|
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||||
|
- reason + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ);
|
||||||
|
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ) + " - " + getTickThreadInformation(world.getServer());
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
@@ -65,7 +67,7 @@ public class TickThread extends Thread {
|
||||||
|
public static void ensureTickThread(final Entity entity, final String reason) {
|
||||||
|
if (!isTickThreadFor(entity)) {
|
||||||
|
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||||
|
- reason + ", entity=" + entity;
|
||||||
|
+ reason + ", entity=" + entity + " - " + getTickThreadInformation(entity.getServer());
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
@@ -74,7 +76,7 @@ public class TickThread extends Thread {
|
||||||
|
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
|
||||||
|
if (!isTickThreadFor(world, aabb)) {
|
||||||
|
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||||
|
- reason + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb;
|
||||||
|
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb + " - " + getTickThreadInformation(world.getServer());
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
@@ -83,12 +85,74 @@ public class TickThread extends Thread {
|
||||||
|
public static void ensureTickThread(final Level world, final double blockX, final double blockZ, final String reason) {
|
||||||
|
if (!isTickThreadFor(world, blockX, blockZ)) {
|
||||||
|
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||||
|
- reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ);
|
||||||
|
+ reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ) + " - " + getTickThreadInformation(world.getServer());
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // SparklyPaper - parallel world ticking
|
||||||
|
+ // This is an additional method to check if the tick thread is bound to a specific world because, by default, Paper's isTickThread methods do not provide this information
|
||||||
|
+ // Because we only tick worlds in parallel (instead of regions), we can use this for our checks
|
||||||
|
+ public static void ensureTickThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
|
||||||
|
+ if (!isTickThreadFor(world)) {
|
||||||
|
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable());
|
||||||
|
+ if (HARD_THROW)
|
||||||
|
+ throw new IllegalStateException(reason);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // SparklyPaper - parallel world ticking
|
||||||
|
+ // This is an additional method to check if it is a tick thread but ONLY a tick thread
|
||||||
|
+ public static void ensureOnlyTickThread(final String reason) {
|
||||||
|
+ boolean isTickThread = isTickThread();
|
||||||
|
+ boolean isServerLevelTickThread = isServerLevelTickThread();
|
||||||
|
+ if (!isTickThread || isServerLevelTickThread) {
|
||||||
|
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread ONLY tick thread check: " + reason, new Throwable());
|
||||||
|
+ if (HARD_THROW)
|
||||||
|
+ throw new IllegalStateException(reason);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // SparklyPaper - parallel world ticking
|
||||||
|
+ // This is an additional method to check if the tick thread is bound to a specific world or if it is an async thread.
|
||||||
|
+ public static void ensureTickThreadOrAsyncThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
|
||||||
|
+ boolean isValidTickThread = isTickThreadFor(world);
|
||||||
|
+ boolean isAsyncThread = !isTickThread();
|
||||||
|
+ boolean isValid = isAsyncThread || isValidTickThread;
|
||||||
|
+ if (!isValid) {
|
||||||
|
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread or async thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable());
|
||||||
|
+ if (HARD_THROW)
|
||||||
|
+ throw new IllegalStateException(reason);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static String getTickThreadInformation(net.minecraft.server.MinecraftServer minecraftServer) {
|
||||||
|
+ StringBuilder sb = new StringBuilder();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+ sb.append("Is tick thread? ");
|
||||||
|
+ sb.append(currentThread instanceof TickThread);
|
||||||
|
+ sb.append("; Is server level tick thread? ");
|
||||||
|
+ sb.append(currentThread instanceof ServerLevelTickThread);
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ sb.append("; Currently ticking level: ");
|
||||||
|
+ if (serverLevelTickThread.currentlyTickingServerLevel != null) {
|
||||||
|
+ sb.append(serverLevelTickThread.currentlyTickingServerLevel.getWorld().getName());
|
||||||
|
+ } else {
|
||||||
|
+ sb.append("null");
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ sb.append("; Is iterating over levels? ");
|
||||||
|
+ sb.append(minecraftServer.isIteratingOverLevels);
|
||||||
|
+ sb.append("; Are we going to hard throw? ");
|
||||||
|
+ sb.append(HARD_THROW);
|
||||||
|
+ return sb.toString();
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public static boolean isServerLevelTickThread() {
|
||||||
|
+ return Thread.currentThread() instanceof ServerLevelTickThread;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
public final int id; /* We don't override getId as the spec requires that it be unique (with respect to all other threads) */
|
||||||
|
|
||||||
|
private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
|
||||||
|
@@ -123,7 +187,11 @@ public class TickThread extends Thread {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final BlockPos pos) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final BlockPos pos, final int blockRadius) {
|
||||||
|
@@ -131,38 +199,103 @@ public class TickThread extends Thread {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final ChunkPos pos) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final Vec3 pos) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final AABB aabb) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final double blockX, final double blockZ) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final Vec3 position, final Vec3 deltaMovement, final int buffer) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final int fromChunkX, final int fromChunkZ, final int toChunkX, final int toChunkZ) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ, final int radius) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // SparklyPaper - parallel world ticking
|
||||||
|
+ // This is an additional method to check if the tick thread is bound to a specific world because, by default, Paper's isTickThread methods do not provide this information
|
||||||
|
+ // Because we only tick worlds in parallel (instead of regions), we can use this for our checks
|
||||||
|
+ public static boolean isTickThreadFor(final Level world) {
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isTickThreadFor(final Entity entity) {
|
||||||
|
- return isTickThread();
|
||||||
|
+ if (entity == null) {
|
||||||
|
+ return true;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ Thread currentThread = Thread.currentThread();
|
||||||
|
+
|
||||||
|
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||||
|
+ return serverLevelTickThread.currentlyTickingServerLevel == entity.level();
|
||||||
|
+ } else return currentThread instanceof TickThread;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ public static class ServerLevelTickThread extends TickThread {
|
||||||
|
+ public ServerLevelTickThread(String name) {
|
||||||
|
+ super(name);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public ServerLevelTickThread(Runnable run, String name) {
|
||||||
|
+ super(run, name);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ public net.minecraft.server.level.ServerLevel currentlyTickingServerLevel;
|
||||||
|
}
|
||||||
|
+ // SparklyPaper end
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||||
|
index ba32db69c95b325a781cb2dff4200e4464a11baf..219a87300838cb4d078553dda666b3207f8191b8 100644
|
||||||
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||||
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||||
|
@@ -457,7 +457,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"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
if (!this.isChunkLoaded(x, z)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
@@ -480,6 +480,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||||
|
if (!unloadChunk0(x, z, false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot regenerate chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
warnUnsafeChunk("regenerating a faraway chunk", x, z); // Paper
|
||||||
|
|
||||||
|
final long chunkKey = ChunkCoordIntPair.pair(x, z);
|
||||||
|
@@ -501,6 +502,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"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
|
||||||
|
if (playerChunk == null) return false;
|
||||||
|
|
||||||
|
@@ -551,7 +553,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"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
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
|
||||||
|
|
||||||
|
@@ -779,6 +781,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
this.world.captureTreeGeneration = true;
|
||||||
|
this.world.captureBlockStates = true;
|
||||||
|
boolean grownTree = this.generateTree(loc, type);
|
||||||
|
@@ -894,6 +897,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<net.minecraft.world.level.ServerExplosion> configurator) {
|
||||||
|
// Paper end - expand explosion API
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
net.minecraft.world.level.Level.ExplosionInteraction explosionType;
|
||||||
|
if (!breakBlocks) {
|
||||||
|
explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks
|
||||||
|
@@ -985,6 +989,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"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
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);
|
||||||
|
@@ -1015,6 +1020,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||||
|
@Override
|
||||||
|
public void setBiome(int x, int y, int z, Holder<net.minecraft.world.level.biome.Biome> bb) {
|
||||||
|
BlockPos pos = new BlockPos(x, 0, z);
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
if (this.world.hasChunkAt(pos)) {
|
||||||
|
net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos);
|
||||||
|
|
||||||
|
@@ -2292,6 +2298,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||||
|
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..78f9c3f3b068f638570942961ad41969abc9c028 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 - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // Folia end - parallel world ticking
|
||||||
|
return this.world.getBlockState(this.position);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -157,6 +162,11 @@ public class CraftBlock implements Block {
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setData(final byte data, int flag) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -198,6 +208,12 @@ 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) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
+
|
||||||
|
// 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 +359,33 @@ public class CraftBlock implements Block {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Biome getBiome() {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paper start
|
||||||
|
@Override
|
||||||
|
public Biome getComputedBiome() {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ());
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBiome(Biome bio) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -402,6 +433,11 @@ public class CraftBlock implements Block {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isBlockFaceIndirectlyPowered(BlockFace face) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face));
|
||||||
|
|
||||||
|
Block relative = this.getRelative(face);
|
||||||
|
@@ -414,6 +450,11 @@ public class CraftBlock implements Block {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBlockPower(BlockFace face) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
int power = 0;
|
||||||
|
net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
|
||||||
|
int x = this.getX();
|
||||||
|
@@ -484,6 +525,11 @@ public class CraftBlock implements Block {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean breakNaturally() {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
return this.breakNaturally(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -543,6 +589,11 @@ public class CraftBlock implements Block {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean applyBoneMeal(BlockFace face) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
Direction direction = CraftBlock.blockFaceToNotch(face);
|
||||||
|
BlockFertilizeEvent event = null;
|
||||||
|
ServerLevel world = this.getCraftWorld().getHandle();
|
||||||
|
@@ -554,8 +605,8 @@ public class CraftBlock implements Block {
|
||||||
|
world.captureTreeGeneration = false;
|
||||||
|
|
||||||
|
if (world.capturedBlockStates.size() > 0) {
|
||||||
|
- TreeType treeType = SaplingBlock.treeType;
|
||||||
|
- SaplingBlock.treeType = null;
|
||||||
|
+ TreeType treeType = SaplingBlock.treeTypeRT.get(); // SparklyPaper - parallel world ticking
|
||||||
|
+ SaplingBlock.treeTypeRT.set(null); // SparklyPaper - parallel world ticking
|
||||||
|
List<BlockState> blocks = new ArrayList<>(world.capturedBlockStates.values());
|
||||||
|
world.capturedBlockStates.clear();
|
||||||
|
StructureGrowEvent structureEvent = null;
|
||||||
|
@@ -644,6 +695,11 @@ public class CraftBlock implements Block {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
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) {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
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,6 +780,11 @@ public class CraftBlock implements Block {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void tick() {
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (world instanceof ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
final ServerLevel level = this.world.getMinecraftWorld();
|
||||||
|
this.getNMS().tick(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..3e90f16d303a8f3d1e2b01e7cbd62cbd991d3f06 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<T extends BlockEntity> extends Craft
|
||||||
|
private final T tileEntity;
|
||||||
|
private final T snapshot;
|
||||||
|
public boolean snapshotDisabled; // Paper
|
||||||
|
- public static boolean DISABLE_SNAPSHOT = false; // Paper
|
||||||
|
+ public static ThreadLocal<Boolean> DISABLE_SNAPSHOT = ThreadLocal.withInitial(() -> Boolean.FALSE); // SparklyPaper - parallel world ticking
|
||||||
|
|
||||||
|
public CraftBlockEntityState(World world, T tileEntity) {
|
||||||
|
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
|
||||||
|
@@ -34,8 +34,8 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> 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(); // SparklyPaper - parallel world ticking
|
||||||
|
+ if (DISABLE_SNAPSHOT.get()) { // SparklyPaper - parallel world ticking
|
||||||
|
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..9856860ee2987738bbcad5d752670e30f569ba74 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();
|
||||||
|
|
||||||
|
+ // SparklyPaper start - parallel world ticking
|
||||||
|
+ if (access instanceof net.minecraft.server.level.ServerLevel serverWorld) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||||
|
+ }
|
||||||
|
+ // SparklyPaper end - parallel world ticking
|
||||||
|
+
|
||||||
|
if (block.getType() != this.getType()) {
|
||||||
|
if (!force) {
|
||||||
|
return false;
|
||||||
|
@@ -350,6 +356,7 @@ public class CraftBlockState implements BlockState {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public java.util.Collection<org.bukkit.inventory.ItemStack> getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) {
|
||||||
|
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); // SparklyPaper - parallel world ticking
|
||||||
|
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..ad507c36d89ce8639fbedbb1df0da66bdc96affa 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(); // SparklyPaper - parallel world ticking
|
||||||
|
+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(!useSnapshot); // SparklyPaper - parallel world ticking
|
||||||
|
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(prev); // SparklyPaper - parallel world ticking
|
||||||
|
}
|
||||||
|
// Paper end
|
||||||
|
}
|
||||||
|
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||||
|
index bbd000e3a3e9112e10a09e5d3ef6851b28e900fa..6b91661e920b80fb2ddf2b3e9e2c2839a7986b01 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<BlockPos> 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. // SparklyPaper - parallel world ticking (this is from Folia, fixes concurrency bugs with sculk catalysts)
|
||||||
|
|
||||||
|
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); // SparklyPaper - parallel world ticking
|
||||||
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
|
|
||||||
|
if (!event.isCancelled()) {
|
||||||
|
@@ -2248,7 +2248,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()) { // SparklyPaper - parallel world ticking
|
||||||
|
if (!event.callEvent()) {
|
||||||
|
return itemStack;
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: MrPowerGamerBR <git@mrpowergamerbr.com>
|
||||||
|
Date: Wed, 12 Jun 2024 11:53:09 -0300
|
||||||
|
Subject: [PATCH] SPARKLYPOWER Add custom blocks
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
||||||
|
index 002e635137a8b015af9799d6a8854ebc6330bfb4..0f02a9793937a492003bbfff827ac6483c1baa14 100644
|
||||||
|
--- a/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
||||||
|
+++ b/src/test/java/org/bukkit/craftbukkit/legacy/LegacyTest.java
|
||||||
|
@@ -135,6 +135,9 @@ public class LegacyTest {
|
||||||
|
// 1.21.4
|
||||||
|
Material.OPEN_EYEBLOSSOM, Material.CLOSED_EYEBLOSSOM, Material.RESIN_CLUMP, Material.RESIN_BLOCK, Material.RESIN_BRICKS, Material.RESIN_BRICK_STAIRS, Material.RESIN_BRICK_SLAB, Material.RESIN_BRICK_WALL, Material.CHISELED_RESIN_BRICKS,
|
||||||
|
Material.RESIN_BRICK, Material.POTTED_OPEN_EYEBLOSSOM, Material.POTTED_CLOSED_EYEBLOSSOM,
|
||||||
|
+ // SparklyPower custom blocks
|
||||||
|
+ Material.SPARKLYPOWER_RAINBOW_WOOL, Material.SPARKLYPOWER_RAINBOW_CONCRETE, Material.SPARKLYPOWER_RAINBOW_TERRACOTTA, Material.SPARKLYPOWER_ASPHALT_PLAYER, Material.SPARKLYPOWER_ASPHALT_SERVER, Material.SPARKLYPOWER_ASPHALT_PLAYER_SLAB,
|
||||||
|
+ Material.SPARKLYPOWER_ASPHALT_SERVER_SLAB,
|
||||||
|
//
|
||||||
|
Material.LEGACY_AIR, Material.LEGACY_DEAD_BUSH, Material.LEGACY_BURNING_FURNACE, Material.LEGACY_WALL_SIGN, Material.LEGACY_REDSTONE_TORCH_OFF, Material.LEGACY_SKULL, Material.LEGACY_REDSTONE_COMPARATOR_ON, Material.LEGACY_WALL_BANNER, Material.LEGACY_MONSTER_EGG));
|
||||||
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
--- a/src/main/resources/data/.paperassetsroot
|
||||||
|
+++ b/src/main/resources/data/.paperassetsroot
|
||||||
|
@@ -1,0 +_,0 @@
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
package net.sparklypower.sparklypaper;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntOpenHashSet;
|
||||||
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
|
import net.minecraft.world.level.block.entity.TickingBlockEntity;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list for ServerLevel's blockEntityTickers
|
||||||
|
* <p>
|
||||||
|
* This list is behaves identically to ObjectArrayList, but it has an additional method, `removeAllByIndex`, that allows a list of integers to be passed indicating what
|
||||||
|
* indexes should be deleted from the list
|
||||||
|
* <p>
|
||||||
|
* This is faster than using removeAll, since we don't need to compare the identity of each block entity, and faster than looping thru each index manually and deleting with remove,
|
||||||
|
* since we don't need to resize the array every single remove.
|
||||||
|
*/
|
||||||
|
public final class BlockEntityTickersList extends ObjectArrayList<TickingBlockEntity> {
|
||||||
|
private final IntOpenHashSet toRemove = new IntOpenHashSet();
|
||||||
|
private int startSearchFromIndex = -1;
|
||||||
|
|
||||||
|
/** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. */
|
||||||
|
public BlockEntityTickersList() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new array list and fills it with a given collection.
|
||||||
|
*
|
||||||
|
* @param c a collection that will be used to fill the array list.
|
||||||
|
*/
|
||||||
|
public BlockEntityTickersList(final Collection<? extends TickingBlockEntity> c) {
|
||||||
|
super(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marks an entry as removed
|
||||||
|
*
|
||||||
|
* @param index the index of the item on the list to be marked as removed
|
||||||
|
*/
|
||||||
|
public void markAsRemoved(final int index) {
|
||||||
|
// The block entities list always loop starting from 0, so we only need to check if the startSearchFromIndex is -1 and that's it
|
||||||
|
if (this.startSearchFromIndex == -1)
|
||||||
|
this.startSearchFromIndex = index;
|
||||||
|
this.toRemove.add(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes elements that have been marked as removed.
|
||||||
|
*/
|
||||||
|
public void removeMarkedEntries() {
|
||||||
|
if (this.startSearchFromIndex == -1) // No entries in the list, skip
|
||||||
|
return;
|
||||||
|
|
||||||
|
removeAllByIndex(startSearchFromIndex, toRemove);
|
||||||
|
toRemove.clear();
|
||||||
|
this.startSearchFromIndex = -1; // Reset the start search index
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes elements by their index.
|
||||||
|
*/
|
||||||
|
private void removeAllByIndex(final int startSearchFromIndex, final IntOpenHashSet c) { // can't use Set<Integer> because we want to avoid autoboxing when using contains
|
||||||
|
final int requiredMatches = c.size();
|
||||||
|
if (requiredMatches == 0)
|
||||||
|
return; // exit early, we don't need to do anything
|
||||||
|
|
||||||
|
final Object[] a = this.a;
|
||||||
|
int j = startSearchFromIndex;
|
||||||
|
int matches = 0;
|
||||||
|
for (int i = startSearchFromIndex; i < size; i++) { // If the user knows the first index to be removed, we can skip a lot of unnecessary comparsions
|
||||||
|
if (!c.contains(i)) {
|
||||||
|
// TODO: It can be possible to optimize this loop by tracking the start/finish and then using arraycopy to "skip" the elements,
|
||||||
|
// this would optimize cases where the index to be removed are far apart, HOWEVER it does have a big performance impact if you are doing
|
||||||
|
// "arraycopy" for each element
|
||||||
|
a[j++] = a[i];
|
||||||
|
} else {
|
||||||
|
matches++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matches == requiredMatches) { // Exit the loop if we already removed everything, we don't need to check anything else
|
||||||
|
// We need to update the final size here, because we know that we already found everything!
|
||||||
|
// Because we know that the size must be currentSize - requiredMatches (because we have matched everything), let's update the value
|
||||||
|
// However, we need to copy the rest of the stuff over
|
||||||
|
if (i != (size - 1)) { // If it isn't the last index...
|
||||||
|
// i + 1 because we want to copy the *next* element over
|
||||||
|
// and the size - i - 1 is because we want to get the current size, minus the current index (which is i), and then - 1 because we want to copy -1 ahead (remember, we are adding +1 to copy the *next* element)
|
||||||
|
System.arraycopy(a, i + 1, a, j, size - i - 1);
|
||||||
|
}
|
||||||
|
j = size - requiredMatches;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Arrays.fill(a, j, size, null);
|
||||||
|
size = j;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package net.sparklypower.sparklypaper.commands;
|
||||||
|
|
||||||
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.sparklypower.sparklypaper.configs.SparklyPaperConfigUtils;
|
||||||
|
import org.bukkit.ChatColor;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.command.Command;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class SparklyPaperCommand extends Command {
|
||||||
|
public SparklyPaperCommand(String name) {
|
||||||
|
super(name);
|
||||||
|
this.description = "SparklyPaper related commands";
|
||||||
|
this.usageMessage = "/sparklypaper [reload | version]";
|
||||||
|
this.setPermission("bukkit.command.sparklypaper");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
|
||||||
|
if (args.length == 1) {
|
||||||
|
return Stream.of("reload", "version")
|
||||||
|
.filter(arg -> arg.startsWith(args[0].toLowerCase()))
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||||
|
if (!testPermission(sender)) return true;
|
||||||
|
|
||||||
|
if (args.length != 1) {
|
||||||
|
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args[0].equalsIgnoreCase("reload")) {
|
||||||
|
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.");
|
||||||
|
|
||||||
|
MinecraftServer console = MinecraftServer.getServer();
|
||||||
|
SparklyPaperConfigUtils.INSTANCE.init((File) console.options.valueOf("sparklypaper-settings"));
|
||||||
|
for (ServerLevel level : console.getAllLevels()) {
|
||||||
|
level.sparklyPaperConfig = SparklyPaperConfigUtils.INSTANCE.getWorldSettings(level.serverLevelData.getLevelName());
|
||||||
|
}
|
||||||
|
console.server.reloadCount++;
|
||||||
|
|
||||||
|
Command.broadcastCommandMessage(sender, ChatColor.GREEN + "SparklyPaper config reload complete.");
|
||||||
|
} else if (args[0].equalsIgnoreCase("version")) {
|
||||||
|
Command verCmd = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version");
|
||||||
|
if (verCmd != null) {
|
||||||
|
return verCmd.execute(sender, commandLabel, new String[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
package net.sparklypower.sparklypaper
|
||||||
|
|
||||||
|
import com.mojang.logging.LogUtils
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.Month
|
||||||
|
import java.time.ZoneOffset
|
||||||
|
import java.util.concurrent.*
|
||||||
|
|
||||||
|
class HalloweenManager {
|
||||||
|
companion object {
|
||||||
|
private val LOGGER = LogUtils.getLogger()
|
||||||
|
}
|
||||||
|
private var spookySeasonStartEpoch = 0L
|
||||||
|
private var spookySeasonEndEpoch = 0L
|
||||||
|
private var halloweenStartEpoch = 0L
|
||||||
|
private var halloweenEndEpoch = 0L
|
||||||
|
private var executor = Executors.newSingleThreadScheduledExecutor(object: ThreadFactory {
|
||||||
|
override fun newThread(p0: Runnable): Thread {
|
||||||
|
val thread = Thread(p0)
|
||||||
|
thread.name = "halloween-timer-updater"
|
||||||
|
thread.priority = 1 // Minimum priority
|
||||||
|
return thread
|
||||||
|
}
|
||||||
|
})
|
||||||
|
private var latch = CountDownLatch(1)
|
||||||
|
|
||||||
|
fun startHalloweenEpochTask() {
|
||||||
|
var isFirst = true
|
||||||
|
executor.scheduleAtFixedRate({
|
||||||
|
updateEpoch()
|
||||||
|
if (isFirst)
|
||||||
|
latch.countDown()
|
||||||
|
isFirst = false
|
||||||
|
}, 0L, 90L, TimeUnit.DAYS) // Every 90 days
|
||||||
|
}
|
||||||
|
|
||||||
|
fun waitUntilEpochHasBeenUpdated() {
|
||||||
|
latch.await()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun updateEpoch() {
|
||||||
|
LOGGER.info("Updating Spooky Season and Halloween Time")
|
||||||
|
this.spookySeasonStartEpoch = getEpochMillisAtDate(20, Month.OCTOBER, false)
|
||||||
|
this.spookySeasonEndEpoch = getEpochMillisAtDate(3, Month.NOVEMBER, true)
|
||||||
|
this.halloweenStartEpoch = getEpochMillisAtDate(31, Month.OCTOBER, false)
|
||||||
|
this.halloweenEndEpoch = getEpochMillisAtDate(31, Month.OCTOBER, true)
|
||||||
|
LOGGER.info("Updated Spooky Season and Halloween Time!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isSpookySeason() = System.currentTimeMillis() in spookySeasonStartEpoch until spookySeasonEndEpoch
|
||||||
|
fun isHalloween() = System.currentTimeMillis() in halloweenStartEpoch until halloweenEndEpoch
|
||||||
|
|
||||||
|
private fun getEpochMillisAtDate(dayOfMonth: Int, month: Month, isEnd: Boolean): Long {
|
||||||
|
// Get the current year
|
||||||
|
val currentYear = LocalDateTime.now().year
|
||||||
|
|
||||||
|
// Define the target date (20/10/CurrentYear at midnight)
|
||||||
|
val targetDate = LocalDateTime.of(
|
||||||
|
currentYear,
|
||||||
|
month,
|
||||||
|
dayOfMonth,
|
||||||
|
if (isEnd)
|
||||||
|
23
|
||||||
|
else
|
||||||
|
0,
|
||||||
|
if (isEnd)
|
||||||
|
59
|
||||||
|
else
|
||||||
|
0,
|
||||||
|
if (isEnd)
|
||||||
|
59
|
||||||
|
else
|
||||||
|
0,
|
||||||
|
if (isEnd)
|
||||||
|
999_999_999
|
||||||
|
else
|
||||||
|
0,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check if the target date is in the past
|
||||||
|
val now = LocalDateTime.now()
|
||||||
|
val adjustedDate = if (now.isAfter(targetDate)) {
|
||||||
|
// If in the past, adjust to the same date in the next year
|
||||||
|
targetDate.plusYears(1)
|
||||||
|
} else {
|
||||||
|
// If in the future or today, use the original target date
|
||||||
|
targetDate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the adjusted date to epoch time in milliseconds
|
||||||
|
return adjustedDate.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
package net.sparklypower.sparklypaper
|
||||||
|
|
||||||
|
import ca.spottedleaf.dataconverter.types.MapType
|
||||||
|
|
||||||
|
object LegacyNBTRemapper {
|
||||||
|
/**
|
||||||
|
* Remaps hacky direct NBT storage used in SparklyPower to proper PersistentDataContainer data
|
||||||
|
*/
|
||||||
|
fun remap(tag: MapType<String>) {
|
||||||
|
val perfectDreamsMap = tag.getMap<String>("PerfectDreams")
|
||||||
|
|
||||||
|
if (perfectDreamsMap != null) {
|
||||||
|
val publicBukkitValuesMap = tag.getOrCreateMap<String>("PublicBukkitValues")
|
||||||
|
|
||||||
|
// The "setBoolean" functions do set bytes behind the scenes, just like how we do the things in SparklyPower
|
||||||
|
perfectDreamsMap.getStringAndRemove("isJetpack")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_jetpack", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("disallowCrafting")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:disallow_crafting", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("poop")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_poop", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("renamedBySeuZe")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_renamed_by_seu_ze", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("isMonsterPickaxe")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_monster_tool", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("itemOwner")?.let {
|
||||||
|
publicBukkitValuesMap.setString("sparklypower:item_owner", it)
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("DreamFusca")?.let {
|
||||||
|
publicBukkitValuesMap.setString("sparklypower:fusca_info", it)
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("isFusca")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_fusca", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("fancyLeatherArmor")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_fancy_leather_armor", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("caixaSecretaLevel")?.let {
|
||||||
|
publicBukkitValuesMap.setInt("sparklypower:caixa_secreta_level", it.toInt())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("caixaSecretaWorld")?.let {
|
||||||
|
publicBukkitValuesMap.setString("sparklypower:caixa_secreta_world", it)
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("isMoveSpawners")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_move_spawners_tool", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("spawnerType")?.let {
|
||||||
|
publicBukkitValuesMap.setString("sparklypower:spawner_type", it)
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("isMochila")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_mochila", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("mochilaId")?.let {
|
||||||
|
publicBukkitValuesMap.setLong("sparklypower:mochila_id", it.toLong())
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("customMapOwner")?.let {
|
||||||
|
publicBukkitValuesMap.setString("sparklypower:map_custom_owner", it)
|
||||||
|
}
|
||||||
|
|
||||||
|
perfectDreamsMap.getStringAndRemove("quickTeleport")?.let {
|
||||||
|
publicBukkitValuesMap.setBoolean("sparklypower:is_quick_resources_teleport", it.toBoolean())
|
||||||
|
}
|
||||||
|
|
||||||
|
// If it is empty, then it means that we have migrated everything and we can remove the old PerfectDreams tag, yay!
|
||||||
|
if (perfectDreamsMap.isEmpty)
|
||||||
|
tag.remove("PerfectDreams")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun MapType<String>.getStringAndRemove(key: String): String? {
|
||||||
|
val v = getString(key)
|
||||||
|
remove(key)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package net.sparklypower.sparklypaper
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.util.TickThread
|
||||||
|
import java.util.concurrent.ThreadFactory
|
||||||
|
|
||||||
|
class ServerLevelTickExecutorThreadFactory(private val worldName: String) : ThreadFactory {
|
||||||
|
override fun newThread(p0: Runnable): Thread {
|
||||||
|
val tickThread = TickThread.ServerLevelTickThread(p0, "serverlevel-tick-worker [$worldName]")
|
||||||
|
|
||||||
|
if (tickThread.isDaemon) {
|
||||||
|
tickThread.isDaemon = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tickThread.priority != 5) {
|
||||||
|
tickThread.priority = 5
|
||||||
|
}
|
||||||
|
|
||||||
|
return tickThread
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package net.sparklypower.sparklypaper
|
||||||
|
|
||||||
|
import net.minecraft.server.MinecraftServer
|
||||||
|
import net.sparklypower.sparklypaper.commands.SparklyPaperCommand
|
||||||
|
import org.bukkit.command.Command
|
||||||
|
import org.checkerframework.checker.nullness.qual.NonNull
|
||||||
|
import org.checkerframework.framework.qual.DefaultQualifier
|
||||||
|
|
||||||
|
@DefaultQualifier(NonNull::class)
|
||||||
|
object SparklyPaperCommands {
|
||||||
|
private val COMMANDS = mapOf(
|
||||||
|
"sparklypaper" to SparklyPaperCommand("sparklypaper")
|
||||||
|
)
|
||||||
|
|
||||||
|
fun registerCommands(server: MinecraftServer) {
|
||||||
|
COMMANDS.forEach { (s: String, command: Command) ->
|
||||||
|
server.server.commandMap.register(
|
||||||
|
s, "SparklyPaper", command
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
package net.sparklypower.sparklypaper.configs
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SparklyPaperConfig(
|
||||||
|
@SerialName("config-version")
|
||||||
|
override val configVersion: Int,
|
||||||
|
@SerialName("parallel-world-ticking")
|
||||||
|
val parallelWorldTicking: ParallelWorldTicking,
|
||||||
|
@SerialName("world-settings")
|
||||||
|
val worldSettings: Map<String, SparklyPaperWorldConfig>
|
||||||
|
) : UpgradeableConfig {
|
||||||
|
override fun isNewest() = true
|
||||||
|
|
||||||
|
override fun upgradeToNext() = error("This config is already the newest version!")
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class ParallelWorldTicking(
|
||||||
|
val threads: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SparklyPaperWorldConfig(
|
||||||
|
@SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
||||||
|
val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
||||||
|
@SerialName("blazingly-simple-farm-checks")
|
||||||
|
val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks,
|
||||||
|
@SerialName("ticks-per")
|
||||||
|
val ticksPer: TicksPer,
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class BlazinglySimpleFarmChecks(
|
||||||
|
val enabled: Boolean,
|
||||||
|
@SerialName("default-growth-speed")
|
||||||
|
val defaultGrowthSpeed: Float,
|
||||||
|
@SerialName("moist-growth-speed")
|
||||||
|
val moistGrowthSpeed: Float,
|
||||||
|
@SerialName("skip-middle-aging-stages-for-crops")
|
||||||
|
val skipMiddleAgingStagesForCrops: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class TicksPer(
|
||||||
|
@SerialName("hopper-cooldown-when-target-container-is-full")
|
||||||
|
val hopperCooldownWhenTargetContainerIsFull: Int
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,94 @@
|
|||||||
|
package net.sparklypower.sparklypaper.configs
|
||||||
|
|
||||||
|
import com.charleskorn.kaml.*
|
||||||
|
import com.google.common.base.Throwables
|
||||||
|
import kotlinx.serialization.SerializationException
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import net.sparklypower.sparklypaper.configs.previous.SparklyPaperConfigV1
|
||||||
|
import org.bukkit.Bukkit
|
||||||
|
import java.io.File
|
||||||
|
import java.util.logging.Level
|
||||||
|
|
||||||
|
object SparklyPaperConfigUtils {
|
||||||
|
private const val CURRENT_CONFIG_VERSION = 2
|
||||||
|
val yaml = Yaml(
|
||||||
|
configuration = YamlConfiguration(
|
||||||
|
strictMode = false
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val deserializationStrategiesForVersions = mapOf(
|
||||||
|
1 to SparklyPaperConfigV1.serializer(),
|
||||||
|
CURRENT_CONFIG_VERSION to SparklyPaperConfig.serializer()
|
||||||
|
)
|
||||||
|
|
||||||
|
lateinit var config: SparklyPaperConfig
|
||||||
|
val logContainerCreationStacktraces = java.lang.Boolean.getBoolean("sparklypaper.logContainerCreationStacktraces")
|
||||||
|
|
||||||
|
fun init(configFile: File) {
|
||||||
|
// Write default config if the file doesn't exist
|
||||||
|
if (!configFile.exists()) {
|
||||||
|
configFile.writeText(
|
||||||
|
yaml.encodeToString(
|
||||||
|
SparklyPaperConfig(
|
||||||
|
CURRENT_CONFIG_VERSION,
|
||||||
|
SparklyPaperConfig.ParallelWorldTicking(
|
||||||
|
threads = 8
|
||||||
|
),
|
||||||
|
mapOf(
|
||||||
|
"default" to SparklyPaperConfig.SparklyPaperWorldConfig(
|
||||||
|
skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer = true,
|
||||||
|
blazinglySimpleFarmChecks = SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
||||||
|
enabled = false,
|
||||||
|
defaultGrowthSpeed = 1.0f,
|
||||||
|
moistGrowthSpeed = 5.0f,
|
||||||
|
skipMiddleAgingStagesForCrops = true
|
||||||
|
),
|
||||||
|
SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
||||||
|
hopperCooldownWhenTargetContainerIsFull = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val loadedConfig = try {
|
||||||
|
// Read the version file from the config before attempting to parse
|
||||||
|
val yamlNode = yaml.parseToYamlNode(configFile.readText())
|
||||||
|
var configVersion = yamlNode.yamlMap.getScalar("config-version")?.toInt() ?: 1 // The first config version didn't have the "config-version" key
|
||||||
|
|
||||||
|
if (configVersion != CURRENT_CONFIG_VERSION) {
|
||||||
|
var upgradedVersion: UpgradeableConfig? = null
|
||||||
|
|
||||||
|
while (configVersion != CURRENT_CONFIG_VERSION) {
|
||||||
|
Bukkit.getLogger().log(Level.INFO, "Attempting to upgrade SparklyPaper Config from version $configVersion to the next version...")
|
||||||
|
|
||||||
|
val upgradeableConfig = yaml.decodeFromYamlNode(deserializationStrategiesForVersions[configVersion]!!, yamlNode)
|
||||||
|
if (!upgradeableConfig.isNewest()) {
|
||||||
|
upgradedVersion = upgradeableConfig.upgradeToNext()
|
||||||
|
|
||||||
|
Bukkit.getLogger().log(Level.INFO, "Upgraded SparklyPaper Config from version $configVersion to ${upgradedVersion.configVersion}")
|
||||||
|
configVersion = upgradedVersion.configVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
upgradedVersion as SparklyPaperConfig
|
||||||
|
} else {
|
||||||
|
yaml.decodeFromYamlNode(SparklyPaperConfig.serializer(), yamlNode)
|
||||||
|
}
|
||||||
|
} catch (e: SerializationException) {
|
||||||
|
Bukkit.getLogger().log(Level.SEVERE, "Could not load sparklypaper.yml, please correct your syntax errors", e)
|
||||||
|
throw Throwables.propagate(e)
|
||||||
|
}
|
||||||
|
// Rewrite the config file to remove old fields and stuff
|
||||||
|
// TODO: Maybe handle this in another way? This feels kinda bad
|
||||||
|
configFile.writeText(yaml.encodeToString(loadedConfig))
|
||||||
|
config = loadedConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getWorldSettings(levelName: String): SparklyPaperConfig.SparklyPaperWorldConfig {
|
||||||
|
return config.worldSettings[levelName] ?: config.worldSettings["default"] ?: error("Missing default world-settings in sparklypaper.yml!")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package net.sparklypower.sparklypaper.configs
|
||||||
|
|
||||||
|
interface UpgradeableConfig {
|
||||||
|
abstract val configVersion: Int
|
||||||
|
fun isNewest(): Boolean
|
||||||
|
fun upgradeToNext(): UpgradeableConfig
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
package net.sparklypower.sparklypaper.configs.previous
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import net.sparklypower.sparklypaper.configs.SparklyPaperConfig
|
||||||
|
import net.sparklypower.sparklypaper.configs.UpgradeableConfig
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SparklyPaperConfigV1(
|
||||||
|
@SerialName("parallel-world-ticking")
|
||||||
|
val parallelWorldTicking: ParallelWorldTicking,
|
||||||
|
@SerialName("world-settings")
|
||||||
|
val worldSettings: Map<String, SparklyPaperWorldConfig>
|
||||||
|
) : UpgradeableConfig {
|
||||||
|
override val configVersion = 1
|
||||||
|
|
||||||
|
override fun isNewest() = false
|
||||||
|
|
||||||
|
override fun upgradeToNext(): UpgradeableConfig {
|
||||||
|
return SparklyPaperConfig(
|
||||||
|
2,
|
||||||
|
SparklyPaperConfig.ParallelWorldTicking(
|
||||||
|
this.parallelWorldTicking.threads
|
||||||
|
),
|
||||||
|
worldSettings.mapValues {
|
||||||
|
SparklyPaperConfig.SparklyPaperWorldConfig(
|
||||||
|
it.value.skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer,
|
||||||
|
SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
||||||
|
it.value.blazinglySimpleFarmChecks.enabled,
|
||||||
|
it.value.blazinglySimpleFarmChecks.defaultGrowthSpeed,
|
||||||
|
it.value.blazinglySimpleFarmChecks.moistGrowthSpeed,
|
||||||
|
it.value.blazinglySimpleFarmChecks.skipMiddleAgingStagesForCrops,
|
||||||
|
),
|
||||||
|
SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
||||||
|
0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class ParallelWorldTicking(
|
||||||
|
val threads: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class SparklyPaperWorldConfig(
|
||||||
|
@SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
||||||
|
val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
||||||
|
@SerialName("blazingly-simple-farm-checks")
|
||||||
|
val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class BlazinglySimpleFarmChecks(
|
||||||
|
val enabled: Boolean,
|
||||||
|
@SerialName("default-growth-speed")
|
||||||
|
val defaultGrowthSpeed: Float,
|
||||||
|
@SerialName("moist-growth-speed")
|
||||||
|
val moistGrowthSpeed: Float,
|
||||||
|
@SerialName("skip-middle-aging-stages-for-crops")
|
||||||
|
val skipMiddleAgingStagesForCrops: Boolean
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user