diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 210d3ca..0000000 --- a/.editorconfig +++ /dev/null @@ -1,6 +0,0 @@ -[*.java] -charset=utf-8 -end_of_line=lf -insert_final_newline=true -indent_style=space -indent_size=4 diff --git a/.gitattributes b/.gitattributes index 2fb638f..ece71ae 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,11 @@ -* text=auto +# +# https://help.github.com/articles/dealing-with-line-endings/ +# +# Linux start script should use lf +/gradlew text eol=lf -*.sh text eol=lf -gradlew text eol=lf -*.bat text eol=crlf +# These are Windows script files and should use crlf +*.bat text eol=crlf -*.jar binary +# Binary files should be left untouched +*.jar binary \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ed8839c..1412be9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,30 +21,24 @@ jobs: - name: Checkout Git Repository uses: actions/checkout@v4 - - name: Validate Gradle wrapper - uses: gradle/wrapper-validation-action@v2 - - - name: Setup Gradle - uses: gradle/gradle-build-action@v3 - - name: Set up JDK uses: actions/setup-java@v4 with: distribution: temurin java-version: 21 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 - name: Configure Git User Details run: | git config --global user.email "actions@github.com" && git config --global user.name "Github Actions" - name: Apply Patches - run: ./gradlew applyPatches + run: ./gradlew applyAllPatches - name: Build MojmapPaperclip run: ./gradlew createMojmapPaperclipJar - - - name: Build ReobfPaperclip - run: ./gradlew createReobfPaperclipJar - name: Make release uses: marvinpinto/action-automatic-releases@master diff --git a/.gitignore b/.gitignore index 0b28dc6..89463a1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,56 +1,19 @@ -.gradle/ -build/ +# Ignore Gradle project-specific cache directory +.gradle -# Eclipse stuff -.classpath -.project -.settings/ +# Ignore Gradle build output directory +build -# VSCode stuff -.vscode/ +/run -# netbeans -nbproject/ -nbactions.xml +/folia-server/build.gradle.kts +/folia-server/src/minecraft +/foldenor-server/build.gradle.kts +/foldenor-server/src/minecraft +/paper-server +/folia-api/build.gradle.kts +/foldenor-api/build.gradle.kts +/paper-api +/paper-api-generator -# we use maven! -build.xml - -# maven -target/ -dependency-reduced-pom.xml - -# vim -.*.sw[a-p] - -# various other potential build files -build/ -bin/ -dist/ -manifest.mf - -# Mac filesystem dust -.DS_Store/ -.DS_Store - -# intellij -*.iml -*.ipr -*.iws -.idea/ -out/ - -# Linux temp files -*~ - -# other stuff -run/ - -Folia-Server -Folia-API - -!gradle/wrapper/gradle-wrapper.jar -Foldenor-Server/ -Foldenor-API/ -.патчи -/paper-api-generator/ +.idea/ \ No newline at end of file diff --git a/build-data/dev-imports.txt b/build-data/dev-imports.txt index f35428a..8c500e9 100644 --- a/build-data/dev-imports.txt +++ b/build-data/dev-imports.txt @@ -7,4 +7,8 @@ # datafixerupper com/mojang/datafixers/util/Either.java # To import classes from the vanilla Minecraft jar use `minecraft` as the artifactId: # minecraft net.minecraft.world.level.entity.LevelEntityGetterAdapter -# minecraft net/minecraft/world/level/entity/LevelEntityGetter.java \ No newline at end of file +# minecraft net/minecraft/world/level/entity/LevelEntityGetter.java +# To import minecraft data files, like the default chat type, use `mc_data` as the prefix: +# mc_data chat_type/chat.json +# mc_data dimension_type/overworld.json +# \ No newline at end of file diff --git a/build-data/reobf-mappings-patch.tiny b/build-data/reobf-mappings-patch.tiny index e975a3c..e69de29 100644 --- a/build-data/reobf-mappings-patch.tiny +++ b/build-data/reobf-mappings-patch.tiny @@ -1,18 +0,0 @@ -# We would like for paperweight to generate 100% perfect reobf mappings (and deobf mappings for that matter). -# But unfortunately it's not quite there yet - and it may be some time before that happens. Generating perfect mappings -# from Spigot's mappings is extremely difficult due to Spigot's bad tooling and bad mappings. To add insult to injury -# we remap Spigot's _source code_ which is a lot more complex and error-prone than bytecode remapping. So with all that -# said, this file exists to help fill in the gap. -# -# We will continue to improve paperweight and will work on fixing these issues so they don't come up in the first place, -# but these mappings exist to prevent these issues from holding everything else in Paper up while we work through all -# of these issues. Due to the complex nature of mappings generation and the debugging difficulty involved it may take -# a significant amount of time for us to track down every possible issue, so this file will likely be around and in -# use - at least in some capacity - for a long time. -# -# If you are adding mappings patches which are correcting for issues in paperweight's reobf mappings generation, -# unrelated to any changes in your patches, we ask that you PR the mapping to Paper so more users can benefit rather -# than keep the fix for your own fork. If the mappings patch is there to correct reobf for changes made in your patches, -# then obviously it doesn't make any sense to PR them upstream. - -tiny 2 0 mojang+yarn spigot diff --git a/build.gradle.kts b/build.gradle.kts index 76b3a9b..f3993be 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,59 +1,72 @@ +import org.gradle.api.tasks.testing.logging.TestExceptionFormat +import org.gradle.api.tasks.testing.logging.TestLogEvent +import io.papermc.paperweight.tasks.RebuildGitPatches plugins { - java - `maven-publish` - id("io.papermc.paperweight.patcher") version "1.7.7" + java // TODO java launcher tasks + id("io.papermc.paperweight.patcher") version "2.0.0-beta.13" } -val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" - -repositories { - mavenCentral() - maven(paperMavenPublicUrl) { - content { onlyForConfigurations(configurations.paperclip.name) } +paperweight { + upstreams.register("Folia") { + repo = github("PaperMC", "Folia") + ref = providers.gradleProperty("foliaRef") + + patchFile { + path = "folia-server/build.gradle.kts" + outputFile = file("foldenor-server/build.gradle.kts") + patchFile = file("foldenor-server/build.gradle.kts.patch") + } + patchFile { + path = "folia-api/build.gradle.kts" + outputFile = file("foldenor-api/build.gradle.kts") + patchFile = file("foldenor-api/build.gradle.kts.patch") + } + patchRepo("paperApi") { + upstreamPath = "paper-api" + patchesDir = file("foldenor-api/paper-patches") + outputDir = file("paper-api") + } + patchRepo("paperApiGenerator") { + upstreamPath = "paper-api-generator" + patchesDir = file("foldenor-api-generator/paper-patches") + outputDir = file("paper-api-generator") + } + patchDir("foliaApi") { + upstreamPath = "folia-api" + excludes = listOf("build.gradle.kts", "build.gradle.kts.patch", "paper-patches") + patchesDir = file("foldenor-api/fork-patches") + outputDir = file("folia-api") + } } - maven("https://maven.nostal.ink/repository/maven-snapshots/") } -dependencies { - remapper("net.fabricmc:tiny-remapper:0.10.3:fat") - decompiler("org.vineflower:vineflower:1.10.1") - paperclip("io.papermc:paperclip:3.0.3") -} -allprojects { - apply(plugin = "java") +val paperMavenPublicUrl = "https://repo.papermc.io/repository/maven-public/" + +subprojects { + apply(plugin = "java-library") apply(plugin = "maven-publish") java { toolchain { - languageVersion.set(JavaLanguageVersion.of(21)) + languageVersion = JavaLanguageVersion.of(21) } } - /*publishing { - repositories { - maven { - name = "githubPackage" - url = uri("https://maven.pkg.github.com/Edenor-Minecraft/Foldenor") - - credentials { - username = System.getenv("GITHUB_USERNAME") - password = System.getenv("GITHUB_TOKEN") - } - } - - publications.register("gpr") { - from(components["java"]) - } - } - }*/ -} + repositories { + mavenCentral() + maven(paperMavenPublicUrl) + } -subprojects { + tasks.withType().configureEach { + isPreserveFileTimestamps = false + isReproducibleFileOrder = true + } tasks.withType { options.encoding = Charsets.UTF_8.name() - options.release.set(21) + options.release = 21 + options.isFork = true } tasks.withType { options.encoding = Charsets.UTF_8.name() @@ -61,39 +74,38 @@ subprojects { tasks.withType { filteringCharset = Charsets.UTF_8.name() } + tasks.withType { + testLogging { + showStackTraces = true + exceptionFormat = TestExceptionFormat.FULL + events(TestLogEvent.STANDARD_OUT) + } + } - repositories { - mavenCentral() - maven(paperMavenPublicUrl) + extensions.configure { + repositories { + /* + maven("https://repo.papermc.io/repository/maven-snapshots/") { + name = "paperSnapshots" + credentials(PasswordCredentials::class) + } + */ + } } } -paperweight { - serverProject.set(project(":foldenor-server")) - - remapRepo.set(paperMavenPublicUrl) - decompileRepo.set(paperMavenPublicUrl) - - useStandardUpstream("Folia") { - url.set(github("PaperMC", "Folia")) - ref.set(providers.gradleProperty("foliaRef")) - - withStandardPatcher { - apiSourceDirPath.set("folia-api") - serverSourceDirPath.set("folia-server") - - apiPatchDir.set(layout.projectDirectory.dir("patches/api")) - apiOutputDir.set(layout.projectDirectory.dir("Foldenor-api")) +tasks.withType { + filterPatches.set(false) +} - serverPatchDir.set(layout.projectDirectory.dir("patches/server")) - serverOutputDir.set(layout.projectDirectory.dir("Foldenor-server")) - } +tasks.register("printMinecraftVersion") { + doLast { + println(providers.gradleProperty("mcVersion").get().trim()) + } +} - patchTasks.register("generatedApi") { - isBareDirectory = true - upstreamDirPath = "paper-api-generator/generated" - patchDir = layout.projectDirectory.dir("patches/generatedApi") - outputDir = layout.projectDirectory.dir("paper-api-generator/generated") - } +tasks.register("printPaperVersion") { + doLast { + println(project.version) } } \ No newline at end of file diff --git a/foldenor-api/build.gradle.kts.patch b/foldenor-api/build.gradle.kts.patch new file mode 100644 index 0000000..57c7c5d --- /dev/null +++ b/foldenor-api/build.gradle.kts.patch @@ -0,0 +1,24 @@ +--- a/folia-api/build.gradle.kts ++++ b/folia-api/build.gradle.kts +@@ -104,17 +_,21 @@ + java { + srcDir(generatedApiPath) + srcDir(file("../paper-api/src/main/java")) ++ srcDir(file("../folia-api/src/main/java")) + } + resources { + srcDir(file("../paper-api/src/main/resources")) ++ srcDir(file("../folia-api/src/main/resources")) + } + } + test { + java { + srcDir(file("../paper-api/src/test/java")) ++ srcDir(file("../folia-api/src/test/java")) + } + resources { + srcDir(file("../paper-api/src/test/resources")) ++ srcDir(file("../folia-api/src/test/resources")) + } + } + } diff --git a/foldenor-server/build.gradle.kts.patch b/foldenor-server/build.gradle.kts.patch new file mode 100644 index 0000000..a55c7b1 --- /dev/null +++ b/foldenor-server/build.gradle.kts.patch @@ -0,0 +1,92 @@ +--- a/folia-server/build.gradle.kts ++++ b/folia-server/build.gradle.kts +@@ -22,6 +_,7 @@ + // gitFilePatches = true + + val fork = forks.register("folia") { ++ rootDirectory = upstreamsDirectory().map { it.dir("folia") } + upstream.patchDir("paperServer") { + upstreamPath = "paper-server" + excludes = setOf("src/minecraft", "patches", "build.gradle.kts") +@@ -30,7 +_,24 @@ + } + } + +- activeFork = fork ++ val foldenor = forks.register("foldenor") { ++ forks = fork ++ upstream.patchRepo("paperServer") { ++ upstreamRepo = fork.patchedRepo("paperServer") ++ patchesDir = rootDirectory.dir("foldenor-server/paper-patches") ++ outputDir = rootDirectory.dir("paper-server") ++ rejectsDir = file("foldenor-server/paper-rejects") ++ } ++ upstream.patchDir("foliaServer") { ++ upstreamPath = "folia-server" ++ excludes = setOf("src/minecraft", "paper-patches", "minecraft-patches", "build.gradle.kts", "build.gradle.kts.patch") ++ patchesDir = rootDirectory.dir("foldenor-server/folia-patches") ++ outputDir = rootDirectory.dir("folia-server") ++ rejectsDir = file("foldenor-server/rejects") ++ } ++ } ++ ++ activeFork = foldenor + + paper { + paperServerDir = upstreamsDirectory().map { it.dir("paper/paper-server") } +@@ -120,10 +_,14 @@ + main { + java { srcDir("../paper-server/src/main/java") } + resources { srcDir("../paper-server/src/main/resources") } ++ java { srcDir("../folia-server/src/main/java") } ++ resources { srcDir("../folia-server/src/main/resources") } + } + test { + java { srcDir("../paper-server/src/test/java") } + resources { srcDir("../paper-server/src/test/resources") } ++ java { srcDir("../folia-server/src/main/java") } ++ resources { srcDir("../folia-server/src/main/resources") } + } + } + +@@ -147,7 +_,7 @@ + } + + dependencies { +- implementation(project(":folia-api")) ++ implementation(project(":foldenor-api")) + implementation("ca.spottedleaf:concurrentutil:0.0.3") + implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ + implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21 +@@ -177,6 +_,11 @@ + runtimeOnly("com.mysql:mysql-connector-j:9.1.0") + runtimeOnly("com.lmax:disruptor:3.4.4") + ++ // LinearPaper start ++ implementation("com.github.luben:zstd-jni:1.5.6-6") ++ implementation("org.lz4:lz4-java:1.8.0") ++ // LinearPaper end ++ + runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6") + runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") + runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") +@@ -216,14 +_,14 @@ + val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() + attributes( + "Main-Class" to "org.bukkit.craftbukkit.Main", +- "Implementation-Title" to "Folia", ++ "Implementation-Title" to "Foldenor", + "Implementation-Version" to implementationVersion, + "Implementation-Vendor" to date, +- "Specification-Title" to "Folia", ++ "Specification-Title" to "Foldenor", + "Specification-Version" to project.version, +- "Specification-Vendor" to "Paper Team", +- "Brand-Id" to "papermc:folia", +- "Brand-Name" to "Folia", ++ "Specification-Vendor" to "Edenor", ++ "Brand-Id" to "edenor:foldenor", ++ "Brand-Name" to "Foldenor", + "Build-Number" to (build ?: ""), + "Build-Time" to buildTime.toString(), + "Git-Branch" to gitBranch, diff --git a/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java.patch b/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java.patch new file mode 100644 index 0000000..c775816 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java.patch @@ -0,0 +1,14 @@ +--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java +@@ -8,9 +_,9 @@ + + public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ); + +- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); ++ public com.triassic.linearpaper.region.AbstractRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // LinearPaper + +- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; ++ public com.triassic.linearpaper.region.AbstractRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // LinearPaper + + public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite( + final int chunkX, final int chunkZ, final CompoundTag compound diff --git a/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java.patch b/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java.patch new file mode 100644 index 0000000..c853109 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java.patch @@ -0,0 +1,11 @@ +--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java +@@ -1462,7 +_,7 @@ + + public static interface IORunnable { + +- public void run(final RegionFile regionFile) throws IOException; ++ public void run(final com.triassic.linearpaper.region.AbstractRegionFile regionFile) throws IOException; // LinearPaper + + } + } diff --git a/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java.patch b/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java.patch new file mode 100644 index 0000000..6ca24c0 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java.patch @@ -0,0 +1,9 @@ +--- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java ++++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java +@@ -8,5 +_,5 @@ + + public void moonrise$setWriteOnClose(final boolean value); + +- public void moonrise$write(final RegionFile regionFile) throws IOException; ++ public void moonrise$write(final com.triassic.linearpaper.region.AbstractRegionFile regionFile) throws IOException; // LinearPaper + } diff --git a/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/AbstractRegionFile.java.patch b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/AbstractRegionFile.java.patch new file mode 100644 index 0000000..4909d31 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/AbstractRegionFile.java.patch @@ -0,0 +1,31 @@ +--- /dev/null ++++ b/com/triassic/linearpaper/region/AbstractRegionFile.java +@@ -1,0 +_,28 @@ ++package com.triassic.linearpaper.region; ++ ++import java.io.DataInputStream; ++import java.io.DataOutputStream; ++import java.io.IOException; ++import java.nio.ByteBuffer; ++import java.nio.file.Path; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.world.level.ChunkPos; ++ ++public interface AbstractRegionFile extends AutoCloseable { ++ ++ Path getPath(); ++ DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; ++ DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; ++ CompoundTag getOversizedData(int x, int z) throws IOException; ++ ++ boolean hasChunk(ChunkPos pos); ++ boolean doesChunkExist(ChunkPos pos); ++ boolean isOversized(int x, int z); ++ boolean recalculateHeader() throws IOException; ++ ++ void flush() throws IOException; ++ void close() throws IOException; ++ void clear(ChunkPos pos) throws IOException; ++ void setOversized(int x, int z, boolean oversized) throws IOException; ++ void write(ChunkPos pos, ByteBuffer buf) throws IOException; ++} diff --git a/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/AbstractRegionFileFactory.java.patch b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/AbstractRegionFileFactory.java.patch new file mode 100644 index 0000000..4a34e84 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/AbstractRegionFileFactory.java.patch @@ -0,0 +1,25 @@ +--- /dev/null ++++ b/com/triassic/linearpaper/region/AbstractRegionFileFactory.java +@@ -1,0 +_,22 @@ ++package com.triassic.linearpaper.region; ++ ++import java.io.IOException; ++import java.nio.file.Path; ++import net.minecraft.world.level.chunk.storage.RegionFile; ++import net.minecraft.world.level.chunk.storage.RegionFileVersion; ++import net.minecraft.world.level.chunk.storage.RegionStorageInfo; ++ ++public class AbstractRegionFileFactory { ++ ++ public static AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { ++ return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); ++ } ++ ++ public static AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { ++ if (path.toString().endsWith(".linear")) { ++ return new LinearRegionFile(path, storageKey.linearCompressionLevel()); ++ } else { ++ return new RegionFile(storageKey, path, directory, compressionFormat, dsync); ++ } ++ } ++} diff --git a/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/LinearRegionFile.java.patch b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/LinearRegionFile.java.patch new file mode 100644 index 0000000..fceeecd --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/LinearRegionFile.java.patch @@ -0,0 +1,318 @@ +--- /dev/null ++++ b/com/triassic/linearpaper/region/LinearRegionFile.java +@@ -1,0 +_,315 @@ ++package com.triassic.linearpaper.region; ++ ++import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; ++import com.github.luben.zstd.ZstdInputStream; ++import com.github.luben.zstd.ZstdOutputStream; ++import com.mojang.logging.LogUtils; ++import java.io.BufferedOutputStream; ++import java.io.ByteArrayInputStream; ++import java.io.ByteArrayOutputStream; ++import java.io.DataInputStream; ++import java.io.DataOutputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.FileOutputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.nio.ByteBuffer; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.StandardCopyOption; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.List; ++import java.util.concurrent.atomic.AtomicBoolean; ++import javax.annotation.Nullable; ++import net.jpountz.lz4.LZ4Compressor; ++import net.jpountz.lz4.LZ4Factory; ++import net.jpountz.lz4.LZ4FastDecompressor; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.world.level.ChunkPos; ++import org.slf4j.Logger; ++ ++public class LinearRegionFile implements AbstractRegionFile, AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { ++ ++ private static final long SUPERBLOCK = -4323716122432332390L; ++ private static final byte VERSION = 2; ++ private static final int HEADER_SIZE = 32; ++ private static final int FOOTER_SIZE = 8; ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ private static final List SUPPORTED_VERSIONS = Arrays.asList((byte) 1, (byte) 2); ++ private static final LinearRegionFileFlusher linearRegionFileFlusher = new LinearRegionFileFlusher(); ++ private final byte[][] buffer = new byte[1024][]; ++ private final int[] bufferUncompressedSize = new int[1024]; ++ private final int[] chunkTimestamps = new int[1024]; ++ private final LZ4Compressor compressor; ++ private final LZ4FastDecompressor decompressor; ++ private final int compressionLevel; ++ private final AtomicBoolean markedToSave = new AtomicBoolean(false); ++ public boolean closed = false; ++ public Path path; ++ ++ ++ public LinearRegionFile(Path file, int compression) throws IOException { ++ this.path = file; ++ this.compressionLevel = compression; ++ this.compressor = LZ4Factory.fastestInstance().fastCompressor(); ++ this.decompressor = LZ4Factory.fastestInstance().fastDecompressor(); ++ ++ File regionFile = new File(this.path.toString()); ++ ++ Arrays.fill(this.bufferUncompressedSize, 0); ++ ++ if (!regionFile.canRead()) return; ++ ++ try (FileInputStream fileStream = new FileInputStream(regionFile); ++ DataInputStream rawDataStream = new DataInputStream(fileStream)) { ++ ++ long superBlock = rawDataStream.readLong(); ++ if (superBlock != SUPERBLOCK) ++ throw new RuntimeException("Invalid superblock: " + superBlock + " in " + file); ++ ++ byte version = rawDataStream.readByte(); ++ if (!SUPPORTED_VERSIONS.contains(version)) ++ throw new RuntimeException("Invalid version: " + version + " in " + file); ++ ++ // Skip newestTimestamp (Long) + Compression level (Byte) + Chunk count (Short): Unused. ++ rawDataStream.skipBytes(11); ++ ++ int dataCount = rawDataStream.readInt(); ++ long fileLength = file.toFile().length(); ++ if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) ++ throw new IOException("Invalid file length: " + this.path + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE)); ++ ++ rawDataStream.skipBytes(8); // Skip data hash (Long): Unused. ++ ++ byte[] rawCompressed = new byte[dataCount]; ++ rawDataStream.readFully(rawCompressed, 0, dataCount); ++ ++ superBlock = rawDataStream.readLong(); ++ if (superBlock != SUPERBLOCK) ++ throw new IOException("Footer superblock invalid " + this.path); ++ ++ try (DataInputStream dataStream = new DataInputStream(new ZstdInputStream(new ByteArrayInputStream(rawCompressed)))) { ++ ++ int[] starts = new int[1024]; ++ for (int i = 0; i < 1024; i++) { ++ starts[i] = dataStream.readInt(); ++ dataStream.skipBytes(4); // Skip timestamps (Int): Unused. ++ } ++ ++ for (int i = 0; i < 1024; i++) { ++ if (starts[i] > 0) { ++ int size = starts[i]; ++ byte[] b = new byte[size]; ++ dataStream.readFully(b, 0, size); ++ ++ int maxCompressedLength = this.compressor.maxCompressedLength(size); ++ byte[] compressed = new byte[maxCompressedLength]; ++ int compressedLength = this.compressor.compress(b, 0, size, compressed, 0, maxCompressedLength); ++ b = new byte[compressedLength]; ++ System.arraycopy(compressed, 0, b, 0, compressedLength); ++ ++ this.buffer[i] = b; ++ this.bufferUncompressedSize[i] = size; ++ } ++ } ++ } ++ } ++ } ++ ++ private static int getChunkIndex(int x, int z) { ++ return (x & 31) + ((z & 31) << 5); ++ } ++ ++ private static int getTimestamp() { ++ return (int) (System.currentTimeMillis() / 1000L); ++ } ++ ++ public Path getPath() { ++ return this.path; ++ } ++ ++ public void flush() throws IOException { ++ if (isMarkedToSave()) flushWrapper(); // sync ++ } ++ ++ private void markToSave() { ++ linearRegionFileFlusher.scheduleSave(this); ++ markedToSave.set(true); ++ } ++ ++ public boolean isMarkedToSave() { ++ return markedToSave.getAndSet(false); ++ } ++ ++ public void flushWrapper() { ++ try { ++ save(); ++ } catch (IOException e) { ++ LOGGER.error("Failed to flush region file {}", path.toAbsolutePath(), e); ++ } ++ } ++ ++ public boolean doesChunkExist(ChunkPos pos) { ++ return false; ++ } ++ ++ private synchronized void save() throws IOException { ++ long timestamp = getTimestamp(); ++ short chunkCount = 0; ++ ++ File tempFile = new File(path.toString() + ".tmp"); ++ ++ try (FileOutputStream fileStream = new FileOutputStream(tempFile); ++ ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream(); ++ ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, this.compressionLevel); ++ DataOutputStream zstdDataStream = new DataOutputStream(zstdStream); ++ DataOutputStream dataStream = new DataOutputStream(fileStream)) { ++ ++ dataStream.writeLong(SUPERBLOCK); ++ dataStream.writeByte(VERSION); ++ dataStream.writeLong(timestamp); ++ dataStream.writeByte(this.compressionLevel); ++ ++ ArrayList byteBuffers = new ArrayList<>(); ++ for (int i = 0; i < 1024; i++) { ++ if (this.bufferUncompressedSize[i] != 0) { ++ chunkCount += 1; ++ byte[] content = new byte[bufferUncompressedSize[i]]; ++ this.decompressor.decompress(buffer[i], 0, content, 0, bufferUncompressedSize[i]); ++ ++ byteBuffers.add(content); ++ } else byteBuffers.add(null); ++ } ++ for (int i = 0; i < 1024; i++) { ++ zstdDataStream.writeInt(this.bufferUncompressedSize[i]); // Write uncompressed size ++ zstdDataStream.writeInt(this.chunkTimestamps[i]); // Write timestamp ++ } ++ for (int i = 0; i < 1024; i++) { ++ if (byteBuffers.get(i) != null) ++ zstdDataStream.write(byteBuffers.get(i), 0, byteBuffers.get(i).length); ++ } ++ zstdDataStream.close(); ++ ++ dataStream.writeShort(chunkCount); ++ ++ byte[] compressed = zstdByteArray.toByteArray(); ++ ++ dataStream.writeInt(compressed.length); ++ dataStream.writeLong(0); ++ ++ dataStream.write(compressed, 0, compressed.length); ++ dataStream.writeLong(SUPERBLOCK); ++ ++ dataStream.flush(); ++ fileStream.getFD().sync(); ++ fileStream.getChannel().force(true); // Ensure atomicity on Btrfs ++ } ++ Files.move(tempFile.toPath(), this.path, StandardCopyOption.REPLACE_EXISTING); ++ } ++ ++ public synchronized void write(ChunkPos pos, ByteBuffer buffer) { ++ try { ++ byte[] b = toByteArray(new ByteArrayInputStream(buffer.array())); ++ int uncompressedSize = b.length; ++ ++ int maxCompressedLength = this.compressor.maxCompressedLength(b.length); ++ byte[] compressed = new byte[maxCompressedLength]; ++ int compressedLength = this.compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength); ++ b = new byte[compressedLength]; ++ System.arraycopy(compressed, 0, b, 0, compressedLength); ++ ++ int index = getChunkIndex(pos.x, pos.z); ++ this.buffer[index] = b; ++ this.chunkTimestamps[index] = getTimestamp(); ++ this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize; ++ } catch (IOException e) { ++ LOGGER.error("Chunk write IOException {} {}", e, this.path); ++ } ++ markToSave(); ++ } ++ ++ public DataOutputStream getChunkDataOutputStream(ChunkPos pos) { ++ return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos))); ++ } ++ ++ private byte[] toByteArray(InputStream in) throws IOException { ++ ByteArrayOutputStream out = new ByteArrayOutputStream(); ++ byte[] tempBuffer = new byte[4096]; ++ ++ int length; ++ while ((length = in.read(tempBuffer)) >= 0) { ++ out.write(tempBuffer, 0, length); ++ } ++ ++ return out.toByteArray(); ++ } ++ ++ @Nullable ++ public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) { ++ if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) { ++ byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]]; ++ this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]); ++ return new DataInputStream(new ByteArrayInputStream(content)); ++ } ++ return null; ++ } ++ ++ public void clear(ChunkPos pos) { ++ int i = getChunkIndex(pos.x, pos.z); ++ this.buffer[i] = null; ++ this.bufferUncompressedSize[i] = 0; ++ this.chunkTimestamps[i] = getTimestamp(); ++ markToSave(); ++ } ++ ++ public boolean hasChunk(ChunkPos pos) { ++ return this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] > 0; ++ } ++ ++ public void close() throws IOException { ++ if (closed) return; ++ closed = true; ++ flush(); // sync ++ } ++ ++ public boolean recalculateHeader() { ++ return false; ++ } ++ ++ public void setOversized(int x, int z, boolean something) { ++ } ++ ++ public CompoundTag getOversizedData(int x, int z) throws IOException { ++ throw new IOException("getOversizedData is a stub " + this.path); ++ } ++ ++ public boolean isOversized(int x, int z) { ++ return false; ++ } ++ ++ @Override ++ public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) throws IOException { ++ final DataOutputStream out = this.getChunkDataOutputStream(pos); ++ ++ return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData( ++ data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE, ++ out, regionFile -> out.close() ++ ); ++ } ++ ++ private class ChunkBuffer extends ByteArrayOutputStream { ++ private final ChunkPos pos; ++ ++ public ChunkBuffer(ChunkPos chunkcoordintpair) { ++ super(); ++ this.pos = chunkcoordintpair; ++ } ++ ++ public void close() { ++ ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); ++ LinearRegionFile.this.write(this.pos, bytebuffer); ++ } ++ } ++} diff --git a/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/LinearRegionFileFlusher.java.patch b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/LinearRegionFileFlusher.java.patch new file mode 100644 index 0000000..9b704de --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/LinearRegionFileFlusher.java.patch @@ -0,0 +1,54 @@ +--- /dev/null ++++ b/com/triassic/linearpaper/region/LinearRegionFileFlusher.java +@@ -1,0 +_,51 @@ ++package com.triassic.linearpaper.region; ++ ++import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import java.util.Queue; ++import java.util.concurrent.ExecutorService; ++import java.util.concurrent.Executors; ++import java.util.concurrent.LinkedBlockingQueue; ++import java.util.concurrent.ScheduledExecutorService; ++import java.util.concurrent.TimeUnit; ++ ++import net.edenor.foldenor.config.FoldenorConfig; ++import org.bukkit.Bukkit; ++ ++public class LinearRegionFileFlusher { ++ ++ private final Queue savingQueue = new LinkedBlockingQueue<>(); ++ private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor( ++ new ThreadFactoryBuilder() ++ .setNameFormat("linear-flush-scheduler") ++ .build() ++ ); ++ private final ExecutorService executor = Executors.newFixedThreadPool( ++ FoldenorConfig.linearFlushThreads, ++ new ThreadFactoryBuilder() ++ .setNameFormat("linear-flusher-%d") ++ .build() ++ ); ++ ++ public LinearRegionFileFlusher() { ++ Bukkit.getLogger().info("Using " + FoldenorConfig.linearFlushThreads + " threads for linear region flushing."); ++ scheduler.scheduleAtFixedRate(this::pollAndFlush, 0L, FoldenorConfig.linearFlushFrequency, TimeUnit.SECONDS); ++ } ++ ++ public void scheduleSave(LinearRegionFile regionFile) { ++ if (savingQueue.contains(regionFile)) return; ++ savingQueue.add(regionFile); ++ } ++ ++ private void pollAndFlush() { ++ while (!savingQueue.isEmpty()) { ++ LinearRegionFile regionFile = savingQueue.poll(); ++ if (!regionFile.closed && regionFile.isMarkedToSave()) ++ executor.execute(regionFile::flushWrapper); ++ } ++ } ++ ++ public void shutdown() { ++ executor.shutdown(); ++ scheduler.shutdown(); ++ } ++} diff --git a/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/RegionFileFormat.java.patch b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/RegionFileFormat.java.patch new file mode 100644 index 0000000..a46b291 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/com/triassic/linearpaper/region/RegionFileFormat.java.patch @@ -0,0 +1,19 @@ +--- /dev/null ++++ b/com/triassic/linearpaper/region/RegionFileFormat.java +@@ -1,0 +_,16 @@ ++package com.triassic.linearpaper.region; ++ ++public enum RegionFileFormat { ++ ANVIL, ++ LINEAR, ++ INVALID; ++ ++ public static RegionFileFormat fromString(String format) { ++ for (RegionFileFormat rff : values()) { ++ if (rff.name().equalsIgnoreCase(format)) { ++ return rff; ++ } ++ } ++ return RegionFileFormat.INVALID; ++ } ++} diff --git a/foldenor-server/minecraft-patches/sources/gg/airplane/structs/ItemListWithBitset.java.patch b/foldenor-server/minecraft-patches/sources/gg/airplane/structs/ItemListWithBitset.java.patch new file mode 100644 index 0000000..f579759 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/gg/airplane/structs/ItemListWithBitset.java.patch @@ -0,0 +1,140 @@ +--- /dev/null ++++ b/gg/airplane/structs/ItemListWithBitset.java +@@ -1,0 +_,137 @@ ++package gg.airplane.structs; ++ ++import net.minecraft.core.NonNullList; ++import net.minecraft.world.item.ItemStack; ++import org.apache.commons.lang.Validate; ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.AbstractList; ++import java.util.Arrays; ++import java.util.List; ++ ++public class ItemListWithBitset extends AbstractList { ++ ++ // Hopper / Hopper Minecart: 5 ++ // Dispenser / Dropper: 9 ++ // Chest / Chest Minecart / Trap Chest / Barrel / Shulker Box: 27 ++ private static final int MAX_SIZE = Integer.SIZE; ++ ++ private static final int ALL_BITS_5 = createAllBits(5); ++ private static final int ALL_BITS_9 = createAllBits(9); ++ private static final int ALL_BITS_27 = createAllBits(27); ++ ++ private static int createAllBits(int size) { ++ return ((1 << size) - 1); ++ } ++ ++ private static int allBits(int size) { ++ if (size == 5) { ++ return ALL_BITS_5; ++ } else if (size == 9) { ++ return ALL_BITS_9; ++ } else if (size == 27) { ++ return ALL_BITS_27; ++ } else { ++ return createAllBits(size); ++ } ++ } ++ ++ public static ItemListWithBitset fromList(List list) { ++ if (list instanceof ItemListWithBitset ours) { ++ return ours; ++ } ++ return new ItemListWithBitset(list); ++ } ++ ++ private static ItemStack[] createArray(int size) { ++ ItemStack[] array = new ItemStack[size]; ++ Arrays.fill(array, ItemStack.EMPTY); ++ return array; ++ } ++ ++ private final ItemStack[] items; ++ ++ private int bitSet = 0; ++ ++ private static class OurNonNullList extends NonNullList { ++ protected OurNonNullList(List delegate) { ++ super(delegate, ItemStack.EMPTY); ++ } ++ } ++ ++ public final NonNullList nonNullList = new OurNonNullList(this); ++ ++ private ItemListWithBitset(List list) { ++ this(list.size()); ++ ++ for (int i = 0; i < list.size(); i++) { ++ this.set(i, list.get(i)); ++ } ++ } ++ ++ public ItemListWithBitset(int size) { ++ Validate.isTrue(size < MAX_SIZE, "size is too large"); ++ ++ this.items = createArray(size); ++ } ++ ++ public boolean isCompletelyEmpty() { ++ return this.bitSet == 0; ++ } ++ ++ public boolean isSlotFilled() { ++ int allBits = allBits(this.items.length); ++ return (this.bitSet & allBits) == allBits; ++ } ++ ++ @Override ++ public ItemStack set(int index, @NotNull ItemStack itemStack) { ++ ItemStack existing = this.items[index]; ++ ++ this.items[index] = itemStack; ++ ++ if (itemStack.isEmpty()) { ++ this.bitSet &= ~(1 << index); ++ } else { ++ this.bitSet |= (1 << index); ++ } ++ ++ return existing; ++ } ++ ++ @NotNull ++ @Override ++ public ItemStack get(int var0) { ++ return this.items[var0]; ++ } ++ ++ @Override ++ public int size() { ++ return this.items.length; ++ } ++ ++ @Override ++ public void clear() { ++ Arrays.fill(this.items, ItemStack.EMPTY); ++ } ++ ++ // these are unsupported for block inventories which have a static size ++ @Override ++ public void add(int var0, ItemStack var1) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public ItemStack remove(int var0) { ++ throw new UnsupportedOperationException(); ++ } ++ ++ @Override ++ public String toString() { ++ return "ItemListWithBitset{" + ++ "items=" + Arrays.toString(this.items) + ++ ", slotState=" + Long.toString(this.bitSet, 2) + ++ ", size=" + this.items.length + ++ '}'; ++ } ++} diff --git a/foldenor-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch b/foldenor-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch new file mode 100644 index 0000000..779e468 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/io/papermc/paper/entity/activation/ActivationRange.java.patch @@ -0,0 +1,77 @@ +--- a/io/papermc/paper/entity/activation/ActivationRange.java ++++ b/io/papermc/paper/entity/activation/ActivationRange.java +@@ -1,5 +_,6 @@ + package io.papermc.paper.entity.activation; + ++import net.edenor.foldenor.config.FoldenorConfig; + import net.minecraft.core.BlockPos; + import net.minecraft.server.MinecraftServer; + import net.minecraft.world.entity.Entity; +@@ -32,6 +_,7 @@ + import net.minecraft.world.entity.schedule.Activity; + import net.minecraft.world.level.Level; + import net.minecraft.world.phys.AABB; ++import net.minecraft.world.phys.Vec3; + import org.spigotmc.SpigotWorldConfig; + + public final class ActivationRange { +@@ -138,6 +_,8 @@ + maxRange = Math.min((world.spigotConfig.simulationDistance << 4) - 8, maxRange); + + for (final Player player : world.getLocalPlayers()) { // Folia - region threading ++ if (FoldenorConfig.entityActivationCheckFrequency > 1 && (player.getId() + io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick()) % FoldenorConfig ++ .entityActivationCheckFrequency != 0) continue; // ShreddedPaper - Configurable entity activation check frequency + player.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - region threading + if (world.spigotConfig.ignoreSpectatorActivation && player.isSpectator()) { + continue; +@@ -168,6 +_,24 @@ + } + + ActivationRange.activateEntity(entity, bbByType); // Folia - threaded regions ++ ++ // Pufferfish start ++ if (FoldenorConfig.dearEnabled && entity.getType().dabEnabled) { ++ if (!entity.activatedPriorityReset) { ++ entity.activatedPriorityReset = true; ++ entity.activatedPriority = FoldenorConfig.maximumActivationPrio; ++ } ++ Vec3 playerVec = player.position(); ++ Vec3 entityVec = entity.position(); ++ double diffX = playerVec.x - entityVec.x, diffY = playerVec.y - entityVec.y, diffZ = playerVec.z - entityVec.z; ++ int squaredDistance = (int) (diffX * diffX + diffY * diffY + diffZ * diffZ); ++ entity.activatedPriority = squaredDistance > FoldenorConfig.startDistanceSquared ? ++ Math.max(1, Math.min(squaredDistance >> FoldenorConfig.activationDistanceMod, entity.activatedPriority)) : ++ 1; ++ } else { ++ entity.activatedPriority = 1; ++ } ++ // Pufferfish end + } + } + } +@@ -178,13 +_,13 @@ + * @param entity + */ + private static void activateEntity(final Entity entity, final AABB[] bbByType) { // Folia - threaded regions +- if (io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() > entity.activatedTick) { // Folia - threaded regions ++ if (io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + Math.max(0, FoldenorConfig.entityActivationCheckFrequency) > entity.activatedTick ) {// Folia - threaded regions // ShreddedPaper - Configurable entity activation check frequency + if (entity.defaultActivationState) { +- entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions ++ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + Math.max(0, FoldenorConfig.entityActivationCheckFrequency); // Folia - threaded regions // ShreddedPaper - Configurable entity activation check frequency + return; + } + if (bbByType[entity.activationType.ordinal()].intersects(entity.getBoundingBox())) { // Folia - threaded regions +- entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick(); // Folia - threaded regions ++ entity.activatedTick = io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() + Math.max(0, FoldenorConfig.entityActivationCheckFrequency); // Folia - threaded regions // ShreddedPaper - Configurable entity activation check frequency + } + } + } +@@ -225,7 +_,7 @@ + } + // special cases. + if (entity instanceof final LivingEntity living) { +- if (living.onClimbable() || living.jumping || living.hurtTime > 0 || !living.activeEffects.isEmpty() || living.isFreezing()) { ++ if ( living.onClimableCached() || living.jumping || living.hurtTime > 0 || living.activeEffects.size() > 0) {// Paper + return 1; + } + if (entity instanceof final Mob mob && mob.getTarget() != null) { diff --git a/foldenor-server/minecraft-patches/sources/io/papermc/paper/threadedregions/TeleportUtils.java.patch b/foldenor-server/minecraft-patches/sources/io/papermc/paper/threadedregions/TeleportUtils.java.patch new file mode 100644 index 0000000..35642ea --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/io/papermc/paper/threadedregions/TeleportUtils.java.patch @@ -0,0 +1,26 @@ +--- a/io/papermc/paper/threadedregions/TeleportUtils.java ++++ b/io/papermc/paper/threadedregions/TeleportUtils.java +@@ -1,6 +_,7 @@ + package io.papermc.paper.threadedregions; + + import ca.spottedleaf.concurrentutil.completable.CallbackCompletable; ++import net.minecraft.server.level.ServerPlayer; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.phys.Vec3; + import org.bukkit.Location; +@@ -25,6 +_,15 @@ + } + final boolean scheduled = from.getBukkitEntity().taskScheduler.schedule( + (final Entity realFrom) -> { ++ ++ if (realFrom instanceof ServerPlayer player){ ++ if (player.isSpectator()){ ++ if (player.isSpectator() && player.getCamera() != player){ ++ player.setCamera(player); ++ } ++ } ++ } ++ + final Vec3 pos = new Vec3( + loc.getX(), loc.getY(), loc.getZ() + ); diff --git a/foldenor-server/minecraft-patches/sources/io/papermc/paper/threadedregions/commands/CommandProfiler.java.patch b/foldenor-server/minecraft-patches/sources/io/papermc/paper/threadedregions/commands/CommandProfiler.java.patch new file mode 100644 index 0000000..dc90e78 --- /dev/null +++ b/foldenor-server/minecraft-patches/sources/io/papermc/paper/threadedregions/commands/CommandProfiler.java.patch @@ -0,0 +1,11 @@ +--- a/io/papermc/paper/threadedregions/commands/CommandProfiler.java ++++ b/io/papermc/paper/threadedregions/commands/CommandProfiler.java +@@ -52,7 +_,7 @@ + super("profiler"); + this.setUsage("/