rebase c2me port

This commit is contained in:
Simon Gardling 2021-05-14 14:53:43 -04:00
parent fd74d8f1ad
commit 2372955f66
11 changed files with 1436 additions and 9 deletions

View File

@ -27,7 +27,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
java: [ '8', '11', '15', '16' ]
java: [ '11', '15', '16' ]
fail-fast: false
steps:
- uses: actions/checkout@v2

11
Jenkinsfile vendored
View File

@ -9,7 +9,7 @@ pipeline {
stages {
stage('Cleanup') {
tools {
jdk "OpenJDK 8"
jdk "OpenJDK 11"
}
steps {
scmSkip(deleteBuild: true, skipPattern:'.*\\[CI-SKIP\\].*')
@ -29,7 +29,7 @@ pipeline {
}
stage('Init project & submodules') {
tools {
jdk "OpenJDK 8"
jdk "OpenJDK 11"
}
steps {
withMaven(
@ -43,7 +43,7 @@ pipeline {
}
stage('Decompile & apply patches') {
tools {
jdk "OpenJDK 8"
jdk "OpenJDK 11"
}
steps {
withMaven(
@ -60,7 +60,7 @@ pipeline {
}
stage('Build') {
tools {
jdk "OpenJDK 8"
jdk "OpenJDK 11"
}
steps {
withMaven(
@ -76,7 +76,8 @@ pipeline {
paperworkdir="$basedir/Paper/work"
mcver=$(cat "$paperworkdir/BuildData/info.json" | grep minecraftVersion | cut -d '"' -f 4)
patchedJarPath="$basedir/Yatopia-Server/build/libs/yatopia-server-$mcver-R0.1-SNAPSHOT.jar"
patchedJarPath=$(find "$basedir/Yatopia-Server/build/libs/" -type f -name "*.jar" | grep -v '\\-sources.jar$')
vanillaJarPath="$paperworkdir/Minecraft/$mcver/$mcver.jar"
cd "$paperworkdir/Paperclip"

View File

@ -105,6 +105,7 @@ # Patches
| server | Breedable Polar Bears | William Blake Galbreath | |
| api | Bring back server name | William Blake Galbreath | |
| server | Bring back server name | William Blake Galbreath | |
| server | C2ME Port | ishland | Simon Gardling |
| server | Cache climbing check for activation | Paul Sauve | |
| server | Cache coordinate key for micro opt | Paul Sauve | |
| server | Cache entityhuman display name | Paul Sauve | |
@ -229,6 +230,7 @@ # Patches
| server | Fix the dead lagging the server | William Blake Galbreath | |
| server | Fix vanilla command permission handler | William Blake Galbreath | |
| server | Flying squids! Oh my! | William Blake Galbreath | |
| server | Force world save | ishland | |
| api | Full netherite armor grants fire resistance | BillyGalbreath | |
| server | Full netherite armor grants fire resistance | BillyGalbreath | |
| server | Gamemode extra permissions | BillyGalbreath | |
@ -293,6 +295,7 @@ # Patches
| server | Movement options for armor stands | Mariell Hoversholm | |
| server | Multi-Threaded Server Ticking Vanilla | Spottedleaf | |
| server | Multi-Threaded ticking CraftBukkit | Spottedleaf | |
| server | Multi-threaded World Upgrade | ishland | |
| server | Name craft scheduler threads according to the plugin using | Spottedleaf | |
| server | New nbt cache | Hugo Planque | ishland |
| server | Nuke streams off BlockPosition | Ivan Pekov | |
@ -439,11 +442,14 @@ # Patches
| server | Zombie horse naturally spawn | William Blake Galbreath | |
| server | add config for logging login location | Simon Gardling | |
| server | dont load chunks for physics | Aikar | |
| api | java 11 | Simon Gardling | |
| server | java 11 | Simon Gardling | |
| server | lithium DataTrackerMixin | JellySquid | tr7zw |
| server | lithium HashedList | JellySquid | |
| server | lithium MixinBox | JellySquid | |
| server | lithium MixinDirection | JellySquid | |
| server | lithium MixinGoalSelector | JellySquid | |
| server | lithium MultiNoiseBiomeSourceMixin | ishland | |
| server | lithium NoiseChunkGeneratorMixin | JellySquid | |
| server | lithium PerlinNoiseSamplerMixin | JellySquid | Bud Gidiere |
| server | lithium VoronoiBiomeAccessTypeMixin | JellySquid | |

View File

@ -59,10 +59,10 @@ subprojects {
}
java {
if(JavaVersion.VERSION_1_8 > JavaVersion.current()){
error("This build must be run with Java 8 or better")
if(JavaVersion.VERSION_11 > JavaVersion.current()){
error("This build must be run with Java 11 or later")
}
sourceCompatibility = JavaVersion.VERSION_1_8
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.current()
withSourcesJar()
}

View File

@ -0,0 +1,21 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Simon Gardling <titaniumtown@gmail.com>
Date: Fri, 23 Apr 2021 11:11:13 -0400
Subject: [PATCH] java 11
diff --git a/pom.xml b/pom.xml
index cc3149a51f5780b73c11492e13dbe7eb86d83e6c..6143478e7e4bfb12208b290b64eee0f95a84f445 100644
--- a/pom.xml
+++ b/pom.xml
@@ -19,8 +19,8 @@
<properties>
<!-- <skipTests>true</skipTests> Paper - This [was] not going to end well -->
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
+ <maven.compiler.source>11</maven.compiler.source>
+ <maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<adventure.version>4.7.0</adventure.version> <!-- Paper - When updating this make sure to update the linked JavaDocs on the homepage as well! -->
</properties>

View File

@ -0,0 +1,307 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Sun, 15 Nov 2020 10:42:27 +0800
Subject: [PATCH] Multi-threaded RegionFile IO
diff --git a/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
index 9fe91f9512ee8c2589fc8da76bda5f6d70c9fac4..8b81119cfdef81665a302d96cfada5bb43bc1077 100644
--- a/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
+++ b/src/main/java/com/destroystokyo/paper/io/PaperFileIOThread.java
@@ -35,7 +35,7 @@ import java.util.function.Function;
* @see #scheduleSave(WorldServer, int, int, NBTTagCompound, NBTTagCompound, int)
* @see #loadChunkDataAsync(WorldServer, int, int, int, Consumer, boolean, boolean, boolean)
*/
-public final class PaperFileIOThread extends QueueExecutorThread {
+public final class PaperFileIOThread { // Yatopia
public static final Logger LOGGER = MinecraftServer.LOGGER;
public static final NBTTagCompound FAILURE_VALUE = new NBTTagCompound();
@@ -44,23 +44,84 @@ public final class PaperFileIOThread extends QueueExecutorThread {
public static final PaperFileIOThread INSTANCE = new PaperFileIOThread();
+ /* Yatopia
static {
INSTANCE.start();
}
+ */
}
private final AtomicLong writeCounter = new AtomicLong();
+ // Yatopia start - multi-threaded RegionFile IO
+ private final com.ibm.asyncutil.locks.AsyncNamedLock<RegionFileCoord> regionFileLock = com.ibm.asyncutil.locks.AsyncNamedLock.createFair();
+ private final PrioritizedTaskQueue<PrioritizedTaskQueue.PrioritizedTask> queue;
+ private final PaperFileIOThread.FileIOExecutorThread receiver;
+ private final java.util.Set<Thread> executorThreads = com.google.common.collect.Sets.newConcurrentHashSet();
+ private final java.util.concurrent.ExecutorService executor = java.util.concurrent.Executors.newFixedThreadPool(
+ org.yatopiamc.yatopia.server.YatopiaConfig.regionFileIOThreadPoolSize == -1 ? Math.min(Runtime.getRuntime().availableProcessors(), Integer.getInteger("paper.maxChunkThreads", 8)) : org.yatopiamc.yatopia.server.YatopiaConfig.regionFileIOThreadPoolSize,
+ new com.google.common.util.concurrent.ThreadFactoryBuilder()
+ .setNameFormat("Paper RegionFile IO Worker #%d")
+ .setPriority(Thread.NORM_PRIORITY - 1)
+ .setDaemon(true)
+ .setThreadFactory(r -> {
+ Thread thr = new Thread(r);
+ executorThreads.add(thr);
+ return thr;
+ })
+ .setUncaughtExceptionHandler((t, e) -> {
+ LOGGER.fatal("Uncaught exception thrown from " + t.getName() + ", report this!", e);
+ executorThreads.remove(t);
+ })
+ .build()
+ );
private PaperFileIOThread() {
- super(new PrioritizedTaskQueue<>(), (int)(1.0e6)); // 1.0ms spinwait time
- this.setName("Paper RegionFile IO Thread");
- this.setPriority(Thread.NORM_PRIORITY - 1); // we keep priority close to normal because threads can wait on us
- this.setUncaughtExceptionHandler((final Thread unused, final Throwable thr) -> {
- LOGGER.fatal("Uncaught exception thrown from IO thread, report this!", thr);
+ queue = new PrioritizedTaskQueue<>();
+ receiver = new PaperFileIOThread.FileIOExecutorThread(queue, (int) (1.0e6)); // 1.0ms spinwait time
+ receiver.setName("Paper RegionFile IO Task Receiver");
+ receiver.setPriority(Thread.NORM_PRIORITY - 1); // we keep priority close to normal because threads can wait on us
+ receiver.setUncaughtExceptionHandler((final Thread thread, final Throwable thr) -> {
+ LOGGER.fatal("Uncaught exception thrown from " + thread.getName() + ", report this!", thr);
});
+ receiver.start();
+
+ }
+
+ public void flush() {
+ receiver.flush();
+ final java.util.Set<CompletableFuture<?>> runningTasks = new java.util.HashSet<>(receiver.runningTasks);
+ LOGGER.debug("Flushing Chunk IO: Waiting for {} futures", runningTasks.size());
+ for(CompletableFuture<?> future: runningTasks) {
+ try {
+ future.join();
+ } catch (Throwable ignored) {
+ }
+ }
+ }
+
+ private void queueTask(PrioritizedTaskQueue.PrioritizedTask newTask) {
+ queue.add(newTask);
+ receiver.notifyTasks();
+ }
+
+ public void close(final boolean wait) {
+ receiver.close(wait, true);
+ this.flush();
+ executor.shutdown();
+ while (wait && !executor.isTerminated()) {
+ try {
+ executor.awaitTermination(30, java.util.concurrent.TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ @SuppressWarnings("BooleanMethodIsAlwaysInverted")
+ public boolean isOnWorkerThread() {
+ return executorThreads.contains(Thread.currentThread());
}
- /* run() is implemented by superclass */
+ // Yatopia end
/*
*
@@ -394,6 +455,85 @@ public final class PaperFileIOThread extends QueueExecutorThread {
this.queueTask(new GeneralTask(priority, runnable));
}
+ // Yatopia start
+ public static final class RegionFileCoord {
+
+ public final int x;
+ public final int z;
+
+ public RegionFileCoord(int x, int z) {
+ this.x = x;
+ this.z = z;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ RegionFileCoord that = (RegionFileCoord) o;
+ return x == that.x && z == that.z;
+ }
+
+ @Override
+ public int hashCode() {
+ return java.util.Objects.hash(x, z);
+ }
+ }
+
+ final class FileIOExecutorThread<T extends PrioritizedTaskQueue.PrioritizedTask & Runnable> extends QueueExecutorThread<T> {
+ private final java.util.Set<CompletableFuture<?>> runningTasks = com.google.common.collect.Sets.newConcurrentHashSet();
+
+ public FileIOExecutorThread(PrioritizedTaskQueue<T> queue, long spinWaitTime) {
+ super(queue, spinWaitTime);
+ }
+
+ @Override
+ protected void preMainLoop() {
+ runningTasks.removeIf(CompletableFuture::isDone);
+ }
+
+ @Override
+ protected boolean pollTasks(boolean flushTasks) {
+ Runnable task;
+ boolean ret = false;
+
+ while ((task = this.queue.poll()) != null) {
+ ret = true;
+ if (task instanceof ChunkDataTask) {
+ ChunkDataTask chunkDataTask = (ChunkDataTask) task;
+ runningTasks.add(regionFileLock.acquireLock(new RegionFileCoord(chunkDataTask.x >> 5, chunkDataTask.z >> 5))
+ .thenApplyAsync(lockToken -> {
+ try {
+ chunkDataTask.run();
+ } finally {
+ lockToken.releaseLock();
+ }
+ return null;
+ }, executor)
+ .exceptionally(throwable -> {
+ LOGGER.fatal("Exception thrown from prioritized runnable task in thread '" + Thread.currentThread().getName() + "': " + IOUtil.genericToString(chunkDataTask), throwable);
+ return null;
+ }).toCompletableFuture());
+ } else {
+ Runnable finalTask = task;
+ runningTasks.add(CompletableFuture.supplyAsync(() -> {
+ finalTask.run();
+ return null;
+ }).exceptionally(throwable -> {
+ LOGGER.fatal("Exception thrown from prioritized runnable task in thread '" + Thread.currentThread().getName() + "': " + IOUtil.genericToString(finalTask), throwable);
+ return null;
+ }));
+ }
+ }
+
+ if (flushTasks) {
+ this.handleFlushThreads(false);
+ }
+
+ return ret;
+ }
+ }
+ // Yatopia end
static final class GeneralTask extends PrioritizedTaskQueue.PrioritizedTask implements Runnable {
private final Runnable run;
diff --git a/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java b/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
index ee906b594b306906c170180a29a8b61997d05168..7e348fcb813707fee830082b826932e0bbba1c49 100644
--- a/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
+++ b/src/main/java/com/destroystokyo/paper/io/QueueExecutorThread.java
@@ -35,6 +35,7 @@ public class QueueExecutorThread<T extends PrioritizedTaskQueue.PrioritizedTask
final long spinWaitTime = this.spinWaitTime;
main_loop:
for (;;) {
+ preMainLoop(); // Yatopia
this.pollTasks(true);
// spinwait
@@ -81,11 +82,17 @@ public class QueueExecutorThread<T extends PrioritizedTaskQueue.PrioritizedTask
// LockSupport.park() can fail for any reason
do {
Thread.interrupted();
- LockSupport.park("Waiting on tasks");
+ LockSupport.parkNanos("Waiting on tasks", 1_000_000_000); // Yatopia - prevent dead lock
} while (this.parked.get());
}
}
+ // Yatopia start
+ protected void preMainLoop() {
+ // Used for PaperFileIOThread
+ }
+ // Yatopia end
+
protected boolean handleClose() {
if (this.closed) {
this.pollTasks(true); // this ensures we've emptied the queue
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 6fd059412e07e1b3b2597b693df5a4f439ebe382..d42d5c7153a655da65d1847541b9f15137b53dbb 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -962,7 +962,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
// Spigot end
// Paper start - move final shutdown items here
LOGGER.info("Flushing Chunk IO");
- com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true, true); // Paper
+ com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.close(true); // Paper // Yatopia
LOGGER.info("Closing Thread Pool");
SystemUtils.shutdownServerThreadPool(); // Paper
LOGGER.info("Closing Server");
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
index 9b3aa025069f45bf94949cbf626ccfa69a646845..aa4b548dbf3366e5bb0df3763be9bdc1c4e9d34d 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
@@ -1725,7 +1725,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@Nullable
@Override
public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws IOException {
- if (Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (!com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
NBTTagCompound ret = com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE
.loadChunkDataAsyncFuture(this.world, chunkcoordintpair.x, chunkcoordintpair.z, com.destroystokyo.paper.io.IOUtil.getPriorityForCurrentThread(),
false, true, true).join().chunkData;
@@ -1740,7 +1740,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
@Override
public void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws IOException {
- if (Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (!com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(
this.world, chunkcoordintpair.x, chunkcoordintpair.z, null, nbttagcompound,
com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); // Tuinity - writes are async, no need for priority
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
index 29cd71efe86eea2227f373c15c39dc530e9e8199..55d497f4305de50e58c7e0788724576f81128138 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
@@ -504,7 +504,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
@javax.annotation.Nullable
@Override
public NBTTagCompound read(ChunkCoordIntPair chunkcoordintpair) throws java.io.IOException {
- if (this.world != null && Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (this.world != null && !com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
NBTTagCompound ret = com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE
.loadChunkDataAsyncFuture(this.world, chunkcoordintpair.x, chunkcoordintpair.z, com.destroystokyo.paper.io.IOUtil.getPriorityForCurrentThread(),
true, false, true).join().poiData;
@@ -519,7 +519,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
@Override
public void write(ChunkCoordIntPair chunkcoordintpair, NBTTagCompound nbttagcompound) throws java.io.IOException {
- if (this.world != null && Thread.currentThread() != com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE) {
+ if (this.world != null && !com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.isOnWorkerThread()) { // Yatopia
com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(
this.world, chunkcoordintpair.x, chunkcoordintpair.z, nbttagcompound, null,
com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); // Tuinity - writes are async, no need for priority
diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
index 545bf94bf47f0c6e9da1a4c162e081cbb2cd8390..e8e8e1fed06f0c17631a134e3673a25549d7c86c 100644
--- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
+++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
@@ -16,6 +16,7 @@ import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
+import com.google.common.base.Preconditions;
public class YatopiaConfig {
@@ -282,4 +283,10 @@ public class YatopiaConfig {
allowThreadedFeatures = getBoolean("settings.c2me.allow-threaded-features", allowThreadedFeatures);
c2meThreads = getInt("settings.c2me.parallelism", c2meThreads);
}
+
+ public static int regionFileIOThreadPoolSize = -1;
+ private static void multiThreadedRegionFile() {
+ regionFileIOThreadPoolSize = getInt("settings.threads.regionfile", -1);
+ Preconditions.checkArgument(regionFileIOThreadPoolSize == -1 || regionFileIOThreadPoolSize > 0, "Invalid settings.threads.regionfile in yatopia.yml");
+ }
}

View File

@ -0,0 +1,653 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Thu, 22 Apr 2021 17:56:12 -0400
Subject: [PATCH] C2ME Port
Port of https://github.com/YatopiaMC/C2ME-fabric
Co-authored-by: Simon Gardling <titaniumtown@gmail.com>
diff --git a/pom.xml b/pom.xml
index d0259f18488e1ecf0276865e0ff7958726a40033..f0a73238612327d71cf78801df816823d80893a0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -203,6 +203,12 @@
<artifactId>commons-rng-core</artifactId>
<version>1.3</version>
</dependency>
+ <!-- https://mvnrepository.com/artifact/com.ibm.async/asyncutil -->
+ <dependency>
+ <groupId>com.ibm.async</groupId>
+ <artifactId>asyncutil</artifactId>
+ <version>0.1.0</version>
+ </dependency>
</dependencies>
<repositories>
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunk.java b/src/main/java/net/minecraft/server/level/PlayerChunk.java
index 06157bb07cce3ba24087ceaca7138b5609b37b5b..47f0604a891d46f688abd5daa6fb4de8b56305e3 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunk.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunk.java
@@ -374,6 +374,7 @@ public class PlayerChunk {
return either == null ? null : (Chunk) either.left().orElse(null); // CraftBukkit - decompile error
}
+ @Nullable public IChunkAccess getCurrentChunk() { return this.f(); } // Yatopia - OBFHELPER
@Nullable
public IChunkAccess f() {
for (int i = PlayerChunk.CHUNK_STATUSES.size() - 1; i >= 0; --i) {
diff --git a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
index e25476f6a9477447cc06f24ed05679326e83cd95..b77793771e8e264e90e09399e10246308ba1cb52 100644
--- a/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/PlayerChunkMap.java
@@ -154,8 +154,9 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
public final LongSet unloadQueue;
private boolean updatingChunksModified;
private final ChunkTaskQueueSorter p;
- private final Mailbox<ChunkTaskQueueSorter.a<Runnable>> mailboxWorldGen;
+ // private final Mailbox<ChunkTaskQueueSorter.a<Runnable>> mailboxWorldGen; // Yatopia
public final Mailbox<ChunkTaskQueueSorter.a<Runnable>> mailboxMain; // Paper - private -> public
+ private final ThreadLocal<ChunkStatus> capturedRequiredStatus = new ThreadLocal<>(); // Yatopia
// Paper start
final Mailbox<ChunkTaskQueueSorter.a<Runnable>> mailboxLight;
public void addLightTask(PlayerChunk playerchunk, Runnable run) {
@@ -461,7 +462,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
// Paper end
this.p = new ChunkTaskQueueSorter(ImmutableList.of(threadedmailbox, mailbox, threadedmailbox1), executor, Integer.MAX_VALUE);
- this.mailboxWorldGen = this.p.a(threadedmailbox, false);
+ // this.mailboxWorldGen = this.p.a(threadedmailbox, false); // Yatopia
this.mailboxMain = this.p.a(mailbox, false);
this.mailboxLight = this.p.a(lightthreaded, false);// Paper
this.lightEngine = new LightEngineThreaded(ilightaccess, this, this.world.getDimensionManager().hasSkyLight(), threadedmailbox1, this.p.a(threadedmailbox1, false));
@@ -1334,7 +1335,8 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return this.z.put(chunkcoordintpair.pair(), (byte) (chunkstatus_type == ChunkStatus.Type.PROTOCHUNK ? -1 : 1));
}
- private CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> b(PlayerChunk playerchunk, ChunkStatus chunkstatus) {
+ private CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> b(PlayerChunk playerchunk, ChunkStatus chunkstatus) { // Yarn: upgradeChunk
+ this.capturedRequiredStatus.set(chunkstatus); // Yatopia - C2ME port
ChunkCoordIntPair chunkcoordintpair = playerchunk.i();
CompletableFuture<Either<List<IChunkAccess>, PlayerChunk.Failure>> completablefuture = this.a(chunkcoordintpair, chunkstatus.f(), (i) -> {
return this.a(chunkstatus, i);
@@ -1372,7 +1374,11 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d {
return;
}
// Paper end
- this.mailboxWorldGen.a(ChunkTaskQueueSorter.a(playerchunk, runnable));
+
+ // Yatopia start - C2ME port
+ org.yatopiamc.c2me.common.threading.GlobalExecutors.scheduler.execute(runnable);
+ // this.mailboxWorldGen.a(ChunkTaskQueueSorter.a(playerchunk, runnable)); // Yatopia
+ // Yatopia end
}).thenComposeAsync((either) -> { // Tuinity start - force competion on the main thread
return CompletableFuture.completedFuture(either);
}, this.mainInvokingExecutor);
diff --git a/src/main/java/net/minecraft/server/level/WorldServer.java b/src/main/java/net/minecraft/server/level/WorldServer.java
index 3068b307b7ad64f5add188e956d59a52126f332a..8892b54c85db83e3f5ad1ae26d3f23de754564f2 100644
--- a/src/main/java/net/minecraft/server/level/WorldServer.java
+++ b/src/main/java/net/minecraft/server/level/WorldServer.java
@@ -178,7 +178,17 @@ import org.bukkit.event.world.TimeSkipEvent;
import it.unimi.dsi.fastutil.ints.IntArrayList; // Tuinity
import net.gegy1000.tictacs.NonBlockingWorldAccess; // Yatopia
-public class WorldServer extends World implements GeneratorAccessSeed, NonBlockingWorldAccess { // Yatopia
+// Yatopia start
+import org.yatopiamc.c2me.common.threading.worldgen.IWorldGenLockable;
+import com.ibm.asyncutil.locks.AsyncLock;
+import com.ibm.asyncutil.locks.AsyncNamedLock;
+// Yatopia end
+
+public class WorldServer extends World implements GeneratorAccessSeed, NonBlockingWorldAccess, IWorldGenLockable { // Yatopia // Yatopia - port C2ME
+
+ private volatile AsyncLock worldGenSingleThreadedLock = null; // Yatopia - port C2ME
+ private volatile AsyncNamedLock<ChunkCoordIntPair> worldGenChunkLock = null;
+ // Yatopia - port C2ME
public static final BlockPosition a = new BlockPosition(100, 50, 0);
private static final Logger LOGGER = LogManager.getLogger();
@@ -608,7 +618,23 @@ public class WorldServer extends World implements GeneratorAccessSeed, NonBlocki
this.asyncChunkTaskManager = new com.destroystokyo.paper.io.chunk.ChunkTaskManager(this); // Paper
this.fakeTime = this.worldDataServer.getDayTime(); // Purpur
+ // Yatopia start - port C2ME
+ this.worldGenSingleThreadedLock = AsyncLock.createFair();
+ this.worldGenChunkLock = AsyncNamedLock.createFair();
+ // Yatopia end - port C2ME
+ }
+
+ // Yatopia start - port C2ME
+ @Override
+ public AsyncLock getWorldGenSingleThreadedLock() {
+ return this.worldGenSingleThreadedLock;
+ }
+
+ @Override
+ public AsyncNamedLock<ChunkCoordIntPair> getWorldGenChunkLock() {
+ return this.worldGenChunkLock;
}
+ // Yatopia end - port C2ME
// Tuinity start - optimise collision
public boolean collidesWithAnyBlockOrWorldBorder(@Nullable Entity entity, AxisAlignedBB axisalignedbb, boolean loadChunks,
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java b/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java
index e2b5d6155bebdbf99b0850de7f9e1f5d342f9e2f..30db0ba3674a85c8dd866fab94c5374ba203c5cd 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/WeightedList.java
@@ -14,7 +14,7 @@ import java.util.stream.Stream;
public class WeightedList<U> {
- protected final List<WeightedList.a<U>> list; public final List<WeightedList.a<U>> getList() { return this.list; } // Paper - decompile conflict // Tuinity - OBFHELPER
+ public final List<WeightedList.a<U>> list; public final List<WeightedList.a<U>> getList() { return this.list; } // Paper - decompile conflict // Tuinity - OBFHELPER // Yatopia - protected -> public
private final Random b;
private final boolean isUnsafe; // Paper
diff --git a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
index f4a4d63a2e21b08580023cf0dcd15a68d192cf14..1802498d48493d3e63c999a067c71e65ea29a890 100644
--- a/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
+++ b/src/main/java/net/minecraft/world/level/chunk/ChunkStatus.java
@@ -22,6 +22,9 @@ import net.minecraft.world.level.levelgen.HeightMap;
import net.minecraft.world.level.levelgen.WorldGenStage;
import net.minecraft.world.level.levelgen.structure.templatesystem.DefinedStructureManager;
import net.minecraft.world.level.lighting.LightEngine;
+import org.yatopiamc.c2me.common.threading.worldgen.ChunkStatusUtils; // Yatopia
+import org.yatopiamc.c2me.common.threading.worldgen.IWorldGenLockable; // Yatopia
+import java.util.function.Supplier; // Yatopia
public class ChunkStatus {
@@ -162,6 +165,7 @@ public class ChunkStatus {
return ichunkaccess.getChunkStatus().b(chunkstatus) && ichunkaccess.r();
}
+ public static ChunkStatus byDistanceFromFull(int level) { return a(level); } // Yatopia - OBFHELPER
public static ChunkStatus a(int i) {
return i >= ChunkStatus.q.size() ? ChunkStatus.EMPTY : (i < 0 ? ChunkStatus.FULL : (ChunkStatus) ChunkStatus.q.get(i));
}
@@ -186,6 +190,14 @@ public class ChunkStatus {
this.t = chunkstatus == null ? 0 : chunkstatus.c() + 1;
}
+ static {
+ // Yatopia start - C2ME port
+ for (ChunkStatus chunkStatus : IRegistry.CHUNK_STATUS) {
+ chunkStatus.calculateReducedTaskRadius();
+ }
+ // Yatopia end
+ }
+
public final int getStatusIndex() { return c(); } // Paper - OBFHELPER
public int c() {
return this.t;
@@ -200,8 +212,44 @@ public class ChunkStatus {
return this.u;
}
+ // Yatopia start - C2ME port
+ private int reducedTaskRadius = -1;
+
+ public void calculateReducedTaskRadius() {
+ if (this.getNeighborRadius() == 0) {
+ this.reducedTaskRadius = 0;
+ } else {
+ for (int i = 0; i <= this.getNeighborRadius(); i++) {
+ final ChunkStatus status = ChunkStatus.byDistanceFromFull(ChunkStatus.getTicketLevelOffset(this) + i); // TODO [VanillaCopy] from TACS getRequiredStatusForGeneration
+ if (status == ChunkStatus.STRUCTURE_STARTS) {
+ this.reducedTaskRadius = Math.min(this.getNeighborRadius(), i);
+ break;
+ }
+ }
+ }
+ //noinspection ConstantConditions
+ if ((Object) this == ChunkStatus.LIGHT) {
+ this.reducedTaskRadius = 1;
+ }
+ System.out.println(String.format("%s task radius: %d -> %d", this, this.getNeighborRadius(), this.reducedTaskRadius));
+ }
+ // Yatopia end
+
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> a(WorldServer worldserver, ChunkGenerator chunkgenerator, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, List<IChunkAccess> list) {
- return this.v.doWork(this, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, (IChunkAccess) list.get(list.size() / 2));
+ // Yatopia start - port C2ME
+ final IChunkAccess targetChunk = (IChunkAccess) list.get(list.size() / 2);
+ final Supplier<CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> generationTask = () ->
+ this.v.doWork(this, worldserver, chunkgenerator, definedstructuremanager, lightenginethreaded, function, list, targetChunk);
+
+ if (targetChunk.getChunkStatus().isAtLeastStatus((ChunkStatus) (Object) this)) {
+ return generationTask.get();
+ } else {
+ int lockRadius = org.yatopiamc.yatopia.server.YatopiaConfig.reduceLockRadius && this.reducedTaskRadius != -1 ? this.reducedTaskRadius : this.getNeighborRadius();
+ //noinspection ConstantConditions
+ return ChunkStatusUtils.runChunkGenWithLock(targetChunk.getPos(), lockRadius, ((IWorldGenLockable) worldserver).getWorldGenChunkLock(), () ->
+ ChunkStatusUtils.getThreadingType((ChunkStatus) (Object) this).runTask(((IWorldGenLockable) worldserver).getWorldGenSingleThreadedLock(), generationTask));
+ }
+ // Yatopia end
}
public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> a(WorldServer worldserver, DefinedStructureManager definedstructuremanager, LightEngineThreaded lightenginethreaded, Function<IChunkAccess, CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> function, IChunkAccess ichunkaccess) {
diff --git a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
index 13983f3271d33ab6e4c7030de5865edbd7b0cd8a..7460f5c85800f0d3c6076bc944b10b5931ba22bf 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/structure/templatesystem/DefinedStructure.java
@@ -843,7 +843,7 @@ public class DefinedStructure {
private final Map<Block, List<DefinedStructure.BlockInfo>> b;
private a(List<DefinedStructure.BlockInfo> list) {
- this.b = Maps.newHashMap();
+ this.b = new java.util.concurrent.ConcurrentHashMap<>(); // Yatopia - port C2ME
this.a = list;
}
diff --git a/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java b/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java
index 5bbd71f2cf6db34dd01e8e209809a4661505aaf1..76995e812492d3fd0f9180525727174bf3d8c409 100644
--- a/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java
+++ b/src/main/java/net/minecraft/world/level/newbiome/layer/GenLayers.java
@@ -13,7 +13,7 @@ import net.minecraft.world.level.newbiome.layer.traits.AreaTransformer2;
public class GenLayers {
- private static final Int2IntMap a = (Int2IntMap) SystemUtils.a((Object) (new Int2IntOpenHashMap()), (int2intopenhashmap) -> {
+ private static final Int2IntMap a = (Int2IntMap) SystemUtils.a((new Int2IntOpenHashMap()), (int2intopenhashmap) -> { // Yatopia - decompile fixes
a(int2intopenhashmap, GenLayers.Type.BEACH, 16);
a(int2intopenhashmap, GenLayers.Type.BEACH, 26);
a(int2intopenhashmap, GenLayers.Type.DESERT, 2);
@@ -154,9 +154,9 @@ public class GenLayers {
public static GenLayer a(long i, boolean flag, int j, int k) {
boolean flag1 = true;
- AreaFactory<AreaLazy> areafactory = a(flag, j, k, (l) -> {
+ AreaFactory<AreaLazy> areafactory = () -> a(flag, j, k, (l) -> { // Yatopia
return new WorldGenContextArea(25, i, l);
- });
+ }).make(); // Yatopia
return new GenLayer(areafactory);
}
diff --git a/src/main/java/org/yatopiamc/c2me/common/threading/GlobalExecutors.java b/src/main/java/org/yatopiamc/c2me/common/threading/GlobalExecutors.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcf55bc98818f98c1a7b6869306a40c11b842cdf
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/threading/GlobalExecutors.java
@@ -0,0 +1,25 @@
+package org.yatopiamc.c2me.common.threading;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.atomic.AtomicReference;
+
+public class GlobalExecutors {
+
+ public static final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(
+ 1,
+ new ThreadFactoryBuilder().setNameFormat("C2ME scheduler").setDaemon(true).setPriority(Thread.NORM_PRIORITY - 1).setThreadFactory(r -> {
+ final Thread thread = new Thread(r);
+ GlobalExecutors.schedulerThread.set(thread);
+ return thread;
+ }).build()
+ );
+ private static final AtomicReference<Thread> schedulerThread = new AtomicReference<>();
+
+ public static void ensureSchedulerThread() {
+ if (Thread.currentThread() != schedulerThread.get())
+ throw new IllegalStateException("Not on scheduler thread");
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/ChunkStatusThreadingType.java b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/ChunkStatusThreadingType.java
new file mode 100644
index 0000000000000000000000000000000000000000..5af95799cb4cd380f25a31f50f67a2bcb9c1bec5
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/ChunkStatusThreadingType.java
@@ -0,0 +1,45 @@
+
+package org.yatopiamc.c2me.common.threading.worldgen;
+
+import com.google.common.base.Preconditions;
+import com.ibm.asyncutil.locks.AsyncLock;
+import com.mojang.datafixers.util.Either;
+
+import net.minecraft.world.level.chunk.IChunkAccess;
+import net.minecraft.server.level.PlayerChunk;
+
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public enum ChunkStatusThreadingType {
+
+ PARALLELIZED() {
+ @Override
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> runTask(AsyncLock lock, Supplier<CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> completableFuture) {
+ return CompletableFuture.supplyAsync(completableFuture, WorldGenThreadingExecutorUtils.mainExecutor).thenCompose(Function.identity());
+ }
+ },
+ SINGLE_THREADED() {
+ @Override
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> runTask(AsyncLock lock, Supplier<CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> completableFuture) {
+ Preconditions.checkNotNull(lock);
+ return lock.acquireLock().toCompletableFuture().thenComposeAsync(lockToken -> {
+ try {
+ return completableFuture.get();
+ } finally {
+ lockToken.releaseLock();
+ }
+ }, WorldGenThreadingExecutorUtils.mainExecutor);
+ }
+ },
+ AS_IS() {
+ @Override
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> runTask(AsyncLock lock, Supplier<CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> completableFuture) {
+ return completableFuture.get();
+ }
+ };
+
+ public abstract CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> runTask(AsyncLock lock, Supplier<CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>> completableFuture);
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/ChunkStatusUtils.java b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/ChunkStatusUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..0c28024cf9a50f35e1a867188b2a3f8fbbccb3ce
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/ChunkStatusUtils.java
@@ -0,0 +1,59 @@
+package org.yatopiamc.c2me.common.threading.worldgen;
+
+import com.ibm.asyncutil.locks.AsyncLock;
+import com.ibm.asyncutil.locks.AsyncNamedLock;
+import org.yatopiamc.c2me.common.threading.GlobalExecutors;
+import org.yatopiamc.c2me.common.util.AsyncCombinedLock;
+import org.yatopiamc.c2me.common.util.AsyncNamedLockDelegateAsyncLock;
+
+import net.minecraft.world.level.chunk.ChunkStatus;
+import net.minecraft.world.level.ChunkCoordIntPair;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+import static org.yatopiamc.c2me.common.threading.worldgen.ChunkStatusThreadingType.AS_IS;
+import static org.yatopiamc.c2me.common.threading.worldgen.ChunkStatusThreadingType.PARALLELIZED;
+import static org.yatopiamc.c2me.common.threading.worldgen.ChunkStatusThreadingType.SINGLE_THREADED;
+import org.yatopiamc.yatopia.server.YatopiaConfig;
+
+public class ChunkStatusUtils {
+
+ public static ChunkStatusThreadingType getThreadingType(final ChunkStatus status) {
+ if (status.equals(ChunkStatus.STRUCTURE_STARTS)
+ || status.equals(ChunkStatus.STRUCTURE_REFERENCES)
+ || status.equals(ChunkStatus.BIOMES)
+ || status.equals(ChunkStatus.NOISE)
+ || status.equals(ChunkStatus.SURFACE)
+ || status.equals(ChunkStatus.CARVERS)
+ || status.equals(ChunkStatus.LIQUID_CARVERS)
+ || status.equals(ChunkStatus.HEIGHTMAPS)) {
+ return PARALLELIZED;
+ } else if (status.equals(ChunkStatus.SPAWN)) {
+ return SINGLE_THREADED;
+ } else if (status.equals(ChunkStatus.FEATURES)) {
+ return YatopiaConfig.allowThreadedFeatures ? PARALLELIZED : SINGLE_THREADED;
+ }
+ return AS_IS;
+ }
+
+ public static <T> CompletableFuture<T> runChunkGenWithLock(ChunkCoordIntPair target, int radius, AsyncNamedLock<ChunkCoordIntPair> chunkLock, Supplier<CompletableFuture<T>> action) {
+ return CompletableFuture.supplyAsync(() -> {
+ ArrayList<ChunkCoordIntPair> fetchedLocks = new ArrayList<>((2 * radius + 1) * (2 * radius + 1));
+ for (int x = target.x - radius; x <= target.x + radius; x++)
+ for (int z = target.z - radius; z <= target.z + radius; z++)
+ fetchedLocks.add(new ChunkCoordIntPair(x, z));
+
+ return new AsyncCombinedLock(chunkLock, new HashSet<>(fetchedLocks)).getFuture().thenComposeAsync(lockToken -> {
+ final CompletableFuture<T> future = action.get();
+ future.thenRun(lockToken::releaseLock);
+ return future;
+ }, GlobalExecutors.scheduler);
+ }, AsyncCombinedLock.lockWorker).thenCompose(Function.identity());
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/IWorldGenLockable.java b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/IWorldGenLockable.java
new file mode 100644
index 0000000000000000000000000000000000000000..b80923bcda9045968e0fad39f2e40b99dba135dc
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/IWorldGenLockable.java
@@ -0,0 +1,13 @@
+package org.yatopiamc.c2me.common.threading.worldgen;
+
+import com.ibm.asyncutil.locks.AsyncLock;
+import com.ibm.asyncutil.locks.AsyncNamedLock;
+import net.minecraft.world.level.ChunkCoordIntPair;
+
+public interface IWorldGenLockable {
+
+ AsyncLock getWorldGenSingleThreadedLock();
+
+ AsyncNamedLock<ChunkCoordIntPair> getWorldGenChunkLock();
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/WorldGenThreadingExecutorUtils.java b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/WorldGenThreadingExecutorUtils.java
new file mode 100644
index 0000000000000000000000000000000000000000..215010825a18881f84d94ead66314b946d46d75b
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/threading/worldgen/WorldGenThreadingExecutorUtils.java
@@ -0,0 +1,17 @@
+package org.yatopiamc.c2me.common.threading.worldgen;
+
+import org.yatopiamc.c2me.common.util.C2MEForkJoinWorkerThreadFactory;
+
+import java.util.concurrent.ForkJoinPool;
+import org.yatopiamc.yatopia.server.YatopiaConfig;
+
+public class WorldGenThreadingExecutorUtils {
+
+ public static final ForkJoinPool mainExecutor = new ForkJoinPool(
+ YatopiaConfig.c2meThreads,
+ new C2MEForkJoinWorkerThreadFactory("C2ME worldgen worker #%d", Thread.NORM_PRIORITY - 1),
+ null,
+ true
+ );
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/yatopiamc/c2me/common/util/AsyncCombinedLock.java b/src/main/java/org/yatopiamc/c2me/common/util/AsyncCombinedLock.java
new file mode 100644
index 0000000000000000000000000000000000000000..9e34b74d9abecae4b386d49514ceb0d1f333e271
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/util/AsyncCombinedLock.java
@@ -0,0 +1,88 @@
+package org.yatopiamc.c2me.common.util;
+
+import com.google.common.collect.Sets;
+import com.ibm.asyncutil.locks.AsyncLock;
+import com.ibm.asyncutil.locks.AsyncNamedLock;
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+import net.minecraft.world.level.ChunkCoordIntPair;
+
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ForkJoinPool;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class AsyncCombinedLock {
+
+ public static final ForkJoinPool lockWorker = new ForkJoinPool(
+ 2,
+ new C2MEForkJoinWorkerThreadFactory("C2ME lock worker #%d", Thread.NORM_PRIORITY - 1),
+ null,
+ true
+ );
+
+ private final AsyncNamedLock<ChunkCoordIntPair> lock;
+ private final ChunkCoordIntPair[] names;
+ private final CompletableFuture<AsyncLock.LockToken> future = new CompletableFuture<>();
+
+ public AsyncCombinedLock(AsyncNamedLock<ChunkCoordIntPair> lock, Set<ChunkCoordIntPair> names) {
+ this.lock = lock;
+ this.names = names.toArray(ChunkCoordIntPair[]::new);
+ lockWorker.execute(this::tryAcquire);
+ }
+
+ private synchronized void tryAcquire() { // TODO optimize logic further
+ final LockEntry[] tryLocks = new LockEntry[names.length];
+ boolean allAcquired = true;
+ for (int i = 0, namesLength = names.length; i < namesLength; i++) {
+ ChunkCoordIntPair name = names[i];
+ final LockEntry entry = new LockEntry(name, this.lock.tryLock(name));
+ tryLocks[i] = entry;
+ if (entry.lockToken.isEmpty()) {
+ allAcquired = false;
+ break;
+ }
+ }
+ if (allAcquired) {
+ future.complete(() -> {
+ for (LockEntry entry : tryLocks) {
+ //noinspection OptionalGetWithoutIsPresent
+ entry.lockToken.get().releaseLock(); // if it isn't present then something is really wrong
+ }
+ });
+ } else {
+ boolean triedRelock = false;
+ for (LockEntry entry : tryLocks) {
+ if (entry == null) continue;
+ entry.lockToken.ifPresent(AsyncLock.LockToken::releaseLock);
+ if (!triedRelock && entry.lockToken.isEmpty()) {
+ this.lock.acquireLock(entry.name).thenCompose(lockToken -> {
+ lockToken.releaseLock();
+ return CompletableFuture.runAsync(this::tryAcquire, lockWorker);
+ });
+ triedRelock = true;
+ }
+ }
+ if (!triedRelock) {
+ // shouldn't happen at all...
+ lockWorker.execute(this::tryAcquire);
+ }
+ }
+ }
+
+ public CompletableFuture<AsyncLock.LockToken> getFuture() {
+ return future.thenApply(Function.identity());
+ }
+
+ @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
+ private static class LockEntry {
+ public final ChunkCoordIntPair name;
+ public final Optional<AsyncLock.LockToken> lockToken;
+
+ private LockEntry(ChunkCoordIntPair name, Optional<AsyncLock.LockToken> lockToken) {
+ this.name = name;
+ this.lockToken = lockToken;
+ }
+ }
+}
diff --git a/src/main/java/org/yatopiamc/c2me/common/util/AsyncNamedLockDelegateAsyncLock.java b/src/main/java/org/yatopiamc/c2me/common/util/AsyncNamedLockDelegateAsyncLock.java
new file mode 100644
index 0000000000000000000000000000000000000000..119421953de58fbc928e14bf618b340ee6b2fe94
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/util/AsyncNamedLockDelegateAsyncLock.java
@@ -0,0 +1,29 @@
+package org.yatopiamc.c2me.common.util;
+
+import com.ibm.asyncutil.locks.AsyncLock;
+import com.ibm.asyncutil.locks.AsyncNamedLock;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.CompletionStage;
+
+public class AsyncNamedLockDelegateAsyncLock<T> implements AsyncLock {
+
+ private final AsyncNamedLock<T> delegate;
+ private final T name;
+
+ public AsyncNamedLockDelegateAsyncLock(AsyncNamedLock<T> delegate, T name) {
+ this.delegate = Objects.requireNonNull(delegate);
+ this.name = name;
+ }
+
+ @Override
+ public CompletionStage<LockToken> acquireLock() {
+ return delegate.acquireLock(name);
+ }
+
+ @Override
+ public Optional<LockToken> tryLock() {
+ return delegate.tryLock(name);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/yatopiamc/c2me/common/util/C2MEForkJoinWorkerThreadFactory.java b/src/main/java/org/yatopiamc/c2me/common/util/C2MEForkJoinWorkerThreadFactory.java
new file mode 100644
index 0000000000000000000000000000000000000000..ab5b9be9dcf67bdd9237fb7d21574155c2d52306
--- /dev/null
+++ b/src/main/java/org/yatopiamc/c2me/common/util/C2MEForkJoinWorkerThreadFactory.java
@@ -0,0 +1,39 @@
+package org.yatopiamc.c2me.common.util;
+
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.ForkJoinWorkerThread;
+import java.util.concurrent.atomic.AtomicLong;
+
+public class C2MEForkJoinWorkerThreadFactory implements ForkJoinPool.ForkJoinWorkerThreadFactory {
+ private final AtomicLong serial = new AtomicLong(0);
+ private final String namePattern;
+ private final int priority;
+
+ public C2MEForkJoinWorkerThreadFactory(String namePattern, int priority) {
+ this.namePattern = namePattern;
+ this.priority = priority;
+ }
+
+ @Override
+ public ForkJoinWorkerThread newThread(ForkJoinPool pool) {
+ final C2MEForkJoinWorkerThread C2MEForkJoinWorkerThread = new C2MEForkJoinWorkerThread(pool);
+ C2MEForkJoinWorkerThread.setName(String.format(namePattern, serial.incrementAndGet()));
+ C2MEForkJoinWorkerThread.setPriority(priority);
+ C2MEForkJoinWorkerThread.setDaemon(true);
+ return C2MEForkJoinWorkerThread;
+ }
+
+ private static class C2MEForkJoinWorkerThread extends ForkJoinWorkerThread {
+
+ /**
+ * Creates a ForkJoinWorkerThread operating in the given pool.
+ *
+ * @param pool the pool this thread works in
+ * @throws NullPointerException if pool is null
+ */
+ protected C2MEForkJoinWorkerThread(ForkJoinPool pool) {
+ super(pool);
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
index fce7ce0efca340cf5820cdcbe010c9fdeae7cafc..1d1717d72ceb56594bc29f8a14437b61f911f817 100644
--- a/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
+++ b/src/main/java/org/yatopiamc/yatopia/server/YatopiaConfig.java
@@ -271,4 +271,12 @@ public class YatopiaConfig {
fixProtocolLib = getBoolean("settings.fix-protocollib", fixProtocolLib);
}
+ public static boolean allowThreadedFeatures = false;
+ public static int c2meThreads = Math.min(6, Runtime.getRuntime().availableProcessors());
+ public static boolean reduceLockRadius = false;
+ private static void c2me() {
+ allowThreadedFeatures = getBoolean("settings.c2me.allow-threaded-features", allowThreadedFeatures);
+ c2meThreads = getInt("settings.c2me.parallelism", c2meThreads);
+ reduceLockRadius = getBoolean("settings.c2me.reduce-lock-radius", reduceLockRadius);
+ }
}

View File

@ -0,0 +1,144 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Fri, 5 Feb 2021 19:34:00 +0800
Subject: [PATCH] Multi-threaded World Upgrade
diff --git a/src/main/java/net/minecraft/server/Main.java b/src/main/java/net/minecraft/server/Main.java
index 6818f8496ab76ee6ffc747bd6848b43830ec8914..1fe2610ed0ddab1e203e273914c9325aec74e7c2 100644
--- a/src/main/java/net/minecraft/server/Main.java
+++ b/src/main/java/net/minecraft/server/Main.java
@@ -281,6 +281,8 @@ public class Main {
WorldUpgrader worldupgrader = new WorldUpgrader(convertable_conversionsession, datafixer, immutableset, flag);
IChatBaseComponent ichatbasecomponent = null;
+ long lastLocation = 0L; // Yatopia
+ long lastTime = System.nanoTime(); // Yatopia
while (!worldupgrader.b()) {
IChatBaseComponent ichatbasecomponent1 = worldupgrader.h();
@@ -289,13 +291,16 @@ public class Main {
Main.LOGGER.info(worldupgrader.h().getString());
}
- int i = worldupgrader.e();
-
- if (i > 0) {
- int j = worldupgrader.f() + worldupgrader.g();
-
- Main.LOGGER.info("{}% completed ({} / {} chunks)...", MathHelper.d((float) j / (float) i * 100.0F), j, i);
- }
+ // Yatopia start
+ long totalChunkCount = worldupgrader.getTotalChunkCount();
+ if (totalChunkCount > 0) {
+ long processedCount = worldupgrader.getUpgradedChunkCount() + worldupgrader.getSkippedChunkCount();
+ long currentTime = System.nanoTime();
+ String speedRate = String.format("%.1f", (processedCount - lastLocation) / ((currentTime - lastTime) / 1_000_000_000.0));
+ Main.LOGGER.info("{}% completed ({} / {} chunks) at {}cps...", MathHelper.d((float) processedCount / (float) totalChunkCount * 100.0F), processedCount, totalChunkCount, speedRate);
+ lastLocation = processedCount;
+ lastTime = currentTime;
+ } // Yatopia end
if (!booleansupplier.getAsBoolean()) {
worldupgrader.a();
diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
index 6725b31a5183d5af7f8f7566ed21eb61797ef4c9..f13e16aca89f5013ef316e7dbf3d4c67885e6f3e 100644
--- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -33,6 +33,13 @@ import net.minecraft.world.level.storage.Convertable;
import net.minecraft.world.level.storage.WorldPersistentData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
+// Yatopia start
+import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
+import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+// Yatopia end
// CraftBukkit start
import net.minecraft.world.level.dimension.DimensionManager;
@@ -50,9 +57,9 @@ public class WorldUpgrader {
private volatile boolean h = true;
private volatile boolean i;
private volatile float j;
- private volatile int k;
- private volatile int l;
- private volatile int m;
+ private volatile long k; // Yatopia - int -> long
+ private volatile long l; // Yatopia - int -> long
+ private volatile long m; // Yatopia - int -> long
private final Object2FloatMap<ResourceKey<DimensionManager>> n = Object2FloatMaps.synchronize(new Object2FloatOpenCustomHashMap(SystemUtils.k())); // CraftBukkit
private volatile IChatBaseComponent o = new ChatMessage("optimizeWorld.stage.counting");
private static final Pattern p = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
@@ -117,6 +124,11 @@ public class WorldUpgrader {
this.o = new ChatMessage("optimizeWorld.stage.upgrading");
+ // Yatopia start
+ final ExecutorService upgradeExecutor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactoryBuilder().setDaemon(true).setPriority(Thread.NORM_PRIORITY - 1).setNameFormat("WorldUpgrader Worker #%d").build());
+ final Set<CompletableFuture<Void>> futures = new ObjectOpenHashSet<>();
+ final com.ibm.asyncutil.locks.AsyncNamedLock<Integer> regionFileLocks = com.ibm.asyncutil.locks.AsyncNamedLock.createFair();
+ // Yatopia end
while (this.h) {
boolean flag = false;
float f1 = 0.0F;
@@ -130,6 +142,11 @@ public class WorldUpgrader {
if (listiterator.hasNext()) {
ChunkCoordIntPair chunkcoordintpair = (ChunkCoordIntPair) listiterator.next();
+ // Yatopia start
+ flag = true;
+ futures.add(regionFileLocks.acquireLock(String.format("%d %d", chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()).hashCode()).toCompletableFuture().thenAcceptAsync(lockToken -> {
+ try {
+ // Yatopia end
boolean flag1 = false;
try {
@@ -179,7 +196,12 @@ public class WorldUpgrader {
++this.m;
}
- flag = true;
+ // Yatopia start
+ } finally {
+ lockToken.releaseLock();
+ }
+ }, upgradeExecutor));
+ // Yatopia end
}
f2 = (float) listiterator.nextIndex() / f;
@@ -192,6 +214,8 @@ public class WorldUpgrader {
}
}
+ CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join(); // Yatopia
+ upgradeExecutor.shutdown(); // Yatopia
this.o = new ChatMessage("optimizeWorld.stage.finished");
UnmodifiableIterator unmodifiableiterator3 = immutablemap1.values().iterator();
@@ -280,16 +304,19 @@ public class WorldUpgrader {
}
public int e() {
- return this.k;
+ return (int) this.k; // Yatopia
}
+ public long getTotalChunkCount() { return this.k; } // Yatopia
public int f() {
- return this.l;
+ return (int) this.l; // Yatopia
}
+ public long getUpgradedChunkCount() { return this.l; } // Yatopia
public int g() {
- return this.m;
+ return (int) this.m; // Yatopia
}
+ public long getSkippedChunkCount() { return this.m; } // Yatopia
public IChatBaseComponent h() {
return this.o;

View File

@ -0,0 +1,195 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Wed, 3 Feb 2021 23:00:18 +0800
Subject: [PATCH] lithium MultiNoiseBiomeSourceMixin
diff --git a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
index c4fb051739c1c186c1574185e0653f513755987d..e9993fa0f3af9e3ecd01f91ef5c14e528bdb33b5 100644
--- a/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
+++ b/src/main/java/net/minecraft/world/level/biome/BiomeBase.java
@@ -52,6 +52,13 @@ import org.apache.logging.log4j.Logger;
public final class BiomeBase {
public static final Logger LOGGER = LogManager.getLogger();
+ // Yatopia start
+ static class cProxy extends BiomeBase.c {
+ public cProxy(float f, float f1, float f2, float f3, float f4) {
+ super(f, f1, f2, f3, f4);
+ }
+ }
+ // Yatopia end
// Paper start
private static class dProxy extends BiomeBase.d {
private dProxy(Precipitation biomebase_precipitation, float f, TemperatureModifier biomebase_temperaturemodifier, float f1) {
diff --git a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
index 5287aec4c384c6cea76334ae1d8dc99070e8f43e..23637d9be9f9973266c1bba699c40cdc6c5d9e6d 100644
--- a/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
+++ b/src/main/java/net/minecraft/world/level/biome/WorldChunkManagerMultiNoise.java
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.mojang.datafixers.util.Either;
import com.mojang.datafixers.util.Function3;
+import com.mojang.datafixers.util.Function6; // Yatopia - decompile fix
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
@@ -27,26 +28,43 @@ import net.minecraft.world.level.levelgen.synth.NoiseGeneratorNormal;
public class WorldChunkManagerMultiNoise extends WorldChunkManager {
+ // Yatopia start - decompile fix
+ private static class aProxy extends WorldChunkManagerMultiNoise.a {
+ public aProxy(int i, List<Double> list) {
+ super(i, list);
+ }
+ }
+ private static class bProxy extends WorldChunkManagerMultiNoise.b {
+ public bProxy(MinecraftKey minecraftkey, Function3<WorldChunkManagerMultiNoise.b, IRegistry<BiomeBase>, Long, WorldChunkManagerMultiNoise> function3) {
+ super(minecraftkey, function3);
+ }
+ }
+ private static class cProxy extends WorldChunkManagerMultiNoise.c {
+ private cProxy(WorldChunkManagerMultiNoise.b worldchunkmanagermultinoise_b, IRegistry<BiomeBase> iregistry, long i) {
+ super(worldchunkmanagermultinoise_b, iregistry, i);
+ }
+ }
+ // Yatopia end
private static final WorldChunkManagerMultiNoise.a g = new WorldChunkManagerMultiNoise.a(-7, ImmutableList.of(1.0D, 1.0D));
public static final MapCodec<WorldChunkManagerMultiNoise> e = RecordCodecBuilder.mapCodec((instance) -> {
return instance.group(Codec.LONG.fieldOf("seed").forGetter((worldchunkmanagermultinoise) -> {
return worldchunkmanagermultinoise.r;
}), RecordCodecBuilder.create((instance1) -> {
- return instance1.group(BiomeBase.c.a.fieldOf("parameters").forGetter(Pair::getFirst), BiomeBase.d.fieldOf("biome").forGetter(Pair::getSecond)).apply(instance1, Pair::of);
- }).listOf().fieldOf("biomes").forGetter((worldchunkmanagermultinoise) -> {
- return worldchunkmanagermultinoise.p;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("temperature_noise").forGetter((worldchunkmanagermultinoise) -> {
+ return instance1.group(BiomeBase.cProxy.a.fieldOf("parameters").forGetter((java.util.function.Function) t -> ((Pair) t).getFirst()), BiomeBase.d.fieldOf("biome").forGetter(t1 -> (Supplier<BiomeBase>) ((Pair) t1).getSecond())).apply(instance1, Pair::of); // Yatopia - decompile fix
+ }).listOf().fieldOf("biomes").forGetter((Function) worldchunkmanagermultinoise -> { // Yatopia - decompile fix
+ return ((WorldChunkManagerMultiNoise) worldchunkmanagermultinoise).p; // Yatopia - decompile fix
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("temperature_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.h;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("humidity_noise").forGetter((worldchunkmanagermultinoise) -> {
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("humidity_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.i;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("altitude_noise").forGetter((worldchunkmanagermultinoise) -> {
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("altitude_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.j;
- }), WorldChunkManagerMultiNoise.a.a.fieldOf("weirdness_noise").forGetter((worldchunkmanagermultinoise) -> {
+ }), WorldChunkManagerMultiNoise.aProxy.a.fieldOf("weirdness_noise").forGetter((worldchunkmanagermultinoise) -> { // Yatopia - decompile fix
return worldchunkmanagermultinoise.k;
- })).apply(instance, WorldChunkManagerMultiNoise::new);
+ })).apply(instance, (Function6<Long, List<Pair<BiomeBase.c, Supplier<BiomeBase>>>, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise.a, WorldChunkManagerMultiNoise>) WorldChunkManagerMultiNoise::new); // Yatopia - decompile fix
});
- public static final Codec<WorldChunkManagerMultiNoise> f = Codec.mapEither(WorldChunkManagerMultiNoise.c.a, WorldChunkManagerMultiNoise.e).xmap((either) -> {
- return (WorldChunkManagerMultiNoise) either.map(WorldChunkManagerMultiNoise.c::d, Function.identity());
+ public static final Codec<WorldChunkManagerMultiNoise> f = Codec.mapEither(WorldChunkManagerMultiNoise.cProxy.a, WorldChunkManagerMultiNoise.e).xmap((either) -> { // Yatopia - decompile fix
+ return (WorldChunkManagerMultiNoise) either.map(c -> c.d(), Function.identity()); // Yatopia - decompile fix
}, (worldchunkmanagermultinoise) -> {
return (Either) worldchunkmanagermultinoise.d().map(Either::left).orElseGet(() -> {
return Either.right(worldchunkmanagermultinoise);
@@ -100,8 +118,44 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
});
}
+ //Yatopia - Faster Method
+ /**
+ * @reason Remove stream based code in favor of regular collections.
+ * @author SuperCoder79
+ */
@Override
public BiomeBase getBiome(int i, int j, int k) {
+ // [VanillaCopy] MultiNoiseBiomeSource#getBiomeForNoiseGen
+
+ // Get the y value for perlin noise sampling. This field is always set to false in vanilla code.
+ int l = this.q ? j : 0;
+
+ // Calculate the noise point based using 4 perlin noise samplers.
+ BiomeBase.c biomebase_c = new BiomeBase.c(
+ (float) this.l.a(i, l, k),
+ (float) this.m.a(i, l, k),
+ (float) this.n.a(i, l, k),
+ (float) this.o.a(i, l, k),
+ 0.0F);
+
+ int idx = -1;
+ float min = Float.POSITIVE_INFINITY;
+
+ // Iterate through the biome points and calculate the distance to the current noise point.
+ for (int itterator = 0; itterator < this.p.size(); itterator++) {
+ float distance = this.p.get(itterator).getFirst().a(biomebase_c);
+
+ // If the distance is less than the recorded minimum, update the minimum and set the current index.
+ if (min > distance) {
+ idx = itterator;
+ min = distance;
+ }
+ }
+
+ // Return the biome with the noise point closest to the evaluated one.
+ return this.p.get(idx).getSecond().get() == null ? BiomeRegistry.b : this.p.get(idx).getSecond().get();
+ }
+ /* //Yatopia - Replace Method
int l = this.q ? j : 0;
BiomeBase.c biomebase_c = new BiomeBase.c((float) this.l.a((double) i, (double) l, (double) k), (float) this.m.a((double) i, (double) l, (double) k), (float) this.n.a((double) i, (double) l, (double) k), (float) this.o.a((double) i, (double) l, (double) k), 0.0F);
@@ -109,15 +163,17 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
return ((BiomeBase.c) pair.getFirst()).a(biomebase_c);
})).map(Pair::getSecond).map(Supplier::get).orElse(BiomeRegistry.b);
}
+ */ //Yatopia End
+
public boolean b(long i) {
- return this.r == i && this.s.isPresent() && Objects.equals(((Pair) this.s.get()).getSecond(), WorldChunkManagerMultiNoise.b.a);
+ return this.r == i && this.s.isPresent() && Objects.equals(((Pair) this.s.get()).getSecond(), WorldChunkManagerMultiNoise.bProxy.a); // Yatopia - decompile fix
}
public static class b {
- private static final Map<MinecraftKey, WorldChunkManagerMultiNoise.b> b = Maps.newHashMap();
- public static final WorldChunkManagerMultiNoise.b a = new WorldChunkManagerMultiNoise.b(new MinecraftKey("nether"), (worldchunkmanagermultinoise_b, iregistry, olong) -> {
+ protected static final Map<MinecraftKey, WorldChunkManagerMultiNoise.b> b = Maps.newHashMap(); // Yatopia - decompile fix
+ public static final WorldChunkManagerMultiNoise.b a = new WorldChunkManagerMultiNoise.b(new MinecraftKey("nether"), (worldchunkmanagermultinoise_b, iregistry, olong) -> { // Yatopia - decompile fix
return new WorldChunkManagerMultiNoise(olong, ImmutableList.of(Pair.of(new BiomeBase.c(0.0F, 0.0F, 0.0F, 0.0F, 0.0F), () -> {
return (BiomeBase) iregistry.d(Biomes.NETHER_WASTES);
}), Pair.of(new BiomeBase.c(0.0F, -0.5F, 0.0F, 0.0F, 0.0F), () -> {
@@ -136,7 +192,7 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
public b(MinecraftKey minecraftkey, Function3<WorldChunkManagerMultiNoise.b, IRegistry<BiomeBase>, Long, WorldChunkManagerMultiNoise> function3) {
this.c = minecraftkey;
this.d = function3;
- WorldChunkManagerMultiNoise.b.b.put(minecraftkey, this);
+ WorldChunkManagerMultiNoise.bProxy.b.put(minecraftkey, this); // Yatopia - decompile fix
}
public WorldChunkManagerMultiNoise a(IRegistry<BiomeBase> iregistry, long i) {
@@ -144,16 +200,16 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
}
}
- static final class c {
+ static class c { // Yatopia - decompile fix
public static final MapCodec<WorldChunkManagerMultiNoise.c> a = RecordCodecBuilder.mapCodec((instance) -> {
return instance.group(MinecraftKey.a.flatXmap((minecraftkey) -> {
- return (DataResult) Optional.ofNullable(WorldChunkManagerMultiNoise.b.b.get(minecraftkey)).map(DataResult::success).orElseGet(() -> {
+ return (DataResult) Optional.ofNullable(bProxy.b.get(minecraftkey)).map(DataResult::success).orElseGet(() -> { // Yatopia - decompile fix
return DataResult.error("Unknown preset: " + minecraftkey);
});
}, (worldchunkmanagermultinoise_b) -> {
- return DataResult.success(worldchunkmanagermultinoise_b.c);
- }).fieldOf("preset").stable().forGetter(WorldChunkManagerMultiNoise.c::a), RegistryLookupCodec.a(IRegistry.ay).forGetter(WorldChunkManagerMultiNoise.c::b), Codec.LONG.fieldOf("seed").stable().forGetter(WorldChunkManagerMultiNoise.c::c)).apply(instance, instance.stable(WorldChunkManagerMultiNoise.c::new));
+ return DataResult.success(((WorldChunkManagerMultiNoise.b) worldchunkmanagermultinoise_b).c); // Yatopia - decompile fix
+ }).fieldOf("preset").stable().forGetter(o -> ((WorldChunkManagerMultiNoise.c) o).a()), (RecordCodecBuilder) RegistryLookupCodec.a(IRegistry.ay).forGetter((Function<WorldChunkManagerMultiNoise.c, IRegistry<BiomeBase>>) c -> c.b()), (RecordCodecBuilder) Codec.LONG.fieldOf("seed").stable().forGetter((Function<WorldChunkManagerMultiNoise.c, Long>) c -> c.c())).apply(instance, instance.stable((Function3<WorldChunkManagerMultiNoise.b, IRegistry<BiomeBase>, Long, WorldChunkManagerMultiNoise.c>) WorldChunkManagerMultiNoise.c::new)); // Yatopia - decompile fix
});
private final WorldChunkManagerMultiNoise.b b;
private final IRegistry<BiomeBase> c;
@@ -187,7 +243,7 @@ public class WorldChunkManagerMultiNoise extends WorldChunkManager {
private final int b;
private final DoubleList c;
public static final Codec<WorldChunkManagerMultiNoise.a> a = RecordCodecBuilder.create((instance) -> {
- return instance.group(Codec.INT.fieldOf("firstOctave").forGetter(WorldChunkManagerMultiNoise.a::a), Codec.DOUBLE.listOf().fieldOf("amplitudes").forGetter(WorldChunkManagerMultiNoise.a::b)).apply(instance, WorldChunkManagerMultiNoise.a::new);
+ return instance.group(Codec.INT.fieldOf("firstOctave").forGetter((Function<WorldChunkManagerMultiNoise.a, Integer>) a -> a.a()), Codec.DOUBLE.listOf().fieldOf("amplitudes").forGetter(a -> a.b())).apply(instance, WorldChunkManagerMultiNoise.a::new); // Yatopia - decompile fix
});
public a(int i, List<Double> list) {

View File

@ -0,0 +1,42 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: ishland <ishlandmc@yeah.net>
Date: Tue, 9 Feb 2021 21:42:09 +0800
Subject: [PATCH] Force world save
diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
index 29cd71efe86eea2227f373c15c39dc530e9e8199..4028526166fe528d772729e9334289df460f3b1e 100644
--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
+++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/VillagePlace.java
@@ -366,6 +366,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
}).orElse(false);
}
+ private final java.util.concurrent.atomic.AtomicBoolean hasWorked = new java.util.concurrent.atomic.AtomicBoolean(false); // Yatopia - enforce one chunk unload per tick
@Override
public void a(BooleanSupplier booleansupplier) {
// Paper start - async chunk io
@@ -373,7 +374,7 @@ public class VillagePlace extends RegionFileSection<VillagePlaceSection> {
super.a(booleansupplier);
} else {
//super.a(booleansupplier); // re-implement below
- while (!((RegionFileSection)this).d.isEmpty() && booleansupplier.getAsBoolean() && !this.world.isSavingDisabled()) { // Tuinity - unload POI data - don't write to disk if saving is disabled
+ hasWorked.set(false); while (!((RegionFileSection)this).d.isEmpty() && (hasWorked.compareAndSet(false, true) || booleansupplier.getAsBoolean()) && !this.world.isSavingDisabled()) { // Tuinity - unload POI data - don't write to disk if saving is disabled // Yatopia - enforce one chunk unload per tick
ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(((RegionFileSection)this).d.firstLong()).r();
NBTTagCompound data;
diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
index f70c14385c95763b5f270a6e2ce372cf047ba7bb..4454489153f7932deaaebe8aa32ecb603764f42b 100644
--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
+++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileSection.java
@@ -50,8 +50,9 @@ public class RegionFileSection<R> extends RegionFileCache implements AutoCloseab
//this.b = new IOWorker(file, flag, file.getName()); // Paper - nuke IOWorker
}
+ private final java.util.concurrent.atomic.AtomicBoolean hasWorked = new java.util.concurrent.atomic.AtomicBoolean(false); // Yatopia - enforce one chunk unload per tick
protected void a(BooleanSupplier booleansupplier) {
- while (!this.d.isEmpty() && booleansupplier.getAsBoolean()) {
+ hasWorked.set(false); while (!this.d.isEmpty() && (hasWorked.compareAndSet(false, true) || booleansupplier.getAsBoolean())) { // Yatopia - enforce one chunk unload per tick
ChunkCoordIntPair chunkcoordintpair = SectionPosition.a(this.d.firstLong()).r(); // Paper - conflict here to avoid obfhelpers
this.d(chunkcoordintpair);

View File

@ -0,0 +1,58 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Simon Gardling <titaniumtown@gmail.com>
Date: Fri, 23 Apr 2021 11:11:20 -0400
Subject: [PATCH] java 11
diff --git a/pom.xml b/pom.xml
index f0a73238612327d71cf78801df816823d80893a0..57a87372c039fb410c97eaa00227b429b90da2b1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -14,8 +14,8 @@
<bt.name>git</bt.name>
<minecraft.version>1.16.5</minecraft.version>
<minecraft_version>1_16_R3</minecraft_version>
- <maven.compiler.source>1.8</maven.compiler.source>
- <maven.compiler.target>1.8</maven.compiler.target>
+ <maven.compiler.source>11</maven.compiler.source>
+ <maven.compiler.target>11</maven.compiler.target>
</properties>
<parent>
diff --git a/src/main/java/io/papermc/paper/util/PaperJvmChecker.java b/src/main/java/io/papermc/paper/util/PaperJvmChecker.java
index c6ea429819c07e7f4bc257cad73463a030767825..3fdca3afeefdb7f850934f9b1b5312f8979b50f3 100644
--- a/src/main/java/io/papermc/paper/util/PaperJvmChecker.java
+++ b/src/main/java/io/papermc/paper/util/PaperJvmChecker.java
@@ -28,21 +28,17 @@ public class PaperJvmChecker {
public static void checkJvm() {
if (getJvmVersion() < 11) {
final Logger logger = LogManager.getLogger();
- logger.warn("************************************************************");
- logger.warn("* WARNING - YOU ARE RUNNING AN OUTDATED VERSION OF JAVA.");
- logger.warn("* PAPER WILL STOP BEING COMPATIBLE WITH THIS VERSION OF");
- logger.warn("* JAVA WHEN MINECRAFT 1.17 IS RELEASED.");
- logger.warn("*");
- logger.warn("* Please update the version of Java you use to run Paper");
- logger.warn("* to at least Java 11. When Paper for Minecraft 1.17 is");
- logger.warn("* released support for versions of Java before 11 will");
- logger.warn("* be dropped.");
- logger.warn("*");
- logger.warn("* Current Java version: {}", System.getProperty("java.version"));
- logger.warn("*");
- logger.warn("* Check this forum post for more information: ");
- logger.warn("* https://papermc.io/java11");
- logger.warn("************************************************************");
+ // Yatopia start - require java 11+
+ // Note - no clue how someone would run a jar built for java 11 on a java version lower than 11, but doesn't hurt to update this warning I guess.
+ logger.fatal("************************************************************");
+ logger.fatal("* ERROR - YOU ARE RUNNING AN OUTDATED VERSION OF JAVA.");
+ logger.fatal("* YOU NEED TO BE RUNNING JAVA 11 OR HIGHER");
+ logger.fatal("* In order to achieve Yatopia's high performance,");
+ logger.fatal("* Yatopia uses features only found in Java 11 or higher.");
+ logger.fatal("* If you do not know how to install Java 11 or have any other questions,");
+ logger.fatal("* Join our discord server (https://discord.io/YatopiaMC) and ask for support in #yatopia-help");
+ logger.fatal("************************************************************");
+ // Yatopia end
}
}
}