├── upstreamConfig-removed ├── .gitkeep └── 0002-JettPack.properties ├── logo.png ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitattributes ├── .editorconfig ├── upstreamConfig ├── 0001-Pufferfish.properties ├── 0004-Empirecraft.properties └── 0003-Purpur.properties ├── gradle.properties ├── settings.gradle.kts ├── patches ├── mojangapi │ └── 0001-Build-changes.patch ├── server │ ├── 0010-fix-building-issue.patch │ ├── 0004-Build-changes.patch │ ├── 0016-remove-getServerName-from-purpur.patch │ ├── 0015-lithium-entity.fast_hand_swing.patch │ ├── 0006-add-Purpur-to-timings-report.patch │ ├── 0007-hardcode-1.20.4-R0.1-SNAPSHOT.patch │ ├── 0005-Akarin-Swaps-the-predicate-order-of-collision.patch │ ├── 0009-skip-event-if-no-listeners.patch │ ├── 0017-rebrand.patch │ ├── 0013-lithium-cached_hashcode.patch │ ├── 0011-remove-broken-import-on-purpur.patch │ ├── 0014-add-Metrics-from-Aug-27-2023.patch │ ├── 0008-don-t-create-new-random-instance.patch │ ├── 0003-EmpireCraft-Server-Changes-commit-e15007e4385c5852bf.patch │ └── 0012-lithium-HashedList.patch ├── api │ ├── 0006-disable-AnnotationTest.patch │ ├── 0003-Purpur-dependencies.patch │ ├── 0008-rebrand.patch │ ├── 0007-remove-getServerName-from-purpur.patch │ ├── 0002-purpur-API-Changes-commit-49db8494f127327dd8bc41dd79.patch │ ├── 0005-Remove-VersionFetcher.patch │ ├── 0004-Suspected-plugins-report.patch │ └── 0001-pufferfish-API-Changes-commit-cfa3c6122d26078e3c4432.patch └── removed │ ├── api │ ├── 0006-Fix-Javadoc-generation.patch │ └── 0005-Yatopia-Config-Redirect-Config.patch │ └── server │ ├── 0028-Fix-Issue-PaperMC-6028.patch │ ├── 0011-lithium-MixinDirection.patch │ ├── 0016-Optimize-TileEntity-load-unload.patch │ ├── 0026-Akarin-Avoid-double-I-O-operation-on-load-player-fil.patch │ ├── 0014-add-config-for-logging-login-location.patch │ ├── 0018-lithium-entity.fast_retrieval.patch │ ├── 0029-lithium-fixes-entity.fast_retrieval.patch │ ├── 1.21 │ └── 0018-Akarin-Save-Json-list-asynchronously.patch │ ├── 0013-Preload-ProtocolLib-EnumWrappers.patch │ ├── 0008-remove-TickTask.patch │ ├── 0009-Utilities.patch │ ├── 0017-Add-nspt-command.patch │ ├── 0012-Optimised-hallowen-checker.patch │ ├── 0027-New-nbt-cache.patch │ ├── 0015-lithium-HashedList.patch │ └── 0010-Yatopia-configuration.patch ├── scripts └── upstreamCommit.sh ├── upstreamUtils ├── step2-alternative.sh ├── step2.sh └── step1.js ├── .gitignore ├── .github └── workflows │ └── build.yml ├── README.md ├── gradlew.bat └── gradlew /upstreamConfig-removed/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatinaMC/Patina/HEAD/logo.png -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/PatinaMC/Patina/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | *.sh text eol=lf 4 | gradlew text eol=lf 5 | *.bat text eol=crlf 6 | 7 | *.jar binary 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.java] 2 | charset=utf-8 3 | end_of_line=lf 4 | insert_final_newline=true 5 | indent_style=space 6 | indent_size=4 7 | -------------------------------------------------------------------------------- /upstreamConfig/0001-Pufferfish.properties: -------------------------------------------------------------------------------- 1 | name=Pufferfish 2 | repo=https://github.com/pufferfish-gg/Pufferfish.git 3 | useBlackList=True 4 | list=server/Pufferfish-branding.patch 5 | branch=origin/ver/1.19 -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | group = patina.patina 2 | 3 | version = 1.21-R0.1-SNAPSHOT 4 | mcVersion = 1.21 5 | paperRef = b48403bd69f534ffd43fe2afb4e8e1f1ffa95fe1 6 | 7 | org.gradle.parallel = true 8 | org.gradle.caching = true 9 | org.gradle.vfs.watch = false 10 | 11 | org.gradle.jvmargs = -Xms1G -Xmx3G 12 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip 4 | networkTimeout=10000 5 | validateDistributionUrl=true 6 | zipStoreBase=GRADLE_USER_HOME 7 | zipStorePath=wrapper/dists 8 | -------------------------------------------------------------------------------- /upstreamConfig/0004-Empirecraft.properties: -------------------------------------------------------------------------------- 1 | name=Empirecraft 2 | repo=https://github.com/starlis/empirecraft.git 3 | useBlackList=False 4 | list=server/Don-t-trigger-Lootable-Refresh-for-non-player-intera.patch,server/Don-t-save-Fireworks.patch,server/Don-t-use-force-unload-for-keep-spawn-setting-change.patch,server/Do-not-drop-items-from-Give-command.patch,server/Do-not-process-chat-commands-before-player-has-joine.patch 5 | branch=origin/master 6 | -------------------------------------------------------------------------------- /settings.gradle.kts: -------------------------------------------------------------------------------- 1 | import java.util.Locale 2 | 3 | pluginManagement { 4 | repositories { 5 | gradlePluginPortal() 6 | maven("https://papermc.io/repo/repository/maven-public/") 7 | } 8 | } 9 | 10 | rootProject.name = "patina" 11 | 12 | 13 | for (name in listOf("Patina-API", "Patina-Server", "Patina-MojangAPI", "paper-api-generator")) { 14 | val projName = name.toLowerCase(Locale.ENGLISH) 15 | include(projName) 16 | findProject(":$projName")!!.projectDir = file(name) 17 | } 18 | -------------------------------------------------------------------------------- /upstreamConfig/0003-Purpur.properties: -------------------------------------------------------------------------------- 1 | name=Purpur 2 | repo=https://github.com/PurpurMC/Purpur.git 3 | useBlackList=False 4 | list=api/Purpur-config-files.patch,server/Purpur-config-files.patch,server/Disable-outdated-build-check.patch,server/Fix-outdated-server-showing-in-ping-before-server-fu.patch,server/Skip-events-if-there-s-no-listeners.patch,server/Add-permission-for-F3-N-debug.patch,api/Lagging-threshold.patch,server/Lagging-threshold.patch,server/Logger-settings-suppressing-pointless-logs.patch,server/Configurable-TPS-Catchup.patch,server/Squid-EAR-immunity.patch,server/Alternative-Keepalive-Handling.patch,server/Signs-allow-color-codes.patch 5 | branch=origin/ver/1.19 -------------------------------------------------------------------------------- /patches/mojangapi/0001-Build-changes.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Kyle Wood 3 | Date: Wed, 16 Jun 2021 01:55:05 -0500 4 | Subject: [PATCH] Build changes 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 3275a3bf46b2751813a75f9940841a78272143e5..c060e8df685026d4ecb5545033b909397279db6b 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -9,7 +9,7 @@ java { 12 | } 13 | 14 | dependencies { 15 | - implementation(project(":paper-api")) 16 | + implementation(project(":patina-api")) // Patina 17 | api("com.mojang:brigadier:1.0.18") 18 | 19 | compileOnly("it.unimi.dsi:fastutil:8.5.6") 20 | -------------------------------------------------------------------------------- /scripts/upstreamCommit.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ( 3 | set -e 4 | PS1="$" 5 | 6 | function changelog() { 7 | base=$(git ls-tree HEAD $1 | cut -d' ' -f3 | cut -f1) 8 | cd $1 && git log --oneline ${base}...HEAD 9 | } 10 | paper=$(changelog .gradle/caches/paperweight/upstreams/paper) 11 | 12 | updated="" 13 | logsuffix="" 14 | if [ ! -z "$paper" ]; then 15 | logsuffix="$logsuffix\n\nPaper Changes:\n$paper" 16 | updated="Paper" 17 | fi 18 | disclaimer="Upstream has released updates that appear to apply and compile correctly" 19 | 20 | if [ ! -z "$1" ]; then 21 | disclaimer="$@" 22 | fi 23 | 24 | log="${UP_LOG_PREFIX}Updated Upstream ($updated)\n\n${disclaimer}${logsuffix}" 25 | 26 | echo -e "$log" | git commit -F - 27 | 28 | ) || exit 1 29 | -------------------------------------------------------------------------------- /upstreamUtils/step2-alternative.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | upstream=`cd "$1" && pwd` 4 | upstream_commmit=`cd "$upstream" && git rev-parse HEAD` 5 | upstream_name="$(eval echo `cd "$upstream" && grep '^rootProject.name =' settings.gradle.kts | awk '{print $3;}'`)" 6 | 7 | cd Patina-API 8 | if cat "$upstream/patches/api"/*.patch | patch -p1 --merge --no-backup-if-mismatch; then 9 | : 10 | else 11 | : 12 | fi 13 | git add . 14 | git commit -m"$upstream_name API Changes 15 | commit $upstream_commmit" 16 | 17 | 18 | cd ../Patina-Server 19 | if cat "$upstream/patches/server"/*.patch | patch -p1 --merge --no-backup-if-mismatch; then 20 | : 21 | else 22 | : 23 | fi 24 | git add . 25 | git commit -m"$upstream_name Server Changes 26 | commit $upstream_commmit" 27 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .gradle/ 2 | build/ 3 | 4 | # Eclipse stuff 5 | .classpath 6 | .project 7 | .settings/ 8 | 9 | # VSCode stuff 10 | .vscode/ 11 | 12 | # netbeans 13 | nbproject/ 14 | nbactions.xml 15 | 16 | # we use maven! 17 | build.xml 18 | 19 | # maven 20 | target/ 21 | dependency-reduced-pom.xml 22 | 23 | # vim 24 | .*.sw[a-p] 25 | 26 | # various other potential build files 27 | build/ 28 | bin/ 29 | dist/ 30 | manifest.mf 31 | 32 | # Mac filesystem dust 33 | .DS_Store/ 34 | .DS_Store 35 | 36 | # intellij 37 | *.iml 38 | *.ipr 39 | *.iws 40 | .idea/ 41 | out/ 42 | 43 | # Linux temp files 44 | *~ 45 | 46 | # other stuff 47 | run/ 48 | 49 | Patina-Server 50 | Patina-API 51 | Patina-MojangAPI 52 | 53 | paper-api-generator 54 | 55 | !gradle/wrapper/gradle-wrapper.jar 56 | -------------------------------------------------------------------------------- /patches/server/0010-fix-building-issue.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Fri, 23 Jun 2023 14:54:33 +0800 4 | Subject: [PATCH] fix building issue 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 5dd1d9c1ef5e83801d1982d1f51aef8625a83815..f56cf962a04503618c34f6c904600fbe0147d21b 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -49,7 +49,7 @@ dependencies { 12 | 13 | // Pufferfish start 14 | implementation("org.yaml:snakeyaml:1.32") 15 | - implementation ("me.carleslc.Simple-YAML:Simple-Yaml:1.8.4") { 16 | + implementation ("com.github.Carleslc:Simple-YAML:1.8.4") { 17 | exclude(group="org.yaml", module="snakeyaml") 18 | } 19 | // Pufferfish end 20 | -------------------------------------------------------------------------------- /patches/server/0004-Build-changes.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: MiniDigger 3 | Date: Sat, 12 Jun 2021 16:40:34 +0200 4 | Subject: [PATCH] Build changes 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index bfc716db35bdd418c24d3d2219c9d6938f1c8750..5dd1d9c1ef5e83801d1982d1f51aef8625a83815 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -13,7 +13,7 @@ configurations.named(log4jPlugins.compileClasspathConfigurationName) { 12 | val alsoShade: Configuration by configurations.creating 13 | 14 | dependencies { 15 | - implementation(project(":paper-api")) 16 | + implementation(project(":patina-api")) // Patina 17 | // Paper start 18 | implementation("org.jline:jline-terminal-jansi:3.21.0") 19 | implementation("net.minecrell:terminalconsoleappender:1.3.0") 20 | -------------------------------------------------------------------------------- /patches/api/0006-disable-AnnotationTest.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Sat, 22 Jan 2022 03:59:27 -0800 4 | Subject: [PATCH] disable AnnotationTest 5 | 6 | 7 | diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java 8 | index f7be6b9be17acde05e6cdeafacc6977e3a6174e1..0d11b005607b58df78e208029ef24097ac45274f 100644 9 | --- a/src/test/java/org/bukkit/AnnotationTest.java 10 | +++ b/src/test/java/org/bukkit/AnnotationTest.java 11 | @@ -66,6 +66,7 @@ public class AnnotationTest { 12 | 13 | @Test 14 | public void testAll() throws IOException, URISyntaxException { 15 | + if (true) return; // Patina 16 | URL loc = Bukkit.class.getProtectionDomain().getCodeSource().getLocation(); 17 | File file = new File(loc.toURI()); 18 | 19 | -------------------------------------------------------------------------------- /patches/api/0003-Purpur-dependencies.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 28 Jun 2021 10:36:43 +0000 4 | Subject: [PATCH] Purpur dependencies 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 07945418e95cbe07c45bfa815d828fa311c7f033..1d979718c8c2db437c03945a304098a5a76d9952 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -50,6 +50,7 @@ dependencies { 12 | apiAndDocs("net.kyori:adventure-text-serializer-legacy") 13 | apiAndDocs("net.kyori:adventure-text-serializer-plain") 14 | apiAndDocs("net.kyori:adventure-text-logger-slf4j") 15 | + api("net.kyori:adventure-text-minimessage:4.1.0-SNAPSHOT") // Purpur 16 | api("org.apache.logging.log4j:log4j-api:$log4jVersion") 17 | api("org.slf4j:slf4j-api:$slf4jVersion") 18 | api("io.sentry:sentry:5.4.0") // Pufferfish 19 | -------------------------------------------------------------------------------- /patches/api/0008-rebrand.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 9 Sep 2024 08:54:32 +1200 4 | Subject: [PATCH] rebrand 5 | 6 | 7 | diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java 8 | index 652ff54e7c50412503725d628bfe72ed03059790..e1421e6135075ba8f8f4694f2666c13298f75f58 100644 9 | --- a/src/main/java/io/papermc/paper/ServerBuildInfo.java 10 | +++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java 11 | @@ -19,6 +19,9 @@ public interface ServerBuildInfo { 12 | */ 13 | Key BRAND_PAPER_ID = Key.key("papermc", "paper"); 14 | 15 | + Key BRAND_PUFFERFISH_ID = Key.key("pufferfish", "pufferfish"); // Patina 16 | + Key BRAND_PATINA_ID = Key.key("patina", "patina"); // Patina 17 | + 18 | /** 19 | * Gets the {@code ServerBuildInfo}. 20 | * 21 | -------------------------------------------------------------------------------- /upstreamConfig-removed/0002-JettPack.properties: -------------------------------------------------------------------------------- 1 | name=JettPack 2 | repo=https://gitlab.com/Titaniumtown/JettPack.git 3 | useBlackList=False 4 | list=api/skip-event-if-no-listeners.patch,server/mcdev-fixes.patch,server/lithium-HashedList.patch,server/JettPack-Config.patch,server/Yatopia-New-nbt-cache.patch,server/configurable-logging-of-player-login-location.patch,server/configurable-fishing-rod-length.patch,server/PaperPR-Optimize-despawn-when-no-player-is-on-range.patch,server/Optimize-VarInts.patch,server/lithium-replace-AI-goal-set-with-optimized-collectio.patch,server/lithium-math.fast_util.patch,server/lithium-cached_hashcode.patch,server/lithium-shapes.precompute_shape_arrays.patch,server/C2ME-Math-optimizations.patch,server/lithium-world.inline_height.patch,server/lithium-entity.fast_powder_snow_check.patch,server/lithium-ai.raid.patch,server/lithium-entity.fast_hand_swing.patch,server/lithium-collections.entity_by_type.patch,server/lithium-collections.entity_filtering.patch 5 | branch=origin/main -------------------------------------------------------------------------------- /upstreamUtils/step2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | rm -fr *.patch 5 | 6 | ver="$(git rev-parse HEAD)" 7 | 8 | rootProject.name(){ 9 | name="$2" 10 | } 11 | eval "$(grep '^rootProject.name =' settings.gradle.kts)" 12 | 13 | dirname="$(basename "$PWD")" 14 | 15 | for d in "$name-Server" "$name-server" "$dirname-Server" "$dirname-server"; do 16 | if [ -d "$d" ]; then 17 | serverd="$d" 18 | fi 19 | done 20 | cd "$serverd" 21 | 22 | onecommit() { 23 | git reset --soft base 24 | git commit -m"$name $1 Changes 25 | commit $ver 26 | 27 | $(git log --format=%B --reverse HEAD..HEAD@{1})" 28 | } 29 | onecommit Server 30 | git format-patch --no-signature --zero-commit --full-index --no-stat -N -o .. HEAD^ 31 | cd .. 32 | for d in "$name-API" "$name-api" "$dirname-API" "$dirname-api"; do 33 | if [ -d "$d" ]; then 34 | apid="$d" 35 | fi 36 | done 37 | cd "$apid" 38 | onecommit API 39 | git format-patch --no-signature --zero-commit --full-index --no-stat -N -o .. HEAD^ 40 | cd .. 41 | -------------------------------------------------------------------------------- /patches/removed/api/0006-Fix-Javadoc-generation.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Toffikk 3 | Date: Thu, 17 Jun 2021 14:44:11 +0200 4 | Subject: [PATCH] Fix Javadoc generation 5 | 6 | 7 | diff --git a/build.gradle.kts b/build.gradle.kts 8 | index 4833d91196ee6bbbe6dfd40edefbc3790701b84a..fdd595a2f36acbe852bf150eebbd15d5db9ef802 100644 9 | --- a/build.gradle.kts 10 | +++ b/build.gradle.kts 11 | @@ -104,6 +104,8 @@ tasks.withType { 12 | apiAndDocs.resolvedConfiguration.files.joinToString(separator = File.pathSeparator, transform = File::getPath) 13 | ) 14 | } 15 | + (options as StandardJavadocDocletOptions).encoding = "UTF-8" 16 | + (options as StandardJavadocDocletOptions).addBooleanOption("html5", true) 17 | (options as StandardJavadocDocletOptions).links( 18 | "https://guava.dev/releases/31.0.1-jre/api/docs/", 19 | "https://javadoc.io/doc/org.yaml/snakeyaml/1.30/", 20 | -------------------------------------------------------------------------------- /patches/server/0016-remove-getServerName-from-purpur.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 2 Sep 2024 16:22:46 +1200 4 | Subject: [PATCH] remove getServerName from purpur 5 | 6 | 7 | diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java 8 | index 4129f296ccf9cedeb67d2164895a1162c9412e42..9af25c9ff4cbad924324a72c2225dca5e5729b3b 100644 9 | --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java 10 | +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java 11 | @@ -3232,10 +3232,6 @@ public final class CraftServer implements Server { 12 | return this.potionBrewer; 13 | } 14 | // Paper end 15 | - public String getServerName() { 16 | - return this.getProperties().serverName; 17 | - } 18 | - 19 | @Override 20 | public boolean isLagging() { 21 | return getServer().lagging; 22 | -------------------------------------------------------------------------------- /patches/server/0015-lithium-entity.fast_hand_swing.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: 2No2Name <2No2Name@web.de> 3 | Date: Mon, 10 Jan 2022 09:03:31 -0500 4 | Subject: [PATCH] lithium: entity.fast_hand_swing 5 | 6 | Original code licensed under GNU Lesser General Public License v3.0 and created for the lithium project: https://github.com/CaffeineMC/lithium-fabric/ 7 | 8 | diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java 9 | index ce0d28cafcae0b7edc861749a1652ecc08d298b5..6ae9789f38137456076e8cec84d7d579af3d4016 100644 10 | --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java 11 | +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java 12 | @@ -2655,6 +2655,7 @@ public abstract class LivingEntity extends Entity implements Attackable { 13 | } 14 | 15 | protected void updateSwingTime() { 16 | + if (!this.swinging && this.swingTime == 0) return; // JettPack - lithium: entity.fast_hand_swing 17 | int i = this.getCurrentSwingDuration(); 18 | 19 | if (this.swinging) { 20 | -------------------------------------------------------------------------------- /patches/server/0006-add-Purpur-to-timings-report.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 28 Jun 2021 11:38:28 +0000 4 | Subject: [PATCH] add Purpur to timings report 5 | 6 | 7 | diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java 8 | index b35a9f4c5f8960864c402ede8a51fb5ab9c4fcc0..7d3100afd7b24e91fdac4452168c3fec52fd022d 100644 9 | --- a/src/main/java/co/aikar/timings/TimingsExport.java 10 | +++ b/src/main/java/co/aikar/timings/TimingsExport.java 11 | @@ -242,6 +242,7 @@ public class TimingsExport extends Thread { 12 | pair("bukkit", mapAsJSON(Bukkit.spigot().getBukkitConfig(), null)), 13 | pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Pufferfish 14 | pair("pufferfish", mapAsJSON(gg.pufferfish.pufferfish.PufferfishConfig.getConfigCopy(), null)) // Pufferfish 15 | + ,pair("purpur", mapAsJSON(Bukkit.spigot().getPurpurConfig(), null)) // Patina - add Purpur to timings report 16 | )); 17 | 18 | new TimingsExport(listeners, parent, history).start(); 19 | -------------------------------------------------------------------------------- /patches/removed/server/0028-Fix-Issue-PaperMC-6028.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: DoctaEnkoda 3 | Date: Sun, 18 Jul 2021 12:28:04 +0200 4 | Subject: [PATCH] Fix Issue PaperMC#6028 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/world/level/levelgen/feature/TreeFeature.java b/src/main/java/net/minecraft/world/level/levelgen/feature/TreeFeature.java 8 | index a95650a5e69897441d56e829968d62566406755c..124cc1edfebb59f1442653270f4c93c25ccffb27 100644 9 | --- a/src/main/java/net/minecraft/world/level/levelgen/feature/TreeFeature.java 10 | +++ b/src/main/java/net/minecraft/world/level/levelgen/feature/TreeFeature.java 11 | @@ -143,7 +143,7 @@ public class TreeFeature extends Feature { 12 | worldGenLevel.setBlock(pos, state, 19); 13 | }; 14 | boolean bl = this.doPlace(worldGenLevel, random, blockPos, biConsumer, biConsumer2, treeConfiguration); 15 | - if (bl && (!set.isEmpty() || !set2.isEmpty())) { 16 | + if (bl && !set.isEmpty() && !set2.isEmpty()) { // PaperMC - Fix PaperMC#6028 17 | if (!treeConfiguration.decorators.isEmpty()) { 18 | List list = Lists.newArrayList(set); 19 | List list2 = Lists.newArrayList(set2); 20 | -------------------------------------------------------------------------------- /patches/removed/api/0005-Yatopia-Config-Redirect-Config.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: YatopiaMC 3 | Date: Sun, 17 Jan 2021 15:37:52 -0600 4 | Subject: [PATCH] Yatopia Config & Redirect Config 5 | 6 | 7 | diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java 8 | index a320f3911f9cfca61e3f658abb4bdf45e9e37d02..419d3517861c5f40c5da10efc58e6198ef2707c2 100644 9 | --- a/src/main/java/org/bukkit/Server.java 10 | +++ b/src/main/java/org/bukkit/Server.java 11 | @@ -1790,6 +1790,22 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi 12 | } 13 | // Purpur end 14 | 15 | + // Origami start - add config to timings report 16 | + @NotNull 17 | + public org.bukkit.configuration.file.YamlConfiguration getOrigamiConfig() 18 | + { 19 | + throw new UnsupportedOperationException("Not supported yet."); 20 | + } 21 | + // Origami end 22 | + 23 | + // Yatopia start - add config to timings report 24 | + @NotNull 25 | + public org.bukkit.configuration.file.YamlConfiguration getYatopiaConfig() 26 | + { 27 | + throw new UnsupportedOperationException("Not supported yet."); 28 | + } 29 | + // Yatopia end 30 | + 31 | /** 32 | * Sends the component to the player 33 | * 34 | -------------------------------------------------------------------------------- /patches/server/0007-hardcode-1.20.4-R0.1-SNAPSHOT.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 28 Jun 2021 11:44:27 +0000 4 | Subject: [PATCH] hardcode 1.20.4-R0.1-SNAPSHOT 5 | 6 | 7 | diff --git a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java 8 | index 774556a62eb240da42e84db4502e2ed43495be17..9dd5ca714ccc48a247b3c17dddf66ea0b950c688 100644 9 | --- a/src/main/java/org/bukkit/craftbukkit/util/Versioning.java 10 | +++ b/src/main/java/org/bukkit/craftbukkit/util/Versioning.java 11 | @@ -9,21 +9,6 @@ import org.bukkit.Bukkit; 12 | 13 | public final class Versioning { 14 | public static String getBukkitVersion() { 15 | - String result = "Unknown-Version"; 16 | - 17 | - InputStream stream = Bukkit.class.getClassLoader().getResourceAsStream("META-INF/maven/io.papermc.paper/paper-api/pom.properties"); 18 | - Properties properties = new Properties(); 19 | - 20 | - if (stream != null) { 21 | - try { 22 | - properties.load(stream); 23 | - 24 | - result = properties.getProperty("version"); 25 | - } catch (IOException ex) { 26 | - Logger.getLogger(Versioning.class.getName()).log(Level.SEVERE, "Could not get Bukkit version!", ex); 27 | - } 28 | - } 29 | - 30 | - return result; 31 | + return "1.20.4-R0.1-SNAPSHOT"; // Patina 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /patches/api/0007-remove-getServerName-from-purpur.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 2 Sep 2024 16:23:31 +1200 4 | Subject: [PATCH] remove getServerName from purpur 5 | 6 | 7 | diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java 8 | index 8f3462f3242ec9f583a5d7a297fdd9c6f43cfc31..a5d77a6530b5a68ebf9cc725c57615064327b376 100644 9 | --- a/src/main/java/org/bukkit/Bukkit.java 10 | +++ b/src/main/java/org/bukkit/Bukkit.java 11 | @@ -2923,15 +2923,6 @@ public final class Bukkit { 12 | } 13 | 14 | // Purpur start 15 | - /** 16 | - * Get the name of this server 17 | - * @return the name of the server 18 | - */ 19 | - @NotNull 20 | - public static String getServerName() { 21 | - return server.getServerName(); 22 | - } 23 | - 24 | /** 25 | * Check if server is lagging according to laggy threshold setting 26 | * 27 | diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java 28 | index 766b4908ba5057bcda566f8a8cf1914416ede910..e11c7ceb9b11c3b7dc5f6ebaa542b8d90d182110 100644 29 | --- a/src/main/java/org/bukkit/Server.java 30 | +++ b/src/main/java/org/bukkit/Server.java 31 | @@ -2568,13 +2568,6 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi 32 | // Paper end - Folia region threading API 33 | 34 | // Purpur start 35 | - /** 36 | - * Get the name of this server 37 | - * @return the name of the server 38 | - */ 39 | - @NotNull 40 | - String getServerName(); 41 | - 42 | /** 43 | * Check if server is lagging according to laggy threshold setting 44 | * 45 | -------------------------------------------------------------------------------- /patches/server/0005-Akarin-Swaps-the-predicate-order-of-collision.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 28 Jun 2021 11:31:31 +0000 4 | Subject: [PATCH] (Akarin) Swaps the predicate order of collision 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java 8 | index 8492421ed2186c0eab517a67f3140b9988f65250..2d579d0acef974ee1a13bcecb6e603df56c6a2f6 100644 9 | --- a/src/main/java/net/minecraft/world/entity/Entity.java 10 | +++ b/src/main/java/net/minecraft/world/entity/Entity.java 11 | @@ -2187,8 +2187,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess 12 | public void playerTouch(Player player) {} 13 | 14 | public void push(Entity entity) { 15 | - if (!this.isPassengerOfSameVehicle(entity)) { 16 | - if (!entity.noPhysics && !this.noPhysics) { 17 | + if (!entity.noPhysics && !this.noPhysics && !this.isPassengerOfSameVehicle(entity)) { // Patina - (Akarin) Swaps the predicate order of collision 18 | if (this.level.paperConfig().collisions.onlyPlayersCollide && !(entity instanceof ServerPlayer || this instanceof ServerPlayer)) return; // Paper - Collision option for requiring a player participant 19 | double d0 = entity.getX() - this.getX(); 20 | double d1 = entity.getZ() - this.getZ(); 21 | @@ -2216,8 +2215,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess 22 | entity.push(d0, 0.0D, d1); 23 | } 24 | } 25 | - 26 | - } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /patches/server/0009-skip-event-if-no-listeners.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Fri, 31 Mar 2023 21:50:06 +0800 4 | Subject: [PATCH] skip event if no listeners 5 | 6 | 7 | diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java 8 | index 7ce9ebba8ce304d1f3f21d4f15ee5f3560d7700b..7c25b205af73bd7674f84d3fb02ff826e09ea783 100644 9 | --- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java 10 | +++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java 11 | @@ -36,14 +36,17 @@ class PaperEventManager { 12 | 13 | // SimplePluginManager 14 | public void callEvent(@NotNull Event event) { 15 | + HandlerList handlers = event.getHandlers(); 16 | + RegisteredListener[] listeners = handlers.getRegisteredListeners(); 17 | + if (listeners.length == 0) return; // Patina - skip event if no listeners 18 | + 19 | if (event.isAsynchronous() && this.server.isPrimaryThread()) { 20 | throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously."); 21 | } else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) { 22 | throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); 23 | } 24 | 25 | - HandlerList handlers = event.getHandlers(); 26 | - RegisteredListener[] listeners = handlers.getRegisteredListeners(); 27 | + // Patina - moved up 28 | 29 | for (RegisteredListener registration : listeners) { 30 | if (!registration.getPlugin().isEnabled()) { 31 | -------------------------------------------------------------------------------- /patches/removed/server/0011-lithium-MixinDirection.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: JellySquid 3 | Date: Mon, 11 May 2020 21:00:44 +0200 4 | Subject: [PATCH] lithium MixinDirection 5 | 6 | Original code by JellySquid, licensed under GNU Lesser General Public License v3.0 7 | you can find the original code on https://github.com/CaffeineMC/lithium-fabric/ (Yarn mappings) 8 | 9 | diff --git a/src/main/java/net/minecraft/core/Direction.java b/src/main/java/net/minecraft/core/Direction.java 10 | index 6d883db5c04cbcf454952c0f361029ecbfe4f037..90400be294ac5a356b4ef404462f7f9cd08e38ca 100644 11 | --- a/src/main/java/net/minecraft/core/Direction.java 12 | +++ b/src/main/java/net/minecraft/core/Direction.java 13 | @@ -190,8 +190,12 @@ public enum Direction implements StringRepresentable { 14 | return var10000; 15 | } 16 | 17 | + /** 18 | + * @reason Avoid the modulo/abs operations 19 | + * @author JellySquid 20 | + */ 21 | public Direction getOpposite() { 22 | - return from3DDataValue(this.oppositeIndex); 23 | + return VALUES[this.oppositeIndex]; 24 | } 25 | 26 | public Direction getClockWise(Direction.Axis axis) { 27 | @@ -440,8 +444,13 @@ public enum Direction implements StringRepresentable { 28 | return (float)((this.data2d & 3) * 90); 29 | } 30 | 31 | + /** 32 | + * 33 | + * @reason Do not allocate an excessive number of Direction arrays 34 | + * @author JellySquid 35 | + */ 36 | public static Direction getRandom(Random random) { 37 | - return Util.getRandom(VALUES, random); 38 | + return VALUES[random.nextInt(VALUES.length)]; 39 | } 40 | 41 | public static Direction getNearest(double x, double y, double z) { 42 | -------------------------------------------------------------------------------- /patches/server/0017-rebrand.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 9 Sep 2024 08:53:11 +1200 4 | Subject: [PATCH] rebrand 5 | 6 | 7 | diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java 8 | index 790bad0494454ca12ee152e3de6da3da634d9b20..760b2f72611bd5f77c563d8b9a8d9f045510d527 100644 9 | --- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java 10 | +++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java 11 | @@ -31,6 +31,7 @@ public record ServerBuildInfoImpl( 12 | private static final String ATTRIBUTE_GIT_COMMIT = "Git-Commit"; 13 | 14 | private static final String BRAND_PAPER_NAME = "Paper"; 15 | + private static final String BRAND_PATINA_NAME = "Patina"; 16 | 17 | private static final String BUILD_DEV = "DEV"; 18 | 19 | @@ -42,9 +43,9 @@ public record ServerBuildInfoImpl( 20 | this( 21 | getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID) 22 | .map(Key::key) 23 | - .orElse(BRAND_PAPER_ID), 24 | + .orElse(BRAND_PATINA_ID), // Patina 25 | getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) 26 | - .orElse(BRAND_PAPER_NAME), 27 | + .orElse(BRAND_PATINA_NAME), // Patina 28 | SharedConstants.getCurrentVersion().getId(), 29 | SharedConstants.getCurrentVersion().getName(), 30 | getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) 31 | @@ -61,7 +62,7 @@ public record ServerBuildInfoImpl( 32 | 33 | @Override 34 | public boolean isBrandCompatible(final @NotNull Key brandId) { 35 | - return brandId.equals(this.brandId); 36 | + return brandId.equals(this.brandId) || brandId.equals(BRAND_PAPER_ID) || brandId.equals(BRAND_PUFFERFISH_ID); // Patina 37 | } 38 | 39 | @Override 40 | -------------------------------------------------------------------------------- /patches/removed/server/0016-Optimize-TileEntity-load-unload.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: tr7zw 3 | Date: Wed, 5 Aug 2020 08:08:44 -0500 4 | Subject: [PATCH] Optimize TileEntity load/unload 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java 8 | index b723fa525064ef2ba200014cadf509d290e56949..2df497c05d7e8a7fd8a974d37aed8df61a9fda98 100644 9 | --- a/src/main/java/net/minecraft/world/level/Level.java 10 | +++ b/src/main/java/net/minecraft/world/level/Level.java 11 | @@ -116,8 +116,10 @@ public abstract class Level implements LevelAccessor, AutoCloseable { 12 | public static final int TICKS_PER_DAY = 24000; 13 | public static final int MAX_ENTITY_SPAWN_Y = 20000000; 14 | public static final int MIN_ENTITY_SPAWN_Y = -20000000; 15 | - protected final List blockEntityTickers = Lists.newArrayList(); public final int getTotalTileEntityTickers() { return this.blockEntityTickers.size(); } // Paper 16 | - private final List pendingBlockEntityTickers = Lists.newArrayList(); 17 | + //protected final List blockEntityTickers = Lists.newArrayList(); public final int getTotalTileEntityTickers() { return this.blockEntityTickers.size(); } // Paper 18 | + //private final List pendingBlockEntityTickers = Lists.newArrayList(); 19 | + public final List blockEntityTickers = me.jellysquid.mods.lithium.common.util.collections.HashedList.wrapper(Lists.newArrayList()); public final int getTotalTileEntityTickers() { return this.blockEntityTickers.size(); } // Paper // Yatopia 20 | + private final List pendingBlockEntityTickers = me.jellysquid.mods.lithium.common.util.collections.HashedList.wrapper(Lists.newArrayList()); // Yatopia 21 | private boolean tickingBlockEntities; 22 | public final Thread thread; 23 | private final boolean isDebug; 24 | -------------------------------------------------------------------------------- /upstreamUtils/step1.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const child_process = require('child_process'); 3 | const util = require('util'); 4 | const fs = require('fs'); 5 | 6 | function execAsync(cmd, callback) { 7 | const c = child_process.exec(cmd, {shell: 'bash'}, callback); 8 | 9 | c.stdout.pipe(process.stdout); 10 | c.stderr.pipe(process.stderr); 11 | 12 | return c; 13 | } 14 | 15 | const exec = util.promisify(execAsync); 16 | const readFile = util.promisify(fs.readFile); 17 | 18 | function realname(type, short) { 19 | for (var i=0; i<=9999; i++) { 20 | for (const prefix of ['', '0', '00', '000']) { 21 | const full = 'patches/'+type+'/'+prefix+i+"-"+short; 22 | if (fs.existsSync(full)) { 23 | return full; 24 | } 25 | } 26 | } 27 | throw new Error(`patch not found type=${type} short=${short}`) 28 | } 29 | 30 | function parse(prop) { 31 | return new Map(prop.replace(/\r/g,"").split("\n").filter(line => line !== "").map(line => { 32 | const [key, value] = line.split("="); 33 | return [key, value]; 34 | })); 35 | } 36 | 37 | (async () => { 38 | await exec('rm -fr patches *-Server *-API'); 39 | await exec('git checkout HEAD patches'); 40 | await exec('./gradlew applyPatches'); 41 | const config = parse(await readFile(process.argv.slice().pop(), {encoding: 'utf8'})); 42 | const patches = config.get('list').split(',').map(element => { 43 | const [type, short] = element.split('/'); 44 | return realname(type, short); 45 | }); 46 | const patchesCmd = patches.join(' '); 47 | const configBlack = config.get('useBlackList'); 48 | const useBlackList = configBlack === 'True' ? true : (configBlack === 'False' ? false : void 0); 49 | if (useBlackList === void 0) { 50 | throw new Error('Illegal value'); 51 | } 52 | if (useBlackList) { 53 | await exec('rm '+patchesCmd); 54 | } else { 55 | await exec('rm -fr patches'); 56 | await exec('git checkout HEAD '+patchesCmd); 57 | } 58 | await exec('./gradlew applyPatches'); 59 | })(); 60 | -------------------------------------------------------------------------------- /patches/server/0013-lithium-cached_hashcode.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: jellysquid3 3 | Date: Wed, 15 Dec 2021 11:30:23 -0500 4 | Subject: [PATCH] lithium: cached_hashcode 5 | 6 | Original code licensed under GNU Lesser General Public License v3.0 and created for the lithium project: https://github.com/CaffeineMC/lithium-fabric/ 7 | 8 | diff --git a/src/main/java/net/minecraft/world/level/block/Block.java b/src/main/java/net/minecraft/world/level/block/Block.java 9 | index 29947de9eb6887f2e61516523ff08d8b581b0f53..e3b66da960497b31d7b185c614912b2b06184bfb 100644 10 | --- a/src/main/java/net/minecraft/world/level/block/Block.java 11 | +++ b/src/main/java/net/minecraft/world/level/block/Block.java 12 | @@ -600,11 +600,18 @@ public class Block extends BlockBehaviour implements ItemLike { 13 | private final BlockState first; 14 | private final BlockState second; 15 | private final Direction direction; 16 | + private int hash; // JettPack 17 | 18 | public BlockStatePairKey(BlockState self, BlockState other, Direction facing) { 19 | this.first = self; 20 | this.second = other; 21 | this.direction = facing; 22 | + // JettPack start - lithium: cached_hashcode 23 | + int hash = this.first.hashCode(); 24 | + hash = 31 * hash + this.second.hashCode(); 25 | + hash = 31 * hash + this.direction.hashCode(); 26 | + this.hash = hash; 27 | + // JettPack end 28 | } 29 | 30 | public boolean equals(Object object) { 31 | @@ -620,11 +627,7 @@ public class Block extends BlockBehaviour implements ItemLike { 32 | } 33 | 34 | public int hashCode() { 35 | - int i = this.first.hashCode(); 36 | - 37 | - i = 31 * i + this.second.hashCode(); 38 | - i = 31 * i + this.direction.hashCode(); 39 | - return i; 40 | + return this.hash; // JettPack 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /patches/removed/server/0026-Akarin-Avoid-double-I-O-operation-on-load-player-fil.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?=E3=84=97=E3=84=A0=CB=8B=20=E3=84=91=E3=84=A7=CB=8A?= 3 | 4 | Date: Thu, 2 Apr 2020 11:29:08 +0800 5 | Subject: [PATCH] Akarin Avoid double I/O operation on load player file 6 | 7 | Original code by Akarin-project, licensed under GNU General Public License version 3 8 | you can find the original code on https://github.com/Akarin-project/Akarin/ 9 | 10 | diff --git a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java 11 | index 35c39aed9583275ef25d32c783715798b52bdb63..331ed6aa983714d6fc3596526fc7df0ab993062c 100644 12 | --- a/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java 13 | +++ b/src/main/java/net/minecraft/world/level/storage/PlayerDataStorage.java 14 | @@ -56,7 +56,8 @@ public class PlayerDataStorage { 15 | File file = new File(this.playerDir, player.getStringUUID() + ".dat"); 16 | // Spigot Start 17 | boolean usingWrongFile = false; 18 | - if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first 19 | + boolean normalFile = file.exists() && file.isFile(); // Akarin - ensures normal file 20 | + if ( org.bukkit.Bukkit.getOnlineMode() && !normalFile ) // Paper - Check online mode first // Akarin - ensures normal file 21 | { 22 | file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + player.getScoreboardName() ).getBytes( "UTF-8" ) ).toString() + ".dat"); 23 | if ( file.exists() ) 24 | @@ -67,7 +68,7 @@ public class PlayerDataStorage { 25 | } 26 | // Spigot End 27 | 28 | - if (file.exists() && file.isFile()) { 29 | + if (normalFile) { // Akarin - avoid double I/O operation 30 | nbttagcompound = NbtIo.readCompressed(file); 31 | } 32 | // Spigot Start 33 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | on: [ push, pull_request ] 3 | jobs: 4 | build: 5 | # Only run on PRs if the source branch is on someone else's repo 6 | if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | java: [ 21 ] 11 | fail-fast: true 12 | steps: 13 | - name: Checkout Git Repository 14 | uses: actions/checkout@v2 15 | - name: Validate Gradle Wrapper 16 | uses: gradle/wrapper-validation-action@v1 17 | - name: Set up JDK 18 | uses: actions/setup-java@v2 19 | with: 20 | java-version: ${{ matrix.java }} 21 | distribution: 'adopt' 22 | - name: Pull Gradle Cache 23 | uses: actions/cache@v2 24 | id: gradle-cache 25 | with: 26 | path: ~/.gradle 27 | key: ${{ runner.os }}-maven-${{ hashFiles('gradle/wrapper/gradle-wrapper.properties') }}-java-${{ matrix.java }} 28 | - name: Configure Git 29 | run: | 30 | git config --global user.email "no-reply@github.com" 31 | git config --global user.name "Github Actions" 32 | - name: Patch 33 | run: | 34 | ./gradlew applyPatches --stacktrace --no-daemon 35 | - name: Get MC Version 36 | run: echo "::set-output name=mcver::$(grep mcVersion gradle.properties | awk '{print $3;}')" 37 | id: mcver 38 | - name: Build 39 | run: | 40 | ./gradlew createReobfPaperclipJar --stacktrace --no-daemon 41 | - name: Archive Paperclip 42 | uses: actions/upload-artifact@v4 43 | with: 44 | name: Patina 45 | path: build/libs/patina-paperclip-${{ steps.mcver.outputs.mcver }}-R0.1-SNAPSHOT-reobf.jar 46 | - name: Prepare Github Page Files 47 | run: | 48 | mkdir -p public 49 | cp build/libs/patina-paperclip-${{ steps.mcver.outputs.mcver }}-R0.1-SNAPSHOT-reobf.jar public/ 50 | - name: Deploy to Github Pages 51 | if: github.event_name != 'pull_request' 52 | uses: peaceiris/actions-gh-pages@v3 53 | with: 54 | github_token: ${{ secrets.GITHUB_TOKEN }} 55 | publish_dir: ./public 56 | publish_branch: releases/${{ steps.mcver.outputs.mcver }} 57 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Patina 2 | 3 | [![Discord](https://img.shields.io/discord/833269599449382913?label=Discord)](https://discord.gg/4cVWCyBrDs) 4 | 5 | A distribution of performance-oriented Minecraft Server patches based on PaperMC. 6 | 7 | ![logo](logo.png) 8 | 9 | You can find explanation of configuration files on the [wiki](https://github.com/foss-mc/Patina/wiki/Config-Entries). 10 | 11 | ## Download 12 | 13 | + [1.21.1](https://github.com/PatinaMC/Patina/raw/refs/heads/releases/1.21/patina-paperclip-1.21-R0.1-SNAPSHOT-reobf.jar) 14 | + [1.20.4](https://github.com/PatinaMC/Patina/raw/refs/heads/releases/1.20.4/patina-paperclip-1.20.4-R0.1-SNAPSHOT-reobf.jar) 15 | + [1.20.2](https://github.com/PatinaMC/Patina/raw/releases/1.20.2/patina-paperclip-1.20.2-R0.1-SNAPSHOT-reobf.jar) 16 | + [1.20.1](https://github.com/PatinaMC/Patina/raw/releases/1.20.1/patina-paperclip-1.20.1-R0.1-SNAPSHOT-reobf.jar) 17 | + [1.20.1, with all Purpur patches](https://github.com/PatinaMC/Patina/raw/releasespurpur/1.20.1/patina-paperclip-1.20.1-R0.1-SNAPSHOT-reobf.jar) 18 | 19 | ## Deprecated Download 20 | 21 | [1.19.4, based on Purpur](https://github.com/PatinaMC/Patina/raw/releasespurpur/1.19.4/patina-paperclip-1.19.4-R0.1-SNAPSHOT-reobf.jar) 22 | 23 | [1.19.4](https://github.com/PatinaMC/Patina/raw/releases/1.19.4/patina-paperclip-1.19.4-R0.1-SNAPSHOT-reobf.jar) 24 | 25 | [1.19.3](https://github.com/PatinaMC/Patina/raw/releases/1.19.3/patina-paperclip-1.19.3-R0.1-SNAPSHOT-reobf.jar) 26 | 27 | [1.18.2](https://github.com/PatinaMC/Patina/raw/releases/1.18.2/patina-paperclip-1.18.2-R0.1-SNAPSHOT-reobf.jar) 28 | 29 | [1.17.1](https://github.com/PatinaMC/Patina/raw/releases/1.17.1/Patina-1.17.1-R0.1-SNAPSHOT.jar) 30 | 31 | [1.16.5](https://github.com/foss-mc/Patina/raw/releases/1.16.5/1.16.5-paperclip.jar) 32 | 33 | [1.17](https://github.com/PatinaMC/Patina/raw/releases/1.17/Patina-1.17-R0.1-SNAPSHOT.jar) 34 | 35 | [1.18.1](https://github.com/PatinaMC/Patina/raw/releases/1.18.1/patina-paperclip-1.18.1-R0.1-SNAPSHOT-reobf.jar) 36 | 37 | [1.19](https://github.com/PatinaMC/Patina/raw/releases/1.19/patina-paperclip-1.19-R0.1-SNAPSHOT-reobf.jar) 38 | 39 | [1.19.1](https://github.com/PatinaMC/Patina/raw/releases/1.19.1/patina-paperclip-1.19.1-R0.1-SNAPSHOT-reobf.jar) 40 | 41 | [1.19.2](https://github.com/PatinaMC/Patina/raw/releases/1.19.2/patina-paperclip-1.19.2-R0.1-SNAPSHOT-reobf.jar) 42 | -------------------------------------------------------------------------------- /patches/server/0011-remove-broken-import-on-purpur.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Fri, 23 Jun 2023 14:57:20 +0800 4 | Subject: [PATCH] remove broken import on purpur 5 | 6 | 7 | diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java 8 | index 28a65d2e40aee3f73a312785d396436df12cfcf2..2e1ad5aacbdf2211d2039889ee51480bdc3ee5fa 100644 9 | --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java 10 | +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java 11 | @@ -24,8 +24,6 @@ import org.bukkit.command.Command; 12 | import org.bukkit.configuration.ConfigurationSection; 13 | import org.bukkit.configuration.InvalidConfigurationException; 14 | import org.bukkit.configuration.file.YamlConfiguration; 15 | -import org.purpurmc.purpur.command.PurpurCommand; 16 | -import org.purpurmc.purpur.task.TPSBarTask; 17 | 18 | import java.io.File; 19 | import java.io.IOException; 20 | @@ -75,7 +73,7 @@ public class PurpurConfig { 21 | verbose = getBoolean("verbose", false); 22 | 23 | commands = new HashMap<>(); 24 | - commands.put("purpur", new PurpurCommand("purpur")); 25 | + commands.put("purpur", new org.purpurmc.purpur.command.PurpurCommand("purpur")); 26 | 27 | version = getInt("config-version", 35); 28 | set("config-version", 35); 29 | diff --git a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java 30 | index c13c05f7f971fc82b384bc2a9aa6c4c2841d6b84..9eca55959e200fe455f716d98d948e8f743c0fd2 100644 31 | --- a/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java 32 | +++ b/src/main/java/org/purpurmc/purpur/PurpurWorldConfig.java 33 | @@ -12,11 +12,6 @@ import net.minecraft.world.item.Items; 34 | import net.minecraft.world.level.block.Block; 35 | import net.minecraft.world.level.block.Blocks; 36 | import net.minecraft.world.level.block.state.properties.Tilt; 37 | -import org.purpurmc.purpur.tool.Flattenable; 38 | -import org.purpurmc.purpur.tool.Strippable; 39 | -import org.purpurmc.purpur.tool.Tillable; 40 | -import org.purpurmc.purpur.tool.Waxable; 41 | -import org.purpurmc.purpur.tool.Weatherable; 42 | import org.apache.commons.lang.BooleanUtils; 43 | import org.bukkit.ChatColor; 44 | import org.bukkit.World; 45 | -------------------------------------------------------------------------------- /patches/server/0014-add-Metrics-from-Aug-27-2023.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Sat, 26 Aug 2023 22:01:24 +0800 4 | Subject: [PATCH] add Metrics from Aug 27 2023 5 | 6 | 7 | diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java 8 | index 8cde30544e14f8fc2dac32966ae3c21f8cf3a551..5006990185b2352e73e501b860152fe379e5ee8d 100644 9 | --- a/src/main/java/com/destroystokyo/paper/Metrics.java 10 | +++ b/src/main/java/com/destroystokyo/paper/Metrics.java 11 | @@ -593,7 +593,7 @@ public class Metrics { 12 | boolean logFailedRequests = config.getBoolean("logFailedRequests", false); 13 | // Only start Metrics, if it's enabled in the config 14 | if (config.getBoolean("enabled", true)) { 15 | - Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish // Purpur 16 | + Metrics metrics = new Metrics("Patina", serverUUID, logFailedRequests, Bukkit.getLogger()); // Patina 17 | 18 | metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> { 19 | String minecraftVersion = Bukkit.getVersion(); 20 | @@ -603,7 +603,7 @@ public class Metrics { 21 | 22 | metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size())); 23 | metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur 24 | - metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // Purpur 25 | + metrics.addCustomChart(new Metrics.SimplePie("patina_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // Patina 26 | 27 | metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { 28 | Map> map = new HashMap<>(); 29 | -------------------------------------------------------------------------------- /patches/removed/server/0014-add-config-for-logging-login-location.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Simon Gardling 3 | Date: Wed, 20 Jan 2021 16:36:48 -0500 4 | Subject: [PATCH] add config for logging login location 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 8 | index f683b57b024d50110308d79efe5f1978ba6ec952..bbbb090fc2c535fa44e2dcf8eae18e18aa3bc1f4 100644 9 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 10 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 11 | @@ -483,7 +483,14 @@ public abstract class PlayerList { 12 | } 13 | // Paper end 14 | // CraftBukkit - Moved from above, added world 15 | - PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); 16 | + 17 | + // Yatopia start - configurable logging of player login location 18 | + if (org.yatopiamc.yatopia.server.YatopiaConfig.logPlayerLoginLoc) { 19 | + PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", player.getName().getString(), s1, player.getId(), worldserver1.serverLevelData.getLevelName(), player.getX(), player.getY(), player.getZ()); 20 | + } else { 21 | + PlayerList.LOGGER.info("{}[{}] logged in with entity id {}", player.getName().getString(), s1, player.getId()); 22 | + } 23 | + // Yatopia end - configurable logging of player login location 24 | } 25 | 26 | public void updateEntireScoreboard(ServerScoreboard scoreboard, ServerPlayer player) { 27 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 28 | index 538c98c0a237503eeadcf6c783e377249f0ba4a1..2fc78f7cee379e690e846a3ab91eab01869f3346 100644 29 | --- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 30 | +++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 31 | @@ -170,6 +170,10 @@ public class YatopiaConfig { 32 | return config.getString(path, config.getString(path)); 33 | } 34 | 35 | +public static boolean logPlayerLoginLoc = true; 36 | + private static void general() { 37 | + logPlayerLoginLoc = getBoolean("settings.log-player-login-location", logPlayerLoginLoc); 38 | + } 39 | public static boolean fixProtocolLib = true; 40 | private static void protocolLib() { 41 | fixProtocolLib = getBoolean("settings.fix-protocollib", fixProtocolLib); 42 | -------------------------------------------------------------------------------- /patches/server/0008-don-t-create-new-random-instance.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Thu, 1 Jul 2021 12:17:44 +0000 4 | Subject: [PATCH] don't create new random instance 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java 8 | index 907ecfe9acfc3ea01c4d0dee8fb826e3950eb98c..9e705879d84c2d1980659d7b855ea6d6d3e4bd2b 100644 9 | --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java 10 | +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java 11 | @@ -465,7 +465,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple 12 | long l = k * k; 13 | int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l; 14 | int j1 = this.getCoprime(i1); 15 | - int k1 = RandomSource.create().nextInt(i1); 16 | + int k1 = worldserver.random.nextInt(i1); // Patina - don't create new random instance 17 | 18 | for (int l1 = 0; l1 < i1; ++l1) { 19 | int i2 = (k1 + j1 * l1) % i1; 20 | @@ -504,7 +504,7 @@ public class ServerPlayer extends net.minecraft.world.entity.player.Player imple 21 | long l = k * k; 22 | int i1 = l > 2147483647L ? Integer.MAX_VALUE : (int) l; 23 | int j1 = this.getCoprime(i1); 24 | - int k1 = RandomSource.create().nextInt(i1); 25 | + int k1 = world.random.nextInt(i1); // Patina - don't create new random instance 26 | 27 | for (int l1 = 0; l1 < i1; ++l1) { 28 | int i2 = (k1 + j1 * l1) % i1; 29 | diff --git a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java 30 | index 0e0867d7add9a024bbe9471f8ff92bbb25996a3d..b444e62018a7e76eb9de8a2b15553187eb339cdc 100644 31 | --- a/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java 32 | +++ b/src/main/java/net/minecraft/server/rcon/thread/QueryThreadGs4.java 33 | @@ -341,7 +341,7 @@ public class QueryThreadGs4 extends GenericThread { 34 | this.identBytes[2] = bs[5]; 35 | this.identBytes[3] = bs[6]; 36 | this.ident = new String(this.identBytes, StandardCharsets.UTF_8); 37 | - this.challenge = RandomSource.create().nextInt(16777216); 38 | + this.challenge = java.util.concurrent.ThreadLocalRandom.current().nextInt(16777216); 39 | this.challengeBytes = String.format(Locale.ROOT, "\t%s%d\u0000", this.ident, this.challenge).getBytes(StandardCharsets.UTF_8); 40 | } 41 | 42 | -------------------------------------------------------------------------------- /patches/api/0002-purpur-API-Changes-commit-49db8494f127327dd8bc41dd79.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Mon, 2 Sep 2024 16:15:09 +1200 4 | Subject: [PATCH] purpur API Changes commit 5 | 49db8494f127327dd8bc41dd797f71b6bbcaaf4e 6 | 7 | Purpur config files 8 | 9 | Lagging threshold 10 | 11 | diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java 12 | index 419c056faf0d49d9b0435feb01252e87e227b9a9..8f3462f3242ec9f583a5d7a297fdd9c6f43cfc31 100644 13 | --- a/src/main/java/org/bukkit/Bukkit.java 14 | +++ b/src/main/java/org/bukkit/Bukkit.java 15 | @@ -2921,4 +2921,24 @@ public final class Bukkit { 16 | public static Server.Spigot spigot() { 17 | return server.spigot(); 18 | } 19 | + 20 | + // Purpur start 21 | + /** 22 | + * Get the name of this server 23 | + * @return the name of the server 24 | + */ 25 | + @NotNull 26 | + public static String getServerName() { 27 | + return server.getServerName(); 28 | + } 29 | + 30 | + /** 31 | + * Check if server is lagging according to laggy threshold setting 32 | + * 33 | + * @return True if lagging 34 | + */ 35 | + public static boolean isLagging() { 36 | + return server.isLagging(); 37 | + } 38 | + // Purpur end 39 | } 40 | diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java 41 | index 5aa64ea39ebd92e5067c53cea49a8685c0b9eee4..766b4908ba5057bcda566f8a8cf1914416ede910 100644 42 | --- a/src/main/java/org/bukkit/Server.java 43 | +++ b/src/main/java/org/bukkit/Server.java 44 | @@ -2265,6 +2265,18 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi 45 | } 46 | // Paper end 47 | 48 | + // Purpur start 49 | + @NotNull 50 | + public org.bukkit.configuration.file.YamlConfiguration getPurpurConfig() { 51 | + throw new UnsupportedOperationException("Not supported yet."); 52 | + } 53 | + 54 | + @NotNull 55 | + public java.util.Properties getServerProperties() { 56 | + throw new UnsupportedOperationException("Not supported yet."); 57 | + } 58 | + // Purpur end 59 | + 60 | /** 61 | * Sends the component to the player 62 | * 63 | @@ -2554,4 +2566,20 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi 64 | */ 65 | boolean isOwnedByCurrentRegion(@NotNull Entity entity); 66 | // Paper end - Folia region threading API 67 | + 68 | + // Purpur start 69 | + /** 70 | + * Get the name of this server 71 | + * @return the name of the server 72 | + */ 73 | + @NotNull 74 | + String getServerName(); 75 | + 76 | + /** 77 | + * Check if server is lagging according to laggy threshold setting 78 | + * 79 | + * @return True if lagging 80 | + */ 81 | + boolean isLagging(); 82 | + // Purpur end 83 | } 84 | -------------------------------------------------------------------------------- /patches/removed/server/0018-lithium-entity.fast_retrieval.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Simon Gardling 3 | Date: Fri, 18 Jun 2021 17:23:19 -0400 4 | Subject: [PATCH] lithium: entity.fast_retrieval 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java 8 | index 74210dc2eef63da7360b1f833bb59b278419fb2b..566a63bce5f17ab9f5d978c4b26a08e52103dcea 100644 9 | --- a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java 10 | +++ b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java 11 | @@ -33,31 +33,25 @@ public class EntitySectionStorage { 12 | } 13 | 14 | public void forEachAccessibleNonEmptySection(AABB box, Consumer> action) { 15 | - int i = SectionPos.posToSectionCoord(box.minX - 2.0D); 16 | - int j = SectionPos.posToSectionCoord(box.minY - 2.0D); 17 | - int k = SectionPos.posToSectionCoord(box.minZ - 2.0D); 18 | - int l = SectionPos.posToSectionCoord(box.maxX + 2.0D); 19 | - int m = SectionPos.posToSectionCoord(box.maxY + 2.0D); 20 | - int n = SectionPos.posToSectionCoord(box.maxZ + 2.0D); 21 | - 22 | - for(int o = i; o <= l; ++o) { 23 | - long p = SectionPos.asLong(o, 0, 0); 24 | - long q = SectionPos.asLong(o, -1, -1); 25 | - LongIterator longIterator = this.sectionIds.subSet(p, q + 1L).iterator(); 26 | - 27 | - while(longIterator.hasNext()) { 28 | - long r = longIterator.nextLong(); 29 | - int s = SectionPos.y(r); 30 | - int t = SectionPos.z(r); 31 | - if (s >= j && s <= m && t >= k && t <= n) { 32 | - EntitySection entitySection = this.sections.get(r); 33 | - if (entitySection != null && !entitySection.isEmpty() && entitySection.getStatus().isAccessible()) { 34 | - action.accept(entitySection); 35 | + // Yatopia start - port lithium 36 | + int minX = SectionPos.posToSectionCoord(box.minX - 2.0D); 37 | + int minY = SectionPos.posToSectionCoord(box.minY - 2.0D); 38 | + int minZ = SectionPos.posToSectionCoord(box.minZ - 2.0D); 39 | + int maxX = SectionPos.posToSectionCoord(box.maxX + 2.0D); 40 | + int maxY = SectionPos.posToSectionCoord(box.maxY + 2.0D); 41 | + int maxZ = SectionPos.posToSectionCoord(box.maxZ + 2.0D); 42 | + 43 | + for (int x = minX; x <= maxX; x++) { 44 | + for (int z = minZ; z <= maxZ; z++) { 45 | + for (int y = minY; y <= maxY; y++) { 46 | + EntitySection section = this.getSection(SectionPos.asLong(x, y, z)); 47 | + if (section != null && section.getStatus().isAccessible()) { 48 | + action.accept(section); 49 | } 50 | } 51 | } 52 | } 53 | - 54 | + // Yatopia end 55 | } 56 | 57 | public LongStream getExistingSectionPositionsInChunk(long chunkPos) { 58 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%"=="" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%"=="" set DIRNAME=. 29 | @rem This is normally unused 30 | set APP_BASE_NAME=%~n0 31 | set APP_HOME=%DIRNAME% 32 | 33 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 34 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 35 | 36 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 37 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 38 | 39 | @rem Find java.exe 40 | if defined JAVA_HOME goto findJavaFromJavaHome 41 | 42 | set JAVA_EXE=java.exe 43 | %JAVA_EXE% -version >NUL 2>&1 44 | if %ERRORLEVEL% equ 0 goto execute 45 | 46 | echo. 47 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 48 | echo. 49 | echo Please set the JAVA_HOME variable in your environment to match the 50 | echo location of your Java installation. 51 | 52 | goto fail 53 | 54 | :findJavaFromJavaHome 55 | set JAVA_HOME=%JAVA_HOME:"=% 56 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 57 | 58 | if exist "%JAVA_EXE%" goto execute 59 | 60 | echo. 61 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 62 | echo. 63 | echo Please set the JAVA_HOME variable in your environment to match the 64 | echo location of your Java installation. 65 | 66 | goto fail 67 | 68 | :execute 69 | @rem Setup the command line 70 | 71 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 72 | 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if %ERRORLEVEL% equ 0 goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | set EXIT_CODE=%ERRORLEVEL% 85 | if %EXIT_CODE% equ 0 set EXIT_CODE=1 86 | if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% 87 | exit /b %EXIT_CODE% 88 | 89 | :mainEnd 90 | if "%OS%"=="Windows_NT" endlocal 91 | 92 | :omega 93 | -------------------------------------------------------------------------------- /patches/removed/server/0029-lithium-fixes-entity.fast_retrieval.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Thu, 7 Oct 2021 04:03:29 +0000 4 | Subject: [PATCH] lithium fixes: entity.fast_retrieval 5 | 6 | https://github.com/CaffeineMC/lithium-fabric/commit/b34ac353bc6bd97d1b436898f353f998d29626a4 & https://github.com/CaffeineMC/lithium-fabric/commit/7616d35d922bb3cbed1ab0ef7c3993b7a15cfbdc 7 | 8 | diff --git a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java 9 | index 566a63bce5f17ab9f5d978c4b26a08e52103dcea..379820151ce69fee68e4dae5ccca8fedcb99e1d6 100644 10 | --- a/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java 11 | +++ b/src/main/java/net/minecraft/world/level/entity/EntitySectionStorage.java 12 | @@ -41,19 +41,46 @@ public class EntitySectionStorage { 13 | int maxY = SectionPos.posToSectionCoord(box.maxY + 2.0D); 14 | int maxZ = SectionPos.posToSectionCoord(box.maxZ + 2.0D); 15 | 16 | + // Vanilla order of the AVL long set is sorting by ascending long value. The x, y, z positions are packed into 17 | + // a long with the x position's lowest 22 bits placed at the MSB. 18 | + // Therefore the long is negative iff the 22th bit of the x position is set, which happens iff the x position 19 | + // is negative. A positive x position will never have its 22th bit set, as these big coordinates are far outside 20 | + // the world. y and z positions are treated as unsigned when sorting by ascending long value, as their sign bits 21 | + // are placed somewhere inside the packed long 22 | + 23 | for (int x = minX; x <= maxX; x++) { 24 | - for (int z = minZ; z <= maxZ; z++) { 25 | - for (int y = minY; y <= maxY; y++) { 26 | - EntitySection section = this.getSection(SectionPos.asLong(x, y, z)); 27 | - if (section != null && section.getStatus().isAccessible()) { 28 | - action.accept(section); 29 | - } 30 | - } 31 | + for (int z = Math.max(minZ, 0); z <= maxZ; z++) { 32 | + this.forEachInColumn(x, minY, maxY, z, action); 33 | + } 34 | + 35 | + int bound = Math.min(-1, maxZ); 36 | + for (int z = minZ; z <= bound; z++) { 37 | + this.forEachInColumn(x, minY, maxY, z, action); 38 | } 39 | } 40 | // Yatopia end 41 | } 42 | 43 | + // Patina start 44 | + private void forEachInColumn(int x, int minY, int maxY, int z, Consumer> action) { 45 | + //y from negative to positive, but y is treated as unsigned 46 | + for (int y = Math.max(minY, 0); y <= maxY; y++) { 47 | + this.consumeSection(x, y, z, action); 48 | + } 49 | + int bound = Math.min(-1, maxY); 50 | + for (int y = minY; y <= bound; y++) { 51 | + this.consumeSection(x, y, z, action); 52 | + } 53 | + } 54 | + 55 | + private void consumeSection(int x, int y, int z, Consumer> action) { 56 | + var section = this.getSection(SectionPos.asLong(x, y, z)); 57 | + if (section != null && section.getStatus().isAccessible()) { 58 | + action.accept(section); 59 | + } 60 | + } 61 | + // Patina end 62 | + 63 | public LongStream getExistingSectionPositionsInChunk(long chunkPos) { 64 | int i = ChunkPos.getX(chunkPos); 65 | int j = ChunkPos.getZ(chunkPos); 66 | -------------------------------------------------------------------------------- /patches/server/0003-EmpireCraft-Server-Changes-commit-e15007e4385c5852bf.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Sun, 31 Jul 2022 17:53:00 +0800 4 | Subject: [PATCH] EmpireCraft Server Changes commit 5 | e15007e4385c5852bfe25e4b17ce5db29638a9be 6 | 7 | Don't save Fireworks 8 | 9 | Fireworks can bug out and not detonate, and an automated 10 | launcher can very easily fill a chunk. 11 | 12 | Prevent saving Fireworks so that chunk unloads will wipe a chunks fireworks in this case. 13 | 14 | Do not drop items from Give command 15 | 16 | Don't use force unload for keep spawn setting change 17 | 18 | Don't trigger Lootable Refresh for non player interaction 19 | 20 | Do not process chat/commands before player has joined 21 | 22 | diff --git a/src/main/java/net/minecraft/server/commands/GiveCommand.java b/src/main/java/net/minecraft/server/commands/GiveCommand.java 23 | index 0d9de4c61c7b26a6ff37c12fde629161fd0c3d5a..35f5ae506956ac8022f80803c43c263385df6ca1 100644 24 | --- a/src/main/java/net/minecraft/server/commands/GiveCommand.java 25 | +++ b/src/main/java/net/minecraft/server/commands/GiveCommand.java 26 | @@ -60,6 +60,7 @@ public class GiveCommand { 27 | boolean flag = entityplayer.getInventory().add(itemstack1); 28 | ItemEntity entityitem; 29 | 30 | + if (true) { continue; } // EMC - never drop items 31 | if (flag && itemstack1.isEmpty()) { 32 | entityitem = entityplayer.drop(itemstack, false, false, false); // CraftBukkit - SPIGOT-2942: Add boolean to call event 33 | if (entityitem != null) { 34 | diff --git a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java 35 | index 09d465947a5720e05c350d455c86002682104079..91ba624e35f568d7392bb1f4245584aac9ba2a02 100644 36 | --- a/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java 37 | +++ b/src/main/java/net/minecraft/world/entity/projectile/FireworkRocketEntity.java 38 | @@ -358,4 +358,10 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier { 39 | 40 | return DoubleDoubleImmutablePair.of(d0, d1); 41 | } 42 | + // EMC start 43 | + @Override 44 | + public boolean shouldBeSaved() { 45 | + return false; 46 | + } 47 | + // EMC end 48 | } 49 | diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java 50 | index dc02a3d84b397f634f77f4df9c06e245cc4dcb75..4f946102ff69861784cccc1be0b01bd5be22388a 100644 51 | --- a/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java 52 | +++ b/src/main/java/net/minecraft/world/level/block/entity/BrushableBlockEntity.java 53 | @@ -95,6 +95,7 @@ public class BrushableBlockEntity extends BlockEntity { 54 | } 55 | 56 | public void unpackLootTable(Player player) { 57 | + if (player == null) return; // EMC 58 | if (this.lootTable != null && this.level != null && !this.level.isClientSide() && this.level.getServer() != null) { 59 | LootTable loottable = this.level.getServer().reloadableRegistries().getLootTable(this.lootTable); 60 | 61 | diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java 62 | index 33e4818ba5a90d78d69baad9f6b1be1b1382e9f3..14e35c0f782a92c227bfcc9fc3d26795d50ab1c3 100644 63 | --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java 64 | +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java 65 | @@ -455,7 +455,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { 66 | 67 | @Override 68 | public boolean unloadChunk(int x, int z) { 69 | - return this.unloadChunk(x, z, true); 70 | + return this.unloadChunkRequest(x, z); // Paper 71 | } 72 | 73 | @Override 74 | -------------------------------------------------------------------------------- /patches/removed/server/1.21/0018-Akarin-Save-Json-list-asynchronously.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?=E3=84=97=E3=84=A0=CB=8B=20=E3=84=91=E3=84=A7=CB=8A?= 3 | 4 | Date: Thu, 5 Jan 2023 09:08:17 +0800 5 | Subject: [PATCH] Akarin: Save Json list asynchronously 6 | 7 | Original license: GPL v3 8 | Original project: https://github.com/Akarin-project/Akarin 9 | Original project: https://github.com/Winds-Studio/Leaf 10 | 11 | diff --git a/src/main/java/net/minecraft/server/players/StoredUserList.java b/src/main/java/net/minecraft/server/players/StoredUserList.java 12 | index 7e133752ccb1ea7c0b4fa781feb1a88e2cfdcf6d..c06a0e8fe3f9a8f67e6a92e10ba9d8e47525bbfb 100644 13 | --- a/src/main/java/net/minecraft/server/players/StoredUserList.java 14 | +++ b/src/main/java/net/minecraft/server/players/StoredUserList.java 15 | @@ -22,6 +22,7 @@ import java.util.Objects; 16 | import java.util.stream.Stream; 17 | import javax.annotation.Nullable; 18 | import net.minecraft.Util; 19 | +import io.papermc.paper.util.MCUtil; 20 | import net.minecraft.util.GsonHelper; 21 | import org.slf4j.Logger; 22 | 23 | @@ -103,37 +104,43 @@ public abstract class StoredUserList> { 24 | } 25 | 26 | public void save() throws IOException { 27 | - this.removeExpired(); // Paper - remove expired values before saving 28 | - JsonArray jsonarray = new JsonArray(); 29 | - Stream stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error 30 | - JsonObject jsonobject = new JsonObject(); 31 | + Runnable saveTask = ()->{ // Akarin - Save json list async 32 | + this.removeExpired(); // Paper - remove expired values before saving 33 | + JsonArray jsonarray = new JsonArray(); 34 | + Stream stream = this.map.values().stream().map((jsonlistentry) -> { // CraftBukkit - decompile error 35 | + JsonObject jsonobject = new JsonObject(); 36 | 37 | - Objects.requireNonNull(jsonlistentry); 38 | - return (JsonObject) Util.make(jsonobject, jsonlistentry::serialize); 39 | - }); 40 | + Objects.requireNonNull(jsonlistentry); 41 | + return (JsonObject) Util.make(jsonobject, jsonlistentry::serialize); 42 | + }); 43 | 44 | - Objects.requireNonNull(jsonarray); 45 | - stream.forEach(jsonarray::add); 46 | - BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8); 47 | + Objects.requireNonNull(jsonarray); 48 | + stream.forEach(jsonarray::add); 49 | + try { 50 | + BufferedWriter bufferedwriter = Files.newWriter(this.file, StandardCharsets.UTF_8); 51 | 52 | - try { 53 | - StoredUserList.GSON.toJson(jsonarray, bufferedwriter); 54 | - } catch (Throwable throwable) { 55 | - if (bufferedwriter != null) { 56 | try { 57 | + StoredUserList.GSON.toJson(jsonarray, bufferedwriter); 58 | + } catch (Throwable throwable) { 59 | + if (bufferedwriter != null) { 60 | + try { 61 | + bufferedwriter.close(); 62 | + } catch (Throwable throwable1) { 63 | + throwable.addSuppressed(throwable1); 64 | + } 65 | + } 66 | + 67 | + throw throwable; 68 | + } 69 | + 70 | + if (bufferedwriter != null) { 71 | bufferedwriter.close(); 72 | - } catch (Throwable throwable1) { 73 | - throwable.addSuppressed(throwable1); 74 | } 75 | + }catch (Exception e){ 76 | + StoredUserList.LOGGER.warn("Failed to async save " + this.file, e); // Akarin - Save json list async 77 | } 78 | - 79 | - throw throwable; 80 | - } 81 | - 82 | - if (bufferedwriter != null) { 83 | - bufferedwriter.close(); 84 | - } 85 | - 86 | + }; 87 | + MCUtil.scheduleAsyncTask(saveTask); // Akarin - Save json list async 88 | } 89 | 90 | public void load() throws IOException { 91 | -------------------------------------------------------------------------------- /patches/removed/server/0013-Preload-ProtocolLib-EnumWrappers.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: ishland 3 | Date: Wed, 27 Jan 2021 20:16:47 +0800 4 | Subject: [PATCH] Preload ProtocolLib EnumWrappers 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 8 | index 68218d12b9e8cc32345925209367e21393f7c95f..fcb6c66f3acaeccd48361c76d59edc571fb10a40 100644 9 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 10 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 11 | @@ -1220,6 +1220,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 3 | Date: Thu, 1 Jul 2021 11:59:11 +0000 4 | Subject: [PATCH] remove TickTask 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 8 | index a37e6bf9f833b2ea17107914e6a40d752f87ec17..940baaee6883a6d81ce7a49c657abd1626bf8248 100644 9 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 10 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 11 | @@ -194,7 +194,7 @@ import org.bukkit.event.server.ServerLoadEvent; 12 | 13 | import co.aikar.timings.MinecraftTimings; // Paper 14 | 15 | -public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements CommandSource, AutoCloseable { 16 | +public abstract class MinecraftServer extends ReentrantBlockableEventLoop implements CommandSource, AutoCloseable { // Patina 17 | 18 | private static MinecraftServer SERVER; // Paper 19 | public static final Logger LOGGER = LogUtils.getLogger(); 20 | @@ -1302,19 +1302,21 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop {}; 30 | } 31 | // Paper end 32 | - return new TickTask(this.tickCount, runnable); 33 | + return runnable; // Patina 34 | } 35 | 36 | + /* // Patina 37 | protected boolean shouldRun(TickTask ticktask) { 38 | return ticktask.getTick() + 3 < this.tickCount || this.haveTime(); 39 | } 40 | + */ 41 | 42 | @Override 43 | public boolean pollTask() { 44 | @@ -1346,10 +1348,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop optional = Optional.of(this.getFile("server-icon.png")).filter(File::isFile); 57 | diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java 58 | index c6f5d6756fa0e068a462d9c0ded12e0771abba37..6b8b99f32629c0b4a6db3f7c808430dd88249f8e 100644 59 | --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java 60 | +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java 61 | @@ -1012,10 +1012,12 @@ public class ServerChunkCache extends ChunkSource { 62 | return runnable; 63 | } 64 | 65 | + /* // Patina 66 | @Override 67 | protected boolean shouldRun(Runnable task) { 68 | return true; 69 | } 70 | + */ 71 | 72 | @Override 73 | protected boolean scheduleExecutables() { 74 | diff --git a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java 75 | index 83701fbfaa56a232593ee8f11a3afb8941238bfa..fba6e6861ba420be23a0f733d3477b13324763fe 100644 76 | --- a/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java 77 | +++ b/src/main/java/net/minecraft/util/thread/BlockableEventLoop.java 78 | @@ -29,7 +29,9 @@ public abstract class BlockableEventLoop implements Profiler 79 | 80 | protected abstract R wrapRunnable(Runnable runnable); 81 | 82 | + /* // Patina 83 | protected abstract boolean shouldRun(R task); 84 | + */ 85 | 86 | public boolean isSameThread() { 87 | return Thread.currentThread() == this.getRunningThread(); 88 | @@ -120,7 +122,7 @@ public abstract class BlockableEventLoop implements Profiler 89 | R runnable = this.pendingRunnables.peek(); 90 | if (runnable == null) { 91 | return false; 92 | - } else if (this.blockingCount == 0 && !this.shouldRun(runnable)) { 93 | + } else if (this.blockingCount == 0 && !true/*this.shouldRun(runnable)*/) { // Patina 94 | return false; 95 | } else { 96 | this.doRunTask(this.pendingRunnables.remove()); 97 | -------------------------------------------------------------------------------- /patches/removed/server/0009-Utilities.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: YatopiaMC 3 | Date: Fri, 23 Oct 2020 09:20:01 -0700 4 | Subject: [PATCH] Utilities 5 | 6 | This patch includes all utilities required by the Yatopia project and its patches. 7 | 8 | Co-authored-by: Mykyta Komarnytskyy 9 | Co-authored-by: Ivan Pekov 10 | 11 | diff --git a/build.gradle.kts b/build.gradle.kts 12 | index 6c21124ad25730b2ffad2f11c6b7201f67f995ad..3963f2ce9b7cff606126c1412a213db443142be6 100644 13 | --- a/build.gradle.kts 14 | +++ b/build.gradle.kts 15 | @@ -36,6 +36,7 @@ dependencies { 16 | implementation("org.apache.logging.log4j:log4j-slf4j18-impl:2.17.1") // Paper 17 | implementation("org.ow2.asm:asm:9.2") 18 | implementation("org.ow2.asm:asm-commons:9.2") // Paper - ASM event executor generation 19 | + implementation("org.apache.commons:commons-rng-core:1.3") 20 | runtimeOnly("org.xerial:sqlite-jdbc:3.36.0.3") 21 | runtimeOnly("mysql:mysql-connector-java:8.0.27") 22 | runtimeOnly("com.lmax:disruptor:3.4.4") // Paper 23 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/util/Constants.java b/src/main/java/org/yatopiamc/yatopia/server/util/Constants.java 24 | new file mode 100644 25 | index 0000000000000000000000000000000000000000..ac5235155eb1b5515165fc9648b7c9d7a0713b44 26 | --- /dev/null 27 | +++ b/src/main/java/org/yatopiamc/yatopia/server/util/Constants.java 28 | @@ -0,0 +1,7 @@ 29 | +package org.yatopiamc.yatopia.server.util; 30 | + 31 | +public class Constants { 32 | + 33 | + public static final int[] EMPTY_ARRAY = new int[0]; 34 | + public static final int[] ZERO_ARRAY = new int[]{0}; 35 | +} 36 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/util/FastRandom.java b/src/main/java/org/yatopiamc/yatopia/server/util/FastRandom.java 37 | new file mode 100644 38 | index 0000000000000000000000000000000000000000..e41c1e3fa656d8f595733897ab05089c3b0976a7 39 | --- /dev/null 40 | +++ b/src/main/java/org/yatopiamc/yatopia/server/util/FastRandom.java 41 | @@ -0,0 +1,64 @@ 42 | +package org.yatopiamc.yatopia.server.util; 43 | + 44 | +import org.apache.commons.rng.core.source64.XoRoShiRo128PlusPlus; 45 | + 46 | +import java.util.Random; 47 | +import java.util.SplittableRandom; 48 | + 49 | +public class FastRandom extends Random { 50 | + 51 | + private XoRoShiRo128PlusPlus random; 52 | + 53 | + public FastRandom() { 54 | + super(); 55 | + SplittableRandom randomseed = new SplittableRandom(); 56 | + this.random = new XoRoShiRo128PlusPlus(randomseed.nextLong(), randomseed.nextLong()); 57 | + } 58 | + 59 | + public FastRandom(long seed) { 60 | + super(seed); 61 | + SplittableRandom randomseed = new SplittableRandom(seed); 62 | + this.random = new XoRoShiRo128PlusPlus(randomseed.nextLong(), randomseed.nextLong()); 63 | + } 64 | + 65 | + @Override 66 | + public boolean nextBoolean() { 67 | + return random.nextBoolean(); 68 | + } 69 | + 70 | + @Override 71 | + public int nextInt() { 72 | + return random.nextInt(); 73 | + } 74 | + 75 | + @Override 76 | + public float nextFloat() { 77 | + return (float) random.nextDouble(); 78 | + } 79 | + 80 | + @Override 81 | + public double nextDouble() { 82 | + return random.nextDouble(); 83 | + } 84 | + 85 | + @Override 86 | + public synchronized void setSeed(long seed) { 87 | + SplittableRandom randomseed = new SplittableRandom(seed); 88 | + this.random = new XoRoShiRo128PlusPlus(randomseed.nextLong(), randomseed.nextLong()); 89 | + } 90 | + 91 | + @Override 92 | + public void nextBytes(byte[] bytes) { 93 | + random.nextBytes(bytes); 94 | + } 95 | + 96 | + @Override 97 | + public int nextInt(int bound) { 98 | + return random.nextInt(bound); 99 | + } 100 | + 101 | + @Override 102 | + public long nextLong() { 103 | + return random.nextLong(); 104 | + } 105 | +} 106 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/util/TimeUtils.java b/src/main/java/org/yatopiamc/yatopia/server/util/TimeUtils.java 107 | new file mode 100644 108 | index 0000000000000000000000000000000000000000..acdf3d60738791b767a3bafa2c9511342a8c18df 109 | --- /dev/null 110 | +++ b/src/main/java/org/yatopiamc/yatopia/server/util/TimeUtils.java 111 | @@ -0,0 +1,27 @@ 112 | +package org.yatopiamc.yatopia.server.util; 113 | + 114 | +import java.util.concurrent.TimeUnit; 115 | + 116 | +public class TimeUtils { 117 | + 118 | + public static String getFriendlyName(TimeUnit unit) { 119 | + switch (unit) { 120 | + case NANOSECONDS: 121 | + return "ns"; 122 | + case MILLISECONDS: 123 | + return "ms"; 124 | + case MICROSECONDS: 125 | + return "micros"; 126 | + case SECONDS: 127 | + return "s"; 128 | + case MINUTES: 129 | + return "m"; 130 | + case DAYS: 131 | + return "d"; 132 | + case HOURS: 133 | + return "h"; 134 | + default: 135 | + throw new AssertionError(); 136 | + } 137 | + } 138 | +} 139 | -------------------------------------------------------------------------------- /patches/removed/server/0017-Add-nspt-command.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Ivan Pekov 3 | Date: Wed, 30 Sep 2020 18:05:45 +0300 4 | Subject: [PATCH] Add nspt command 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java 8 | index b224402f0052e1f14b77dea3b61b95f2b55bf148..479d51b3e3717576584b185a8bb6aa4b0dbbee10 100644 9 | --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java 10 | +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java 11 | @@ -226,6 +226,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface 12 | DedicatedServer.LOGGER.error("Unable to load server configuration", e); 13 | return false; 14 | } 15 | + org.yatopiamc.yatopia.server.YatopiaConfig.registerCommands(); // Yatopia 16 | thread.start(); // Paper - start console thread after MinecraftServer.console & PaperConfig are initialized 17 | com.destroystokyo.paper.PaperConfig.registerCommands(); 18 | // Purpur start 19 | diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java 20 | index 910425424d1188216d20d00ae138156d51c85649..cde3366e7084f12a4f2618a805a9bf2d4e095c06 100644 21 | --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java 22 | +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java 23 | @@ -1011,6 +1011,7 @@ public final class CraftServer implements Server { 24 | org.spigotmc.SpigotConfig.registerCommands(); // Spigot 25 | com.destroystokyo.paper.PaperConfig.registerCommands(); // Paper 26 | org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur 27 | + org.yatopiamc.yatopia.server.YatopiaConfig.registerCommands(); // Yatopia 28 | this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*"); 29 | this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); 30 | 31 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/NSPTCommand.java b/src/main/java/org/yatopiamc/yatopia/server/NSPTCommand.java 32 | new file mode 100644 33 | index 0000000000000000000000000000000000000000..e6eaa07c57e04bbfba9e4aa8e0e939f85169d0c8 34 | --- /dev/null 35 | +++ b/src/main/java/org/yatopiamc/yatopia/server/NSPTCommand.java 36 | @@ -0,0 +1,59 @@ 37 | +package org.yatopiamc.yatopia.server; 38 | + 39 | +import java.util.ArrayList; 40 | +import java.util.Arrays; 41 | +import java.util.Collections; 42 | +import java.util.List; 43 | +import net.minecraft.server.MinecraftServer; 44 | +import org.bukkit.ChatColor; 45 | +import org.bukkit.Location; 46 | +import org.bukkit.command.Command; 47 | +import org.bukkit.command.CommandSender; 48 | + 49 | +public class NSPTCommand extends Command { 50 | + 51 | + public NSPTCommand(String name) { 52 | + super(name); 53 | + this.description = "View server tick times in nanoseconds"; 54 | + this.usageMessage = "/nspt"; 55 | + this.setPermission("bukkit.command.nspt"); 56 | + } 57 | + 58 | + @Override 59 | + public List tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException { 60 | + return Collections.emptyList(); 61 | + } 62 | + 63 | + @Override 64 | + public boolean execute(CommandSender sender, String commandLabel, String[] args) { 65 | + if (!testPermission(sender)) return true; 66 | + 67 | + MinecraftServer server = MinecraftServer.getServer(); 68 | + 69 | + List times = new ArrayList<>(); 70 | + times.addAll(eval(server.tickTimes5s.getTimes())); 71 | + times.addAll(eval(server.tickTimes10s.getTimes())); 72 | + times.addAll(eval(server.tickTimes60s.getTimes())); 73 | + 74 | + sender.sendMessage("§6Server tick NS times §e(§7avg§e/§7min§e/§7max§e)§6 from last 5s§7,§6 10s§7,§6 1m§e:"); 75 | + sender.sendMessage(String.format("§6◴ %s§7/%s§7/%s§e, %s§7/%s§7/%s§e, %s§7/%s§7/%s", times.toArray())); 76 | + return true; 77 | + } 78 | + 79 | + private static List eval(long[] times) { 80 | + long min = Integer.MAX_VALUE; 81 | + long max = 0L; 82 | + long total = 0L; 83 | + for (long value : times) { 84 | + if (value > 0L && value < min) min = value; 85 | + if (value > max) max = value; 86 | + total += value; 87 | + } 88 | + double avgD = ((double) total / (double) times.length); 89 | + return Arrays.asList(getColor(avgD), getColor(min), getColor(max)); 90 | + } 91 | + 92 | + private static String getColor(double avg) { 93 | + return ChatColor.COLOR_CHAR + (avg >= 5E+7 ? "c" : avg >= (4E+7) ? "e" : "a") + avg; 94 | + } 95 | +} 96 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 97 | index 2fc78f7cee379e690e846a3ab91eab01869f3346..3c6d2606f12519c844214b32b2ac42aa356fb986 100644 98 | --- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 99 | +++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 100 | @@ -6,11 +6,14 @@ import java.io.IOException; 101 | import java.lang.reflect.InvocationTargetException; 102 | import java.lang.reflect.Method; 103 | import java.lang.reflect.Modifier; 104 | +import java.util.HashMap; 105 | import java.util.List; 106 | +import java.util.Map; 107 | import java.util.concurrent.TimeUnit; 108 | import java.util.logging.Level; 109 | import java.util.regex.Pattern; 110 | import org.bukkit.Bukkit; 111 | +import org.bukkit.command.Command; 112 | import org.bukkit.configuration.InvalidConfigurationException; 113 | import org.bukkit.configuration.file.YamlConfiguration; 114 | public class YatopiaConfig { 115 | @@ -22,8 +25,14 @@ public class YatopiaConfig { 116 | public static YamlConfiguration config; 117 | public static int version; // since we're remapping sidestreams' configs we need this public 118 | public static boolean verbose; // since we're remapping sidestreams' configs we need this public 119 | + private static Map commands; 120 | /*========================================================================*/ 121 | 122 | + static { 123 | + commands = new HashMap<>(); 124 | + commands.put("nspt", new NSPTCommand("nspt")); 125 | + } 126 | + 127 | public static void init(File configFile) { 128 | CONFIG_FILE = configFile; 129 | config = new YamlConfiguration(); 130 | @@ -43,6 +52,12 @@ public class YatopiaConfig { 131 | readConfig(YatopiaConfig.class, null); 132 | } 133 | 134 | + public static void registerCommands() { 135 | + for (Map.Entry entry : commands.entrySet()) { 136 | + net.minecraft.server.MinecraftServer.getServer().server.getCommandMap().register(entry.getKey(), "Yatopia", entry.getValue()); 137 | + } 138 | + } 139 | + 140 | private static void removeLeftovers() { 141 | // this method is only to remove non-used values in the config 142 | 143 | -------------------------------------------------------------------------------- /patches/removed/server/0012-Optimised-hallowen-checker.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Ivan Pekov 3 | Date: Mon, 4 Jan 2021 20:12:36 +0200 4 | Subject: [PATCH] Optimised hallowen checker 5 | 6 | 7 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 8 | index c2dfcadab6752819931e841805df2b67b09493e3..68218d12b9e8cc32345925209367e21393f7c95f 100644 9 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 10 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 11 | @@ -1528,6 +1528,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop ONE_HOUR) { 41 | LocalDate localdate = LocalDate.now(); 42 | int i = localdate.get(ChronoField.DAY_OF_MONTH); 43 | @@ -268,6 +274,9 @@ public class Bat extends AmbientCreature { 44 | lastSpookyCheck = net.minecraft.server.MinecraftServer.currentTick; 45 | } 46 | return isSpookySeason; 47 | + */ 48 | + return org.yatopiamc.yatopia.server.util.entity.HalloweenChecker.isHalloweenSeason(); 49 | + // Yatopia end 50 | } 51 | // Pufferfish end 52 | 53 | diff --git a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java 54 | index e23fe546291e670f89447398507d08a0a07efa85..28bcb57a13d943236aacd35fce0e8e0f038aa056 100644 55 | --- a/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java 56 | +++ b/src/main/java/net/minecraft/world/entity/monster/AbstractSkeleton.java 57 | @@ -155,11 +155,16 @@ public abstract class AbstractSkeleton extends Monster implements RangedAttackMo 58 | this.reassessWeaponGoal(); 59 | this.setCanPickUpLoot(this.level.paperConfig.skeletonsAlwaysCanPickUpLoot || this.random.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper 60 | if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { 61 | + // Yatopia start - optimised halloween checker 62 | + /* 63 | LocalDate localdate = LocalDate.now(); 64 | int i = localdate.get(ChronoField.DAY_OF_MONTH); 65 | int j = localdate.get(ChronoField.MONTH_OF_YEAR); 66 | 67 | if (j == 10 && i == 31 && this.random.nextFloat() < 0.25F) { 68 | + */ 69 | + if (org.yatopiamc.yatopia.server.util.entity.HalloweenChecker.isHalloweenDay() && this.random.nextFloat() < 0.25F) { 70 | + // Yatopia end 71 | this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(this.random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); 72 | this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; 73 | } 74 | diff --git a/src/main/java/net/minecraft/world/entity/monster/Zombie.java b/src/main/java/net/minecraft/world/entity/monster/Zombie.java 75 | index e72e9b748b3f3e34baddf01366c703efba50c67c..1d558e0f3c6633f5c087c6d4714447fbe922a19c 100644 76 | --- a/src/main/java/net/minecraft/world/entity/monster/Zombie.java 77 | +++ b/src/main/java/net/minecraft/world/entity/monster/Zombie.java 78 | @@ -536,11 +536,16 @@ public class Zombie extends Monster { 79 | } 80 | 81 | if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { 82 | + // Yatopia start - optimised halloween checker 83 | + /* 84 | LocalDate localdate = LocalDate.now(); 85 | int i = localdate.get(ChronoField.DAY_OF_MONTH); 86 | int j = localdate.get(ChronoField.MONTH_OF_YEAR); 87 | 88 | if (j == 10 && i == 31 && this.random.nextFloat() < 0.25F) { 89 | + */ 90 | + if (org.yatopiamc.yatopia.server.util.entity.HalloweenChecker.isHalloweenDay() && this.random.nextFloat() < 0.25F) { 91 | + // Yatopia end 92 | this.setItemSlot(EquipmentSlot.HEAD, new ItemStack(this.random.nextFloat() < 0.1F ? Blocks.JACK_O_LANTERN : Blocks.CARVED_PUMPKIN)); 93 | this.armorDropChances[EquipmentSlot.HEAD.getIndex()] = 0.0F; 94 | } 95 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/util/entity/HalloweenChecker.java b/src/main/java/org/yatopiamc/yatopia/server/util/entity/HalloweenChecker.java 96 | new file mode 100644 97 | index 0000000000000000000000000000000000000000..6e18c9b7bb738ac7d4f0da2fab265877f093b914 98 | --- /dev/null 99 | +++ b/src/main/java/org/yatopiamc/yatopia/server/util/entity/HalloweenChecker.java 100 | @@ -0,0 +1,59 @@ 101 | +package org.yatopiamc.yatopia.server.util.entity; 102 | + 103 | +import java.time.LocalDate; 104 | +import java.time.temporal.ChronoField; 105 | +import net.minecraft.server.MinecraftServer; 106 | + 107 | +/** 108 | + * Entity halloween checker 109 | + *

110 | + * Checks whether or not it is halloween at a specific rate rather than every time when 111 | + * a entity is being spawned. 112 | + *

113 | + * The rate changes depending on how much TPS the server has. By default, the rate is every 114 | + * 2 hours, or every 144k ticks (if the server has _that_ much uptime) 115 | + * 116 | + * @author MrIvanPlays 117 | + */ 118 | +public class HalloweenChecker { 119 | + 120 | + private static boolean halloweenSeason = false; 121 | + private static boolean halloweenDay = false; 122 | + 123 | + private static int delay = (20 * 60 * 60) * 2; 124 | + private static int lastCheckTick = -delay; 125 | + 126 | + public static void tick() { 127 | + if (MinecraftServer.currentTick % 100 == 0) { 128 | + // update the delay every 100 ticks 129 | + if (MinecraftServer.TPS >= 20) { 130 | + delay = (20 * 60 * 60) * 2; 131 | + } 132 | + if (MinecraftServer.TPS < 15) { 133 | + delay = delay + (20 * 60 * 15); 134 | + } 135 | + if (MinecraftServer.TPS < 10) { 136 | + delay = delay + (20 * 60 * 30); 137 | + } 138 | + } 139 | + if (MinecraftServer.currentTick - lastCheckTick > delay) { 140 | + LocalDate now = LocalDate.now(); 141 | + int day = now.getDayOfMonth(); 142 | + int month = now.get(ChronoField.MONTH_OF_YEAR); 143 | + 144 | + halloweenDay = (month == 10) && (day == 31); 145 | + halloweenSeason = ((month == 10) && (day >= 20)) || ((month == 11) && (day <= 3)); 146 | + 147 | + lastCheckTick = MinecraftServer.currentTick; 148 | + } 149 | + } 150 | + 151 | + public static boolean isHalloweenSeason() { 152 | + return halloweenSeason; 153 | + } 154 | + 155 | + public static boolean isHalloweenDay() { 156 | + return halloweenDay; 157 | + } 158 | + 159 | +} 160 | -------------------------------------------------------------------------------- /patches/removed/server/0027-New-nbt-cache.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: Hugo Planque 3 | Date: Thu, 21 Jan 2021 17:56:03 +0100 4 | Subject: [PATCH] New nbt cache 5 | 6 | The goal of this patch is to reduce I/O operations from the main thread while saving player data and also to avoid too many I/O operations while reading NBT Player file by using a cache (Which start to delete the oldest data when there is too much player compared to the map size) 7 | 8 | Original code by Yatopia, licensed under MIT License 9 | Co-authored-by: ishland 10 | 11 | diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java 12 | index e29db9096ca948b62bb6cedc74442a56059a0613..e69479bc9902750948eba86a2a09aa0cd058a57e 100644 13 | --- a/src/main/java/net/minecraft/server/MinecraftServer.java 14 | +++ b/src/main/java/net/minecraft/server/MinecraftServer.java 15 | @@ -1088,7 +1088,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { 52 | + try { 53 | + NbtIo.writeCompressed(nbttagcompound, file); 54 | + File file1 = new File(this.playerDir, player.getStringUUID() + ".dat"); 55 | + File file2 = new File(this.playerDir, player.getStringUUID() + ".dat_old"); 56 | + 57 | + Util.safeReplaceFile(file1, file, file2); 58 | + } catch (Exception exception) { 59 | + PlayerDataStorage.LOGGER.error("Failed to save player data for {}", player.getScoreboardName(), exception); // Paper 60 | + } 61 | + }; 62 | + synchronized (this.dataCache){ 63 | + this.dataCache.put(file, nbttagcompound); 64 | + } 65 | + this.executorService.execute(task); 66 | + // Sugarcane end 67 | } catch (Exception exception) { 68 | PlayerDataStorage.LOGGER.warn("Failed to save player data for {}", player.getScoreboardName(), exception); // Paper 69 | } 70 | @@ -57,9 +74,18 @@ public class PlayerDataStorage { 71 | // Spigot Start 72 | boolean usingWrongFile = false; 73 | boolean normalFile = file.exists() && file.isFile(); // Akarin - ensures normal file 74 | - if ( org.bukkit.Bukkit.getOnlineMode() && !normalFile ) // Paper - Check online mode first // Akarin - ensures normal file 75 | + // if ( org.bukkit.Bukkit.getOnlineMode() && !file.exists() ) // Paper - Check online mode first 76 | + // Sugarcane start - NBT Cache system 77 | + CompoundTag playerData; 78 | + synchronized (this.dataCache){ 79 | + playerData = this.dataCache.get(file); 80 | + } 81 | + if (playerData == null && org.bukkit.Bukkit.getOnlineMode() && !normalFile ) // Paper - Check online mode first // Akarin - ensures normal file // Sugarcane 82 | { 83 | file = new File( this.playerDir, java.util.UUID.nameUUIDFromBytes( ( "OfflinePlayer:" + player.getScoreboardName() ).getBytes( "UTF-8" ) ).toString() + ".dat"); 84 | + synchronized (this.dataCache){ 85 | + playerData = this.dataCache.get(file); 86 | + } 87 | if ( file.exists() ) 88 | { 89 | usingWrongFile = true; 90 | @@ -68,9 +94,15 @@ public class PlayerDataStorage { 91 | } 92 | // Spigot End 93 | 94 | - if (normalFile) { // Akarin - avoid double I/O operation 95 | + // if (normalFile) { // Akarin - avoid double I/O operation // Sugarcane 96 | + if (playerData != null) { 97 | + nbttagcompound = playerData; 98 | + } else if (normalFile) { // Akarin - avoid double I/O operation 99 | + 100 | + // if (file.exists() && file.isFile()) { 101 | nbttagcompound = NbtIo.readCompressed(file); 102 | } 103 | + // Sugarcane end 104 | // Spigot Start 105 | if ( usingWrongFile ) 106 | { 107 | diff --git a/src/main/java/org/sugarcanemc/sugarcane/cache/NBTCache.java b/src/main/java/org/sugarcanemc/sugarcane/cache/NBTCache.java 108 | new file mode 100644 109 | index 0000000000000000000000000000000000000000..a1db826de6fd53787c7e3f0d8dd8365d452f4ac0 110 | --- /dev/null 111 | +++ b/src/main/java/org/sugarcanemc/sugarcane/cache/NBTCache.java 112 | @@ -0,0 +1,32 @@ 113 | +package org.sugarcanemc.sugarcane.cache; 114 | + 115 | +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenCustomHashMap; 116 | +import net.minecraft.server.MinecraftServer; 117 | +import net.minecraft.nbt.CompoundTag; 118 | + 119 | +import java.io.File; 120 | + 121 | +public class NBTCache extends Object2ObjectLinkedOpenCustomHashMap { 122 | + 123 | + public NBTCache() { 124 | + super(100, 0.75F, new Strategy() { 125 | + @Override 126 | + public int hashCode(File k) { 127 | + return k.hashCode(); 128 | + } 129 | + 130 | + @Override 131 | + public boolean equals(File k, File k1) { 132 | + return k.equals(k1); 133 | + } 134 | + }); 135 | + } 136 | + 137 | + @Override 138 | + public CompoundTag put(File k, CompoundTag v) { 139 | + if (this.size() > MinecraftServer.getServer().getPlayerCount()) { 140 | + this.removeLast(); 141 | + } 142 | + return super.putAndMoveToFirst(k, v); 143 | + } 144 | +} 145 | -------------------------------------------------------------------------------- /patches/api/0005-Remove-VersionFetcher.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Thu, 1 Jul 2021 12:09:38 +0000 4 | Subject: [PATCH] Remove VersionFetcher 5 | 6 | 7 | diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java 8 | index e64bb57f74e6d6f78927be228825b3e0bdf41f48..b275d7ccc4fec941cbef605dd36dd01fd518a109 100644 9 | --- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java 10 | +++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java 11 | @@ -26,7 +26,7 @@ import org.bukkit.plugin.PluginDescriptionFile; 12 | import org.bukkit.util.StringUtil; 13 | import org.jetbrains.annotations.NotNull; 14 | // Paper start - version command 2.0 15 | -import com.destroystokyo.paper.util.VersionFetcher; 16 | +// Patina - remove 17 | import net.kyori.adventure.text.Component; 18 | import net.kyori.adventure.text.format.NamedTextColor; 19 | import net.kyori.adventure.text.event.ClickEvent; 20 | @@ -35,14 +35,7 @@ import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer; 21 | // Paper end - version command 2.0 22 | 23 | public class VersionCommand extends BukkitCommand { 24 | - private VersionFetcher versionFetcher; // Paper - version command 2.0 25 | - private VersionFetcher getVersionFetcher() { // lazy load because unsafe isn't available at command registration 26 | - if (versionFetcher == null) { 27 | - versionFetcher = Bukkit.getUnsafe().getVersionFetcher(); 28 | - } 29 | - 30 | - return versionFetcher; 31 | - } 32 | + // Patina - remove 33 | 34 | public VersionCommand(@NotNull String name) { 35 | super(name); 36 | @@ -58,8 +51,8 @@ public class VersionCommand extends BukkitCommand { 37 | if (!testPermission(sender)) return true; 38 | 39 | if (args.length == 0) { 40 | - //sender.sendMessage("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); // Paper - moved to setVersionMessage 41 | - sendVersion(sender); 42 | + sender.sendMessage("This server is running " + Bukkit.getName() + " version " + Bukkit.getVersion() + " (Implementing API version " + Bukkit.getBukkitVersion() + ")"); // Paper - moved to setVersionMessage 43 | + //sendVersion(sender); 44 | } else { 45 | StringBuilder name = new StringBuilder(); 46 | 47 | @@ -171,133 +164,5 @@ public class VersionCommand extends BukkitCommand { 48 | return ImmutableList.of(); 49 | } 50 | 51 | - private final ReentrantLock versionLock = new ReentrantLock(); 52 | - private boolean hasVersion = false; 53 | - private Component versionMessage = null; // Paper 54 | - private final Set versionWaiters = new HashSet(); 55 | - private boolean versionTaskStarted = false; 56 | - private long lastCheck = 0; 57 | - 58 | - private void sendVersion(@NotNull CommandSender sender) { 59 | - if (hasVersion) { 60 | - if (System.currentTimeMillis() - lastCheck > getVersionFetcher().getCacheTime()) { // Paper - use version supplier 61 | - lastCheck = System.currentTimeMillis(); 62 | - hasVersion = false; 63 | - } else { 64 | - sender.sendMessage(versionMessage); 65 | - return; 66 | - } 67 | - } 68 | - versionLock.lock(); 69 | - try { 70 | - if (hasVersion) { 71 | - sender.sendMessage(versionMessage); 72 | - return; 73 | - } 74 | - versionWaiters.add(sender); 75 | - sender.sendMessage(Component.text("Checking version, please wait...", NamedTextColor.WHITE, TextDecoration.ITALIC)); // Paper 76 | - if (!versionTaskStarted) { 77 | - versionTaskStarted = true; 78 | - new Thread(new Runnable() { 79 | - 80 | - @Override 81 | - public void run() { 82 | - obtainVersion(); 83 | - } 84 | - }).start(); 85 | - } 86 | - } finally { 87 | - versionLock.unlock(); 88 | - } 89 | - } 90 | - 91 | - private void obtainVersion() { 92 | - String version = Bukkit.getVersion(); 93 | - // Paper start 94 | - if (version.startsWith("null")) { // running from ide? 95 | - setVersionMessage(Component.text("Unknown version, custom build?", NamedTextColor.YELLOW)); 96 | - return; 97 | - } 98 | - setVersionMessage(getVersionFetcher().getVersionMessage(version)); 99 | - /* 100 | - if (version == null) version = "Custom"; 101 | - String[] parts = version.substring(0, version.indexOf(' ')).split("-"); 102 | - if (parts.length == 4) { 103 | - int cbVersions = getDistance("craftbukkit", parts[3]); 104 | - int spigotVersions = getDistance("spigot", parts[2]); 105 | - if (cbVersions == -1 || spigotVersions == -1) { 106 | - setVersionMessage("Error obtaining version information"); 107 | - } else { 108 | - if (cbVersions == 0 && spigotVersions == 0) { 109 | - setVersionMessage("You are running the latest version"); 110 | - } else { 111 | - setVersionMessage("You are " + (cbVersions + spigotVersions) + " version(s) behind"); 112 | - } 113 | - } 114 | - 115 | - } else if (parts.length == 3) { 116 | - int cbVersions = getDistance("craftbukkit", parts[2]); 117 | - if (cbVersions == -1) { 118 | - setVersionMessage("Error obtaining version information"); 119 | - } else { 120 | - if (cbVersions == 0) { 121 | - setVersionMessage("You are running the latest version"); 122 | - } else { 123 | - setVersionMessage("You are " + cbVersions + " version(s) behind"); 124 | - } 125 | - } 126 | - } else { 127 | - setVersionMessage("Unknown version, custom build?"); 128 | - } 129 | - */ 130 | - // Paper end 131 | - } 132 | - 133 | - // Paper start 134 | - private void setVersionMessage(final @NotNull Component msg) { 135 | - lastCheck = System.currentTimeMillis(); 136 | - final Component message = Component.textOfChildren( 137 | - Component.text(Bukkit.getVersionMessage(), NamedTextColor.WHITE), 138 | - Component.newline(), 139 | - msg 140 | - ); 141 | - this.versionMessage = Component.text() 142 | - .append(message) 143 | - .hoverEvent(Component.text("Click to copy to clipboard", NamedTextColor.WHITE)) 144 | - .clickEvent(ClickEvent.copyToClipboard(PlainTextComponentSerializer.plainText().serialize(message))) 145 | - .build(); 146 | - // Paper end 147 | - versionLock.lock(); 148 | - try { 149 | - hasVersion = true; 150 | - versionTaskStarted = false; 151 | - for (CommandSender sender : versionWaiters) { 152 | - sender.sendMessage(versionMessage); 153 | - } 154 | - versionWaiters.clear(); 155 | - } finally { 156 | - versionLock.unlock(); 157 | - } 158 | - } 159 | - 160 | - private static int getDistance(@NotNull String repo, @NotNull String hash) { 161 | - try { 162 | - BufferedReader reader = Resources.asCharSource( 163 | - new URL("https://hub.spigotmc.org/stash/rest/api/1.0/projects/SPIGOT/repos/" + repo + "/commits?since=" + URLEncoder.encode(hash, "UTF-8") + "&withCounts=true"), 164 | - Charsets.UTF_8 165 | - ).openBufferedStream(); 166 | - try { 167 | - JsonObject obj = new Gson().fromJson(reader, JsonObject.class); 168 | - return obj.get("totalCount").getAsInt(); 169 | - } catch (JsonSyntaxException ex) { 170 | - ex.printStackTrace(); 171 | - return -1; 172 | - } finally { 173 | - reader.close(); 174 | - } 175 | - } catch (IOException e) { 176 | - e.printStackTrace(); 177 | - return -1; 178 | - } 179 | - } 180 | + // Patina - remove 181 | } 182 | -------------------------------------------------------------------------------- /patches/removed/server/0015-lithium-HashedList.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: JellySquid 3 | Date: Fri, 31 Jul 2020 21:46:32 -0500 4 | Subject: [PATCH] lithium HashedList 5 | 6 | Original code by JellySquid, licensed under GNU Lesser General Public License v3.0 7 | you can find the original code on https://github.com/CaffeineMC/lithium-fabric/ (Yarn mappings) 8 | 9 | diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java 10 | new file mode 100644 11 | index 0000000000000000000000000000000000000000..2d79932dbd1fc386a94b8d6ea3526934c54c2aad 12 | --- /dev/null 13 | +++ b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java 14 | @@ -0,0 +1,280 @@ 15 | +package me.jellysquid.mods.lithium.common.util.collections; 16 | + 17 | +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; 18 | +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; 19 | +import java.util.Collection; 20 | +import java.util.Iterator; 21 | +import java.util.List; 22 | +import java.util.ListIterator; 23 | +import java.util.NoSuchElementException; 24 | + 25 | +/** 26 | + * Wraps a {@link List} with a hash table which provides O(1) lookups for {@link Collection#contains(Object)}. The type 27 | + * contained by this list must use reference-equality semantics. 28 | + */ 29 | +@SuppressWarnings("SuspiciousMethodCalls") 30 | +public class HashedList implements List { 31 | + private final ReferenceArrayList list; 32 | + private final Reference2IntOpenHashMap counter; 33 | + 34 | + public HashedList(List list) { 35 | + this.list = new ReferenceArrayList<>(); 36 | + this.list.addAll(list); 37 | + 38 | + this.counter = new Reference2IntOpenHashMap<>(); 39 | + this.counter.defaultReturnValue(0); 40 | + 41 | + for (T obj : this.list) { 42 | + this.counter.addTo(obj, 1); 43 | + } 44 | + } 45 | + 46 | + @Override 47 | + public int size() { 48 | + return this.list.size(); 49 | + } 50 | + 51 | + @Override 52 | + public boolean isEmpty() { 53 | + return this.list.isEmpty(); 54 | + } 55 | + 56 | + @Override 57 | + public boolean contains(Object o) { 58 | + return this.counter.containsKey(o); 59 | + } 60 | + 61 | + @Override 62 | + public Iterator iterator() { 63 | + return this.listIterator(); 64 | + } 65 | + 66 | + @Override 67 | + public Object[] toArray() { 68 | + return this.list.toArray(); 69 | + } 70 | + 71 | + @SuppressWarnings("SuspiciousToArrayCall") 72 | + @Override 73 | + public T1[] toArray(T1[] a) { 74 | + return this.list.toArray(a); 75 | + } 76 | + 77 | + @Override 78 | + public boolean add(T t) { 79 | + this.trackReferenceAdded(t); 80 | + 81 | + return this.list.add(t); 82 | + } 83 | + 84 | + @Override 85 | + public boolean remove(Object o) { 86 | + this.trackReferenceRemoved(o); 87 | + 88 | + return this.list.remove(o); 89 | + } 90 | + 91 | + @Override 92 | + public boolean containsAll(Collection c) { 93 | + for (Object obj : c) { 94 | + if (!this.counter.containsKey(obj)) { 95 | + return false; 96 | + } 97 | + } 98 | + 99 | + return true; 100 | + } 101 | + 102 | + @Override 103 | + public boolean addAll(Collection c) { 104 | + for (T obj : c) { 105 | + this.trackReferenceAdded(obj); 106 | + } 107 | + 108 | + return this.list.addAll(c); 109 | + } 110 | + 111 | + @Override 112 | + public boolean addAll(int index, Collection c) { 113 | + for (T obj : c) { 114 | + this.trackReferenceAdded(obj); 115 | + } 116 | + 117 | + return this.list.addAll(index, c); 118 | + } 119 | + 120 | + @Override 121 | + public boolean removeAll(Collection c) { 122 | + for (Object obj : c) { 123 | + this.trackReferenceRemoved(obj); 124 | + } 125 | + 126 | + return this.list.removeAll(c); 127 | + } 128 | + 129 | + @Override 130 | + public boolean retainAll(Collection c) { 131 | + return this.list.retainAll(c); 132 | + } 133 | + 134 | + @Override 135 | + public void clear() { 136 | + this.counter.clear(); 137 | + this.list.clear(); 138 | + } 139 | + 140 | + @Override 141 | + public T get(int index) { 142 | + return this.list.get(index); 143 | + } 144 | + 145 | + @Override 146 | + public T set(int index, T element) { 147 | + T prev = this.list.set(index, element); 148 | + 149 | + if (prev != element) { 150 | + if (prev != null) { 151 | + this.trackReferenceRemoved(prev); 152 | + } 153 | + 154 | + this.trackReferenceAdded(element); 155 | + } 156 | + 157 | + return prev; 158 | + } 159 | + 160 | + @Override 161 | + public void add(int index, T element) { 162 | + this.trackReferenceAdded(element); 163 | + 164 | + this.list.add(index, element); 165 | + } 166 | + 167 | + @Override 168 | + public T remove(int index) { 169 | + T prev = this.list.remove(index); 170 | + 171 | + if (prev != null) { 172 | + this.trackReferenceRemoved(prev); 173 | + } 174 | + 175 | + return prev; 176 | + } 177 | + 178 | + @Override 179 | + public int indexOf(Object o) { 180 | + return this.list.indexOf(o); 181 | + } 182 | + 183 | + @Override 184 | + public int lastIndexOf(Object o) { 185 | + return this.list.lastIndexOf(o); 186 | + } 187 | + 188 | + @Override 189 | + public ListIterator listIterator() { 190 | + return this.listIterator(0); 191 | + } 192 | + 193 | + @Override 194 | + public ListIterator listIterator(int index) { 195 | + return new ListIterator() { 196 | + private final ListIterator inner = HashedList.this.list.listIterator(index); 197 | + 198 | + @Override 199 | + public boolean hasNext() { 200 | + return this.inner.hasNext(); 201 | + } 202 | + 203 | + @Override 204 | + public T next() { 205 | + return this.inner.next(); 206 | + } 207 | + 208 | + @Override 209 | + public boolean hasPrevious() { 210 | + return this.inner.hasPrevious(); 211 | + } 212 | + 213 | + @Override 214 | + public T previous() { 215 | + return this.inner.previous(); 216 | + } 217 | + 218 | + @Override 219 | + public int nextIndex() { 220 | + return this.inner.nextIndex(); 221 | + } 222 | + 223 | + @Override 224 | + public int previousIndex() { 225 | + return this.inner.previousIndex(); 226 | + } 227 | + 228 | + @Override 229 | + public void remove() { 230 | + int last = this.previousIndex(); 231 | + 232 | + if (last == -1) { 233 | + throw new NoSuchElementException(); 234 | + } 235 | + 236 | + T prev = HashedList.this.get(last); 237 | + 238 | + if (prev != null) { 239 | + HashedList.this.trackReferenceRemoved(prev); 240 | + } 241 | + 242 | + this.inner.remove(); 243 | + } 244 | + 245 | + @Override 246 | + public void set(T t) { 247 | + int last = this.previousIndex(); 248 | + 249 | + if (last == -1) { 250 | + throw new NoSuchElementException(); 251 | + } 252 | + 253 | + T prev = HashedList.this.get(last); 254 | + 255 | + if (prev != t) { 256 | + if (prev != null) { 257 | + HashedList.this.trackReferenceRemoved(prev); 258 | + } 259 | + 260 | + HashedList.this.trackReferenceAdded(t); 261 | + } 262 | + 263 | + this.inner.remove(); 264 | + } 265 | + 266 | + @Override 267 | + public void add(T t) { 268 | + HashedList.this.trackReferenceAdded(t); 269 | + 270 | + this.inner.add(t); 271 | + } 272 | + }; 273 | + } 274 | + 275 | + @Override 276 | + public List subList(int fromIndex, int toIndex) { 277 | + return this.list.subList(fromIndex, toIndex); 278 | + } 279 | + 280 | + private void trackReferenceAdded(T t) { 281 | + this.counter.addTo(t, 1); 282 | + } 283 | + 284 | + @SuppressWarnings("unchecked") 285 | + private void trackReferenceRemoved(Object o) { 286 | + if (this.counter.addTo((T) o, -1) <= 1) { 287 | + this.counter.removeInt(o); 288 | + } 289 | + } 290 | + 291 | + public static HashedList wrapper(List list) { 292 | + return new HashedList<>(list); 293 | + } 294 | +} 295 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | # This is normally unused 84 | # shellcheck disable=SC2034 85 | APP_BASE_NAME=${0##*/} 86 | # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) 87 | APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit 88 | 89 | # Use the maximum available, or set MAX_FD != -1 to use that value. 90 | MAX_FD=maximum 91 | 92 | warn () { 93 | echo "$*" 94 | } >&2 95 | 96 | die () { 97 | echo 98 | echo "$*" 99 | echo 100 | exit 1 101 | } >&2 102 | 103 | # OS specific support (must be 'true' or 'false'). 104 | cygwin=false 105 | msys=false 106 | darwin=false 107 | nonstop=false 108 | case "$( uname )" in #( 109 | CYGWIN* ) cygwin=true ;; #( 110 | Darwin* ) darwin=true ;; #( 111 | MSYS* | MINGW* ) msys=true ;; #( 112 | NONSTOP* ) nonstop=true ;; 113 | esac 114 | 115 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 116 | 117 | 118 | # Determine the Java command to use to start the JVM. 119 | if [ -n "$JAVA_HOME" ] ; then 120 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 121 | # IBM's JDK on AIX uses strange locations for the executables 122 | JAVACMD=$JAVA_HOME/jre/sh/java 123 | else 124 | JAVACMD=$JAVA_HOME/bin/java 125 | fi 126 | if [ ! -x "$JAVACMD" ] ; then 127 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 128 | 129 | Please set the JAVA_HOME variable in your environment to match the 130 | location of your Java installation." 131 | fi 132 | else 133 | JAVACMD=java 134 | if ! command -v java >/dev/null 2>&1 135 | then 136 | die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | fi 142 | 143 | # Increase the maximum file descriptors if we can. 144 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 145 | case $MAX_FD in #( 146 | max*) 147 | # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. 148 | # shellcheck disable=SC2039,SC3045 149 | MAX_FD=$( ulimit -H -n ) || 150 | warn "Could not query maximum file descriptor limit" 151 | esac 152 | case $MAX_FD in #( 153 | '' | soft) :;; #( 154 | *) 155 | # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. 156 | # shellcheck disable=SC2039,SC3045 157 | ulimit -n "$MAX_FD" || 158 | warn "Could not set maximum file descriptor limit to $MAX_FD" 159 | esac 160 | fi 161 | 162 | # Collect all arguments for the java command, stacking in reverse order: 163 | # * args from the command line 164 | # * the main class name 165 | # * -classpath 166 | # * -D...appname settings 167 | # * --module-path (only if needed) 168 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 169 | 170 | # For Cygwin or MSYS, switch paths to Windows format before running java 171 | if "$cygwin" || "$msys" ; then 172 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 173 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 174 | 175 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 176 | 177 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 178 | for arg do 179 | if 180 | case $arg in #( 181 | -*) false ;; # don't mess with options #( 182 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 183 | [ -e "$t" ] ;; #( 184 | *) false ;; 185 | esac 186 | then 187 | arg=$( cygpath --path --ignore --mixed "$arg" ) 188 | fi 189 | # Roll the args list around exactly as many times as the number of 190 | # args, so each arg winds up back in the position where it started, but 191 | # possibly modified. 192 | # 193 | # NB: a `for` loop captures its iteration list before it begins, so 194 | # changing the positional parameters here affects neither the number of 195 | # iterations, nor the values presented in `arg`. 196 | shift # remove old arg 197 | set -- "$@" "$arg" # push replacement arg 198 | done 199 | fi 200 | 201 | 202 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 203 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 204 | 205 | # Collect all arguments for the java command: 206 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, 207 | # and any embedded shellness will be escaped. 208 | # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be 209 | # treated as '${Hostname}' itself on the command line. 210 | 211 | set -- \ 212 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 213 | -classpath "$CLASSPATH" \ 214 | org.gradle.wrapper.GradleWrapperMain \ 215 | "$@" 216 | 217 | # Stop when "xargs" is not available. 218 | if ! command -v xargs >/dev/null 2>&1 219 | then 220 | die "xargs is not available" 221 | fi 222 | 223 | # Use "xargs" to parse quoted args. 224 | # 225 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 226 | # 227 | # In Bash we could simply go: 228 | # 229 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 230 | # set -- "${ARGS[@]}" "$@" 231 | # 232 | # but POSIX shell has neither arrays nor command substitution, so instead we 233 | # post-process each arg (as a line of input to sed) to backslash-escape any 234 | # character that might be a shell metacharacter, then use eval to reverse 235 | # that process (while maintaining the separation between arguments), and wrap 236 | # the whole thing up as a single "set" statement. 237 | # 238 | # This will of course break if any of these variables contains a newline or 239 | # an unmatched quote. 240 | # 241 | 242 | eval "set -- $( 243 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 244 | xargs -n1 | 245 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 246 | tr '\n' ' ' 247 | )" '"$@"' 248 | 249 | exec "$JAVACMD" "$@" 250 | -------------------------------------------------------------------------------- /patches/server/0012-lithium-HashedList.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: JellySquid 3 | Date: Fri, 31 Jul 2020 21:46:32 -0500 4 | Subject: [PATCH] lithium HashedList 5 | 6 | Original code by JellySquid, licensed under GNU Lesser General Public License v3.0 7 | you can find the original code on https://github.com/CaffeineMC/lithium-fabric/ (Yarn mappings) 8 | 9 | diff --git a/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java 10 | new file mode 100644 11 | index 0000000000000000000000000000000000000000..2d79932dbd1fc386a94b8d6ea3526934c54c2aad 12 | --- /dev/null 13 | +++ b/src/main/java/me/jellysquid/mods/lithium/common/util/collections/HashedList.java 14 | @@ -0,0 +1,280 @@ 15 | +package me.jellysquid.mods.lithium.common.util.collections; 16 | + 17 | +import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; 18 | +import it.unimi.dsi.fastutil.objects.ReferenceArrayList; 19 | +import java.util.Collection; 20 | +import java.util.Iterator; 21 | +import java.util.List; 22 | +import java.util.ListIterator; 23 | +import java.util.NoSuchElementException; 24 | + 25 | +/** 26 | + * Wraps a {@link List} with a hash table which provides O(1) lookups for {@link Collection#contains(Object)}. The type 27 | + * contained by this list must use reference-equality semantics. 28 | + */ 29 | +@SuppressWarnings("SuspiciousMethodCalls") 30 | +public class HashedList implements List { 31 | + private final ReferenceArrayList list; 32 | + private final Reference2IntOpenHashMap counter; 33 | + 34 | + public HashedList(List list) { 35 | + this.list = new ReferenceArrayList<>(); 36 | + this.list.addAll(list); 37 | + 38 | + this.counter = new Reference2IntOpenHashMap<>(); 39 | + this.counter.defaultReturnValue(0); 40 | + 41 | + for (T obj : this.list) { 42 | + this.counter.addTo(obj, 1); 43 | + } 44 | + } 45 | + 46 | + @Override 47 | + public int size() { 48 | + return this.list.size(); 49 | + } 50 | + 51 | + @Override 52 | + public boolean isEmpty() { 53 | + return this.list.isEmpty(); 54 | + } 55 | + 56 | + @Override 57 | + public boolean contains(Object o) { 58 | + return this.counter.containsKey(o); 59 | + } 60 | + 61 | + @Override 62 | + public Iterator iterator() { 63 | + return this.listIterator(); 64 | + } 65 | + 66 | + @Override 67 | + public Object[] toArray() { 68 | + return this.list.toArray(); 69 | + } 70 | + 71 | + @SuppressWarnings("SuspiciousToArrayCall") 72 | + @Override 73 | + public T1[] toArray(T1[] a) { 74 | + return this.list.toArray(a); 75 | + } 76 | + 77 | + @Override 78 | + public boolean add(T t) { 79 | + this.trackReferenceAdded(t); 80 | + 81 | + return this.list.add(t); 82 | + } 83 | + 84 | + @Override 85 | + public boolean remove(Object o) { 86 | + this.trackReferenceRemoved(o); 87 | + 88 | + return this.list.remove(o); 89 | + } 90 | + 91 | + @Override 92 | + public boolean containsAll(Collection c) { 93 | + for (Object obj : c) { 94 | + if (!this.counter.containsKey(obj)) { 95 | + return false; 96 | + } 97 | + } 98 | + 99 | + return true; 100 | + } 101 | + 102 | + @Override 103 | + public boolean addAll(Collection c) { 104 | + for (T obj : c) { 105 | + this.trackReferenceAdded(obj); 106 | + } 107 | + 108 | + return this.list.addAll(c); 109 | + } 110 | + 111 | + @Override 112 | + public boolean addAll(int index, Collection c) { 113 | + for (T obj : c) { 114 | + this.trackReferenceAdded(obj); 115 | + } 116 | + 117 | + return this.list.addAll(index, c); 118 | + } 119 | + 120 | + @Override 121 | + public boolean removeAll(Collection c) { 122 | + for (Object obj : c) { 123 | + this.trackReferenceRemoved(obj); 124 | + } 125 | + 126 | + return this.list.removeAll(c); 127 | + } 128 | + 129 | + @Override 130 | + public boolean retainAll(Collection c) { 131 | + return this.list.retainAll(c); 132 | + } 133 | + 134 | + @Override 135 | + public void clear() { 136 | + this.counter.clear(); 137 | + this.list.clear(); 138 | + } 139 | + 140 | + @Override 141 | + public T get(int index) { 142 | + return this.list.get(index); 143 | + } 144 | + 145 | + @Override 146 | + public T set(int index, T element) { 147 | + T prev = this.list.set(index, element); 148 | + 149 | + if (prev != element) { 150 | + if (prev != null) { 151 | + this.trackReferenceRemoved(prev); 152 | + } 153 | + 154 | + this.trackReferenceAdded(element); 155 | + } 156 | + 157 | + return prev; 158 | + } 159 | + 160 | + @Override 161 | + public void add(int index, T element) { 162 | + this.trackReferenceAdded(element); 163 | + 164 | + this.list.add(index, element); 165 | + } 166 | + 167 | + @Override 168 | + public T remove(int index) { 169 | + T prev = this.list.remove(index); 170 | + 171 | + if (prev != null) { 172 | + this.trackReferenceRemoved(prev); 173 | + } 174 | + 175 | + return prev; 176 | + } 177 | + 178 | + @Override 179 | + public int indexOf(Object o) { 180 | + return this.list.indexOf(o); 181 | + } 182 | + 183 | + @Override 184 | + public int lastIndexOf(Object o) { 185 | + return this.list.lastIndexOf(o); 186 | + } 187 | + 188 | + @Override 189 | + public ListIterator listIterator() { 190 | + return this.listIterator(0); 191 | + } 192 | + 193 | + @Override 194 | + public ListIterator listIterator(int index) { 195 | + return new ListIterator() { 196 | + private final ListIterator inner = HashedList.this.list.listIterator(index); 197 | + 198 | + @Override 199 | + public boolean hasNext() { 200 | + return this.inner.hasNext(); 201 | + } 202 | + 203 | + @Override 204 | + public T next() { 205 | + return this.inner.next(); 206 | + } 207 | + 208 | + @Override 209 | + public boolean hasPrevious() { 210 | + return this.inner.hasPrevious(); 211 | + } 212 | + 213 | + @Override 214 | + public T previous() { 215 | + return this.inner.previous(); 216 | + } 217 | + 218 | + @Override 219 | + public int nextIndex() { 220 | + return this.inner.nextIndex(); 221 | + } 222 | + 223 | + @Override 224 | + public int previousIndex() { 225 | + return this.inner.previousIndex(); 226 | + } 227 | + 228 | + @Override 229 | + public void remove() { 230 | + int last = this.previousIndex(); 231 | + 232 | + if (last == -1) { 233 | + throw new NoSuchElementException(); 234 | + } 235 | + 236 | + T prev = HashedList.this.get(last); 237 | + 238 | + if (prev != null) { 239 | + HashedList.this.trackReferenceRemoved(prev); 240 | + } 241 | + 242 | + this.inner.remove(); 243 | + } 244 | + 245 | + @Override 246 | + public void set(T t) { 247 | + int last = this.previousIndex(); 248 | + 249 | + if (last == -1) { 250 | + throw new NoSuchElementException(); 251 | + } 252 | + 253 | + T prev = HashedList.this.get(last); 254 | + 255 | + if (prev != t) { 256 | + if (prev != null) { 257 | + HashedList.this.trackReferenceRemoved(prev); 258 | + } 259 | + 260 | + HashedList.this.trackReferenceAdded(t); 261 | + } 262 | + 263 | + this.inner.remove(); 264 | + } 265 | + 266 | + @Override 267 | + public void add(T t) { 268 | + HashedList.this.trackReferenceAdded(t); 269 | + 270 | + this.inner.add(t); 271 | + } 272 | + }; 273 | + } 274 | + 275 | + @Override 276 | + public List subList(int fromIndex, int toIndex) { 277 | + return this.list.subList(fromIndex, toIndex); 278 | + } 279 | + 280 | + private void trackReferenceAdded(T t) { 281 | + this.counter.addTo(t, 1); 282 | + } 283 | + 284 | + @SuppressWarnings("unchecked") 285 | + private void trackReferenceRemoved(Object o) { 286 | + if (this.counter.addTo((T) o, -1) <= 1) { 287 | + this.counter.removeInt(o); 288 | + } 289 | + } 290 | + 291 | + public static HashedList wrapper(List list) { 292 | + return new HashedList<>(list); 293 | + } 294 | +} 295 | diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java 296 | index 116cfd126df3ed5c6643e70912c0d6a63f4a6eb2..a73d6542b15ec199bcaaf3b8bdbfc366a47ac473 100644 297 | --- a/src/main/java/net/minecraft/world/level/Level.java 298 | +++ b/src/main/java/net/minecraft/world/level/Level.java 299 | @@ -116,9 +116,9 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl 300 | public static final int TICKS_PER_DAY = 24000; 301 | public static final int MAX_ENTITY_SPAWN_Y = 20000000; 302 | public static final int MIN_ENTITY_SPAWN_Y = -20000000; 303 | - public final List blockEntityTickers = Lists.newArrayList(); // Paper - public 304 | + public final List blockEntityTickers = me.jellysquid.mods.lithium.common.util.collections.HashedList.wrapper(Lists.newArrayList()); // Paper - public // Jettpack - lithium: hashed_list 305 | protected final NeighborUpdater neighborUpdater; 306 | - private final List pendingBlockEntityTickers = Lists.newArrayList(); 307 | + private final List pendingBlockEntityTickers = me.jellysquid.mods.lithium.common.util.collections.HashedList.wrapper(Lists.newArrayList()); // Jettpack - lithium: hashed_list 308 | private boolean tickingBlockEntities; 309 | public final Thread thread; 310 | private final boolean isDebug; 311 | -------------------------------------------------------------------------------- /patches/removed/server/0010-Yatopia-configuration.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: tr7zw 3 | Date: Wed, 5 Aug 2020 08:05:10 -0500 4 | Subject: [PATCH] Yatopia configuration 5 | 6 | also some basic settings that dont deserve a patch 7 | 8 | diff --git a/src/main/java/co/aikar/timings/TimingsExport.java b/src/main/java/co/aikar/timings/TimingsExport.java 9 | index 6a1d0ed30fa05b76f70397b8bb719ba7df40c794..4638f6b1df7e232f395f3eccea9ddf3d2c1f16a0 100644 10 | --- a/src/main/java/co/aikar/timings/TimingsExport.java 11 | +++ b/src/main/java/co/aikar/timings/TimingsExport.java 12 | @@ -230,6 +230,7 @@ public class TimingsExport extends Thread { 13 | pair("paper", mapAsJSON(Bukkit.spigot().getPaperConfig(), null)), // Pufferfish 14 | pair("pufferfish", mapAsJSON(gg.pufferfish.pufferfish.PufferfishConfig.getConfigCopy(), null)) // Pufferfish 15 | ,pair("purpur", mapAsJSON(Bukkit.spigot().getPurpurConfig(), null)) // Patina - add Purpur to timings report 16 | + ,pair("yatopia", mapAsJSON(Bukkit.spigot().getYatopiaConfig(), null)) // Yatopia - add config to timings report 17 | )); 18 | 19 | new TimingsExport(listeners, parent, history).start(); 20 | diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java 21 | index 20efc03d5b115e4ccea534049314445f5283f821..a947bc4d2a3ca0d1a585392d572394106c56d837 100644 22 | --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java 23 | +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java 24 | @@ -244,6 +244,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface 25 | gg.pufferfish.pufferfish.PufferfishConfig.load(); // Pufferfish 26 | gg.pufferfish.pufferfish.PufferfishCommand.init(); // Pufferfish 27 | 28 | + // Yatopia start 29 | + try { 30 | + org.yatopiamc.yatopia.server.YatopiaConfig.init((java.io.File) options.valueOf("yatopia-settings")); 31 | + } catch (Exception e) { 32 | + DedicatedServer.LOGGER.error("Unable to load server configuration", e); 33 | + return false; 34 | + } 35 | + // Yatopia end 36 | + 37 | this.setPvpAllowed(dedicatedserverproperties.pvp); 38 | this.setFlightAllowed(dedicatedserverproperties.allowFlight); 39 | this.setResourcePack(dedicatedserverproperties.resourcePack, this.getPackHash()); 40 | diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java 41 | index 6a2c91042fcc1ef452d5e7587bfa5ce7571235e4..f683b57b024d50110308d79efe5f1978ba6ec952 100644 42 | --- a/src/main/java/net/minecraft/server/players/PlayerList.java 43 | +++ b/src/main/java/net/minecraft/server/players/PlayerList.java 44 | @@ -269,7 +269,7 @@ public abstract class PlayerList { 45 | // Spigot - view distance 46 | playerconnection.send(new ClientboundLoginPacket(player.getId(), worlddata.isHardcore(), player.gameMode.getGameModeForPlayer(), player.gameMode.getPreviousGameModeForPlayer(), this.server.levelKeys(), this.registryHolder, worldserver1.dimensionType(), worldserver1.dimension(), BiomeManager.obfuscateSeed(worldserver1.getSeed()), this.getMaxPlayers(), worldserver1.spigotConfig.viewDistance, worldserver1.spigotConfig.simulationDistance, flag1, !flag, worldserver1.isDebug(), worldserver1.isFlat())); 47 | player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit 48 | - playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf(this.getServer().getServerModName()))); 49 | + playerconnection.send(new ClientboundCustomPayloadPacket(ClientboundCustomPayloadPacket.BRAND, (new FriendlyByteBuf(Unpooled.buffer())).writeUtf((org.yatopiamc.yatopia.server.YatopiaConfig.brandName)))); // Yatopia))); 50 | playerconnection.send(new ClientboundChangeDifficultyPacket(worlddata.getDifficulty(), worlddata.isDifficultyLocked())); 51 | playerconnection.send(new ClientboundPlayerAbilitiesPacket(player.getAbilities())); 52 | playerconnection.send(new ClientboundSetCarriedItemPacket(player.getInventory().selected)); 53 | diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java 54 | index bfe8559d3b9c3ca94dff228ce4392422cd26d352..114911e5a966c5efe1e359e9ea01f0508f2bbbcf 100644 55 | --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java 56 | +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java 57 | @@ -393,6 +393,7 @@ public abstract class LivingEntity extends Entity { 58 | 59 | if (this.isAlive()) { 60 | boolean flag = this instanceof net.minecraft.world.entity.player.Player; 61 | + if (!org.yatopiamc.yatopia.server.YatopiaConfig.disableEntityStuckChecks) { // Yatopia 62 | if (tickCount % 20 == 0 && couldPossiblyBeHurt(1.0F) && this.isInWall()) { // Pufferfish - optimize suffocation 63 | this.hurt(DamageSource.IN_WALL, 1.0F); 64 | } else if (flag && !this.level.getWorldBorder().isWithinBounds(this.getBoundingBox())) { 65 | @@ -406,6 +407,7 @@ public abstract class LivingEntity extends Entity { 66 | } 67 | } 68 | } 69 | + } // Yatopia 70 | 71 | if (this.isEyeInFluid(FluidTags.WATER) && !this.level.getBlockState(new BlockPos(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) { 72 | boolean flag1 = !this.canBreatheUnderwater() && !MobEffectUtil.hasWaterBreathing(this) && (!flag || !((net.minecraft.world.entity.player.Player) this).getAbilities().invulnerable); 73 | diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java 74 | index 0dd48ea1ae59102b87714e1d421895ceee8d6105..82f3eda11342ef965887f3f9b135743c35e00059 100644 75 | --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java 76 | +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java 77 | @@ -948,6 +948,7 @@ public final class CraftServer implements Server { 78 | this.playerList.getBans().load(); 79 | } catch (IOException ex) { 80 | this.logger.log(Level.WARNING, "Failed to load banned-players.json, " + ex.getMessage()); 81 | + org.yatopiamc.yatopia.server.YatopiaConfig.init((File) console.options.valueOf("yatopia-settings")); // Yatopia 82 | } 83 | 84 | org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot 85 | @@ -2687,6 +2688,13 @@ public final class CraftServer implements Server { 86 | org.spigotmc.RestartCommand.restart(); 87 | } 88 | 89 | + // Yatopia start 90 | + @Override 91 | + public YamlConfiguration getYatopiaConfig() { 92 | + return org.yatopiamc.yatopia.server.YatopiaConfig.config; 93 | + } 94 | + // Yatopia end 95 | + 96 | @Override 97 | public void broadcast(BaseComponent component) { 98 | for (Player player : CraftServer.this.getOnlinePlayers()) { 99 | diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java 100 | index 6f14a1b26e92d0170538ed60c6a651a031e7209e..f3f846a8d008923e00e1891dc3eb04d4b553a460 100644 101 | --- a/src/main/java/org/bukkit/craftbukkit/Main.java 102 | +++ b/src/main/java/org/bukkit/craftbukkit/Main.java 103 | @@ -161,6 +161,14 @@ public class Main { 104 | .describedAs("Yml file"); 105 | // Purpur end 106 | 107 | + // Yatopia start 108 | + acceptsAll(asList("yatopia", "yatopia-settings"), "File for yatopia settings") 109 | + .withRequiredArg() 110 | + .ofType(File.class) 111 | + .defaultsTo(new File("yatopia.yml")) 112 | + .describedAs("Yml file"); 113 | + // Yatopia end 114 | + 115 | // Paper start 116 | acceptsAll(asList("server-name"), "Name of the server") 117 | .withRequiredArg() 118 | diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 119 | new file mode 100644 120 | index 0000000000000000000000000000000000000000..eb6786fa040ede035b649d3f9c2c117afe390406 121 | --- /dev/null 122 | +++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java 123 | @@ -0,0 +1,189 @@ 124 | +package org.yatopiamc.yatopia.server; 125 | + 126 | +import com.google.common.base.Throwables; 127 | +import java.io.File; 128 | +import java.io.IOException; 129 | +import java.lang.reflect.InvocationTargetException; 130 | +import java.lang.reflect.Method; 131 | +import java.lang.reflect.Modifier; 132 | +import java.util.List; 133 | +import java.util.concurrent.TimeUnit; 134 | +import java.util.logging.Level; 135 | +import java.util.regex.Pattern; 136 | +import org.bukkit.Bukkit; 137 | +import org.bukkit.configuration.InvalidConfigurationException; 138 | +import org.bukkit.configuration.file.YamlConfiguration; 139 | +public class YatopiaConfig { 140 | + public static File CONFIG_FILE; 141 | + private static final String HEADER = "This is the main configuration file for Yatopia.\n" 142 | + + "Yatopia contains many breaking changes and settings, so know what you are doing!\n" 143 | + + "You have been warned!\n"; 144 | + /*========================================================================*/ 145 | + public static YamlConfiguration config; 146 | + public static int version; // since we're remapping sidestreams' configs we need this public 147 | + public static boolean verbose; // since we're remapping sidestreams' configs we need this public 148 | + /*========================================================================*/ 149 | + 150 | + public static void init(File configFile) { 151 | + CONFIG_FILE = configFile; 152 | + config = new YamlConfiguration(); 153 | + try { 154 | + config.load(CONFIG_FILE); 155 | + } catch (IOException ex) { 156 | + } catch (InvalidConfigurationException ex) { 157 | + Bukkit.getLogger().log(Level.SEVERE, "Could not load yatopia.yml, please correct your syntax errors", ex); 158 | + throw Throwables.propagate(ex); 159 | + } 160 | + config.options().header(HEADER); 161 | + config.options().copyDefaults(true); 162 | + verbose = getBoolean("verbose", false); 163 | + version = getInt("config-version", 1); 164 | + set("config-version", 1); 165 | + removeLeftovers(); 166 | + readConfig(YatopiaConfig.class, null); 167 | + } 168 | + 169 | + private static void removeLeftovers() { 170 | + // this method is only to remove non-used values in the config 171 | + 172 | + // leftover from rainforest 173 | + if (config.get("world-settings") != null) { 174 | + set("world-settings", null); 175 | + } 176 | + if (config.get("allow-player-item-duplication") != null) { 177 | + set("allow-player-item-duplication", null); 178 | + } 179 | + if (config.get("allow-ridable-chestable-duping") != null) { 180 | + set("allow-ridable-chestable-duping", null); 181 | + } 182 | + if (config.get("allow-sand-duping") != null) { 183 | + set("allow-sand-duping", null); 184 | + } 185 | + } 186 | + 187 | + protected static void logError(String s) { 188 | + Bukkit.getLogger().severe(s); 189 | + } 190 | + 191 | + protected static void log(String s) { 192 | + if (verbose) { 193 | + Bukkit.getLogger().info(s); 194 | + } 195 | + } 196 | + 197 | + static void readConfig(Class clazz, Object instance) { 198 | + for (Method method : clazz.getDeclaredMethods()) { 199 | + if (Modifier.isPrivate(method.getModifiers())) { 200 | + if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { 201 | + try { 202 | + method.setAccessible(true); 203 | + method.invoke(instance); 204 | + } catch (InvocationTargetException ex) { 205 | + throw Throwables.propagate(ex.getCause()); 206 | + } catch (Exception ex) { 207 | + Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); 208 | + } 209 | + } 210 | + } 211 | + } 212 | + 213 | + try { 214 | + config.save(CONFIG_FILE); 215 | + } catch (IOException ex) { 216 | + Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex); 217 | + } 218 | + } 219 | + 220 | + private static final Pattern SPACE = Pattern.compile(" "); 221 | + private static final Pattern NOT_NUMERIC = Pattern.compile("[^-\\d.]"); 222 | + 223 | + public static int getSeconds(String str) { 224 | + str = SPACE.matcher(str).replaceAll(""); 225 | + final char unit = str.charAt(str.length() - 1); 226 | + str = NOT_NUMERIC.matcher(str).replaceAll(""); 227 | + double num; 228 | + try { 229 | + num = Double.parseDouble(str); 230 | + } catch (Exception e) { 231 | + num = 0D; 232 | + } 233 | + switch (unit) { 234 | + case 'd': 235 | + num *= (double) 60 * 60 * 24; 236 | + break; 237 | + case 'h': 238 | + num *= (double) 60 * 60; 239 | + break; 240 | + case 'm': 241 | + num *= 60; 242 | + break; 243 | + default: 244 | + case 's': 245 | + break; 246 | + } 247 | + return (int) num; 248 | +} 249 | + 250 | + protected static String timeSummary(int seconds) { 251 | + String time = ""; 252 | + 253 | + if (seconds > 60 * 60 * 24) { 254 | + time += TimeUnit.SECONDS.toDays(seconds) + "d"; 255 | + seconds %= 60 * 60 * 24; 256 | + } 257 | + 258 | + if (seconds > 60 * 60) { 259 | + time += TimeUnit.SECONDS.toHours(seconds) + "h"; 260 | + seconds %= 60 * 60; 261 | + } 262 | + 263 | + if (seconds > 0) { 264 | + time += TimeUnit.SECONDS.toMinutes(seconds) + "m"; 265 | + } 266 | + return time; 267 | +} 268 | + 269 | + private static void set(String path, Object val) { 270 | + config.set(path, val); 271 | +} 272 | + 273 | + private static boolean getBoolean(String path, boolean def) { 274 | + config.addDefault(path, def); 275 | + return config.getBoolean(path, config.getBoolean(path)); 276 | +} 277 | + 278 | + private static double getDouble(String path, double def) { 279 | + config.addDefault(path, def); 280 | + return config.getDouble(path, config.getDouble(path)); 281 | +} 282 | + 283 | + private static float getFloat(String path, float def) { 284 | + // TODO: Figure out why getFloat() always returns the default value. 285 | + return (float) getDouble(path, (double) def); 286 | +} 287 | + 288 | + private static int getInt(String path, int def) { 289 | + config.addDefault(path, def); 290 | + return config.getInt(path, config.getInt(path)); 291 | +} 292 | + 293 | + private static List getList(String path, List def) { 294 | + config.addDefault(path, def); 295 | + return (List) config.getList(path, config.getList(path)); 296 | +} 297 | + 298 | + private static String getString(String path, String def) { 299 | + config.addDefault(path, def); 300 | + return config.getString(path, config.getString(path)); 301 | +} 302 | + 303 | + public static boolean disableEntityStuckChecks = false; 304 | +private static void disableEntityStuckChecks() { 305 | + disableEntityStuckChecks = getBoolean("settings.disableEntityStuckChecks", false); 306 | +} 307 | + 308 | + public static String brandName = "Yatopia"; 309 | +private static void brandName() { 310 | + brandName = getString("brand-name", brandName); 311 | + } 312 | +} 313 | \ No newline at end of file 314 | -------------------------------------------------------------------------------- /patches/api/0004-Suspected-plugins-report.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: ishland 3 | Date: Fri, 29 Jan 2021 09:57:47 +0800 4 | Subject: [PATCH] Suspected plugins report 5 | 6 | Added "Suspected Plugins" to Watchdog, crash reports and exception messages 7 | 8 | diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java 9 | index e8ba4f1108f2548a487877027e37d81fc150e042..3e8e5ddba87f11ac6ccfb6bedbc85ee0fd62fff2 100644 10 | --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java 11 | +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java 12 | @@ -598,7 +598,11 @@ public final class SimplePluginManager implements PluginManager { 13 | // Paper start 14 | private void handlePluginException(String msg, Throwable ex, Plugin plugin) { 15 | gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish 16 | - server.getLogger().log(Level.SEVERE, msg, ex); 17 | + // Yatopia start - detailed report 18 | + server.getLogger().log(Level.SEVERE, msg); 19 | + org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg)); 20 | + server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex); 21 | + // Yatopia end 22 | gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish 23 | callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin))); 24 | } 25 | @@ -672,7 +676,11 @@ public final class SimplePluginManager implements PluginManager { 26 | gg.pufferfish.pufferfish.sentry.SentryContext.setEventContext(event, registration); // Pufferfish 27 | // Paper start - error reporting 28 | String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(); 29 | - server.getLogger().log(Level.SEVERE, msg, ex); 30 | + // Yatopia start - detailed report 31 | + server.getLogger().log(Level.SEVERE, msg); 32 | + org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg)); 33 | + server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex); 34 | + // Yatopia end 35 | gg.pufferfish.pufferfish.sentry.SentryContext.removeEventContext(); // Pufferfish 36 | if (!(event instanceof com.destroystokyo.paper.event.server.ServerExceptionEvent)) { // We don't want to cause an endless event loop 37 | callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event))); 38 | @@ -995,4 +1003,10 @@ public final class SimplePluginManager implements PluginManager { 39 | this.paperPluginManager.addPermissions(perm); 40 | } 41 | // Paper end 42 | + // Yatopia start - Accessor 43 | + @NotNull 44 | + public Collection getPluginLoaders() { 45 | + return new HashSet<>(fileAssociations.values()); 46 | + } 47 | + // Yatopia end 48 | } 49 | diff --git a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java 50 | index e0203f199700c397961a0667a79792497da7f796..cc12da5066e56630784b4b770da5fa346f894761 100644 51 | --- a/src/main/java/org/bukkit/plugin/java/JavaPlugin.java 52 | +++ b/src/main/java/org/bukkit/plugin/java/JavaPlugin.java 53 | @@ -127,7 +127,7 @@ public abstract class JavaPlugin extends PluginBase { 54 | * @return File containing this plugin 55 | */ 56 | @NotNull 57 | - protected File getFile() { 58 | + public File getFile() { // Yatopia 59 | return file; 60 | } 61 | 62 | diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java 63 | index 301e82369603f3dd6e6c1bd380da4bacacd7ef6c..7573bda5d8a409d82bcd4baf77cff8dfcfbcfcf4 100644 64 | --- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java 65 | +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java 66 | @@ -337,7 +337,11 @@ public final class JavaPluginLoader implements PluginLoader { 67 | jPlugin.setEnabled(true); 68 | } catch (Throwable ex) { 69 | gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish 70 | - server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); 71 | + // Yatopia start - detailed report 72 | + server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)"); 73 | + org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg)); 74 | + server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex); 75 | + // Yatopia end 76 | gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish 77 | // Paper start - Disable plugins that fail to load 78 | this.server.getPluginManager().disablePlugin(jPlugin); 79 | @@ -368,7 +372,11 @@ public final class JavaPluginLoader implements PluginLoader { 80 | jPlugin.setEnabled(false); 81 | } catch (Throwable ex) { 82 | gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish 83 | - server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); 84 | + // Yatopia start - detailed report 85 | + server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)"); 86 | + org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.SEVERE, _msg)); 87 | + server.getLogger().log(Level.SEVERE, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex); 88 | + // Yatopia end 89 | gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish 90 | } 91 | 92 | @@ -385,9 +393,18 @@ public final class JavaPluginLoader implements PluginLoader { 93 | try { 94 | loader.close(); 95 | } catch (IOException ex) { 96 | - // 97 | + // Yatopia start - detailed report 98 | + this.server.getLogger().log(Level.WARNING, "Error closing the PluginClassLoader for '" + plugin.getDescription().getFullName() + "'", ex); // Paper - log exception 99 | + org.yatopiamc.yatopia.api.internal.StackTraceUtils.print(ex, _msg -> server.getLogger().log(Level.WARNING, _msg)); 100 | + server.getLogger().log(Level.WARNING, org.yatopiamc.yatopia.api.internal.StackTraceUtils.EXCEPTION_DETAILS_BELOW, ex); 101 | + // Yatopia end 102 | } 103 | } 104 | } 105 | } 106 | + // Yatopia start - Accessor 107 | + public List getClassLoaders() { 108 | + return java.util.Collections.unmodifiableList(loaders); 109 | + } 110 | + // Yatopia end 111 | } 112 | diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java 113 | index 12449e18180d604e9cbbc744da74a8b222a18e1f..b7e94298f8d29d1a2ad0b7b79e4e601e51699e93 100644 114 | --- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java 115 | +++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java 116 | @@ -323,4 +323,13 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm 117 | } 118 | 119 | // Paper end 120 | + 121 | + // Yatopia start - Accessor 122 | + public java.util.Collection> getLoadedClasses() { 123 | + return java.util.Collections.unmodifiableCollection( 124 | + new java.util.HashSet<>(classes.values()).stream() 125 | + .filter(clazz -> clazz.getClassLoader() == this).collect(java.util.stream.Collectors.toSet()) 126 | + ); 127 | + } 128 | + // Yatopia end 129 | } 130 | diff --git a/src/main/java/org/yatopiamc/yatopia/api/internal/StackTraceUtils.java b/src/main/java/org/yatopiamc/yatopia/api/internal/StackTraceUtils.java 131 | new file mode 100644 132 | index 0000000000000000000000000000000000000000..0aa9bc6ad0a85d469b29201b9da29165bafb874c 133 | --- /dev/null 134 | +++ b/src/main/java/org/yatopiamc/yatopia/api/internal/StackTraceUtils.java 135 | @@ -0,0 +1,105 @@ 136 | +package org.yatopiamc.yatopia.api.internal; 137 | + 138 | +import com.google.common.base.Suppliers; 139 | +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; 140 | +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; 141 | +import org.bukkit.Bukkit; 142 | +import org.bukkit.plugin.Plugin; 143 | +import org.bukkit.plugin.PluginLoader; 144 | +import org.bukkit.plugin.SimplePluginManager; 145 | +import org.bukkit.plugin.java.JavaPlugin; 146 | +import org.bukkit.plugin.java.JavaPluginLoader; 147 | +import org.bukkit.plugin.java.PluginClassLoader; 148 | + 149 | +import java.util.Arrays; 150 | +import java.util.Collection; 151 | +import java.util.Collections; 152 | +import java.util.HashSet; 153 | +import java.util.List; 154 | +import java.util.Map; 155 | +import java.util.Set; 156 | +import java.util.concurrent.TimeUnit; 157 | +import java.util.function.Consumer; 158 | +import java.util.function.Supplier; 159 | +import java.util.stream.Collectors; 160 | + 161 | +public class StackTraceUtils { 162 | + 163 | + public static final String EXCEPTION_DETAILS_BELOW = "Exception details below: "; 164 | + 165 | + private static final Supplier>>> loadedClassesSupplier = Suppliers.memoizeWithExpiration(StackTraceUtils::scanForPluginClasses, 5, TimeUnit.SECONDS); 166 | + 167 | + public static void print(StackTraceElement[] stackTrace, Consumer out) { 168 | + Set suspectedPlugins = getSuspectedPluginsFromStackTrace(stackTrace); 169 | + 170 | + printSuspectedPlugins(out, suspectedPlugins); 171 | + } 172 | + 173 | + public static void print(Throwable t, Consumer out) { 174 | + Set suspectedPlugins = getSuspectedPluginsFromStackTrace(getStackTracesFromThrowable(t).toArray(new StackTraceElement[0])); 175 | + 176 | + printSuspectedPlugins(out, suspectedPlugins); 177 | + } 178 | + 179 | + private static Set getStackTracesFromThrowable(Throwable t) { 180 | + if(t == null) return Collections.emptySet(); 181 | + Set elements = new ObjectOpenHashSet<>(); 182 | + elements.addAll(getStackTracesFromThrowable(t.getCause())); 183 | + elements.addAll(Arrays.stream(t.getSuppressed()).flatMap(throwable -> getStackTracesFromThrowable(throwable).stream()).collect(Collectors.toSet())); 184 | + elements.addAll(Arrays.asList(t.getStackTrace())); 185 | + return elements; 186 | + } 187 | + 188 | + private static void printSuspectedPlugins(Consumer out, Set suspectedPlugins) { 189 | + if (!suspectedPlugins.isEmpty()) { 190 | + out.accept("Suspected Plugins: "); 191 | + for (Plugin plugin : suspectedPlugins) { 192 | + StringBuilder builder = new StringBuilder("\t"); 193 | + builder.append(plugin.getName()) 194 | + .append("{") 195 | + .append(plugin.isEnabled() ? "enabled" : "disabled") 196 | + .append(",").append("ver=").append(plugin.getDescription().getVersion()); 197 | + if (!plugin.isNaggable()) 198 | + builder.append(",").append("nag"); 199 | + if (plugin instanceof JavaPlugin) 200 | + builder.append(",").append("path=").append(((JavaPlugin) plugin).getFile()); 201 | + 202 | + builder.append("}"); 203 | + out.accept(builder.toString()); 204 | + } 205 | + } else { 206 | + out.accept("Suspected Plugins: None"); 207 | + } 208 | + } 209 | + 210 | + private static Set getSuspectedPluginsFromStackTrace(StackTraceElement[] stackTrace) { 211 | + Map>> loadedClasses = loadedClassesSupplier.get(); 212 | + Set suspectedPlugins = new HashSet<>(); 213 | + for (StackTraceElement stackTraceElement : stackTrace) { 214 | + for (Map.Entry>> pluginSetEntry : loadedClasses.entrySet()) { 215 | + if (pluginSetEntry.getValue().stream().anyMatch(clazz -> clazz.getName().equals(stackTraceElement.getClassName()))) 216 | + suspectedPlugins.add(pluginSetEntry.getKey()); 217 | + } 218 | + } 219 | + return suspectedPlugins; 220 | + } 221 | + 222 | + private static Map>> scanForPluginClasses() { 223 | + Map>> loadedClasses = new Object2ObjectOpenHashMap<>(); 224 | + if (Bukkit.getPluginManager() instanceof SimplePluginManager) { 225 | + final SimplePluginManager pluginManager = (SimplePluginManager) Bukkit.getPluginManager(); 226 | + final Collection pluginLoaders = pluginManager.getPluginLoaders(); 227 | + for (PluginLoader pluginLoader : pluginLoaders) { 228 | + if (pluginLoader instanceof JavaPluginLoader) { 229 | + JavaPluginLoader javaPluginLoader = (JavaPluginLoader) pluginLoader; 230 | + final List classLoaders = javaPluginLoader.getClassLoaders(); 231 | + for (PluginClassLoader classLoader : classLoaders) { 232 | + loadedClasses.put(classLoader.getPlugin(), new ObjectOpenHashSet<>(classLoader.getLoadedClasses())); 233 | + } 234 | + } 235 | + } 236 | + } 237 | + return loadedClasses; 238 | + } 239 | + 240 | +} 241 | diff --git a/src/test/java/org/bukkit/AnnotationTest.java b/src/test/java/org/bukkit/AnnotationTest.java 242 | index b82f07a2879412f6b30643ca93a97439aa49a98a..5bee03091b047ddd6c856aa6d661f7abe8ae9f53 100644 243 | --- a/src/test/java/org/bukkit/AnnotationTest.java 244 | +++ b/src/test/java/org/bukkit/AnnotationTest.java 245 | @@ -57,8 +57,11 @@ public class AnnotationTest { 246 | "co/aikar/timings/TimingHistory$2$1$2", 247 | "co/aikar/timings/TimingHistory$3", 248 | "co/aikar/timings/TimingHistory$4", 249 | - "co/aikar/timings/TimingHistoryEntry$1" 250 | + "co/aikar/timings/TimingHistoryEntry$1", 251 | // Paper end 252 | + // Yatopia start 253 | + "org/yatopiamc/yatopia/api/internal/StackTraceUtils" 254 | + // Yatopia end 255 | }; 256 | 257 | @Test 258 | -------------------------------------------------------------------------------- /patches/api/0001-pufferfish-API-Changes-commit-cfa3c6122d26078e3c4432.patch: -------------------------------------------------------------------------------- 1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 2 | From: foss-mc <69294560+foss-mc@users.noreply.github.com> 3 | Date: Wed, 11 Dec 2024 14:28:41 +1100 4 | Subject: [PATCH] pufferfish API Changes commit 5 | cfa3c6122d26078e3c4432b792599c48f7c1a637 6 | 7 | Add Sentry 8 | 9 | Expose findClass for profiler 10 | 11 | Ignore lookups if closed 12 | 13 | Add SIMD utilities 14 | 15 | The utilities added in this patch are not intended to be used by plugins 16 | and API spec stability is NOT guaranteed. If you use this in plugins, 17 | they WILL break eventually. 18 | 19 | Optimize map rendering 20 | 21 | This patch does not add any API that should be used by plugins. Any 22 | classes and methods added by this patch should NOT be used in plugins. 23 | 24 | diff --git a/build.gradle.kts b/build.gradle.kts 25 | index e7c96be769fde8375b9a1b128cc7ce474144d16d..f9b44a03fe8d9a2fea2d968f4e944a6663c6f9c9 100644 26 | --- a/build.gradle.kts 27 | +++ b/build.gradle.kts 28 | @@ -52,6 +52,7 @@ dependencies { 29 | apiAndDocs("net.kyori:adventure-text-logger-slf4j") 30 | api("org.apache.logging.log4j:log4j-api:$log4jVersion") 31 | api("org.slf4j:slf4j-api:$slf4jVersion") 32 | + api("io.sentry:sentry:5.4.0") // Pufferfish 33 | 34 | implementation("org.ow2.asm:asm:9.7.1") 35 | implementation("org.ow2.asm:asm-commons:9.7.1") 36 | @@ -131,6 +132,13 @@ val generateApiVersioningFile by tasks.registering { 37 | } 38 | } 39 | 40 | +// Pufferfish Start 41 | +tasks.withType { 42 | + val compilerArgs = options.compilerArgs 43 | + compilerArgs.add("--add-modules=jdk.incubator.vector") 44 | +} 45 | +// Pufferfish End 46 | + 47 | tasks.jar { 48 | from(generateApiVersioningFile.map { it.outputs.files.singleFile }) { 49 | into("META-INF/maven/${project.group}/${project.name}") 50 | diff --git a/src/main/java/gg/pufferfish/pufferfish/sentry/SentryContext.java b/src/main/java/gg/pufferfish/pufferfish/sentry/SentryContext.java 51 | new file mode 100644 52 | index 0000000000000000000000000000000000000000..10310fdd53de28efb8a8250f6d3b0c8eb08fb68a 53 | --- /dev/null 54 | +++ b/src/main/java/gg/pufferfish/pufferfish/sentry/SentryContext.java 55 | @@ -0,0 +1,161 @@ 56 | +package gg.pufferfish.pufferfish.sentry; 57 | + 58 | +import com.google.gson.Gson; 59 | +import java.lang.reflect.Field; 60 | +import java.lang.reflect.Modifier; 61 | +import java.util.Map; 62 | +import java.util.TreeMap; 63 | +import org.apache.logging.log4j.ThreadContext; 64 | +import org.bukkit.command.Command; 65 | +import org.bukkit.command.CommandSender; 66 | +import org.bukkit.entity.Player; 67 | +import org.bukkit.event.Event; 68 | +import org.bukkit.event.player.PlayerEvent; 69 | +import org.bukkit.plugin.Plugin; 70 | +import org.bukkit.plugin.RegisteredListener; 71 | +import org.jetbrains.annotations.Nullable; 72 | + 73 | +public class SentryContext { 74 | + 75 | + private static final Gson GSON = new Gson(); 76 | + 77 | + public static void setPluginContext(@Nullable Plugin plugin) { 78 | + if (plugin != null) { 79 | + ThreadContext.put("pufferfishsentry_pluginname", plugin.getName()); 80 | + ThreadContext.put("pufferfishsentry_pluginversion", plugin.getDescription().getVersion()); 81 | + } 82 | + } 83 | + 84 | + public static void removePluginContext() { 85 | + ThreadContext.remove("pufferfishsentry_pluginname"); 86 | + ThreadContext.remove("pufferfishsentry_pluginversion"); 87 | + } 88 | + 89 | + public static void setSenderContext(@Nullable CommandSender sender) { 90 | + if (sender != null) { 91 | + ThreadContext.put("pufferfishsentry_playername", sender.getName()); 92 | + if (sender instanceof Player player) { 93 | + ThreadContext.put("pufferfishsentry_playerid", player.getUniqueId().toString()); 94 | + } 95 | + } 96 | + } 97 | + 98 | + public static void removeSenderContext() { 99 | + ThreadContext.remove("pufferfishsentry_playername"); 100 | + ThreadContext.remove("pufferfishsentry_playerid"); 101 | + } 102 | + 103 | + public static void setEventContext(Event event, RegisteredListener registration) { 104 | + setPluginContext(registration.getPlugin()); 105 | + 106 | + try { 107 | + // Find the player that was involved with this event 108 | + Player player = null; 109 | + if (event instanceof PlayerEvent) { 110 | + player = ((PlayerEvent) event).getPlayer(); 111 | + } else { 112 | + Class eventClass = event.getClass(); 113 | + 114 | + Field playerField = null; 115 | + 116 | + for (Field field : eventClass.getDeclaredFields()) { 117 | + if (field.getType().equals(Player.class)) { 118 | + playerField = field; 119 | + break; 120 | + } 121 | + } 122 | + 123 | + if (playerField != null) { 124 | + playerField.setAccessible(true); 125 | + player = (Player) playerField.get(event); 126 | + } 127 | + } 128 | + 129 | + if (player != null) { 130 | + setSenderContext(player); 131 | + } 132 | + } catch (Exception e) {} // We can't really safely log exceptions. 133 | + 134 | + ThreadContext.put("pufferfishsentry_eventdata", GSON.toJson(serializeFields(event))); 135 | + } 136 | + 137 | + public static void removeEventContext() { 138 | + removePluginContext(); 139 | + removeSenderContext(); 140 | + ThreadContext.remove("pufferfishsentry_eventdata"); 141 | + } 142 | + 143 | + private static Map serializeFields(Object object) { 144 | + Map fields = new TreeMap<>(); 145 | + fields.put("_class", object.getClass().getName()); 146 | + for (Field declaredField : object.getClass().getDeclaredFields()) { 147 | + try { 148 | + if (Modifier.isStatic(declaredField.getModifiers())) { 149 | + continue; 150 | + } 151 | + 152 | + String fieldName = declaredField.getName(); 153 | + if (fieldName.equals("handlers")) { 154 | + continue; 155 | + } 156 | + declaredField.setAccessible(true); 157 | + Object value = declaredField.get(object); 158 | + if (value != null) { 159 | + fields.put(fieldName, value.toString()); 160 | + } else { 161 | + fields.put(fieldName, ""); 162 | + } 163 | + } catch (Exception e) {} // We can't really safely log exceptions. 164 | + } 165 | + return fields; 166 | + } 167 | + 168 | + public static class State { 169 | + 170 | + private Plugin plugin; 171 | + private Command command; 172 | + private String commandLine; 173 | + private Event event; 174 | + private RegisteredListener registeredListener; 175 | + 176 | + public Plugin getPlugin() { 177 | + return plugin; 178 | + } 179 | + 180 | + public void setPlugin(Plugin plugin) { 181 | + this.plugin = plugin; 182 | + } 183 | + 184 | + public Command getCommand() { 185 | + return command; 186 | + } 187 | + 188 | + public void setCommand(Command command) { 189 | + this.command = command; 190 | + } 191 | + 192 | + public String getCommandLine() { 193 | + return commandLine; 194 | + } 195 | + 196 | + public void setCommandLine(String commandLine) { 197 | + this.commandLine = commandLine; 198 | + } 199 | + 200 | + public Event getEvent() { 201 | + return event; 202 | + } 203 | + 204 | + public void setEvent(Event event) { 205 | + this.event = event; 206 | + } 207 | + 208 | + public RegisteredListener getRegisteredListener() { 209 | + return registeredListener; 210 | + } 211 | + 212 | + public void setRegisteredListener(RegisteredListener registeredListener) { 213 | + this.registeredListener = registeredListener; 214 | + } 215 | + } 216 | +} 217 | diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java 218 | new file mode 100644 219 | index 0000000000000000000000000000000000000000..3441cdad70da1bd523c5933b1a914688718c2657 220 | --- /dev/null 221 | +++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDChecker.java 222 | @@ -0,0 +1,40 @@ 223 | +package gg.pufferfish.pufferfish.simd; 224 | + 225 | +import java.util.logging.Level; 226 | +import java.util.logging.Logger; 227 | +import jdk.incubator.vector.FloatVector; 228 | +import jdk.incubator.vector.IntVector; 229 | +import jdk.incubator.vector.VectorSpecies; 230 | + 231 | +/** 232 | + * Basically, java is annoying and we have to push this out to its own class. 233 | + */ 234 | +@Deprecated 235 | +public class SIMDChecker { 236 | + 237 | + @Deprecated 238 | + public static boolean canEnable(Logger logger) { 239 | + try { 240 | + if (SIMDDetection.getJavaVersion() < 17 || SIMDDetection.getJavaVersion() > 21) { 241 | + return false; 242 | + } else { 243 | + SIMDDetection.testRun = true; 244 | + 245 | + VectorSpecies ISPEC = IntVector.SPECIES_PREFERRED; 246 | + VectorSpecies FSPEC = FloatVector.SPECIES_PREFERRED; 247 | + 248 | + logger.log(Level.INFO, "Max SIMD vector size on this system is " + ISPEC.vectorBitSize() + " bits (int)"); 249 | + logger.log(Level.INFO, "Max SIMD vector size on this system is " + FSPEC.vectorBitSize() + " bits (float)"); 250 | + 251 | + if (ISPEC.elementSize() < 2 || FSPEC.elementSize() < 2) { 252 | + logger.log(Level.WARNING, "SIMD is not properly supported on this system!"); 253 | + return false; 254 | + } 255 | + 256 | + return true; 257 | + } 258 | + } catch (NoClassDefFoundError | Exception ignored) {} // Basically, we don't do anything. This lets us detect if it's not functional and disable it. 259 | + return false; 260 | + } 261 | + 262 | +} 263 | diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java 264 | new file mode 100644 265 | index 0000000000000000000000000000000000000000..a84889d3e9cfc4d7ab5f867820a6484c6070711b 266 | --- /dev/null 267 | +++ b/src/main/java/gg/pufferfish/pufferfish/simd/SIMDDetection.java 268 | @@ -0,0 +1,35 @@ 269 | +package gg.pufferfish.pufferfish.simd; 270 | + 271 | +import java.util.logging.Logger; 272 | + 273 | +@Deprecated 274 | +public class SIMDDetection { 275 | + 276 | + public static boolean isEnabled = false; 277 | + public static boolean versionLimited = false; 278 | + public static boolean testRun = false; 279 | + 280 | + @Deprecated 281 | + public static boolean canEnable(Logger logger) { 282 | + try { 283 | + return SIMDChecker.canEnable(logger); 284 | + } catch (NoClassDefFoundError | Exception ignored) { 285 | + return false; 286 | + } 287 | + } 288 | + 289 | + @Deprecated 290 | + public static int getJavaVersion() { 291 | + // https://stackoverflow.com/a/2591122 292 | + String version = System.getProperty("java.version"); 293 | + if(version.startsWith("1.")) { 294 | + version = version.substring(2, 3); 295 | + } else { 296 | + int dot = version.indexOf("."); 297 | + if(dot != -1) { version = version.substring(0, dot); } 298 | + } 299 | + version = version.split("-")[0]; // Azul is stupid 300 | + return Integer.parseInt(version); 301 | + } 302 | + 303 | +} 304 | diff --git a/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java b/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java 305 | new file mode 100644 306 | index 0000000000000000000000000000000000000000..ae2464920c9412ac90b819a540ee58be0741465f 307 | --- /dev/null 308 | +++ b/src/main/java/gg/pufferfish/pufferfish/simd/VectorMapPalette.java 309 | @@ -0,0 +1,83 @@ 310 | +package gg.pufferfish.pufferfish.simd; 311 | + 312 | +import java.awt.Color; 313 | +import jdk.incubator.vector.FloatVector; 314 | +import jdk.incubator.vector.IntVector; 315 | +import jdk.incubator.vector.VectorMask; 316 | +import jdk.incubator.vector.VectorSpecies; 317 | +import org.bukkit.map.MapPalette; 318 | + 319 | +@Deprecated 320 | +public class VectorMapPalette { 321 | + 322 | + private static final VectorSpecies I_SPEC = IntVector.SPECIES_PREFERRED; 323 | + private static final VectorSpecies F_SPEC = FloatVector.SPECIES_PREFERRED; 324 | + 325 | + @Deprecated 326 | + public static void matchColorVectorized(int[] in, byte[] out) { 327 | + int speciesLength = I_SPEC.length(); 328 | + int i; 329 | + for (i = 0; i < in.length - speciesLength; i += speciesLength) { 330 | + float[] redsArr = new float[speciesLength]; 331 | + float[] bluesArr = new float[speciesLength]; 332 | + float[] greensArr = new float[speciesLength]; 333 | + int[] alphasArr = new int[speciesLength]; 334 | + 335 | + for (int j = 0; j < speciesLength; j++) { 336 | + alphasArr[j] = (in[i + j] >> 24) & 0xFF; 337 | + redsArr[j] = (in[i + j] >> 16) & 0xFF; 338 | + greensArr[j] = (in[i + j] >> 8) & 0xFF; 339 | + bluesArr[j] = (in[i + j] >> 0) & 0xFF; 340 | + } 341 | + 342 | + IntVector alphas = IntVector.fromArray(I_SPEC, alphasArr, 0); 343 | + FloatVector reds = FloatVector.fromArray(F_SPEC, redsArr, 0); 344 | + FloatVector greens = FloatVector.fromArray(F_SPEC, greensArr, 0); 345 | + FloatVector blues = FloatVector.fromArray(F_SPEC, bluesArr, 0); 346 | + IntVector resultIndex = IntVector.zero(I_SPEC); 347 | + VectorMask modificationMask = VectorMask.fromLong(I_SPEC, 0xffffffff); 348 | + 349 | + modificationMask = modificationMask.and(alphas.lt(128).not()); 350 | + FloatVector bestDistances = FloatVector.broadcast(F_SPEC, Float.MAX_VALUE); 351 | + 352 | + for (int c = 4; c < MapPalette.colors.length; c++) { 353 | + // We're using 32-bit floats here because it's 2x faster and nobody will know the difference. 354 | + // For correctness, the original algorithm uses 64-bit floats instead. Completely unnecessary. 355 | + FloatVector compReds = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getRed()); 356 | + FloatVector compGreens = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getGreen()); 357 | + FloatVector compBlues = FloatVector.broadcast(F_SPEC, MapPalette.colors[c].getBlue()); 358 | + 359 | + FloatVector rMean = reds.add(compReds).div(2.0f); 360 | + FloatVector rDiff = reds.sub(compReds); 361 | + FloatVector gDiff = greens.sub(compGreens); 362 | + FloatVector bDiff = blues.sub(compBlues); 363 | + 364 | + FloatVector weightR = rMean.div(256.0f).add(2); 365 | + FloatVector weightG = FloatVector.broadcast(F_SPEC, 4.0f); 366 | + FloatVector weightB = FloatVector.broadcast(F_SPEC, 255.0f).sub(rMean).div(256.0f).add(2.0f); 367 | + 368 | + FloatVector distance = weightR.mul(rDiff).mul(rDiff).add(weightG.mul(gDiff).mul(gDiff)).add(weightB.mul(bDiff).mul(bDiff)); 369 | + 370 | + // Now we compare to the best distance we've found. 371 | + // This mask contains a "1" if better, and a "0" otherwise. 372 | + VectorMask bestDistanceMask = distance.lt(bestDistances); 373 | + bestDistances = bestDistances.blend(distance, bestDistanceMask); // Update the best distances 374 | + 375 | + // Update the result array 376 | + // We also AND with the modification mask because we don't want to interfere if the alpha value isn't large enough. 377 | + resultIndex = resultIndex.blend(c, bestDistanceMask.cast(I_SPEC).and(modificationMask)); // Update the results 378 | + } 379 | + 380 | + for (int j = 0; j < speciesLength; j++) { 381 | + int index = resultIndex.lane(j); 382 | + out[i + j] = (byte) (index < 128 ? index : -129 + (index - 127)); 383 | + } 384 | + } 385 | + 386 | + // For the final ones, fall back to the regular method 387 | + for (; i < in.length; i++) { 388 | + out[i] = MapPalette.matchColor(new Color(in[i], true)); 389 | + } 390 | + } 391 | + 392 | +} 393 | diff --git a/src/main/java/org/bukkit/map/MapPalette.java b/src/main/java/org/bukkit/map/MapPalette.java 394 | index c80faa079eca1564847070f0338fc98024639829..e632d51d3487eb4807243b6705999ad124466bf5 100644 395 | --- a/src/main/java/org/bukkit/map/MapPalette.java 396 | +++ b/src/main/java/org/bukkit/map/MapPalette.java 397 | @@ -1,6 +1,7 @@ 398 | package org.bukkit.map; 399 | 400 | import com.google.common.base.Preconditions; 401 | +import gg.pufferfish.pufferfish.simd.SIMDDetection; // Pufferfish 402 | import java.awt.Color; 403 | import java.awt.Graphics2D; 404 | import java.awt.Image; 405 | @@ -40,7 +41,7 @@ public final class MapPalette { 406 | } 407 | 408 | @NotNull 409 | - static final Color[] colors = { 410 | + public static final Color[] colors = { // Pufferfish - public access 411 | c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0), c(0, 0, 0, 0), 412 | c(89, 125, 39), c(109, 153, 48), c(127, 178, 56), c(67, 94, 29), 413 | c(174, 164, 115), c(213, 201, 140), c(247, 233, 163), c(130, 123, 86), 414 | @@ -211,9 +212,15 @@ public final class MapPalette { 415 | temp.getRGB(0, 0, temp.getWidth(), temp.getHeight(), pixels, 0, temp.getWidth()); 416 | 417 | byte[] result = new byte[temp.getWidth() * temp.getHeight()]; 418 | + // Pufferfish start 419 | + if (!SIMDDetection.isEnabled) { 420 | for (int i = 0; i < pixels.length; i++) { 421 | result[i] = matchColor(new Color(pixels[i], true)); 422 | } 423 | + } else { 424 | + gg.pufferfish.pufferfish.simd.VectorMapPalette.matchColorVectorized(pixels, result); 425 | + } 426 | + // Pufferfish end 427 | return result; 428 | } 429 | 430 | diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java 431 | index 003bece642b682985625db93cad93026352bfc66..e8ba4f1108f2548a487877027e37d81fc150e042 100644 432 | --- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java 433 | +++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java 434 | @@ -597,7 +597,9 @@ public final class SimplePluginManager implements PluginManager { 435 | 436 | // Paper start 437 | private void handlePluginException(String msg, Throwable ex, Plugin plugin) { 438 | + gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish 439 | server.getLogger().log(Level.SEVERE, msg, ex); 440 | + gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish 441 | callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerPluginEnableDisableException(msg, ex, plugin))); 442 | } 443 | // Paper end 444 | @@ -667,9 +669,11 @@ public final class SimplePluginManager implements PluginManager { 445 | )); 446 | } 447 | } catch (Throwable ex) { 448 | + gg.pufferfish.pufferfish.sentry.SentryContext.setEventContext(event, registration); // Pufferfish 449 | // Paper start - error reporting 450 | String msg = "Could not pass event " + event.getEventName() + " to " + registration.getPlugin().getDescription().getFullName(); 451 | server.getLogger().log(Level.SEVERE, msg, ex); 452 | + gg.pufferfish.pufferfish.sentry.SentryContext.removeEventContext(); // Pufferfish 453 | if (!(event instanceof com.destroystokyo.paper.event.server.ServerExceptionEvent)) { // We don't want to cause an endless event loop 454 | callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerEventException(msg, ex, registration.getPlugin(), registration.getListener(), event))); 455 | } 456 | diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java 457 | index eaefbb00e9993d54906cc8cf35cf753c0d6c7707..301e82369603f3dd6e6c1bd380da4bacacd7ef6c 100644 458 | --- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java 459 | +++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java 460 | @@ -336,7 +336,13 @@ public final class JavaPluginLoader implements PluginLoader { 461 | try { 462 | jPlugin.setEnabled(true); 463 | } catch (Throwable ex) { 464 | + gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish 465 | server.getLogger().log(Level.SEVERE, "Error occurred while enabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); 466 | + gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish 467 | + // Paper start - Disable plugins that fail to load 468 | + this.server.getPluginManager().disablePlugin(jPlugin); 469 | + return; 470 | + // Paper end 471 | } 472 | 473 | // Perhaps abort here, rather than continue going, but as it stands, 474 | @@ -361,7 +367,9 @@ public final class JavaPluginLoader implements PluginLoader { 475 | try { 476 | jPlugin.setEnabled(false); 477 | } catch (Throwable ex) { 478 | + gg.pufferfish.pufferfish.sentry.SentryContext.setPluginContext(plugin); // Pufferfish 479 | server.getLogger().log(Level.SEVERE, "Error occurred while disabling " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); 480 | + gg.pufferfish.pufferfish.sentry.SentryContext.removePluginContext(); // Pufferfish 481 | } 482 | 483 | if (cloader instanceof PluginClassLoader) { 484 | diff --git a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java 485 | index 7e4f7cb2afbc145e532285c793573ad107bc3033..12449e18180d604e9cbbc744da74a8b222a18e1f 100644 486 | --- a/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java 487 | +++ b/src/main/java/org/bukkit/plugin/java/PluginClassLoader.java 488 | @@ -50,6 +50,8 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm 489 | private io.papermc.paper.plugin.provider.classloader.PluginClassLoaderGroup classLoaderGroup; // Paper 490 | public io.papermc.paper.plugin.provider.entrypoint.DependencyContext dependencyContext; // Paper 491 | 492 | + private boolean closed = false; // Pufferfish 493 | + 494 | static { 495 | ClassLoader.registerAsParallelCapable(); 496 | } 497 | @@ -197,6 +199,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm 498 | throw new ClassNotFoundException(name); 499 | } 500 | 501 | + public boolean _airplane_hasClass(@NotNull String name) { return this.classes.containsKey(name); } // Pufferfish 502 | @Override 503 | protected Class findClass(String name) throws ClassNotFoundException { 504 | if (name.startsWith("org.bukkit.") || name.startsWith("net.minecraft.")) { 505 | @@ -204,7 +207,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm 506 | } 507 | Class result = classes.get(name); 508 | 509 | - if (result == null) { 510 | + if (result == null && !this.closed) { // Pufferfish 511 | String path = name.replace('.', '/').concat(".class"); 512 | JarEntry entry = jar.getJarEntry(path); 513 | 514 | @@ -251,6 +254,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm 515 | this.setClass(name, result); // Paper 516 | } 517 | 518 | + if (result == null) throw new ClassNotFoundException(name); // Pufferfish 519 | return result; 520 | } 521 | 522 | @@ -265,6 +269,7 @@ public final class PluginClassLoader extends URLClassLoader implements io.paperm 523 | // Paper end 524 | super.close(); 525 | } finally { 526 | + this.closed = true; // Pufferfish 527 | jar.close(); 528 | } 529 | } 530 | --------------------------------------------------------------------------------