mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-23 17:09:29 +00:00
Merge branch 'ver/1.21.4' into dev/1.21.5
This commit is contained in:
@@ -17,6 +17,7 @@ public net.minecraft.world.entity.decoration.ArmorStand noTickEquipmentDirty
|
||||
public net.minecraft.world.entity.monster.Shulker MAX_SCALE
|
||||
public net.minecraft.world.entity.player.Player canGlide()Z
|
||||
public net.minecraft.world.item.CrossbowItem getShotPitch(Lnet/minecraft/util/RandomSource;I)F
|
||||
public net.minecraft.world.level.block.PoweredRailBlock findPoweredRailSignal(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;ZI)Z
|
||||
public net.minecraft.world.level.block.entity.FuelValues values
|
||||
public net.minecraft.world.level.chunk.PaletteResize
|
||||
public net.minecraft.world.level.chunk.storage.RegionFile getOversizedData(II)Lnet/minecraft/nbt/CompoundTag;
|
||||
|
||||
@@ -35,7 +35,7 @@ subprojects {
|
||||
options.release = 21
|
||||
options.isFork = true
|
||||
options.compilerArgs.addAll(listOf("-Xlint:-deprecation", "-Xlint:-removal"))
|
||||
options.forkOptions.memoryMaximumSize = "6g" // Prevent OOM during building
|
||||
options.forkOptions.memoryMaximumSize = "2g" // Prevent OOM during building
|
||||
}
|
||||
tasks.withType<Javadoc> {
|
||||
options.encoding = Charsets.UTF_8.name()
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
|
||||
Date: Wed, 31 Jul 2024 22:05:21 +0800
|
||||
Subject: [PATCH] Leaf Bootstrap
|
||||
|
||||
Removed since Leaf 1.21.4, useless
|
||||
|
||||
org.bukkit.craftbukkit.Main#main -> LeafBootstrap -> PaperBootstrap -> ...
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index ecb0fcd1f3b3f3d7751eded3cdf0977c1889c9ed..d0becb56a9911ef4cc55ae8d7c47832f442ad52f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -278,7 +278,8 @@ public class Main {
|
||||
System.setProperty("jdk.console", "java.base"); // Paper - revert default console provider back to java.base so we can have our own jline
|
||||
//System.out.println("Loading libraries, please wait...");
|
||||
//net.minecraft.server.Main.main(options);
|
||||
- io.papermc.paper.PaperBootstrap.boot(options);
|
||||
+ //io.papermc.paper.PaperBootstrap.boot(options); // Leaf - Leaf Boostrap - diff on change
|
||||
+ org.dreeam.leaf.LeafBootstrap.boot(options); // Leaf - Leaf Boostrap
|
||||
} catch (Throwable t) {
|
||||
t.printStackTrace();
|
||||
}
|
||||
@@ -4,6 +4,7 @@ Date: Thu, 1 Aug 2024 00:43:05 +0900
|
||||
Subject: [PATCH] ShreddedPaper: Don't block main thread in
|
||||
Connection#syncAfterConfigurationChange
|
||||
|
||||
Removed since Leaf 1.21.4, replaced by async config switch
|
||||
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index 00a82873d226f113278632a53c0faca420dd67d4..5b46036868b6c9d082e35591e58735e16adaae62 100644
|
||||
@@ -3,6 +3,8 @@ From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 5 Sep 2024 15:42:15 -0700
|
||||
Subject: [PATCH] Moonrise: Optimise checkInsideBlocks
|
||||
|
||||
Removed since Leaf 1.21.3, Optimized in Minecraft
|
||||
|
||||
Original license: GPLv3
|
||||
Original project: https://github.com/Tuinity/Moonrise
|
||||
|
||||
@@ -3,6 +3,8 @@ From: Spottedleaf <Spottedleaf@users.noreply.github.com>
|
||||
Date: Thu, 5 Sep 2024 16:23:04 -0700
|
||||
Subject: [PATCH] Moonrise: Avoid streams for block retrieval in Entity#move
|
||||
|
||||
Removed since Leaf 1.21.3, Optimized in Minecraft
|
||||
|
||||
Original license: GPLv3
|
||||
Original project: https://github.com/Tuinity/Moonrise
|
||||
|
||||
@@ -3,6 +3,7 @@ From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Fri, 8 Nov 2024 00:54:42 +0100
|
||||
Subject: [PATCH] Use MCUtil.asyncExecutor for MAIN_WORKER_EXECUTOR
|
||||
|
||||
Removed since Leaf 1.21.3
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/Util.java b/src/main/java/net/minecraft/Util.java
|
||||
index 815253d03b85a7a476c1efdeca9496fd64afc137..bb4c9bbebaefe9a0c7d213e9b2b07308e684dc7c 100644
|
||||
@@ -105,7 +105,7 @@ index dddbb18992348fb7e8a6552423d134809cd7fdbc..0e6e71030e3fd1335fff796b861524a4
|
||||
if (this.hidesOnlinePlayers()) {
|
||||
return new ServerStatus.Players(maxPlayers, players.size(), List.of());
|
||||
diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java
|
||||
index 792ba93b531e9586e26aafa00830022a8996fc04..e4ea26ae84efde7ce54e08a246a6ea2ae2a17151 100644
|
||||
index abccabb8a0a1a9730b7df070dd25f3ca215af362..0a4bcc4c44fed2ededafaf0641315e072b7ba771 100644
|
||||
--- a/net/minecraft/server/PlayerAdvancements.java
|
||||
+++ b/net/minecraft/server/PlayerAdvancements.java
|
||||
@@ -168,6 +168,11 @@ public class PlayerAdvancements {
|
||||
@@ -134,7 +134,7 @@ index 5c0a04db38821dbb0cba2bb6f0787f113d167efd..cd153db93f709c3142942fac88ae3ca2
|
||||
.filter(player -> !playerList.isOp(player.getGameProfile()))
|
||||
.map(player -> player.getGameProfile().getName()),
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 94ee31a4a02edb003b98a09b0311355c1db4f547..f8bd39ddd7b6948734254acfb8b0235eff774133 100644
|
||||
index b49dd636e730f0c5b609df68ee51bcd12efc1eaa..5e971bca365c692d4ce0c58693592002ce01471c 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -216,6 +216,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -153,7 +153,7 @@ index 94ee31a4a02edb003b98a09b0311355c1db4f547..f8bd39ddd7b6948734254acfb8b0235e
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@@ -2672,6 +2674,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -2698,6 +2700,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
ServerLevel.this.players.add(serverPlayer);
|
||||
@@ -165,7 +165,7 @@ index 94ee31a4a02edb003b98a09b0311355c1db4f547..f8bd39ddd7b6948734254acfb8b0235e
|
||||
ServerLevel.this.updateSleepingPlayerList();
|
||||
}
|
||||
|
||||
@@ -2742,6 +2749,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -2768,6 +2775,11 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
ServerLevel.this.getChunkSource().removeEntity(entity);
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
ServerLevel.this.players.remove(serverPlayer);
|
||||
@@ -178,7 +178,7 @@ index 94ee31a4a02edb003b98a09b0311355c1db4f547..f8bd39ddd7b6948734254acfb8b0235e
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index 622257dbbe572de33e15abef9055016268730261..dfb4524d80f642eff1b146dd2fbfa07f21d844c6 100644
|
||||
index d44c3baa2ef30d5cd4c46e491ff9198fa558513c..f89d28595fa9ca12e414f7b3cc86085ff0769e72 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -195,7 +195,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
@@ -191,7 +191,7 @@ index 622257dbbe572de33e15abef9055016268730261..dfb4524d80f642eff1b146dd2fbfa07f
|
||||
private final ServerStatsCounter stats;
|
||||
private float lastRecordedHealthAndAbsorption = Float.MIN_VALUE;
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index e3d09d5f4efb32bb276e001e5ee747a775b502ee..78b15d750d75e5d4c2318a3a18e83afdd5f4fbe1 100644
|
||||
index c26bf04abe86b566e7f5cd29191a0a853f9808f8..4c172e2aee3e48d42009cd39b28f694aa71e20e3 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -132,6 +132,7 @@ public abstract class PlayerList {
|
||||
|
||||
@@ -265,7 +265,7 @@ index 5ab2c8333178335515e619b87ae420f948c83bd1..be3b2f023897a8823560ee059cb16ec9
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11b57ae175 100644
|
||||
index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..7f791ff5bdf6c29c78f863d21af16270a74d8e7e 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -291,6 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -326,7 +326,20 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1677,6 +1690,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -923,6 +936,12 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
serverLevel.save(null, flush, serverLevel.noSave && !forced, close); // Paper - add close param
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads
|
||||
+ // Only prepare shutdown if 'close' is true, indicating this save is part of server shutdown
|
||||
+ if (close && org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) {
|
||||
+ serverLevel.prepareShutdown();
|
||||
+ }
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking - Shutdown handling for async reads
|
||||
flag = true;
|
||||
}
|
||||
|
||||
@@ -1677,6 +1696,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,7 +358,7 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11
|
||||
protected void tickChildren(BooleanSupplier hasTimeLeft) {
|
||||
this.getPlayerList().getPlayers().forEach(serverPlayer1 -> serverPlayer1.connection.suspendFlushing());
|
||||
this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
|
||||
@@ -1743,28 +1768,50 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1743,28 +1774,50 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked
|
||||
@@ -414,7 +427,7 @@ index c50a301a0c2365c2052aefc6a23fcf6fa82e1b9d..ac751d460ae0c8dbb858c4047c459a11
|
||||
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
|
||||
|
||||
this.tickConnection();
|
||||
@@ -1844,6 +1891,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1844,6 +1897,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
|
||||
Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
|
||||
newLevels.remove(level.dimension());
|
||||
@@ -568,7 +581,7 @@ index d4048661575ebfaf128ba25da365843774364e0e..33dd16a26edd2974f04d9a868d3e58e8
|
||||
|
||||
// Gale start - Pufferfish - SIMD support
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d08e18122 100644
|
||||
index a66e5f6652d9633c856490de36d8d8fdf8a5298a..d6524d5c442555eaeb4d90f6a101262ee669f0d9 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -182,7 +182,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -580,23 +593,173 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
|
||||
// Paper - rewrite chunk system
|
||||
private final GameEventDispatcher gameEventDispatcher;
|
||||
public boolean noSave;
|
||||
@@ -208,6 +208,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -208,7 +208,9 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
private double preciseTime; // Purpur - Configurable daylight cycle
|
||||
private boolean forceTime; // Purpur - Configurable daylight cycle
|
||||
private final RandomSequences randomSequences;
|
||||
-
|
||||
+ public java.util.concurrent.ExecutorService tickExecutor; // SparklyPaper - parallel world ticking
|
||||
|
||||
+ public final java.util.concurrent.ConcurrentLinkedQueue<org.dreeam.leaf.async.world.WorldReadRequest> asyncReadRequestQueue = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Leaf - SparklyPaper - parallel world ticking
|
||||
+ private volatile boolean isShuttingDown = false; // Leaf - SparklyPaper - parallel world ticking - Shutdown handling for async reads
|
||||
// CraftBukkit start
|
||||
public final LevelStorageSource.LevelStorageAccess levelStorageAccess;
|
||||
@@ -703,6 +704,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
public final UUID uuid;
|
||||
@@ -703,8 +705,26 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
||||
this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
|
||||
this.realPlayers = Lists.newArrayList(); // Leaves - skip
|
||||
+ this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.dreeam.leaf.async.world.SparklyPaperServerLevelTickExecutorThreadFactory(getWorld().getName())); // SparklyPaper - parallel world ticking
|
||||
+ }
|
||||
+
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking - Shutdown handling for async reads
|
||||
+ public boolean isShuttingDown() {
|
||||
+ return this.isShuttingDown;
|
||||
}
|
||||
|
||||
+ public void prepareShutdown() {
|
||||
+ this.isShuttingDown = true;
|
||||
+ org.dreeam.leaf.async.world.WorldReadRequest req;
|
||||
+ int clearedRequests = 0;
|
||||
+ while ((req = this.asyncReadRequestQueue.poll()) != null) {
|
||||
+ req.future().completeExceptionally(new IllegalStateException("World " + this.getWorld().getName() + " is shutting down. Cannot process buffered read: " + req.type()));
|
||||
+ clearedRequests++;
|
||||
+ }
|
||||
+ if (clearedRequests > 0) MinecraftServer.LOGGER.info("PWT: Cleared " + clearedRequests + " pending async read requests for world " + this.getWorld().getName() + " during shutdown.");
|
||||
+ }
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking - Shutdown handling for async reads
|
||||
+
|
||||
// Paper start
|
||||
@@ -1313,9 +1315,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@Override
|
||||
public boolean hasChunk(int chunkX, int chunkZ) {
|
||||
@@ -737,8 +757,112 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
public Player[] eligibleDespawnCheckingPlayerCache = new Player[0]; // Leaf - Cache eligible players for despawn checks
|
||||
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking
|
||||
+ private void processAsyncReadRequests() {
|
||||
+ // Only process if parallel ticking is enabled and buffering is active
|
||||
+ if (!org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled ||
|
||||
+ !org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.asyncUnsafeReadHandling.equals("BUFFERED")) {
|
||||
+ // Clear queue if buffering gets disabled to prevent memory leaks
|
||||
+ if (!this.asyncReadRequestQueue.isEmpty()) {
|
||||
+ org.dreeam.leaf.async.world.WorldReadRequest req;
|
||||
+ while ((req = this.asyncReadRequestQueue.poll()) != null) {
|
||||
+ req.future().completeExceptionally(new IllegalStateException("Async read buffering disabled while request was pending."));
|
||||
+ }
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ org.dreeam.leaf.async.world.WorldReadRequest request;
|
||||
+ int processed = 0;
|
||||
+ // Limit processing per tick to avoid stalling the tick loop
|
||||
+ int maxToProcess = 16384; // Consider making this configurable
|
||||
+
|
||||
+ while (processed < maxToProcess && (request = this.asyncReadRequestQueue.poll()) != null) {
|
||||
+ processed++;
|
||||
+ // Ensure we are on the correct thread before executing
|
||||
+ // This check might be redundant if called correctly from tick(), but good for safety
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Processing async read request off-thread");
|
||||
+
|
||||
+ try {
|
||||
+ Object result = executeReadRequest(request);
|
||||
+ request.future().complete(result);
|
||||
+ } catch (Throwable t) {
|
||||
+ // Log the error from the tick thread side
|
||||
+ org.bukkit.Bukkit.getLogger().log(java.util.logging.Level.SEVERE, "Exception processing buffered async world read for type " + request.type(), t);
|
||||
+ request.future().completeExceptionally(t);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Executes the actual read operation based on the request type
|
||||
+ private Object executeReadRequest(org.dreeam.leaf.async.world.WorldReadRequest request) {
|
||||
+ Object[] params = request.params();
|
||||
+ BlockPos pos; // Declare pos outside the switch
|
||||
+
|
||||
+ switch (request.type()) {
|
||||
+ case BLOCK_GET_NMS_STATE: { //
|
||||
+ pos = (BlockPos) params[0];
|
||||
+ return this.getBlockState(pos);
|
||||
+ }
|
||||
+ case BLOCK_GET_BIOME: {
|
||||
+ pos = (BlockPos) params[0];
|
||||
+ return this.getNoiseBiome(pos.getX() >> 2, pos.getY() >> 2, pos.getZ() >> 2);
|
||||
+ }
|
||||
+ case BLOCK_GET_COMPUTED_BIOME: {
|
||||
+ pos = (BlockPos) params[0];
|
||||
+ return this.getBiome(pos);
|
||||
+ }
|
||||
+ case BLOCK_IS_INDIRECTLY_POWERED: {
|
||||
+ pos = (BlockPos) params[0];
|
||||
+ return this.hasNeighborSignal(pos);
|
||||
+ }
|
||||
+ case BLOCK_GET_BLOCK_POWER: {
|
||||
+ pos = (BlockPos) params[0];
|
||||
+ org.bukkit.block.BlockFace face = (org.bukkit.block.BlockFace) params[1];
|
||||
+ int power = 0;
|
||||
+ Direction notchDir = org.bukkit.craftbukkit.block.CraftBlock.blockFaceToNotch(face);
|
||||
+
|
||||
+ if ((face == org.bukkit.block.BlockFace.DOWN || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.below(), Direction.DOWN)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.below()));
|
||||
+ if ((face == org.bukkit.block.BlockFace.UP || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.above(), Direction.UP)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.above()));
|
||||
+ if ((face == org.bukkit.block.BlockFace.EAST || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.east(), Direction.EAST)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.east()));
|
||||
+ if ((face == org.bukkit.block.BlockFace.WEST || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.west(), Direction.WEST)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.west()));
|
||||
+ if ((face == org.bukkit.block.BlockFace.NORTH || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.north(), Direction.NORTH)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.north()));
|
||||
+ if ((face == org.bukkit.block.BlockFace.SOUTH || face == org.bukkit.block.BlockFace.SELF) && this.hasSignal(pos.south(), Direction.SOUTH)) power = org.bukkit.craftbukkit.block.CraftBlock.getPower(power, this.getBlockState(pos.south()));
|
||||
+
|
||||
+ boolean indirectlyPowered = (face == org.bukkit.block.BlockFace.SELF) ? this.hasNeighborSignal(pos) : (this.getSignal(pos, notchDir) > 0); // Simplified indirect check for faces
|
||||
+ return power > 0 ? power : (indirectlyPowered ? 15 : 0);
|
||||
+ }
|
||||
+ case BLOCK_RAY_TRACE: {
|
||||
+ pos = (BlockPos) params[0];
|
||||
+ org.bukkit.Location start = (org.bukkit.Location) params[1];
|
||||
+ org.bukkit.util.Vector direction = (org.bukkit.util.Vector) params[2];
|
||||
+ double maxDistance = (double) params[3];
|
||||
+ org.bukkit.FluidCollisionMode fluidCollisionMode = (org.bukkit.FluidCollisionMode) params[4];
|
||||
+
|
||||
+ org.bukkit.util.Vector dir = direction.clone().normalize().multiply(maxDistance);
|
||||
+ Vec3 startPos = org.bukkit.craftbukkit.util.CraftLocation.toVec3D(start);
|
||||
+ Vec3 endPos = startPos.add(dir.getX(), dir.getY(), dir.getZ());
|
||||
+
|
||||
+ return this.clip(new net.minecraft.world.level.ClipContext(startPos, endPos, net.minecraft.world.level.ClipContext.Block.OUTLINE, org.bukkit.craftbukkit.CraftFluidCollisionMode.toNMS(fluidCollisionMode), net.minecraft.world.phys.shapes.CollisionContext.empty()), pos); // Pass block pos
|
||||
+ }
|
||||
+ case BLOCK_CAN_PLACE: {
|
||||
+ pos = (BlockPos) params[0];
|
||||
+ org.bukkit.block.data.BlockData data = (org.bukkit.block.data.BlockData) params[1];
|
||||
+ net.minecraft.world.level.block.state.BlockState nmsData = ((org.bukkit.craftbukkit.block.data.CraftBlockData) data).getState();
|
||||
+ return nmsData.canSurvive(this, pos);
|
||||
+ }
|
||||
+ // Add cases for other ReadOperationType values here...
|
||||
+ // case GET_ENTITIES_IN_BOX: ... (complex, needs careful list handling)
|
||||
+
|
||||
+ default:
|
||||
+ throw new UnsupportedOperationException("Unsupported buffered read type: " + request.type());
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking
|
||||
+
|
||||
public void tick(BooleanSupplier hasTimeLeft) {
|
||||
this.handlingTick = true;
|
||||
+ this.processAsyncReadRequests(); // Leaf - SparklyPaper - parallel world ticking
|
||||
TickRateManager tickRateManager = this.tickRateManager();
|
||||
boolean runsNormally = tickRateManager.runsNormally();
|
||||
if (runsNormally) {
|
||||
@@ -746,6 +870,14 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.advanceWeatherCycle();
|
||||
}
|
||||
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking
|
||||
+ if (!org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) {
|
||||
+ this.moonrise$midTickTasks();
|
||||
+ } else if ((++this.tickedBlocksOrFluids & 7L) != 0L) { // Keep original mid-tick logic for PWT enabled
|
||||
+ this.server.moonrise$executeMidTickTasks();
|
||||
+ }
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking
|
||||
+
|
||||
int _int = this.getGameRules().getInt(GameRules.RULE_PLAYERS_SLEEPING_PERCENTAGE);
|
||||
if (this.purpurConfig.playersSkipNight && this.sleepStatus.areEnoughSleeping(_int) && this.sleepStatus.areEnoughDeepSleeping(_int, this.players)) { // Purpur - Config for skipping night
|
||||
// Paper start - create time skip event - move up calculations
|
||||
@@ -1313,9 +1445,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
fluidState.tick(this, pos, blockState);
|
||||
}
|
||||
// Paper start - rewrite chunk system
|
||||
@@ -611,7 +774,7 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
}
|
||||
@@ -1326,9 +1331,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1326,9 +1461,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
blockState.tick(this, pos, this.random);
|
||||
}
|
||||
// Paper start - rewrite chunk system
|
||||
@@ -626,7 +789,7 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
}
|
||||
@@ -1579,6 +1587,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1579,6 +1717,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
|
||||
private void addPlayer(ServerPlayer player) {
|
||||
@@ -635,7 +798,7 @@ index a66e5f6652d9633c856490de36d8d8fdf8a5298a..60e0296312030d25f917c568c17ce86d
|
||||
Entity entity = this.getEntities().get(player.getUUID());
|
||||
if (entity != null) {
|
||||
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
|
||||
@@ -1591,7 +1601,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1591,7 +1731,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
// CraftBukkit start
|
||||
private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
|
||||
|
||||
@@ -6,10 +6,10 @@ Subject: [PATCH] SparklyPaper: Track each world MSPT
|
||||
Original project: https://github.com/SparklyPower/SparklyPaper
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index ac751d460ae0c8dbb858c4047c459a11b57ae175..24926aa7ed5c78b235659daf18b224b14beb744c 100644
|
||||
index 7f791ff5bdf6c29c78f863d21af16270a74d8e7e..1431a0fac3c8a846535c1bd2f60a1279d08f14ea 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1693,7 +1693,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1699,7 +1699,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// Leaf start - SparklyPaper - parallel world ticking mod (move level ticking logic out for branch convergence)
|
||||
private void tickLevel(ServerLevel serverLevel, BooleanSupplier hasTimeLeft) {
|
||||
try {
|
||||
@@ -27,10 +27,10 @@ index ac751d460ae0c8dbb858c4047c459a11b57ae175..24926aa7ed5c78b235659daf18b224b1
|
||||
CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world");
|
||||
serverLevel.fillReportDetails(crashReport);
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 31abf2da10bc9b4b7825ed4b3d4e9da52feb2e39..9ba1c29b75ba0eb545097eef4fe568c53ebd885c 100644
|
||||
index d6524d5c442555eaeb4d90f6a101262ee669f0d9..5c1f99a8fd9920b30e6a80769bc306591510012a 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -573,6 +573,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -574,6 +574,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper end - chunk tick iteration
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ Original project: https://github.com/LeavesMC/Leaves
|
||||
Commit: 41476d86922416c45f703df2871890831fc42bb5
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index aa6f0588f282e3152ef9639d6fb2b8cd1d54bdb7..514c2d414ac59c71929a7686204465c72d122513 100644
|
||||
index ddf9a5d3af7ebe8e5c69d7dcb8a1c3a28d8178e3..3fabeaa91832eacc103416682aec3ce6121858fb 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -508,6 +508,7 @@ public final class CraftServer implements Server {
|
||||
@@ -509,6 +509,7 @@ public final class CraftServer implements Server {
|
||||
this.potionBrewer = new io.papermc.paper.potion.PaperPotionBrewer(console); // Paper - custom potion mixes
|
||||
datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper
|
||||
this.spark = new io.papermc.paper.SparksFly(this); // Paper - spark
|
||||
@@ -23,7 +23,7 @@ index aa6f0588f282e3152ef9639d6fb2b8cd1d54bdb7..514c2d414ac59c71929a7686204465c7
|
||||
}
|
||||
|
||||
public boolean getCommandBlockOverride(String command) {
|
||||
@@ -1140,6 +1141,7 @@ public final class CraftServer implements Server {
|
||||
@@ -1141,6 +1142,7 @@ public final class CraftServer implements Server {
|
||||
org.purpurmc.purpur.PurpurConfig.registerCommands(); // Purpur - Purpur config files
|
||||
this.overrideAllCommandBlockCommands = this.commandsConfiguration.getStringList("command-block-overrides").contains("*");
|
||||
this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions");
|
||||
@@ -27,10 +27,10 @@ index 4c003acccdd2dd17918b15316001e52e7670123e..780f3a48152fef6a06dc67bf7fbd1965
|
||||
HandlerList handlers = event.getHandlers();
|
||||
RegisteredListener[] listeners = handlers.getRegisteredListeners();
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index eec03c52172b8250c18318094093c752da97dbe6..f57e12a72cabe279a6a465f4397b44621a2d5cb0 100644
|
||||
index 3fabeaa91832eacc103416682aec3ce6121858fb..7ca77be262e6c8c9882db42295a42487b672d43e 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -322,6 +322,8 @@ public final class CraftServer implements Server {
|
||||
@@ -323,6 +323,8 @@ public final class CraftServer implements Server {
|
||||
private final io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler asyncScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaAsyncScheduler();
|
||||
private final io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler globalRegionScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler();
|
||||
|
||||
@@ -39,7 +39,7 @@ index eec03c52172b8250c18318094093c752da97dbe6..f57e12a72cabe279a6a465f4397b4462
|
||||
@Override
|
||||
public final io.papermc.paper.threadedregions.scheduler.RegionScheduler getRegionScheduler() {
|
||||
return this.regionizedScheduler;
|
||||
@@ -410,7 +412,7 @@ public final class CraftServer implements Server {
|
||||
@@ -411,7 +413,7 @@ public final class CraftServer implements Server {
|
||||
public CraftServer(DedicatedServer console, PlayerList playerList) {
|
||||
this.console = console;
|
||||
this.playerList = (DedicatedPlayerList) playerList;
|
||||
@@ -48,7 +48,7 @@ index eec03c52172b8250c18318094093c752da97dbe6..f57e12a72cabe279a6a465f4397b4462
|
||||
@Override
|
||||
public CraftPlayer apply(ServerPlayer player) {
|
||||
return player.getBukkitEntity();
|
||||
@@ -3456,4 +3458,11 @@ public final class CraftServer implements Server {
|
||||
@@ -3461,4 +3463,11 @@ public final class CraftServer implements Server {
|
||||
return getServer().lagging;
|
||||
}
|
||||
// Purpur end - Lagging threshold
|
||||
@@ -74,10 +74,10 @@ index 8635cd772c5c2ae0ba326812ff2a1a179285a86f..cc024874fbde9678bdddfdca7c250808
|
||||
if (entity instanceof EnderDragonPart complexPart) {
|
||||
if (complexPart.parentMob instanceof EnderDragon) {
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index 2f027c504859f7ef41ef243bbc16535c6595ec28..abc762829bc0447936ab9e06eabcb42419578585 100644
|
||||
index 9d733dd366d54b0780746a6235d81dc17607cad2..7bd58d683ca2534d36510590e0895dce7c46551a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2281,7 +2281,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
@@ -2280,7 +2280,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
|
||||
@Override
|
||||
public boolean canSee(Player player) {
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,703 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Altiami <yoshimo.kristin@gmail.com>
|
||||
Date: Wed, 5 Mar 2025 13:16:44 -0800
|
||||
Subject: [PATCH] SparklyPaper: Parallel world ticking
|
||||
|
||||
Original project: https://github.com/SparklyPower/SparklyPaper
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||
index a4aa2615823d77920ff55b8aa0bcc27a54b8c3e1..2fb65ce228da94eb7d9364ee0f94582300178f1d 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
|
||||
@@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
public class TickThread extends Thread {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TickThread.class);
|
||||
+ private static final boolean HARD_THROW = !org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.disableHardThrow; // SparklyPaper - parallel world ticking - THIS SHOULD NOT BE DISABLED SINCE IT CAN CAUSE DATA CORRUPTION!!! Anyhow, for production servers, if you want to make a test run to see if the server could crash, you can test it with this disabled
|
||||
|
||||
private static String getThreadContext() {
|
||||
return "thread=" + Thread.currentThread().getName();
|
||||
@@ -26,14 +27,14 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final String reason) {
|
||||
if (!isTickThread()) {
|
||||
LOGGER.error("Thread failed main thread check: " + reason + ", context=" + getThreadContext(), new Throwable());
|
||||
- throw new IllegalStateException(reason);
|
||||
+ if (HARD_THROW) throw new IllegalStateException(reason); // SparklyPaper - parallel world ticking
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureTickThread(final Level world, final BlockPos pos, final String reason) {
|
||||
if (!isTickThreadFor(world, pos)) {
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos;
|
||||
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + " - " + getTickThreadInformation(world.getServer()); // SparklyPaper - parallel world ticking
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -42,7 +43,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final BlockPos pos, final int blockRadius, final String reason) {
|
||||
if (!isTickThreadFor(world, pos, blockRadius)) {
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius;
|
||||
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius + " - " + getTickThreadInformation(world.getServer()); // SparklyPaper - parallel world ticking
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -51,7 +52,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final ChunkPos pos, final String reason) {
|
||||
if (!isTickThreadFor(world, pos)) {
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + pos;
|
||||
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + pos + " - " + getTickThreadInformation(world.getServer()); // SparklyPaper - parallel world ticking
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -60,7 +61,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final int chunkX, final int chunkZ, final String reason) {
|
||||
if (!isTickThreadFor(world, chunkX, chunkZ)) {
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ);
|
||||
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ) + " - " + getTickThreadInformation(world.getServer()); // SparklyPaper - parallel world ticking
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -69,7 +70,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Entity entity, final String reason) {
|
||||
if (!isTickThreadFor(entity)) {
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
- reason + ", context=" + getThreadContext() + ", entity=" + EntityUtil.dumpEntity(entity);
|
||||
+ reason + ", context=" + getThreadContext() + ", entity=" + EntityUtil.dumpEntity(entity) + " - " + getTickThreadInformation(entity.getServer()); // SparklyPaper - parallel world ticking
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -78,7 +79,7 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
|
||||
if (!isTickThreadFor(world, aabb)) {
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb;
|
||||
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb + " - " + getTickThreadInformation(world.getServer()); // SparklyPaper - parallel world ticking
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -87,12 +88,70 @@ public class TickThread extends Thread {
|
||||
public static void ensureTickThread(final Level world, final double blockX, final double blockZ, final String reason) {
|
||||
if (!isTickThreadFor(world, blockX, blockZ)) {
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ);
|
||||
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ) + " - " + getTickThreadInformation(world.getServer()); // SparklyPaper - parallel world ticking
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ // This is an additional method to check if the tick thread is bound to a specific world because, by default, Paper's isTickThread methods do not provide this information
|
||||
+ // Because we only tick worlds in parallel (instead of regions), we can use this for our checks
|
||||
+ public static void ensureTickThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
|
||||
+ if (!isTickThreadFor(world)) {
|
||||
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable()); // SparklyPaper - parallel world ticking
|
||||
+ if (HARD_THROW) throw new IllegalStateException(reason);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // This is an additional method to check if it is a tick thread but ONLY a tick thread
|
||||
+ public static void ensureOnlyTickThread(final String reason) {
|
||||
+ boolean isTickThread = isTickThread();
|
||||
+ boolean isServerLevelTickThread = isServerLevelTickThread();
|
||||
+ if (!isTickThread || isServerLevelTickThread) {
|
||||
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread ONLY tick thread check: " + reason, new Throwable());
|
||||
+ if (HARD_THROW) throw new IllegalStateException(reason);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // This is an additional method to check if the tick thread is bound to a specific world or if it is an async thread.
|
||||
+ public static void ensureTickThreadOrAsyncThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
|
||||
+ boolean isValidTickThread = isTickThreadFor(world);
|
||||
+ boolean isAsyncThread = !isTickThread();
|
||||
+ boolean isValid = isAsyncThread || isValidTickThread;
|
||||
+ if (!isValid) {
|
||||
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread or async thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable());
|
||||
+ if (HARD_THROW) throw new IllegalStateException(reason);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static String getTickThreadInformation(net.minecraft.server.MinecraftServer minecraftServer) {
|
||||
+ StringBuilder sb = new StringBuilder();
|
||||
+ Thread currentThread = Thread.currentThread();
|
||||
+ sb.append("Is tick thread? ");
|
||||
+ sb.append(currentThread instanceof TickThread);
|
||||
+ sb.append("; Is server level tick thread? ");
|
||||
+ sb.append(currentThread instanceof ServerLevelTickThread);
|
||||
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ sb.append("; Currently ticking level: ");
|
||||
+ if (serverLevelTickThread.currentlyTickingServerLevel != null) {
|
||||
+ sb.append(serverLevelTickThread.currentlyTickingServerLevel.getWorld().getName());
|
||||
+ } else {
|
||||
+ sb.append("null");
|
||||
+ }
|
||||
+ }
|
||||
+ sb.append("; Is iterating over levels? ");
|
||||
+ sb.append(minecraftServer.isIteratingOverLevels);
|
||||
+ sb.append("; Are we going to hard throw? ");
|
||||
+ sb.append(HARD_THROW);
|
||||
+ return sb.toString();
|
||||
+ }
|
||||
+
|
||||
+ public static boolean isServerLevelTickThread() {
|
||||
+ return Thread.currentThread() instanceof ServerLevelTickThread;
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
+
|
||||
public final int id; /* We don't override getId as the spec requires that it be unique (with respect to all other threads) */
|
||||
|
||||
private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
|
||||
@@ -133,46 +192,74 @@ public class TickThread extends Thread {
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final BlockPos pos) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final BlockPos pos, final int blockRadius) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (add missing replacement / use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final ChunkPos pos) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final Vec3 pos) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final AABB aabb) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final double blockX, final double blockZ) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final Vec3 position, final Vec3 deltaMovement, final int buffer) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final int fromChunkX, final int fromChunkZ, final int toChunkX, final int toChunkZ) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ, final int radius) {
|
||||
- return isTickThread();
|
||||
+ return isTickThreadFor(world); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
+ }
|
||||
+
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ // This is an additional method to check if the tick thread is bound to a specific world because, by default, Paper's isTickThread methods do not provide this information
|
||||
+ // Because we only tick worlds in parallel (instead of regions), we can use this for our checks
|
||||
+ public static boolean isTickThreadFor(final Level world) {
|
||||
+ if (Thread.currentThread() instanceof ServerLevelTickThread serverLevelTickThread) {
|
||||
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
|
||||
+ } else {
|
||||
+ return isTickThread();
|
||||
+ }
|
||||
}
|
||||
|
||||
public static boolean isTickThreadFor(final Entity entity) {
|
||||
- return isTickThread();
|
||||
+ if (entity == null) {
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return isTickThreadFor(entity.level()); // Leaf - SparklyPaper - parallel world ticking mod (use methods for what they were made for)
|
||||
+ }
|
||||
+
|
||||
+ public static class ServerLevelTickThread extends TickThread {
|
||||
+ public ServerLevelTickThread(String name) {
|
||||
+ super(name);
|
||||
+ }
|
||||
+
|
||||
+ public ServerLevelTickThread(Runnable run, String name) {
|
||||
+ super(run, name);
|
||||
+ }
|
||||
+
|
||||
+ public net.minecraft.server.level.ServerLevel currentlyTickingServerLevel;
|
||||
}
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
|
||||
index 548fcd9646dee0c40b6ba9b3dafb9ca157dfe324..d7af94890bfccd6ff665d920cecfa1e5be626aa4 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
|
||||
@@ -40,6 +40,12 @@ class PaperEventManager {
|
||||
if (listeners.length == 0) return;
|
||||
// Leaf end - Skip event if no listeners
|
||||
if (event.isAsynchronous() && this.server.isPrimaryThread()) {
|
||||
+ // Leaf start - Parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.runAsyncTasksSync) {
|
||||
+ org.dreeam.leaf.async.world.PWTEventScheduler.getScheduler().scheduleTask(event::callEvent);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Parallel world ticking
|
||||
throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously.");
|
||||
} else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) {
|
||||
// Leaf start - Multithreaded tracker
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
index af33cab59932f4ec135caf94dc5828930833daf6..92463ddc6fdcf542ce4a6d2a5059d4a9f7a6085a 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
||||
@@ -455,7 +455,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
|
||||
private boolean unloadChunk0(int x, int z, boolean save) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot unload chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
+ else
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
if (!this.isChunkLoaded(x, z)) {
|
||||
return true;
|
||||
}
|
||||
@@ -472,6 +477,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public boolean refreshChunk(int x, int z) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot refresh chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
|
||||
if (playerChunk == null) return false;
|
||||
|
||||
@@ -522,7 +529,12 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public boolean loadChunk(int x, int z, boolean generate) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "May not sync load chunks asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
+ else
|
||||
+ org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
warnUnsafeChunk("loading a faraway chunk", x, z); // Paper
|
||||
ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper
|
||||
|
||||
@@ -750,6 +762,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
this.world.captureTreeGeneration = true;
|
||||
this.world.captureBlockStates = true;
|
||||
boolean grownTree = this.generateTree(loc, type);
|
||||
@@ -865,6 +879,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
}
|
||||
public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source, Consumer<net.minecraft.world.level.ServerExplosion> configurator) {
|
||||
// Paper end - expand explosion API
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
net.minecraft.world.level.Level.ExplosionInteraction explosionType;
|
||||
if (!breakBlocks) {
|
||||
explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks
|
||||
@@ -956,6 +972,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x >> 4, z >> 4, "Cannot retrieve chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper
|
||||
// Transient load for this tick
|
||||
return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z);
|
||||
@@ -986,6 +1004,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
@Override
|
||||
public void setBiome(int x, int y, int z, Holder<net.minecraft.world.level.biome.Biome> bb) {
|
||||
BlockPos pos = new BlockPos(x, 0, z);
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
if (this.world.hasChunkAt(pos)) {
|
||||
net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos);
|
||||
|
||||
@@ -2328,6 +2348,8 @@ public class CraftWorld extends CraftRegionAccessor implements World {
|
||||
|
||||
@Override
|
||||
public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); // SparklyPaper - parallel world ticking (additional concurrency issues logs)
|
||||
getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position));
|
||||
}
|
||||
// Paper end
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
index 811823a1a7e24a19a7e37eb4c08efdfa19e839ed..b94efcab12d41fa8745e5bb55cfa6481d8262e74 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
|
||||
@@ -75,6 +75,11 @@ public class CraftBlock implements Block {
|
||||
}
|
||||
|
||||
public net.minecraft.world.level.block.state.BlockState getNMS() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.world.getBlockState(this.position);
|
||||
}
|
||||
|
||||
@@ -157,6 +162,11 @@ public class CraftBlock implements Block {
|
||||
}
|
||||
|
||||
private void setData(final byte data, int flag) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag);
|
||||
}
|
||||
|
||||
@@ -198,6 +208,12 @@ public class CraftBlock implements Block {
|
||||
}
|
||||
|
||||
public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
+
|
||||
// SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup
|
||||
if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes
|
||||
// SPIGOT-4612: faster - just clear tile
|
||||
@@ -343,18 +359,33 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public Biome getBiome() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ());
|
||||
}
|
||||
|
||||
// Paper start
|
||||
@Override
|
||||
public Biome getComputedBiome() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ());
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@Override
|
||||
public void setBiome(Biome bio) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio);
|
||||
}
|
||||
|
||||
@@ -375,6 +406,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean isBlockIndirectlyPowered() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.world.getMinecraftWorld().hasNeighborSignal(this.position);
|
||||
}
|
||||
|
||||
@@ -414,6 +450,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public int getBlockPower(BlockFace face) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
int power = 0;
|
||||
net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
|
||||
int x = this.getX();
|
||||
@@ -484,6 +525,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean breakNaturally() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
return this.breakNaturally(null);
|
||||
}
|
||||
|
||||
@@ -543,6 +589,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean applyBoneMeal(BlockFace face) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
Direction direction = CraftBlock.blockFaceToNotch(face);
|
||||
BlockFertilizeEvent event = null;
|
||||
ServerLevel world = this.getCraftWorld().getHandle();
|
||||
@@ -554,8 +605,8 @@ public class CraftBlock implements Block {
|
||||
world.captureTreeGeneration = false;
|
||||
|
||||
if (world.capturedBlockStates.size() > 0) {
|
||||
- TreeType treeType = SaplingBlock.treeType;
|
||||
- SaplingBlock.treeType = null;
|
||||
+ TreeType treeType = SaplingBlock.getTreeTypeRT(); // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
+ SaplingBlock.setTreeTypeRT(null); // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
List<BlockState> blocks = new ArrayList<>(world.capturedBlockStates.values());
|
||||
world.capturedBlockStates.clear();
|
||||
StructureGrowEvent structureEvent = null;
|
||||
@@ -644,6 +695,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
Preconditions.checkArgument(start != null, "Location start cannot be null");
|
||||
Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world");
|
||||
start.checkFinite();
|
||||
@@ -685,6 +741,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public boolean canPlace(BlockData data) {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
Preconditions.checkArgument(data != null, "BlockData cannot be null");
|
||||
net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState();
|
||||
net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
|
||||
@@ -719,6 +780,11 @@ public class CraftBlock implements Block {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && world instanceof ServerLevel serverWorld) { // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
final ServerLevel level = this.world.getMinecraftWorld();
|
||||
this.getNMS().tick(level, this.position, level.random);
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
index 768d3f93da2522d467183654260a8bd8653588b1..5cef786fa2e5dfd3e7b79918bc73af02891b0bea 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
|
||||
@@ -26,6 +26,27 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
|
||||
private final T snapshot;
|
||||
public boolean snapshotDisabled; // Paper
|
||||
public static boolean DISABLE_SNAPSHOT = false; // Paper
|
||||
+ public static ThreadLocal<Boolean> DISABLE_SNAPSHOT_TL = ThreadLocal.withInitial(() -> Boolean.FALSE); // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (distinguish name)
|
||||
+
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking mod
|
||||
+ // refer to original field in case plugins attempt to modify it
|
||||
+ public static boolean getDisableSnapshotTL() {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && DISABLE_SNAPSHOT_TL.get())
|
||||
+ return true;
|
||||
+ synchronized (CraftBlockEntityState.class) {
|
||||
+ return DISABLE_SNAPSHOT;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // update original field in case plugins attempt to access it
|
||||
+ public static void setDisableSnapshotTL(boolean value) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled)
|
||||
+ DISABLE_SNAPSHOT_TL.set(value);
|
||||
+ synchronized (CraftBlockEntityState.class) {
|
||||
+ DISABLE_SNAPSHOT = value;
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking mod
|
||||
|
||||
public CraftBlockEntityState(World world, T tileEntity) {
|
||||
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
|
||||
@@ -34,8 +55,8 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
|
||||
|
||||
try { // Paper - Show blockstate location if we failed to read it
|
||||
// Paper start
|
||||
- this.snapshotDisabled = DISABLE_SNAPSHOT;
|
||||
- if (DISABLE_SNAPSHOT) {
|
||||
+ this.snapshotDisabled = getDisableSnapshotTL(); // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
+ if (this.snapshotDisabled) { // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
this.snapshot = this.tileEntity;
|
||||
} else {
|
||||
this.snapshot = this.createSnapshot(tileEntity);
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
|
||||
index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..d106f65e4b745242484a195958fc559268a7dee0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
|
||||
@@ -215,6 +215,12 @@ public class CraftBlockState implements BlockState {
|
||||
LevelAccessor access = this.getWorldHandle();
|
||||
CraftBlock block = this.getBlock();
|
||||
|
||||
+ // SparklyPaper start - parallel world ticking
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && access instanceof net.minecraft.server.level.ServerLevel serverWorld) {
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
|
||||
+ }
|
||||
+ // SparklyPaper end - parallel world ticking
|
||||
+
|
||||
if (block.getType() != this.getType()) {
|
||||
if (!force) {
|
||||
return false;
|
||||
@@ -350,6 +356,8 @@ public class CraftBlockState implements BlockState {
|
||||
|
||||
@Override
|
||||
public java.util.Collection<org.bukkit.inventory.ItemStack> getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled) // Leaf - SparklyPaper - parallel world ticking mod (make configurable)
|
||||
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); // SparklyPaper - parallel world ticking
|
||||
this.requirePlaced();
|
||||
net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item);
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
index 55572e799b5c8a74a546ac8febc14f80d5731c52..08a06c23c831a4de45b3e537228b837911019da8 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
|
||||
@@ -249,8 +249,8 @@ public final class CraftBlockStates {
|
||||
net.minecraft.world.level.block.state.BlockState blockData = craftBlock.getNMS();
|
||||
BlockEntity tileEntity = craftBlock.getHandle().getBlockEntity(blockPosition);
|
||||
// Paper start - block state snapshots
|
||||
- boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT;
|
||||
- CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot;
|
||||
+ boolean prev = CraftBlockEntityState.getDisableSnapshotTL(); // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
+ CraftBlockEntityState.setDisableSnapshotTL(!useSnapshot); // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
try {
|
||||
// Paper end
|
||||
CraftBlockState blockState = CraftBlockStates.getBlockState(world, blockPosition, blockData, tileEntity);
|
||||
@@ -258,7 +258,7 @@ public final class CraftBlockStates {
|
||||
return blockState;
|
||||
// Paper start
|
||||
} finally {
|
||||
- CraftBlockEntityState.DISABLE_SNAPSHOT = prev;
|
||||
+ CraftBlockEntityState.setDisableSnapshotTL(prev); // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
}
|
||||
// Paper end
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index c2552c3706831f7012b5b449fa43c7d5990056a4..4e8a1d01a6c0afef92ae56cc4909af06d63e5268 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -961,6 +961,28 @@ public class CraftEventFactory {
|
||||
}
|
||||
|
||||
public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
|
||||
+ public static final ThreadLocal<BlockPos> sourceBlockOverrideRT = new ThreadLocal<>(); // SparklyPaper - parallel world ticking (this is from Folia, fixes concurrency bugs with sculk catalysts)
|
||||
+
|
||||
+ // Leaf start - SparklyPaper - parallel world ticking mod
|
||||
+ // refer to original field in case plugins attempt to modify it
|
||||
+ public static BlockPos getSourceBlockOverrideRT() {
|
||||
+ BlockPos sourceBlockOverrideRTCopy;
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled && (sourceBlockOverrideRTCopy = sourceBlockOverrideRT.get()) != null)
|
||||
+ return sourceBlockOverrideRTCopy;
|
||||
+ synchronized (CraftEventFactory.class) {
|
||||
+ return sourceBlockOverride;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // update original field in case plugins attempt to access it
|
||||
+ public static void setSourceBlockOverrideRT(BlockPos value) {
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled)
|
||||
+ sourceBlockOverrideRT.set(value);
|
||||
+ synchronized (CraftEventFactory.class) {
|
||||
+ sourceBlockOverride = value;
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - SparklyPaper - parallel world ticking mod
|
||||
|
||||
public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) {
|
||||
// Suppress during worldgen
|
||||
@@ -972,7 +994,10 @@ public class CraftEventFactory {
|
||||
CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag);
|
||||
state.setData(block);
|
||||
|
||||
- BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), state);
|
||||
+ // Leaf start - SparklyPaper parallel world ticking mod (collapse original behavior)
|
||||
+ final BlockPos sourceBlockOverrideRTSnap = getSourceBlockOverrideRT();
|
||||
+ BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, sourceBlockOverrideRTSnap != null ? sourceBlockOverrideRTSnap : source), state); // SparklyPaper - parallel world ticking
|
||||
+ // Leaf end - SparklyPaper parallel world ticking mod (collapse original behavior)
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
|
||||
if (!event.isCancelled()) {
|
||||
@@ -2265,7 +2290,7 @@ public class CraftEventFactory {
|
||||
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1));
|
||||
|
||||
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to));
|
||||
- if (!net.minecraft.world.level.block.DispenserBlock.eventFired) {
|
||||
+ if (!net.minecraft.world.level.block.DispenserBlock.getEventFiredTL()) { // SparklyPaper - parallel world ticking // Leaf - SparklyPaper - parallel world ticking mod (collapse original behavior)
|
||||
if (!event.callEvent()) {
|
||||
return itemStack;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
|
||||
index e4e2e42d0ca25df7fe9f2dd4275610e45fcb2c84..e7c6b2ab5f2c68f3319ccd52785c8d3488a2eef7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftAsyncTask.java
|
||||
@@ -19,11 +19,39 @@ class CraftAsyncTask extends CraftTask {
|
||||
|
||||
@Override
|
||||
public boolean isSync() {
|
||||
+ // Leaf start - Parallel world ticking
|
||||
+ // Return true if we should run this task synchronously when parallel world ticking is enabled and runAsyncTasksSync is true
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled &&
|
||||
+ org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.runAsyncTasksSync) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // Leaf end - Parallel world ticking
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
+ // Leaf start - Parallel world ticking
|
||||
+ // If parallel world ticking is enabled and we're configured to run async tasks sync,
|
||||
+ // execute the task as if it were a sync task (directly on the main thread)
|
||||
+ if (org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.enabled &&
|
||||
+ org.dreeam.leaf.config.modules.async.SparklyPaperParallelWorldTicking.runAsyncTasksSync) {
|
||||
+ try {
|
||||
+ super.run();
|
||||
+ } catch (final Throwable t) {
|
||||
+ this.getOwner().getLogger().log(
|
||||
+ Level.WARNING,
|
||||
+ String.format(
|
||||
+ "Plugin %s generated an exception while executing task %s (forced sync mode)",
|
||||
+ this.getOwner().getDescription().getFullName(),
|
||||
+ this.getTaskId()),
|
||||
+ t);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Parallel world ticking
|
||||
+
|
||||
+ // Original async implementation
|
||||
final Thread thread = Thread.currentThread();
|
||||
// Paper start - name threads according to running plugin
|
||||
final String nameBefore = thread.getName();
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.dreeam.leaf.async.world;
|
||||
|
||||
public enum ReadOperationType {
|
||||
BLOCK_GET_BIOME,
|
||||
BLOCK_GET_COMPUTED_BIOME,
|
||||
BLOCK_IS_INDIRECTLY_POWERED,
|
||||
BLOCK_GET_BLOCK_POWER,
|
||||
BLOCK_RAY_TRACE,
|
||||
BLOCK_CAN_PLACE,
|
||||
BLOCK_GET_NMS_STATE
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.dreeam.leaf.async.world;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public record WorldReadRequest(
|
||||
ReadOperationType type,
|
||||
Object[] params, // Parameters for the read operation
|
||||
CompletableFuture<Object> future // Future to complete with the result
|
||||
) {
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package org.dreeam.leaf.config.modules.network;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollPackets;
|
||||
import org.dreeam.leaf.protocol.DoABarrelRollProtocol;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ import net.minecraft.world.level.ChunkPos;
|
||||
import org.dreeam.leaf.config.modules.misc.RegionFormatConfig;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
|
||||
public class LinearRegionFile implements IRegionFile {
|
||||
|
||||
private static final long SUPERBLOCK = -4323716122432332390L;
|
||||
@@ -148,6 +150,7 @@ public class LinearRegionFile implements IRegionFile {
|
||||
// Save only once on shutdown
|
||||
if (!closed) return;
|
||||
}
|
||||
|
||||
long timestamp = getTimestamp();
|
||||
short chunkCount = 0;
|
||||
|
||||
|
||||
@@ -1,405 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
|
||||
Date: Sat, 17 Feb 2024 17:57:08 -0500
|
||||
Subject: [PATCH] Rail Optimization: optimized PoweredRailBlock logic
|
||||
|
||||
Original project: https://github.com/FxMorin/RailOptimization
|
||||
|
||||
Full Rewrite of the powered rail iteration logic
|
||||
that makes powered/activator rails turning on/off up to 4x faster.
|
||||
This rewrite brings a massive performance boost while keeping the vanilla order. This is achieved by running all the
|
||||
powered rail logic from a single rail instead of each block iterating separately. Which was not only very
|
||||
expensive but also completely unnecessary and with a lot of massive overhead
|
||||
|
||||
diff --git a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
index bd14c08defe8afc5ceca59d16a5b1dbad178f594..b37ab12d4c51aca1576a14147a959188031d0fd7 100644
|
||||
--- a/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
+++ b/src/main/java/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
@@ -29,7 +29,7 @@ public class PoweredRailBlock extends BaseRailBlock {
|
||||
this.registerDefaultState((BlockState) ((BlockState) ((BlockState) ((BlockState) this.stateDefinition.any()).setValue(PoweredRailBlock.SHAPE, RailShape.NORTH_SOUTH)).setValue(PoweredRailBlock.POWERED, false)).setValue(PoweredRailBlock.WATERLOGGED, false));
|
||||
}
|
||||
|
||||
- protected boolean findPoweredRailSignal(Level world, BlockPos pos, BlockState state, boolean flag, int distance) {
|
||||
+ public boolean findPoweredRailSignal(Level world, BlockPos pos, BlockState state, boolean flag, int distance) { // Leaf - Rail Optimization - protected -> public
|
||||
if (distance >= world.purpurConfig.railActivationRange) { // Purpur
|
||||
return false;
|
||||
} else {
|
||||
@@ -117,6 +117,12 @@ public class PoweredRailBlock extends BaseRailBlock {
|
||||
|
||||
@Override
|
||||
protected void updateState(BlockState state, Level world, BlockPos pos, Block neighbor) {
|
||||
+ // Leaf start - Rail Optimization
|
||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizedPoweredRails.enabled) {
|
||||
+ org.dreeam.leaf.optimize.OptimizedPoweredRails.customUpdateState(this, state, world, pos);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Rail Optimization
|
||||
boolean flag = (Boolean) state.getValue(PoweredRailBlock.POWERED);
|
||||
boolean flag1 = world.hasNeighborSignal(pos) || this.findPoweredRailSignal(world, pos, state, true, 0) || this.findPoweredRailSignal(world, pos, state, false, 0);
|
||||
|
||||
diff --git a/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizedPoweredRails.java b/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizedPoweredRails.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..ded3c385fcfc6c35086f76bed1b2223a6a29a43e
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizedPoweredRails.java
|
||||
@@ -0,0 +1,18 @@
|
||||
+package org.dreeam.leaf.config.modules.opt;
|
||||
+
|
||||
+import org.dreeam.leaf.config.ConfigModules;
|
||||
+import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
+
|
||||
+public class OptimizedPoweredRails extends ConfigModules {
|
||||
+
|
||||
+ public String getBasePath() {
|
||||
+ return EnumConfigCategory.PERF.getBaseKeyName() + ".optimized-powered-rails";
|
||||
+ }
|
||||
+
|
||||
+ public static boolean enabled = true;
|
||||
+
|
||||
+ @Override
|
||||
+ public void onLoaded() {
|
||||
+ enabled = config().getBoolean(getBasePath(), enabled);
|
||||
+ }
|
||||
+}
|
||||
diff --git a/src/main/java/org/dreeam/leaf/optimize/OptimizedPoweredRails.java b/src/main/java/org/dreeam/leaf/optimize/OptimizedPoweredRails.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..9e8bc27585e204aa2df77a90418bbe9e00bcd040
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/org/dreeam/leaf/optimize/OptimizedPoweredRails.java
|
||||
@@ -0,0 +1,335 @@
|
||||
+package org.dreeam.leaf.optimize;
|
||||
+
|
||||
+import net.minecraft.core.BlockPos;
|
||||
+import net.minecraft.core.Direction;
|
||||
+import net.minecraft.world.level.Level;
|
||||
+import net.minecraft.world.level.block.Block;
|
||||
+import net.minecraft.world.level.block.PoweredRailBlock;
|
||||
+import net.minecraft.world.level.block.state.BlockState;
|
||||
+import net.minecraft.world.level.block.state.properties.RailShape;
|
||||
+
|
||||
+import java.util.HashMap;
|
||||
+
|
||||
+import static net.minecraft.world.level.block.Block.*;
|
||||
+import static net.minecraft.world.level.block.PoweredRailBlock.POWERED;
|
||||
+import static net.minecraft.world.level.block.PoweredRailBlock.SHAPE;
|
||||
+
|
||||
+public class OptimizedPoweredRails {
|
||||
+
|
||||
+ private static final Direction[] EAST_WEST_DIR = new Direction[]{Direction.WEST, Direction.EAST};
|
||||
+ private static final Direction[] NORTH_SOUTH_DIR = new Direction[]{Direction.SOUTH, Direction.NORTH};
|
||||
+
|
||||
+ private static final int UPDATE_FORCE_PLACE = UPDATE_MOVE_BY_PISTON | UPDATE_KNOWN_SHAPE | UPDATE_CLIENTS;
|
||||
+
|
||||
+ public static int RAIL_POWER_LIMIT = 8;
|
||||
+
|
||||
+ public static void giveShapeUpdate(Level level, BlockState state, BlockPos pos, BlockPos fromPos, Direction direction) {
|
||||
+ BlockState oldState = level.getBlockState(pos);
|
||||
+ Block.updateOrDestroy(
|
||||
+ oldState,
|
||||
+ oldState.updateShape(direction.getOpposite(), state, level, pos, fromPos),
|
||||
+ level,
|
||||
+ pos,
|
||||
+ UPDATE_CLIENTS & -34,
|
||||
+ 0
|
||||
+ );
|
||||
+ }
|
||||
+
|
||||
+ public static void setRailPowerLimit(int powerLimit) {
|
||||
+ RAIL_POWER_LIMIT = powerLimit;
|
||||
+ }
|
||||
+
|
||||
+ public static void customUpdateState(PoweredRailBlock self, BlockState state, Level level, BlockPos pos) {
|
||||
+ boolean shouldBePowered = level.hasNeighborSignal(pos) ||
|
||||
+ self.findPoweredRailSignal(level, pos, state, true, 0) ||
|
||||
+ self.findPoweredRailSignal(level, pos, state, false, 0);
|
||||
+ if (shouldBePowered != state.getValue(POWERED)) {
|
||||
+ RailShape railShape = state.getValue(SHAPE);
|
||||
+ if (railShape.isAscending()) {
|
||||
+ level.setBlock(pos, state.setValue(POWERED, shouldBePowered), 3);
|
||||
+ level.updateNeighborsAtExceptFromFacing(pos.below(), self, Direction.UP);
|
||||
+ level.updateNeighborsAtExceptFromFacing(pos.above(), self, Direction.DOWN); //isAscending
|
||||
+ } else if (shouldBePowered) {
|
||||
+ powerLane(self, level, pos, state, railShape);
|
||||
+ } else {
|
||||
+ dePowerLane(self, level, pos, state, railShape);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static boolean findPoweredRailSignalFaster(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
+ boolean bl, int distance, RailShape shape,
|
||||
+ HashMap<BlockPos, Boolean> checkedPos) {
|
||||
+ BlockState blockState = world.getBlockState(pos);
|
||||
+ boolean speedCheck = checkedPos.containsKey(pos) && checkedPos.get(pos);
|
||||
+ if (speedCheck) {
|
||||
+ return world.hasNeighborSignal(pos) ||
|
||||
+ findPoweredRailSignalFaster(self, world, pos, blockState, bl, distance + 1, checkedPos);
|
||||
+ } else {
|
||||
+ if (blockState.is(self)) {
|
||||
+ RailShape railShape = blockState.getValue(SHAPE);
|
||||
+ if (shape == RailShape.EAST_WEST && (
|
||||
+ railShape == RailShape.NORTH_SOUTH ||
|
||||
+ railShape == RailShape.ASCENDING_NORTH ||
|
||||
+ railShape == RailShape.ASCENDING_SOUTH
|
||||
+ ) || shape == RailShape.NORTH_SOUTH && (
|
||||
+ railShape == RailShape.EAST_WEST ||
|
||||
+ railShape == RailShape.ASCENDING_EAST ||
|
||||
+ railShape == RailShape.ASCENDING_WEST
|
||||
+ )) {
|
||||
+ return false;
|
||||
+ } else if (blockState.getValue(POWERED)) {
|
||||
+ return world.hasNeighborSignal(pos) ||
|
||||
+ findPoweredRailSignalFaster(self, world, pos, blockState, bl, distance + 1, checkedPos);
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static boolean findPoweredRailSignalFaster(PoweredRailBlock self, Level level,
|
||||
+ BlockPos pos, BlockState state, boolean bl, int distance,
|
||||
+ HashMap<BlockPos, Boolean> checkedPos) {
|
||||
+ if (distance >= RAIL_POWER_LIMIT - 1) return false;
|
||||
+ int i = pos.getX();
|
||||
+ int j = pos.getY();
|
||||
+ int k = pos.getZ();
|
||||
+ boolean bl2 = true;
|
||||
+ RailShape railShape = state.getValue(SHAPE);
|
||||
+ switch (railShape.ordinal()) {
|
||||
+ case 0 -> {
|
||||
+ if (bl) ++k;
|
||||
+ else --k;
|
||||
+ }
|
||||
+ case 1 -> {
|
||||
+ if (bl) --i;
|
||||
+ else ++i;
|
||||
+ }
|
||||
+ case 2 -> {
|
||||
+ if (bl) {
|
||||
+ --i;
|
||||
+ } else {
|
||||
+ ++i;
|
||||
+ ++j;
|
||||
+ bl2 = false;
|
||||
+ }
|
||||
+ railShape = RailShape.EAST_WEST;
|
||||
+ }
|
||||
+ case 3 -> {
|
||||
+ if (bl) {
|
||||
+ --i;
|
||||
+ ++j;
|
||||
+ bl2 = false;
|
||||
+ } else {
|
||||
+ ++i;
|
||||
+ }
|
||||
+ railShape = RailShape.EAST_WEST;
|
||||
+ }
|
||||
+ case 4 -> {
|
||||
+ if (bl) {
|
||||
+ ++k;
|
||||
+ } else {
|
||||
+ --k;
|
||||
+ ++j;
|
||||
+ bl2 = false;
|
||||
+ }
|
||||
+ railShape = RailShape.NORTH_SOUTH;
|
||||
+ }
|
||||
+ case 5 -> {
|
||||
+ if (bl) {
|
||||
+ ++k;
|
||||
+ ++j;
|
||||
+ bl2 = false;
|
||||
+ } else {
|
||||
+ --k;
|
||||
+ }
|
||||
+ railShape = RailShape.NORTH_SOUTH;
|
||||
+ }
|
||||
+ }
|
||||
+ return findPoweredRailSignalFaster(
|
||||
+ self, level, new BlockPos(i, j, k),
|
||||
+ bl, distance, railShape, checkedPos
|
||||
+ ) ||
|
||||
+ (bl2 && findPoweredRailSignalFaster(
|
||||
+ self, level, new BlockPos(i, j - 1, k),
|
||||
+ bl, distance, railShape, checkedPos
|
||||
+ ));
|
||||
+ }
|
||||
+
|
||||
+ public static void powerLane(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
+ BlockState mainState, RailShape railShape) {
|
||||
+ world.setBlock(pos, mainState.setValue(POWERED, true), UPDATE_FORCE_PLACE);
|
||||
+ HashMap<BlockPos, Boolean> checkedPos = new HashMap<>();
|
||||
+ checkedPos.put(pos, true);
|
||||
+ int[] count = new int[2];
|
||||
+ if (railShape == RailShape.NORTH_SOUTH) { //Order: +z, -z
|
||||
+ for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) {
|
||||
+ setRailPositionsPower(self, world, pos, checkedPos, count, i, NORTH_SOUTH_DIR[i]);
|
||||
+ }
|
||||
+ updateRails(self, false, world, pos, mainState, count);
|
||||
+ } else if (railShape == RailShape.EAST_WEST) { //Order: -x, +x
|
||||
+ for (int i = 0; i < EAST_WEST_DIR.length; ++i) {
|
||||
+ setRailPositionsPower(self, world, pos, checkedPos, count, i, EAST_WEST_DIR[i]);
|
||||
+ }
|
||||
+ updateRails(self, true, world, pos, mainState, count);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public static void dePowerLane(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
+ BlockState mainState, RailShape railShape) {
|
||||
+ world.setBlock(pos, mainState.setValue(POWERED, false), UPDATE_FORCE_PLACE);
|
||||
+ int[] count = new int[2];
|
||||
+ if (railShape == RailShape.NORTH_SOUTH) { //Order: +z, -z
|
||||
+ for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) {
|
||||
+ setRailPositionsDePower(self, world, pos, count, i, NORTH_SOUTH_DIR[i]);
|
||||
+ }
|
||||
+ updateRails(self, false, world, pos, mainState, count);
|
||||
+ } else if (railShape == RailShape.EAST_WEST) { //Order: -x, +x
|
||||
+ for (int i = 0; i < EAST_WEST_DIR.length; ++i) {
|
||||
+ setRailPositionsDePower(self, world, pos, count, i, EAST_WEST_DIR[i]);
|
||||
+ }
|
||||
+ updateRails(self, true, world, pos, mainState, count);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void setRailPositionsPower(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
+ HashMap<BlockPos, Boolean> checkedPos, int[] count, int i, Direction dir) {
|
||||
+ for (int z = 1; z < RAIL_POWER_LIMIT; z++) {
|
||||
+ BlockPos newPos = pos.relative(dir, z);
|
||||
+ BlockState state = world.getBlockState(newPos);
|
||||
+ if (checkedPos.containsKey(newPos)) {
|
||||
+ if (!checkedPos.get(newPos)) break;
|
||||
+ count[i]++;
|
||||
+ } else if (!state.is(self) || state.getValue(POWERED) || !(
|
||||
+ world.hasNeighborSignal(newPos) ||
|
||||
+ findPoweredRailSignalFaster(self, world, newPos, state, true, 0, checkedPos) ||
|
||||
+ findPoweredRailSignalFaster(self, world, newPos, state, false, 0, checkedPos)
|
||||
+ )) {
|
||||
+ checkedPos.put(newPos, false);
|
||||
+ break;
|
||||
+ } else {
|
||||
+ checkedPos.put(newPos, true);
|
||||
+ world.setBlock(newPos, state.setValue(POWERED, true), UPDATE_FORCE_PLACE);
|
||||
+ count[i]++;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void setRailPositionsDePower(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
+ int[] count, int i, Direction dir) {
|
||||
+ for (int z = 1; z < RAIL_POWER_LIMIT; z++) {
|
||||
+ BlockPos newPos = pos.relative(dir, z);
|
||||
+ BlockState state = world.getBlockState(newPos);
|
||||
+ if (!state.is(self) || !state.getValue(POWERED) || world.hasNeighborSignal(newPos) ||
|
||||
+ self.findPoweredRailSignal(world, newPos, state, true, 0) ||
|
||||
+ self.findPoweredRailSignal(world, newPos, state, false, 0)) break;
|
||||
+ world.setBlock(newPos, state.setValue(POWERED, false), UPDATE_FORCE_PLACE);
|
||||
+ count[i]++;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void shapeUpdateEnd(PoweredRailBlock self, Level world, BlockPos pos, BlockState mainState,
|
||||
+ int endPos, Direction direction, int currentPos, BlockPos blockPos) {
|
||||
+ if (currentPos == endPos) {
|
||||
+ BlockPos newPos = pos.relative(direction, currentPos + 1);
|
||||
+ OptimizedPoweredRails.giveShapeUpdate(world, mainState, newPos, pos, direction);
|
||||
+ BlockState state = world.getBlockState(blockPos);
|
||||
+ if (state.is(self) && state.getValue(SHAPE).isAscending())
|
||||
+ OptimizedPoweredRails.giveShapeUpdate(world, mainState, newPos.above(), pos, direction);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void neighborUpdateEnd(PoweredRailBlock self, Level world, BlockPos pos, int endPos,
|
||||
+ Direction direction, Block block, int currentPos, BlockPos blockPos) {
|
||||
+ if (currentPos == endPos) {
|
||||
+ BlockPos newPos = pos.relative(direction, currentPos + 1);
|
||||
+ world.neighborChanged(newPos, block, pos);
|
||||
+ BlockState state = world.getBlockState(blockPos);
|
||||
+ if (state.is(self) && state.getValue(SHAPE).isAscending())
|
||||
+ world.neighborChanged(newPos.above(), block, blockPos);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static void updateRailsSectionEastWestShape(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
+ int c, BlockState mainState, Direction dir,
|
||||
+ int[] count, int countAmt) {
|
||||
+ BlockPos pos1 = pos.relative(dir, c);
|
||||
+ if (c == 0 && count[1] == 0)
|
||||
+ giveShapeUpdate(world, mainState, pos1.relative(dir.getOpposite()), pos, dir.getOpposite());
|
||||
+ shapeUpdateEnd(self, world, pos, mainState, countAmt, dir, c, pos1);
|
||||
+ giveShapeUpdate(world, mainState, pos1.below(), pos, Direction.DOWN);
|
||||
+ giveShapeUpdate(world, mainState, pos1.above(), pos, Direction.UP);
|
||||
+ giveShapeUpdate(world, mainState, pos1.north(), pos, Direction.NORTH);
|
||||
+ giveShapeUpdate(world, mainState, pos1.south(), pos, Direction.SOUTH);
|
||||
+ }
|
||||
+
|
||||
+ private static void updateRailsSectionNorthSouthShape(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
+ int c, BlockState mainState, Direction dir,
|
||||
+ int[] count, int countAmt) {
|
||||
+ BlockPos pos1 = pos.relative(dir, c);
|
||||
+ giveShapeUpdate(world, mainState, pos1.west(), pos, Direction.WEST);
|
||||
+ giveShapeUpdate(world, mainState, pos1.east(), pos, Direction.EAST);
|
||||
+ giveShapeUpdate(world, mainState, pos1.below(), pos, Direction.DOWN);
|
||||
+ giveShapeUpdate(world, mainState, pos1.above(), pos, Direction.UP);
|
||||
+ shapeUpdateEnd(self, world, pos, mainState, countAmt, dir, c, pos1);
|
||||
+ if (c == 0 && count[1] == 0)
|
||||
+ giveShapeUpdate(world, mainState, pos1.relative(dir.getOpposite()), pos, dir.getOpposite());
|
||||
+ }
|
||||
+
|
||||
+ private static void updateRails(PoweredRailBlock self, boolean eastWest, Level world,
|
||||
+ BlockPos pos, BlockState mainState, int[] count) {
|
||||
+ if (eastWest) {
|
||||
+ for (int i = 0; i < EAST_WEST_DIR.length; ++i) {
|
||||
+ int countAmt = count[i];
|
||||
+ if (i == 1 && countAmt == 0) continue;
|
||||
+ Direction dir = EAST_WEST_DIR[i];
|
||||
+ Block block = mainState.getBlock();
|
||||
+ for (int c = countAmt; c >= i; c--) {
|
||||
+ BlockPos p = pos.relative(dir, c);
|
||||
+ if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()), block, pos);
|
||||
+ neighborUpdateEnd(self, world, pos, countAmt, dir, block, c, p);
|
||||
+ world.neighborChanged(p.below(), block, pos);
|
||||
+ world.neighborChanged(p.above(), block, pos);
|
||||
+ world.neighborChanged(p.north(), block, pos);
|
||||
+ world.neighborChanged(p.south(), block, pos);
|
||||
+ BlockPos pos2 = pos.relative(dir, c).below();
|
||||
+ world.neighborChanged(pos2.below(), block, pos);
|
||||
+ world.neighborChanged(pos2.north(), block, pos);
|
||||
+ world.neighborChanged(pos2.south(), block, pos);
|
||||
+ if (c == countAmt) world.neighborChanged(pos.relative(dir, c + 1).below(), block, pos);
|
||||
+ if (c == 0 && count[1] == 0)
|
||||
+ world.neighborChanged(p.relative(dir.getOpposite()).below(), block, pos);
|
||||
+ }
|
||||
+ for (int c = countAmt; c >= i; c--)
|
||||
+ updateRailsSectionEastWestShape(self, world, pos, c, mainState, dir, count, countAmt);
|
||||
+ }
|
||||
+ } else {
|
||||
+ for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) {
|
||||
+ int countAmt = count[i];
|
||||
+ if (i == 1 && countAmt == 0) continue;
|
||||
+ Direction dir = NORTH_SOUTH_DIR[i];
|
||||
+ Block block = mainState.getBlock();
|
||||
+ for (int c = countAmt; c >= i; c--) {
|
||||
+ BlockPos p = pos.relative(dir, c);
|
||||
+ world.neighborChanged(p.west(), block, pos);
|
||||
+ world.neighborChanged(p.east(), block, pos);
|
||||
+ world.neighborChanged(p.below(), block, pos);
|
||||
+ world.neighborChanged(p.above(), block, pos);
|
||||
+ neighborUpdateEnd(self, world, pos, countAmt, dir, block, c, p);
|
||||
+ if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()), block, pos);
|
||||
+ BlockPos pos2 = pos.relative(dir, c).below();
|
||||
+ world.neighborChanged(pos2.west(), block, pos);
|
||||
+ world.neighborChanged(pos2.east(), block, pos);
|
||||
+ world.neighborChanged(pos2.below(), block, pos);
|
||||
+ if (c == countAmt) world.neighborChanged(pos.relative(dir, c + 1).below(), block, pos);
|
||||
+ if (c == 0 && count[1] == 0)
|
||||
+ world.neighborChanged(p.relative(dir.getOpposite()).below(), block, pos);
|
||||
+ }
|
||||
+ for (int c = countAmt; c >= i; c--)
|
||||
+ updateRailsSectionNorthSouthShape(self, world, pos, c, mainState, dir, count, countAmt);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
\ No newline at end of file
|
||||
@@ -15750,13 +15750,13 @@ index 248ac9bc820a96fc7653471308b18834fc735a77..ef70ba88e492904c426c7d35df442fa6
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/net/minecraft/world/level/block/PoweredRailBlock.java b/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
index 5ec12356e9f044d99762bf64a6d3bf74856d97a6..e80069d27ff60e0967d9333e2a0d6c8bf2f20a16 100644
|
||||
index 6c64fc260669266869f7495ff07e1270dcb4ac75..a2202d2b4352be07b2445064339c61ba6a2521c7 100644
|
||||
--- a/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
+++ b/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
@@ -28,7 +28,7 @@ public class PoweredRailBlock extends BaseRailBlock {
|
||||
}
|
||||
|
||||
protected boolean findPoweredRailSignal(Level level, BlockPos pos, BlockState state, boolean searchForward, int recursionCount) {
|
||||
public boolean findPoweredRailSignal(Level level, BlockPos pos, BlockState state, boolean searchForward, int recursionCount) {
|
||||
- if (recursionCount >= 8) {
|
||||
+ if (recursionCount >= level.purpurConfig.railActivationRange) { // Purpur - Config for powered rail activation distance
|
||||
return false;
|
||||
|
||||
@@ -65,7 +65,7 @@ index 35fd539eb2bfe60ad17ab1e558a01273666acc54..445bbdc8da7f1fdbddfc4d8787d78fea
|
||||
this.values[this.vp++ & 0xFF] = (int)(l * 100L / Runtime.getRuntime().maxMemory());
|
||||
this.repaint();
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index d2c1da7df4961fddbb7db952d817f127ece275d9..39d4ae0ae1ec89007fe1c86dc8d3409902890552 100644
|
||||
index 35ca166964e8436154891708f69ac010491b64aa..586c00610fdba178f27391820d623c3a5254529f 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1289,7 +1289,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -78,7 +78,7 @@ index d2c1da7df4961fddbb7db952d817f127ece275d9..39d4ae0ae1ec89007fe1c86dc8d34099
|
||||
this.disconnectAsync(Component.literal("Book too large!"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_ACTION); // Paper - kick event cause // Paper - add proper async disconnect
|
||||
return;
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 30e341bd5fca8b95d6911ca94f4aac17962f3269..55854dbacef9b3da9f12f67be21dd49007ea3c45 100644
|
||||
index b714c64a318d38e309351f34426406c70d35d384..4e3b73bee5dae2b5921db86cc53b4cd9ebbd06f8 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -522,23 +522,36 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
@@ -128,7 +128,7 @@ index 30e341bd5fca8b95d6911ca94f4aac17962f3269..55854dbacef9b3da9f12f67be21dd490
|
||||
public Entity(EntityType<?> entityType, Level level) {
|
||||
this.type = entityType;
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index eb17ef1e0c350e97149452dbdc79398d71370fb1..d265278a56575529198735c113fa72c53b541669 100644
|
||||
index cd8c764f9aa2321c6e157abe958d89868a9f7bd1..ed15b5f29658d799a36dcbd196a8fcb107be4bda 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1024,13 +1024,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
@@ -150,7 +150,7 @@ index eb17ef1e0c350e97149452dbdc79398d71370fb1..d265278a56575529198735c113fa72c5
|
||||
}
|
||||
// Purpur end - Mob head visibility percent
|
||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||
index ba2f9ab55e52e25788b38c81e1070ae953b66371..33c99f3b24596fbbf3283b455ea8bf340203e01b 100644
|
||||
index 6a94f42c8e048985b94db64fa0405e12824a8a0f..fbcf26c0bfb9f496c99bd5a2ba988be06162cd52 100644
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -1505,10 +1505,6 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
@@ -279,7 +279,7 @@ index 584955d151e95727406bc68d6a6f15a33c0f920c..865a83fc73d79893e9bdedad37a6e398
|
||||
HoglinAi.updateActivity(this);
|
||||
if (this.isConverting()) {
|
||||
diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
|
||||
index bac328ebdf9f94d156211e03d3913157e2b80374..bf1b33b7bb71ec8387d95d9089f199627a041945 100644
|
||||
index 0afdfdc07764a26316c171c2a6722caf786875f2..732d44372cf226ca9d008ebc26d1838237ec96d6 100644
|
||||
--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
|
||||
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
|
||||
@@ -357,8 +357,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
|
||||
@@ -293,7 +293,7 @@ index bac328ebdf9f94d156211e03d3913157e2b80374..bf1b33b7bb71ec8387d95d9089f19962
|
||||
PiglinAi.updateActivity(this);
|
||||
super.customServerAiStep(level);
|
||||
diff --git a/net/minecraft/world/entity/projectile/Projectile.java b/net/minecraft/world/entity/projectile/Projectile.java
|
||||
index bde9370798c037c494a9c73f328cb251e68c21b1..3a6be0122d49b20f78be6cc8f1c7acb5c2e45f39 100644
|
||||
index 9f1c07be83999b7bafdee9238e8bad8c646d42f1..554e679a756dc1bf529053594231a958717f3573 100644
|
||||
--- a/net/minecraft/world/entity/projectile/Projectile.java
|
||||
+++ b/net/minecraft/world/entity/projectile/Projectile.java
|
||||
@@ -85,7 +85,7 @@ public abstract class Projectile extends Entity implements TraceableEntity {
|
||||
@@ -305,3 +305,21 @@ index bde9370798c037c494a9c73f328cb251e68c21b1..3a6be0122d49b20f78be6cc8f1c7acb5
|
||||
} else if (maxProjectileChunkLoadsConfig.perProjectile.resetMovementAfterReachLimit) {
|
||||
this.setDeltaMovement(0, this.getDeltaMovement().y, 0);
|
||||
}
|
||||
diff --git a/org/purpurmc/purpur/PurpurWorldConfig.java b/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..cadfbb7310fce33eda24d69c39fda5689c7fb882 100644
|
||||
--- a/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
+++ b/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
@@ -2435,6 +2435,13 @@ public class PurpurWorldConfig {
|
||||
piglinMobGriefingOverride = getBooleanOrDefault("mobs.piglin.mob-griefing-override", piglinMobGriefingOverride);
|
||||
piglinTakeDamageFromWater = getBoolean("mobs.piglin.takes-damage-from-water", piglinTakeDamageFromWater);
|
||||
piglinPortalSpawnModifier = getInt("mobs.piglin.portal-spawn-modifier", piglinPortalSpawnModifier);
|
||||
+ // Leaf start - Fix Pufferfish and Purpur patches - better input sanitization
|
||||
+ if (piglinPortalSpawnModifier < 1) {
|
||||
+ piglinPortalSpawnModifier = 1;
|
||||
+ log(Level.WARNING, "mobs.piglin.portal-spawn-modifier is set to below minimum allowed value of 1");
|
||||
+ log(Level.WARNING, "Using value of 1 to prevent issues");
|
||||
+ }
|
||||
+ // Leaf end - Fix Pufferfish and Purpur patches - better input sanitization
|
||||
piglinAlwaysDropExp = getBoolean("mobs.piglin.always-drop-exp", piglinAlwaysDropExp);
|
||||
piglinHeadVisibilityPercent = getDouble("mobs.piglin.head-visibility-percent", piglinHeadVisibilityPercent);
|
||||
piglinIgnoresArmorWithGoldTrim = getBoolean("mobs.piglin.ignores-armor-with-gold-trim", piglinIgnoresArmorWithGoldTrim);
|
||||
|
||||
@@ -19,7 +19,7 @@ This patch was ported downstream from the Petal fork.
|
||||
Makes most pathfinding-related work happen asynchronously
|
||||
|
||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||
index 33c99f3b24596fbbf3283b455ea8bf340203e01b..e9ebf23b0b1af85e3738a70acc0eaa3e8980261f 100644
|
||||
index fbcf26c0bfb9f496c99bd5a2ba988be06162cd52..cf136bc3d0d285ebde23c6e31c002933564fdcb2 100644
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -243,6 +243,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
@@ -560,19 +560,20 @@ index 1f96fd5085bacb4c584576c7cb9f51e7898e9b03..03b6c8c8dcd42e864751e68be9d35d20
|
||||
+ // Leaf end - Kaiiju - await on async path processing
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
|
||||
index e9dfff7e3726cd2229f89bb39fa1ca4815d99a6d..654ecd20ef4a43f7ffc447c15434ce46ab89efe9 100644
|
||||
index e9dfff7e3726cd2229f89bb39fa1ca4815d99a6d..04c0dad21c4cdd464a8ebe830bcdd217bb4156ec 100644
|
||||
--- a/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -936,7 +936,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
@@ -936,7 +936,8 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
} else {
|
||||
Bee.this.pathfindRandomlyTowards(Bee.this.hivePos);
|
||||
}
|
||||
- } else {
|
||||
+ } else if (navigation.getPath() != null && navigation.getPath().isProcessed()) { // Kaiiju - petal - check processing
|
||||
+ //} else if (navigation.getPath() != null && navigation.getPath().isProcessed()) { // Kaiiju - petal - check processing // todo
|
||||
+ } else {
|
||||
boolean flag = this.pathfindDirectlyTowards(Bee.this.hivePos);
|
||||
if (!flag) {
|
||||
this.dropAndBlacklistHive();
|
||||
@@ -990,7 +990,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
@@ -990,7 +991,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
return true;
|
||||
} else {
|
||||
Path path = Bee.this.navigation.getPath();
|
||||
|
||||
@@ -83,7 +83,7 @@ index 39489c8a347031fb4f73faca46039786e35762ac..4de1d0966157b20526386becee10b9be
|
||||
}
|
||||
|
||||
diff --git a/org/purpurmc/purpur/PurpurWorldConfig.java b/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..67739ba7cb82d615a5f0c4db7aaa5552c53a42c5 100644
|
||||
index cadfbb7310fce33eda24d69c39fda5689c7fb882..21765347d7a81f4111f23685f699286d5e5cccb6 100644
|
||||
--- a/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
+++ b/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
@@ -1625,6 +1625,7 @@ public class PurpurWorldConfig {
|
||||
@@ -118,7 +118,7 @@ index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..67739ba7cb82d615a5f0c4db7aaa5552
|
||||
}
|
||||
|
||||
public boolean illusionerRidable = false;
|
||||
@@ -3417,6 +3421,7 @@ public class PurpurWorldConfig {
|
||||
@@ -3424,6 +3428,7 @@ public class PurpurWorldConfig {
|
||||
public boolean zombieTakeDamageFromWater = false;
|
||||
public boolean zombieAlwaysDropExp = false;
|
||||
public double zombieHeadVisibilityPercent = 0.5D;
|
||||
@@ -126,7 +126,7 @@ index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..67739ba7cb82d615a5f0c4db7aaa5552
|
||||
private void zombieSettings() {
|
||||
zombieRidable = getBoolean("mobs.zombie.ridable", zombieRidable);
|
||||
zombieRidableInWater = getBoolean("mobs.zombie.ridable-in-water", zombieRidableInWater);
|
||||
@@ -3442,6 +3447,7 @@ public class PurpurWorldConfig {
|
||||
@@ -3449,6 +3454,7 @@ public class PurpurWorldConfig {
|
||||
zombieTakeDamageFromWater = getBoolean("mobs.zombie.takes-damage-from-water", zombieTakeDamageFromWater);
|
||||
zombieAlwaysDropExp = getBoolean("mobs.zombie.always-drop-exp", zombieAlwaysDropExp);
|
||||
zombieHeadVisibilityPercent = getDouble("mobs.zombie.head-visibility-percent", zombieHeadVisibilityPercent);
|
||||
@@ -134,7 +134,7 @@ index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..67739ba7cb82d615a5f0c4db7aaa5552
|
||||
}
|
||||
|
||||
public boolean zombieHorseRidable = false;
|
||||
@@ -3491,6 +3497,7 @@ public class PurpurWorldConfig {
|
||||
@@ -3498,6 +3504,7 @@ public class PurpurWorldConfig {
|
||||
public int zombieVillagerCuringTimeMax = 6000;
|
||||
public boolean zombieVillagerCureEnabled = true;
|
||||
public boolean zombieVillagerAlwaysDropExp = false;
|
||||
@@ -142,7 +142,7 @@ index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..67739ba7cb82d615a5f0c4db7aaa5552
|
||||
private void zombieVillagerSettings() {
|
||||
zombieVillagerRidable = getBoolean("mobs.zombie_villager.ridable", zombieVillagerRidable);
|
||||
zombieVillagerRidableInWater = getBoolean("mobs.zombie_villager.ridable-in-water", zombieVillagerRidableInWater);
|
||||
@@ -3511,6 +3518,7 @@ public class PurpurWorldConfig {
|
||||
@@ -3518,6 +3525,7 @@ public class PurpurWorldConfig {
|
||||
zombieVillagerCuringTimeMax = getInt("mobs.zombie_villager.curing_time.max", zombieVillagerCuringTimeMax);
|
||||
zombieVillagerCureEnabled = getBoolean("mobs.zombie_villager.cure.enabled", zombieVillagerCureEnabled);
|
||||
zombieVillagerAlwaysDropExp = getBoolean("mobs.zombie_villager.always-drop-exp", zombieVillagerAlwaysDropExp);
|
||||
@@ -150,7 +150,7 @@ index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..67739ba7cb82d615a5f0c4db7aaa5552
|
||||
}
|
||||
|
||||
public boolean zombifiedPiglinRidable = false;
|
||||
@@ -3525,6 +3533,7 @@ public class PurpurWorldConfig {
|
||||
@@ -3532,6 +3540,7 @@ public class PurpurWorldConfig {
|
||||
public boolean zombifiedPiglinCountAsPlayerKillWhenAngry = false;
|
||||
public boolean zombifiedPiglinTakeDamageFromWater = false;
|
||||
public boolean zombifiedPiglinAlwaysDropExp = false;
|
||||
@@ -158,7 +158,7 @@ index 31cc4e6e68a9743aaaeb296cb31e64526d3f1f73..67739ba7cb82d615a5f0c4db7aaa5552
|
||||
private void zombifiedPiglinSettings() {
|
||||
zombifiedPiglinRidable = getBoolean("mobs.zombified_piglin.ridable", zombifiedPiglinRidable);
|
||||
zombifiedPiglinRidableInWater = getBoolean("mobs.zombified_piglin.ridable-in-water", zombifiedPiglinRidableInWater);
|
||||
@@ -3546,6 +3555,7 @@ public class PurpurWorldConfig {
|
||||
@@ -3553,6 +3562,7 @@ public class PurpurWorldConfig {
|
||||
zombifiedPiglinCountAsPlayerKillWhenAngry = getBoolean("mobs.zombified_piglin.count-as-player-kill-when-angry", zombifiedPiglinCountAsPlayerKillWhenAngry);
|
||||
zombifiedPiglinTakeDamageFromWater = getBoolean("mobs.zombified_piglin.takes-damage-from-water", zombifiedPiglinTakeDamageFromWater);
|
||||
zombifiedPiglinAlwaysDropExp = getBoolean("mobs.zombified_piglin.always-drop-exp", zombifiedPiglinAlwaysDropExp);
|
||||
|
||||
@@ -263,7 +263,7 @@ index 234f123959830cc2adb78b9dc8752906140e5b11..e0dceff32b47b334ddcb76271e3cf3ea
|
||||
org.bukkit.event.inventory.InventoryType.ENDER_CHEST.setDefaultSize(enderChestSixRows ? 54 : 27);
|
||||
enderChestPermissionRows = getBoolean("settings.blocks.ender_chest.use-permissions-for-rows", enderChestPermissionRows);
|
||||
diff --git a/org/purpurmc/purpur/PurpurWorldConfig.java b/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
index 67739ba7cb82d615a5f0c4db7aaa5552c53a42c5..d81e06592aa9521f866c2c910b43a7364de3796e 100644
|
||||
index 21765347d7a81f4111f23685f699286d5e5cccb6..8459f5b9bf548e51b85e753a4e65dd86baa2b5df 100644
|
||||
--- a/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
+++ b/org/purpurmc/purpur/PurpurWorldConfig.java
|
||||
@@ -1189,12 +1189,20 @@ public class PurpurWorldConfig {
|
||||
@@ -353,7 +353,7 @@ index 67739ba7cb82d615a5f0c4db7aaa5552c53a42c5..d81e06592aa9521f866c2c910b43a736
|
||||
}
|
||||
|
||||
public boolean ghastRidable = false;
|
||||
@@ -2911,6 +2945,10 @@ public class PurpurWorldConfig {
|
||||
@@ -2918,6 +2952,10 @@ public class PurpurWorldConfig {
|
||||
public double snifferMaxHealth = 14.0D;
|
||||
public double snifferScale = 1.0D;
|
||||
public int snifferBreedingTicks = 6000;
|
||||
@@ -364,7 +364,7 @@ index 67739ba7cb82d615a5f0c4db7aaa5552c53a42c5..d81e06592aa9521f866c2c910b43a736
|
||||
private void snifferSettings() {
|
||||
snifferRidable = getBoolean("mobs.sniffer.ridable", snifferRidable);
|
||||
snifferRidableInWater = getBoolean("mobs.sniffer.ridable-in-water", snifferRidableInWater);
|
||||
@@ -2918,6 +2956,10 @@ public class PurpurWorldConfig {
|
||||
@@ -2925,6 +2963,10 @@ public class PurpurWorldConfig {
|
||||
snifferMaxHealth = getDouble("mobs.sniffer.attributes.max_health", snifferMaxHealth);
|
||||
snifferScale = Mth.clamp(getDouble("mobs.sniffer.attributes.scale", snifferScale), 0.0625D, 16.0D);
|
||||
snifferBreedingTicks = getInt("mobs.sniffer.breeding-delay-ticks", snifferBreedingTicks);
|
||||
@@ -375,7 +375,7 @@ index 67739ba7cb82d615a5f0c4db7aaa5552c53a42c5..d81e06592aa9521f866c2c910b43a736
|
||||
}
|
||||
|
||||
public boolean squidRidable = false;
|
||||
@@ -3019,10 +3061,20 @@ public class PurpurWorldConfig {
|
||||
@@ -3026,10 +3068,20 @@ public class PurpurWorldConfig {
|
||||
public boolean tadpoleRidable = false;
|
||||
public boolean tadpoleRidableInWater = true;
|
||||
public boolean tadpoleControllable = true;
|
||||
@@ -396,7 +396,7 @@ index 67739ba7cb82d615a5f0c4db7aaa5552c53a42c5..d81e06592aa9521f866c2c910b43a736
|
||||
}
|
||||
|
||||
public boolean traderLlamaRidable = false;
|
||||
@@ -3256,10 +3308,20 @@ public class PurpurWorldConfig {
|
||||
@@ -3263,10 +3315,20 @@ public class PurpurWorldConfig {
|
||||
public boolean wardenRidable = false;
|
||||
public boolean wardenRidableInWater = true;
|
||||
public boolean wardenControllable = true;
|
||||
|
||||
@@ -34,7 +34,7 @@ index f861f9e087182470a3bbb22678dbdacb8a73e943..a3d0d17178eedfaef83e2e0df6b1c2d7
|
||||
|
||||
private DensityFunction wrapNew(DensityFunction densityFunction) {
|
||||
diff --git a/net/minecraft/world/level/levelgen/SurfaceRules.java b/net/minecraft/world/level/levelgen/SurfaceRules.java
|
||||
index 0948c8db90605a15a043b5c5bc74edecd7f9db1b..009e8a270c25614d03413d8b8b1f39c2da8ba12f 100644
|
||||
index 0948c8db90605a15a043b5c5bc74edecd7f9db1b..6cba88415a4715527e163e54662db9b3ab37c747 100644
|
||||
--- a/net/minecraft/world/level/levelgen/SurfaceRules.java
|
||||
+++ b/net/minecraft/world/level/levelgen/SurfaceRules.java
|
||||
@@ -313,8 +313,15 @@ public class SurfaceRules {
|
||||
@@ -48,9 +48,9 @@ index 0948c8db90605a15a043b5c5bc74edecd7f9db1b..009e8a270c25614d03413d8b8b1f39c2
|
||||
+ ++this.lastUpdateY;
|
||||
+ Supplier<Holder<Biome>> getter = this.biome;
|
||||
+ if (getter == null) {
|
||||
+ this.biome = getter = new org.dreeam.leaf.util.biome.PositionalBiomeGetter(this.biomeGetter, this.pos);
|
||||
+ this.biome = getter = new org.dreeam.leaf.world.biome.PositionalBiomeGetter(this.biomeGetter, this.pos);
|
||||
+ }
|
||||
+ ((org.dreeam.leaf.util.biome.PositionalBiomeGetter) getter).update(blockX, blockY, blockZ);
|
||||
+ ((org.dreeam.leaf.world.biome.PositionalBiomeGetter) getter).update(blockX, blockY, blockZ);
|
||||
+ // Leaf end - Reduce worldgen allocations
|
||||
this.blockY = blockY;
|
||||
this.waterHeight = waterHeight;
|
||||
|
||||
@@ -23,6 +23,28 @@ for the case of some NPC plugins which using real entity type, e.g. Citizens.
|
||||
But it is still recommending to use those packet based, virtual entity
|
||||
based NPC plugins, e.g. ZNPC Plus, Adyeshach, Fancy NPC, etc.
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..4200d22606c6a3dbdf282792a4007a51df66963b 100644
|
||||
--- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
@@ -60,7 +60,16 @@ public final class NearbyPlayers {
|
||||
|
||||
private final ServerLevel world;
|
||||
private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
|
||||
- private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<TrackedChunk> byChunk;
|
||||
+ {
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) {
|
||||
+ byChunk = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>());
|
||||
+ } else {
|
||||
+ byChunk = new Long2ReferenceOpenHashMap<>();
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
private final Long2ReferenceOpenHashMap<ReferenceList<ServerPlayer>>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES];
|
||||
{
|
||||
for (int i = 0; i < this.directByChunk.length; ++i) {
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index 02a9ef1694c796584c29430d27f0a09047368835..32608df3da169159c070f37cb55407f4f6187744 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -36,8 +58,20 @@ index 02a9ef1694c796584c29430d27f0a09047368835..32608df3da169159c070f37cb55407f4
|
||||
|
||||
private static final byte CHUNK_TICKET_STAGE_NONE = 0;
|
||||
private static final byte CHUNK_TICKET_STAGE_LOADING = 1;
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java b/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java
|
||||
index 9c0c99b936b4a82ebfe924866e53ec71f7bbe9ad..2ccff968cb2065d34fad4d27573f9e3081edb2f2 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java
|
||||
@@ -32,6 +32,7 @@ public class ClientboundUpdateAttributesPacket implements Packet<ClientGamePacke
|
||||
this.attributes = Lists.newArrayList();
|
||||
|
||||
for (AttributeInstance attributeInstance : attributes) {
|
||||
+ if (attributeInstance == null) continue; // Leaf - Multithreaded tracker
|
||||
this.attributes
|
||||
.add(
|
||||
new ClientboundUpdateAttributesPacket.AttributeSnapshot(
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e693645dfe 100644
|
||||
index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..ae0a7c9b95f4f2561769e0d661fadbe29a2d6f8b 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -255,6 +255,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -70,14 +104,13 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
// Paper start - optimise entity tracker
|
||||
if (true) {
|
||||
this.newTrackerTick();
|
||||
@@ -1135,7 +1151,18 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1135,7 +1151,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final Entity entity;
|
||||
private final int range;
|
||||
SectionPos lastSectionPos;
|
||||
- public final Set<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ public static final ServerPlayerConnection[] EMPTY_OBJECT_ARRAY = new ServerPlayerConnection[0];
|
||||
+ public final Object sync = new Object();
|
||||
+ public final Set<ServerPlayerConnection> seenBy = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled ? it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>()) : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
|
||||
+ private volatile ServerPlayerConnection[] seenByArray = EMPTY_OBJECT_ARRAY;
|
||||
+ public ServerPlayerConnection[] seenBy() {
|
||||
@@ -90,7 +123,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
|
||||
// Paper start - optimise entity tracker
|
||||
private long lastChunkUpdate = -1L;
|
||||
@@ -1162,27 +1189,95 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1162,27 +1188,95 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.lastTrackedChunk = chunk;
|
||||
|
||||
final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
|
||||
@@ -191,7 +224,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(conn.getPlayer())) {
|
||||
foundToRemove = true;
|
||||
break;
|
||||
@@ -1193,12 +1288,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1193,12 +1287,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -207,7 +240,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1208,10 +1304,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1208,10 +1303,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
if (this.seenBy.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -221,7 +254,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1238,7 +1335,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1238,7 +1334,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
public void broadcast(Packet<?> packet) {
|
||||
@@ -230,7 +263,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
serverPlayerConnection.send(packet);
|
||||
}
|
||||
}
|
||||
@@ -1259,21 +1356,34 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1259,21 +1355,34 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
public void broadcastRemoved() {
|
||||
@@ -268,7 +301,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
// Paper start - remove allocation of Vec3D here
|
||||
// Vec3 vec3 = player.position().subtract(this.entity.position());
|
||||
double vec3_dx = player.getX() - this.entity.getX();
|
||||
@@ -1301,6 +1411,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1301,6 +1410,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// CraftBukkit end
|
||||
if (flag) {
|
||||
if (this.seenBy.add(player.connection)) {
|
||||
@@ -276,7 +309,7 @@ index c60b9e4076450de2157c1a3cf4f98cc2c19e4e6a..41da66fd77924a9a4bd9cc12f517e2e6
|
||||
// Paper start - entity tracking events
|
||||
if (io.papermc.paper.event.player.PlayerTrackEntityEvent.getHandlerList().getRegisteredListeners().length == 0 || new io.papermc.paper.event.player.PlayerTrackEntityEvent(player.getBukkitEntity(), this.entity.getBukkitEntity()).callEvent()) {
|
||||
this.serverEntity.addPairing(player);
|
||||
@@ -1309,6 +1420,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
@@ -1309,6 +1419,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.serverEntity.onPlayerAdd(); // Paper - fix desync when a player is added to the tracker
|
||||
}
|
||||
} else if (this.seenBy.remove(player.connection)) {
|
||||
@@ -298,18 +331,10 @@ index f106373ef3ac4a8685c2939c9e8361688a285913..51ae390c68e7a3aa193329cc3bc47ca6
|
||||
public boolean visible = true;
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 1a9601aee097b6c10cf2ae1c52fddf45da85f60f..867936866d952c559b6ffa49fdf78acd70a9bab9 100644
|
||||
index 1a9601aee097b6c10cf2ae1c52fddf45da85f60f..16b2ca8c96e9561aa57e0903d1e98e6441044b6d 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -75,6 +75,7 @@ public class ServerEntity {
|
||||
@Nullable
|
||||
private List<SynchedEntityData.DataValue<?>> trackedDataValues;
|
||||
private final Set<net.minecraft.server.network.ServerPlayerConnection> trackedPlayers; // Paper
|
||||
+ public boolean wantSendDirtyEntityData = false; // Leaf - Multithreaded tracker
|
||||
|
||||
public ServerEntity(
|
||||
ServerLevel level,
|
||||
@@ -146,7 +147,7 @@ public class ServerEntity {
|
||||
@@ -146,7 +146,7 @@ public class ServerEntity {
|
||||
MapId mapId = itemFrame.cachedMapId; // Paper - Perf: Cache map ids on item frames
|
||||
MapItemSavedData savedData = MapItem.getSavedData(mapId, this.level);
|
||||
if (savedData != null) {
|
||||
@@ -318,21 +343,17 @@ index 1a9601aee097b6c10cf2ae1c52fddf45da85f60f..867936866d952c559b6ffa49fdf78acd
|
||||
final ServerPlayer serverPlayer = connection.getPlayer(); // Paper
|
||||
savedData.tickCarriedBy(serverPlayer, item);
|
||||
Packet<?> updatePacket = savedData.getUpdatePacket(mapId, serverPlayer);
|
||||
@@ -450,6 +451,12 @@ public class ServerEntity {
|
||||
@@ -468,7 +468,7 @@ public class ServerEntity {
|
||||
this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync));
|
||||
}
|
||||
|
||||
- attributesToSync.clear();
|
||||
+ // attributesToSync.clear(); // Leaf - Multithreaded tracker
|
||||
}
|
||||
}
|
||||
|
||||
public void sendDirtyEntityData() {
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (Thread.currentThread() instanceof org.dreeam.leaf.async.tracker.MultithreadedTracker.MultithreadedTrackerThread) {
|
||||
+ wantSendDirtyEntityData = true;
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
SynchedEntityData entityData = this.entity.getEntityData();
|
||||
List<SynchedEntityData.DataValue<?>> list = entityData.packDirty();
|
||||
if (list != null) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 5943b18f172fb1d77ef1fe768daa8e8f43c3c8c1..7b85a9ebdbe3e8bee0a8fc100ede8a3f07eee5ce 100644
|
||||
index 42f56bd6a9f449df23f7e7f00b3efa114a003449..0471b04833fbca5dfc0cc6575692cdefb83edbed 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2503,7 +2503,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -354,7 +375,7 @@ index 5943b18f172fb1d77ef1fe768daa8e8f43c3c8c1..7b85a9ebdbe3e8bee0a8fc100ede8a3f
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 729f595491c7a4edf24dff2e876dfb69ade87a17..a3069b29a1b78012314747d705e27c167acd10b3 100644
|
||||
index be803fd0a79850254bd4a7f64534142cd5b4ec98..6992a53abdcff6299bedf33ba0b1bc6386a1ea74 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1878,7 +1878,7 @@ public class ServerGamePacketListenerImpl
|
||||
@@ -366,6 +387,233 @@ index 729f595491c7a4edf24dff2e876dfb69ade87a17..a3069b29a1b78012314747d705e27c16
|
||||
// Paper start - Prevent teleporting dead entities
|
||||
if (this.player.isRemoved()) {
|
||||
LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 4c3eadc2d8480b2a2c2c08e58620544d403d3adc..68241d1d488bc2848e3c0d167270c1788e573c37 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1317,13 +1317,13 @@ public abstract class LivingEntity extends Entity implements Attackable {
|
||||
}
|
||||
|
||||
private void refreshDirtyAttributes() {
|
||||
- Set<AttributeInstance> attributesToUpdate = this.getAttributes().getAttributesToUpdate();
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ int[] attributesToUpdate = this.getAttributes().getAttributesToUpdateIds();
|
||||
|
||||
- for (AttributeInstance attributeInstance : attributesToUpdate) {
|
||||
- this.onAttributeUpdated(attributeInstance.getAttribute());
|
||||
+ for (int attribute : attributesToUpdate) {
|
||||
+ this.onAttributeUpdated(net.minecraft.core.registries.BuiltInRegistries.ATTRIBUTE.get(attribute).orElseThrow());
|
||||
}
|
||||
-
|
||||
- attributesToUpdate.clear();
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
}
|
||||
|
||||
protected void onAttributeUpdated(Holder<Attribute> attribute) {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/Attribute.java b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
index f8419dde44ebc7324e783f8bee42132d5ec973c3..406767c60ec1a324faaf5d3658b161647497f99b 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
@@ -16,10 +16,15 @@ public class Attribute {
|
||||
private boolean syncable;
|
||||
private final String descriptionId;
|
||||
private Attribute.Sentiment sentiment = Attribute.Sentiment.POSITIVE;
|
||||
+ // Leaf start - Optimize AttributeMap
|
||||
+ public final int uid;
|
||||
+ private static final java.util.concurrent.atomic.AtomicInteger SIZE = new java.util.concurrent.atomic.AtomicInteger();
|
||||
+ // Leaf end - Optimize AttributeMap
|
||||
|
||||
protected Attribute(String descriptionId, double defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.descriptionId = descriptionId;
|
||||
+ this.uid = SIZE.getAndAdd(1); // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public double getDefaultValue() {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
index 3ac9f36eae87369354e992a1d9b5c5b2d87d17cb..9f09d78a7dac12c7f1b06029d32ad93fae0c2aec 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
@@ -26,8 +26,24 @@ public class AttributeInstance {
|
||||
private final Map<AttributeModifier.Operation, Map<ResourceLocation, AttributeModifier>> modifiersByOperation = Maps.newEnumMap(
|
||||
AttributeModifier.Operation.class
|
||||
);
|
||||
- private final Map<ResourceLocation, AttributeModifier> modifierById = new Object2ObjectArrayMap<>();
|
||||
- private final Map<ResourceLocation, AttributeModifier> permanentModifiers = new Object2ObjectArrayMap<>();
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ private final Map<ResourceLocation, AttributeModifier> modifierById;
|
||||
+ {
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) {
|
||||
+ modifierById = it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this);
|
||||
+ } else {
|
||||
+ modifierById = new Object2ObjectArrayMap<>();
|
||||
+ }
|
||||
+ }
|
||||
+ private final Map<ResourceLocation, AttributeModifier> permanentModifiers;
|
||||
+ {
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) {
|
||||
+ permanentModifiers = it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this);
|
||||
+ } else {
|
||||
+ permanentModifiers = new Object2ObjectArrayMap<>();
|
||||
+ }
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
private double baseValue;
|
||||
private boolean dirty = true;
|
||||
private double cachedValue;
|
||||
@@ -56,7 +72,13 @@ public class AttributeInstance {
|
||||
|
||||
@VisibleForTesting
|
||||
Map<ResourceLocation, AttributeModifier> getModifiers(AttributeModifier.Operation operation) {
|
||||
- return this.modifiersByOperation.computeIfAbsent(operation, operation1 -> new Object2ObjectOpenHashMap<>());
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ return this.modifiersByOperation.computeIfAbsent(operation, operation1 -> {
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled)
|
||||
+ return it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this);
|
||||
+ else return new Object2ObjectArrayMap<>();
|
||||
+ });
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
}
|
||||
|
||||
public Set<AttributeModifier> getModifiers() {
|
||||
@@ -144,8 +166,12 @@ public class AttributeInstance {
|
||||
|
||||
public double getValue() {
|
||||
if (this.dirty) {
|
||||
- this.cachedValue = this.calculateValue();
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ double value = this.calculateValue();
|
||||
+ this.cachedValue = value;
|
||||
this.dirty = false;
|
||||
+ return value;
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
}
|
||||
|
||||
return this.cachedValue;
|
||||
@@ -192,7 +218,15 @@ public class AttributeInstance {
|
||||
compoundTag.store("id", TYPE_CODEC, this.attribute);
|
||||
compoundTag.putDouble("base", this.baseValue);
|
||||
if (!this.permanentModifiers.isEmpty()) {
|
||||
- compoundTag.store("modifiers", AttributeModifier.CODEC.listOf(), List.copyOf(this.permanentModifiers.values()));
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) {
|
||||
+ synchronized (this) {
|
||||
+ compoundTag.store("modifiers", AttributeModifier.CODEC.listOf(), List.copyOf(this.permanentModifiers.values()));
|
||||
+ }
|
||||
+ } else {
|
||||
+ compoundTag.store("modifiers", AttributeModifier.CODEC.listOf(), List.copyOf(this.permanentModifiers.values()));
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
}
|
||||
|
||||
return compoundTag;
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
index 701025715e0aca3c1f920a66f9b3d03ec08eaf02..778872cdd1717f1ad52de32faf43847a08c55269 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
@@ -15,12 +15,14 @@ import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class AttributeMap {
|
||||
// Gale start - Lithium - replace AI attributes with optimized collections
|
||||
- private final Map<Holder<Attribute>, AttributeInstance> attributes = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
|
||||
- private final Set<AttributeInstance> attributesToSync = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
- private final Set<AttributeInstance> attributesToUpdate = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ private final Map<Holder<Attribute>, AttributeInstance> attributes = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap();
|
||||
+ private final org.dreeam.leaf.util.map.AttributeInstanceSet attributesToSync = new org.dreeam.leaf.util.map.AttributeInstanceSet((org.dreeam.leaf.util.map.AttributeInstanceArrayMap) attributes);
|
||||
+ private final org.dreeam.leaf.util.map.AttributeInstanceSet attributesToUpdate = new org.dreeam.leaf.util.map.AttributeInstanceSet((org.dreeam.leaf.util.map.AttributeInstanceArrayMap) attributes);
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
// Gale end - Lithium - replace AI attributes with optimized collections
|
||||
private final AttributeSupplier supplier;
|
||||
- private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations
|
||||
+ //private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations // Leaf - Optimize AttributeMap
|
||||
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
|
||||
|
||||
public AttributeMap(AttributeSupplier supplier) {
|
||||
@@ -31,31 +33,54 @@ public class AttributeMap {
|
||||
this.entity = entity;
|
||||
// Purpur end - Ridables
|
||||
this.supplier = defaultAttributes;
|
||||
- this.createInstance = holder -> this.supplier.createInstance(this::onAttributeModified, holder); // Gale - Airplane - reduce entity allocations
|
||||
+ //this.createInstance = holder -> this.supplier.createInstance(this::onAttributeModified, holder); // Gale - Airplane - reduce entity allocations // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
- private void onAttributeModified(AttributeInstance instance) {
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ private synchronized void onAttributeModified(AttributeInstance instance) {
|
||||
this.attributesToUpdate.add(instance);
|
||||
if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables
|
||||
this.attributesToSync.add(instance);
|
||||
}
|
||||
}
|
||||
|
||||
- public Set<AttributeInstance> getAttributesToSync() {
|
||||
- return this.attributesToSync;
|
||||
+ private static final AttributeInstance[] EMPTY_ATTRIBUTE_INSTANCE = new AttributeInstance[0];
|
||||
+ public synchronized Set<AttributeInstance> getAttributesToSync() {
|
||||
+ var clone = it.unimi.dsi.fastutil.objects.ReferenceArraySet.ofUnchecked(attributesToSync.toArray(EMPTY_ATTRIBUTE_INSTANCE));
|
||||
+ this.attributesToSync.clear();
|
||||
+ return clone;
|
||||
}
|
||||
|
||||
- public Set<AttributeInstance> getAttributesToUpdate() {
|
||||
- return this.attributesToUpdate;
|
||||
+ public synchronized Set<AttributeInstance> getAttributesToUpdate() {
|
||||
+ var clone = it.unimi.dsi.fastutil.objects.ReferenceArraySet.ofUnchecked(attributesToUpdate.toArray(EMPTY_ATTRIBUTE_INSTANCE));
|
||||
+ this.attributesToUpdate.clear();
|
||||
+ return clone;
|
||||
}
|
||||
|
||||
+ public synchronized int[] getAttributesToUpdateIds() {
|
||||
+ int[] clone = attributesToUpdate.inner.toIntArray();
|
||||
+ this.attributesToUpdate.clear();
|
||||
+ return clone;
|
||||
+ }
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
+
|
||||
public Collection<AttributeInstance> getSyncableAttributes() {
|
||||
return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))).collect(Collectors.toList()); // Purpur - Ridables
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AttributeInstance getInstance(Holder<Attribute> attribute) {
|
||||
- return this.attributes.computeIfAbsent(attribute, this.createInstance); // Gale - Airplane - reduce entity allocations - cache lambda, as for some reason java allocates it anyways
|
||||
+ // Leaf start - Multithreaded tracker
|
||||
+ AttributeInstance v;
|
||||
+ if ((v = this.attributes.get(attribute)) == null) {
|
||||
+ AttributeInstance newValue;
|
||||
+ if ((newValue = this.supplier.createInstance(this::onAttributeModified, attribute)) != null) {
|
||||
+ attributes.put(attribute, newValue);
|
||||
+ return newValue;
|
||||
+ }
|
||||
+ }
|
||||
+ return v;
|
||||
+ // Leaf end - Multithreaded tracker
|
||||
}
|
||||
|
||||
public boolean hasAttribute(Holder<Attribute> attribute) {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
index 24710041ccbc70e5506d8d89ae34f0141977f209..05de8a77b389691dd6986f36b4cb8cc0935e21e4 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
@@ -11,7 +11,7 @@ public class AttributeSupplier {
|
||||
private final Map<Holder<Attribute>, AttributeInstance> instances;
|
||||
|
||||
AttributeSupplier(Map<Holder<Attribute>, AttributeInstance> instances) {
|
||||
- this.instances = instances;
|
||||
+ this.instances = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap(instances); // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public AttributeInstance getAttributeInstance(Holder<Attribute> attribute) {
|
||||
@@ -41,7 +41,7 @@ public class AttributeSupplier {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- public AttributeInstance createInstance(Consumer<AttributeInstance> onDirty, Holder<Attribute> attribute) {
|
||||
+ public AttributeInstance createInstance(Consumer<AttributeInstance> onDirty, Holder<Attribute> attribute) { // Leaf - Multithreaded tracker
|
||||
AttributeInstance attributeInstance = this.instances.get(attribute);
|
||||
if (attributeInstance == null) {
|
||||
return null;
|
||||
diff --git a/net/minecraft/world/entity/item/PrimedTnt.java b/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
index 36e3937c9e09852937c94c268c877a15337835c5..8aedc3ca463745fe32cac977208b23dc0b8e73b6 100644
|
||||
--- a/net/minecraft/world/entity/item/PrimedTnt.java
|
||||
|
||||
@@ -9,10 +9,10 @@ This patch didn't cahce SectionPos or BlockPos to chunkKey, since it needs to co
|
||||
TODO: Cache block pos and section pos, whether need?
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..288a3eb57f3431dd624ad8a4b08684563abbc5ad 100644
|
||||
index 4200d22606c6a3dbdf282792a4007a51df66963b..4b258f048c73107d0d050a9aa4b4a39788145b17 100644
|
||||
--- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
@@ -127,7 +127,7 @@ public final class NearbyPlayers {
|
||||
@@ -136,7 +136,7 @@ public final class NearbyPlayers {
|
||||
}
|
||||
|
||||
public TrackedChunk getChunk(final ChunkPos pos) {
|
||||
@@ -21,7 +21,7 @@ index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..288a3eb57f3431dd624ad8a4b0868456
|
||||
}
|
||||
|
||||
public TrackedChunk getChunk(final BlockPos pos) {
|
||||
@@ -143,7 +143,7 @@ public final class NearbyPlayers {
|
||||
@@ -152,7 +152,7 @@ public final class NearbyPlayers {
|
||||
}
|
||||
|
||||
public ReferenceList<ServerPlayer> getPlayers(final ChunkPos pos, final NearbyMapType type) {
|
||||
@@ -97,7 +97,7 @@ index fd3d0f6cb53bc8b6186f0d86575f21007b2c20ed..cddeeab73e7b981701a42c5aad6b4777
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 7b85a9ebdbe3e8bee0a8fc100ede8a3f07eee5ce..c8c99323b6397c3e595e7a9007e5d801ee2ac14a 100644
|
||||
index 0471b04833fbca5dfc0cc6575692cdefb83edbed..1f3020f5a051d5f4e5c8fa088f844962c3105573 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -503,7 +503,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
@@ -8,11 +8,26 @@ Paper: ~75ms
|
||||
Leaf: ~48ms (-36%)
|
||||
This should help drastically on the farms that use actively changing fluids.
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index c6eb136e8db0aa232681ac9bd28c4b70fbbacb40..706e198631e4a3b0a5d2fc3f58060e4a15701ecd 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1300,6 +1300,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.emptyTime = 0;
|
||||
}
|
||||
|
||||
+ // Leaf start - Use BFS on getSlopeDistance
|
||||
+ public it.unimi.dsi.fastutil.longs.LongSet slopeDistanceCacheVisited = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(512);
|
||||
+ public net.minecraft.world.level.material.FlowingFluid.SlopeDistanceNodeDeque slopeDistanceCacheQueue = new net.minecraft.world.level.material.FlowingFluid.SlopeDistanceNodeDeque();
|
||||
+ // Leaf end - Use BFS on getSlopeDistance
|
||||
private void tickFluid(BlockPos pos, Fluid fluid) {
|
||||
BlockState blockState = this.getBlockState(pos);
|
||||
FluidState fluidState = blockState.getFluidState();
|
||||
diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java
|
||||
index 4625bd55e1cb01dfb9921dcd033f05b4a8f9ad74..c0f78556d112e59333ace60f1522e7fd1efe71c3 100644
|
||||
index 4625bd55e1cb01dfb9921dcd033f05b4a8f9ad74..a1c6a30c1e446955b409d1f00c602db06c1e9813 100644
|
||||
--- a/net/minecraft/world/level/material/FlowingFluid.java
|
||||
+++ b/net/minecraft/world/level/material/FlowingFluid.java
|
||||
@@ -342,32 +342,81 @@ public abstract class FlowingFluid extends Fluid {
|
||||
@@ -342,32 +342,124 @@ public abstract class FlowingFluid extends Fluid {
|
||||
|
||||
protected abstract void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state);
|
||||
|
||||
@@ -20,13 +35,15 @@ index 4625bd55e1cb01dfb9921dcd033f05b4a8f9ad74..c0f78556d112e59333ace60f1522e7fd
|
||||
- int i = 1000;
|
||||
+ // Leaf start - Use BFS on getSlopeDistance
|
||||
+ protected int getSlopeDistance(LevelReader level, BlockPos startPos, int initialDepth, Direction excludedDirection, BlockState startState, FlowingFluid.SpreadContext spreadContext) {
|
||||
+ it.unimi.dsi.fastutil.longs.LongSet visited = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(512);
|
||||
+ java.util.Queue<FlowingFluid.SlopeDistanceNode> queue = new java.util.ArrayDeque<>(256);
|
||||
+ it.unimi.dsi.fastutil.longs.LongSet visited = ((ServerLevel) level).slopeDistanceCacheVisited;
|
||||
+ SlopeDistanceNodeDeque queue = ((ServerLevel) level).slopeDistanceCacheQueue;
|
||||
+ visited.clear();
|
||||
+ queue.clear();
|
||||
+
|
||||
+ for (Direction dir : Direction.Plane.HORIZONTAL) {
|
||||
+ if (dir == excludedDirection) continue;
|
||||
+
|
||||
+ BlockPos neighborPos = startPos.relative(dir);
|
||||
+ BlockPos neighborPos = startPos.relative(dir); // immutable
|
||||
+ BlockState neighborState = spreadContext.getBlockStateIfLoaded(neighborPos);
|
||||
+ if (neighborState == null) continue;
|
||||
+
|
||||
@@ -72,7 +89,7 @@ index 4625bd55e1cb01dfb9921dcd033f05b4a8f9ad74..c0f78556d112e59333ace60f1522e7fd
|
||||
+ for (Direction dir : Direction.Plane.HORIZONTAL) {
|
||||
+ if (dir == current.excludedDir) continue;
|
||||
+
|
||||
+ BlockPos nextPos = current.pos.relative(dir);
|
||||
+ BlockPos nextPos = current.pos.relative(dir); // immutable
|
||||
+ BlockState nextState = spreadContext.getBlockStateIfLoaded(nextPos);
|
||||
+ if (nextState == null) continue;
|
||||
+
|
||||
@@ -96,18 +113,59 @@ index 4625bd55e1cb01dfb9921dcd033f05b4a8f9ad74..c0f78556d112e59333ace60f1522e7fd
|
||||
+ return ((long) pos.getX() & 0xFFFFFFFFL) << 32 | ((long) pos.getZ() & 0xFFFFFFFFL) << 4 | (excludedDir.ordinal() & 0x0F);
|
||||
+ }
|
||||
+
|
||||
+ private static class SlopeDistanceNode {
|
||||
+ final BlockPos pos;
|
||||
+ final int depth;
|
||||
+ final Direction excludedDir;
|
||||
+ final BlockState state;
|
||||
+ public static class SlopeDistanceNodeDeque {
|
||||
+ private SlopeDistanceNode[] array;
|
||||
+ private int length;
|
||||
+ private int start;
|
||||
+ private int end;
|
||||
+
|
||||
+ SlopeDistanceNode(BlockPos pos, int depth, Direction excludedDir, BlockState state) {
|
||||
+ this.pos = pos.immutable();
|
||||
+ this.depth = depth;
|
||||
+ this.excludedDir = excludedDir;
|
||||
+ this.state = state;
|
||||
+ public SlopeDistanceNodeDeque() {
|
||||
+ array = new SlopeDistanceNode[256];
|
||||
+ length = array.length;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ private int size() {
|
||||
+ int apparent = end - start;
|
||||
+ return apparent >= 0 ? apparent : length + apparent;
|
||||
+ }
|
||||
+ */
|
||||
+
|
||||
+ private void clear() {
|
||||
+ start = 0;
|
||||
+ end = 0;
|
||||
+ }
|
||||
+
|
||||
+ private boolean isEmpty() {
|
||||
+ return end == start || (end <= start && length == start - end);
|
||||
+ }
|
||||
+
|
||||
+ private SlopeDistanceNode poll() {
|
||||
+ final SlopeDistanceNode t = array[start];
|
||||
+ if (++start == length) start = 0;
|
||||
+ return t;
|
||||
+ }
|
||||
+
|
||||
+ private void add(final SlopeDistanceNode node) {
|
||||
+ array[end++] = node;
|
||||
+ if (end == length) end = 0;
|
||||
+ if (end == start) resize(length, 2 * length);
|
||||
+ }
|
||||
+
|
||||
+ private void resize(final int size, final int newLength) {
|
||||
+ final SlopeDistanceNode[] newArray = new SlopeDistanceNode[newLength];
|
||||
+ if (size != 0) {
|
||||
+ System.arraycopy(array, start, newArray, 0, length - start);
|
||||
+ System.arraycopy(array, 0, newArray, length - start, end);
|
||||
+ }
|
||||
+ start = 0;
|
||||
+ end = size;
|
||||
+ array = newArray;
|
||||
+ length = newLength;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private record SlopeDistanceNode(BlockPos pos, int depth, Direction excludedDir, BlockState state) {
|
||||
}
|
||||
+ // Leaf end - Use BFS on getSlopeDistance
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ Subject: [PATCH] Optimize addOrUpdateTransientModifier
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
index 3ac9f36eae87369354e992a1d9b5c5b2d87d17cb..c39654d3e1e5573646b3729502e4eae1a6dba7c9 100644
|
||||
index 9f09d78a7dac12c7f1b06029d32ad93fae0c2aec..2af5cd6f2b9541cb28075fda014350235a4f72c7 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
@@ -87,8 +87,13 @@ public class AttributeInstance {
|
||||
@@ -109,8 +109,13 @@ public class AttributeInstance {
|
||||
}
|
||||
|
||||
public void addOrUpdateTransientModifier(AttributeModifier modifier) {
|
||||
|
||||
@@ -149,7 +149,7 @@ index 54910c2e1d6e6bb556e536fda060bd09402e04e8..747eb54f84650a9a507398e3d5352e00
|
||||
|
||||
// Gale start - Pufferfish - SIMD support
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 1346cff0018e6d17cb892892c3aeebfb86453b60..a753481afe02a2367c378c7f39206fde23eda00d 100644
|
||||
index 1d2c27a7595701895aa3c96339814fd1454a50dd..db3bff36c812a00fc35ebcc6ac6d11ce24040003 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -173,7 +173,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -220,7 +220,7 @@ index 1346cff0018e6d17cb892892c3aeebfb86453b60..a753481afe02a2367c378c7f39206fde
|
||||
}
|
||||
// Paper - rewrite chunk system
|
||||
}
|
||||
@@ -1312,6 +1337,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1316,6 +1341,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
@@ -228,7 +228,7 @@ index 1346cff0018e6d17cb892892c3aeebfb86453b60..a753481afe02a2367c378c7f39206fde
|
||||
}
|
||||
|
||||
private void tickBlock(BlockPos pos, Block block) {
|
||||
@@ -1325,6 +1351,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1329,6 +1355,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
|
||||
|
||||
@@ -35,10 +35,10 @@ index 78aee57ad8224b0728411c699d2e3844847c9c79..8f5b400bdf5c1c194f75ee98e2f1e984
|
||||
this.tickables.get(i).run();
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 867936866d952c559b6ffa49fdf78acd70a9bab9..b1953701583ba88c524368a52988fea6fb1ab8d2 100644
|
||||
index 16b2ca8c96e9561aa57e0903d1e98e6441044b6d..939400c18eb4e87e0bf1b131e1601f4dcaa4885c 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -298,6 +298,7 @@ public class ServerEntity {
|
||||
@@ -297,6 +297,7 @@ public class ServerEntity {
|
||||
this.entity.hurtMarked = false;
|
||||
this.broadcastAndSend(new ClientboundSetEntityMotionPacket(this.entity));
|
||||
}
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: hayanesuru <hayanesuru@outlook.jp>
|
||||
Date: Thu, 15 May 2025 21:11:18 +0900
|
||||
Subject: [PATCH] Optimize AttributeMap
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/Attribute.java b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
index f8419dde44ebc7324e783f8bee42132d5ec973c3..406767c60ec1a324faaf5d3658b161647497f99b 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
@@ -16,10 +16,15 @@ public class Attribute {
|
||||
private boolean syncable;
|
||||
private final String descriptionId;
|
||||
private Attribute.Sentiment sentiment = Attribute.Sentiment.POSITIVE;
|
||||
+ // Leaf start - Optimize AttributeMap
|
||||
+ public final int uid;
|
||||
+ private static final java.util.concurrent.atomic.AtomicInteger SIZE = new java.util.concurrent.atomic.AtomicInteger();
|
||||
+ // Leaf end - Optimize AttributeMap
|
||||
|
||||
protected Attribute(String descriptionId, double defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.descriptionId = descriptionId;
|
||||
+ this.uid = SIZE.getAndAdd(1); // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public double getDefaultValue() {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
index 701025715e0aca3c1f920a66f9b3d03ec08eaf02..1ef934b02bd99c0fe997e9ec163457b39dba55f0 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
@@ -15,12 +15,12 @@ import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class AttributeMap {
|
||||
// Gale start - Lithium - replace AI attributes with optimized collections
|
||||
- private final Map<Holder<Attribute>, AttributeInstance> attributes = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
|
||||
+ private final Map<Holder<Attribute>, AttributeInstance> attributes = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap(); // Leaf - Optimize AttributeMap
|
||||
private final Set<AttributeInstance> attributesToSync = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
private final Set<AttributeInstance> attributesToUpdate = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
// Gale end - Lithium - replace AI attributes with optimized collections
|
||||
private final AttributeSupplier supplier;
|
||||
- private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations
|
||||
+ //private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations // Leaf - Optimize AttributeMap
|
||||
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
|
||||
|
||||
public AttributeMap(AttributeSupplier supplier) {
|
||||
@@ -31,7 +31,7 @@ public class AttributeMap {
|
||||
this.entity = entity;
|
||||
// Purpur end - Ridables
|
||||
this.supplier = defaultAttributes;
|
||||
- this.createInstance = holder -> this.supplier.createInstance(this::onAttributeModified, holder); // Gale - Airplane - reduce entity allocations
|
||||
+ //this.createInstance = holder -> this.supplier.createInstance(this::onAttributeModified, holder); // Gale - Airplane - reduce entity allocations // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
private void onAttributeModified(AttributeInstance instance) {
|
||||
@@ -55,7 +55,17 @@ public class AttributeMap {
|
||||
|
||||
@Nullable
|
||||
public AttributeInstance getInstance(Holder<Attribute> attribute) {
|
||||
- return this.attributes.computeIfAbsent(attribute, this.createInstance); // Gale - Airplane - reduce entity allocations - cache lambda, as for some reason java allocates it anyways
|
||||
+ // Leaf start - Optimize AttributeMap
|
||||
+ AttributeInstance v;
|
||||
+ if ((v = this.attributes.get(attribute)) == null) {
|
||||
+ AttributeInstance newValue;
|
||||
+ if ((newValue = this.supplier.createInstance(this::onAttributeModified, attribute)) != null) {
|
||||
+ this.attributes.put(attribute, newValue);
|
||||
+ return newValue;
|
||||
+ }
|
||||
+ }
|
||||
+ return v;
|
||||
+ // Leaf end - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public boolean hasAttribute(Holder<Attribute> attribute) {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
index 24710041ccbc70e5506d8d89ae34f0141977f209..09341ef6c651150aba223689badbead490162b2b 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
@@ -11,7 +11,7 @@ public class AttributeSupplier {
|
||||
private final Map<Holder<Attribute>, AttributeInstance> instances;
|
||||
|
||||
AttributeSupplier(Map<Holder<Attribute>, AttributeInstance> instances) {
|
||||
- this.instances = instances;
|
||||
+ this.instances = new org.dreeam.leaf.util.map.AttributeInstanceArrayMap(instances); // Leaf - Optimize AttributeMap
|
||||
}
|
||||
|
||||
public AttributeInstance getAttributeInstance(Holder<Attribute> attribute) {
|
||||
@@ -94,10 +94,10 @@ index 0f9d18dd29e210ad656da211a3cb1cb25cd4efb1..d1c36cd17c83e7e0167046093c4a2b84
|
||||
|
||||
for (LevelChunk levelChunk : list) {
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index a753481afe02a2367c378c7f39206fde23eda00d..753b4255d9e9b9628bc5825a6b4f0f2540f06e7a 100644
|
||||
index db3bff36c812a00fc35ebcc6ac6d11ce24040003..e8706189de80a2f0e60882fff0fe891165050f38 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1367,13 +1367,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1371,13 +1371,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Paper end - log detailed entity tick information
|
||||
|
||||
public void tickNonPassenger(Entity entity) {
|
||||
@@ -111,7 +111,7 @@ index a753481afe02a2367c378c7f39206fde23eda00d..753b4255d9e9b9628bc5825a6b4f0f25
|
||||
entity.setOldPosAndRot();
|
||||
entity.tickCount++;
|
||||
entity.totalEntityAge++; // Paper - age-like counter for all entities
|
||||
@@ -1386,13 +1380,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
@@ -1390,13 +1384,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
for (Entity entity1 : entity.getPassengers()) {
|
||||
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
||||
}
|
||||
@@ -4,18 +4,18 @@ Date: Fri, 23 May 2025 12:01:42 +0900
|
||||
Subject: [PATCH] Cache block path type
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/Bootstrap.java b/net/minecraft/server/Bootstrap.java
|
||||
index 83bc2f6b7774c8753a15dbeb00f0c9103713fd1b..20a720253092b4ec0b648edf06a048f92da201e0 100644
|
||||
--- a/net/minecraft/server/Bootstrap.java
|
||||
+++ b/net/minecraft/server/Bootstrap.java
|
||||
@@ -60,6 +60,7 @@ public class Bootstrap {
|
||||
io.papermc.paper.world.worldgen.OptionallyFlatBedrockConditionSource.bootstrap(); // Paper - Flat bedrock generator settings
|
||||
});
|
||||
// Paper end
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 595284787053a5fb7385e8493953c73a19fe7aee..6dec45b376288638433f0d50e474f9713266d99c 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -360,6 +360,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
|
||||
if (org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled) mobSpawnExecutor.start(); // Pufferfish
|
||||
+ net.minecraft.world.level.block.Blocks.initPathType(); // Leaf - Cache path type
|
||||
CreativeModeTabs.validate();
|
||||
wrapStreams();
|
||||
bootstrapDuration.set(Duration.between(instant, Instant.now()).toMillis());
|
||||
org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur - Implement TPSBar
|
||||
if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur - Give bee counts in beehives to Purpur clients
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/Blocks.java b/net/minecraft/world/level/block/Blocks.java
|
||||
index 303bd27d44e4acfee49334235a6704724e3fd616..d001d0859c9508eb06f05010ab1cb8069f9b87cf 100644
|
||||
--- a/net/minecraft/world/level/block/Blocks.java
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
|
||||
Date: Sat, 17 Feb 2024 17:57:08 -0500
|
||||
Subject: [PATCH] Rail Optimization: optimized PoweredRailBlock logic
|
||||
|
||||
Original project: https://github.com/FxMorin/RailOptimization
|
||||
|
||||
Full Rewrite of the powered rail iteration logic
|
||||
that makes powered/activator rails turning on/off up to 4x faster.
|
||||
This rewrite brings a massive performance boost while keeping the vanilla order. This is achieved by running all the
|
||||
powered rail logic from a single rail instead of each block iterating separately. Which was not only very
|
||||
expensive but also completely unnecessary and with a lot of massive overhead
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/PoweredRailBlock.java b/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
index a2202d2b4352be07b2445064339c61ba6a2521c7..abf0ffa3540963f591f428876c0c671517594c89 100644
|
||||
--- a/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
+++ b/net/minecraft/world/level/block/PoweredRailBlock.java
|
||||
@@ -122,6 +122,12 @@ public class PoweredRailBlock extends BaseRailBlock {
|
||||
|
||||
@Override
|
||||
protected void updateState(BlockState state, Level level, BlockPos pos, Block block) {
|
||||
+ // Leaf start - Rail Optimization
|
||||
+ if (org.dreeam.leaf.config.modules.opt.OptimizedPoweredRails.enabled) {
|
||||
+ org.dreeam.leaf.world.block.OptimizedPoweredRails.updateState(this, state, level, pos);
|
||||
+ return;
|
||||
+ }
|
||||
+ // Leaf end - Rail Optimization
|
||||
boolean poweredValue = state.getValue(POWERED);
|
||||
boolean flag = level.hasNeighborSignal(pos)
|
||||
|| this.findPoweredRailSignal(level, pos, state, true, 0)
|
||||
@@ -71,8 +71,21 @@ index 2a63e8e725fa97da5d4b9fba6bfe19377c7cfbe1..0c286eabd8e4d5e599d93a151874af6b
|
||||
set.add(connection.getPlayer().getBukkitEntity().getPlayer());
|
||||
}
|
||||
return set;
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
index cab15624afaeaca5d69206a0b7fff5da54e5ef29..4533fbbbc35ed92177f7704f243a1614a1773ca1 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
|
||||
@@ -2892,7 +2892,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
|
||||
Iterator<AttributeInstance> iterator = collection.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AttributeInstance genericInstance = iterator.next();
|
||||
- if (genericInstance.getAttribute() == Attributes.MAX_HEALTH) {
|
||||
+ if (genericInstance != null && genericInstance.getAttribute() == Attributes.MAX_HEALTH) { // Leaf - Multithreaded tracker
|
||||
iterator.remove();
|
||||
break;
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
index 3a3fbbfa0b82092cd9ac8eab2d179fb9f590aec8..566eab1add471266c8617747c8c25ee04e13c02f 100644
|
||||
index 5300a513a295d472752d31a6e8af48bb64b06704..fec0f3b72c1808c5019e95760e3fef19c45e1be0 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -1751,6 +1751,26 @@ public class CraftEventFactory {
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com>
|
||||
Date: Thu, 24 Apr 2025 16:36:16 -0400
|
||||
Subject: [PATCH] Paw optimization
|
||||
|
||||
Some random optimizations
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
||||
index 34a2e07dabc546799df6881de30252397d856f05..d8aca1d7ffad3eccaae676263a41a9a1f04988b9 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/block/data/CraftBlockData.java
|
||||
@@ -244,13 +244,37 @@ public class CraftBlockData implements BlockData {
|
||||
|
||||
if (!states.isEmpty()) {
|
||||
stateString.append('[');
|
||||
- stateString.append(states.entrySet().stream().map(StateHolder.PROPERTY_ENTRY_TO_STRING_FUNCTION).collect(Collectors.joining(",")));
|
||||
+ // Leaf start - paw optimization
|
||||
+ int i = 0;
|
||||
+ for (Map.Entry<Property<?>, Comparable<?>> propertyEntry : states.entrySet()) {
|
||||
+ if (propertyEntry == null) {
|
||||
+ stateString.append("<NULL>");
|
||||
+ } else {
|
||||
+ Property<?> property = propertyEntry.getKey();
|
||||
+ Comparable<?> value = propertyEntry.getValue();
|
||||
+
|
||||
+ stateString.append(property.getName()).append("=").append(getValueName(property, value));
|
||||
+ }
|
||||
+
|
||||
+ if (i < states.size() - 1) {
|
||||
+ stateString.append(",");
|
||||
+ }
|
||||
+
|
||||
+ i++;
|
||||
+ }
|
||||
+ // Leaf end - paw optimization
|
||||
stateString.append(']');
|
||||
}
|
||||
|
||||
return stateString.toString();
|
||||
}
|
||||
|
||||
+ // Leaf start - paw optimization
|
||||
+ private <T extends Comparable<T>> String getValueName(Property<T> property, Comparable<?> value) {
|
||||
+ return property.getName((T) value);
|
||||
+ }
|
||||
+ // Leaf end - paw optimization
|
||||
+
|
||||
public Map<String, String> toStates(boolean hideUnspecified) {
|
||||
return (hideUnspecified && this.parsedStates != null) ? CraftBlockData.toStates(this.parsedStates) : CraftBlockData.toStates(this.state.getValues());
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Taiyou06 <kaandindar21@gmail.com>
|
||||
Date: Sun, 1 Jun 2025 18:13:24 +0200
|
||||
Subject: [PATCH] optimise ReferenceList
|
||||
|
||||
|
||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java
|
||||
index 8df9406b77eb3c225ebf88bf76a7adb666452f3b..14ac2a533e0b882f26ee4a11f8d6bccfe752c750 100644
|
||||
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java
|
||||
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java
|
||||
@@ -47,17 +47,21 @@ public final class ReferenceList<E> implements Iterable<E> {
|
||||
|
||||
// move the object at the end to this index
|
||||
final int endIndex = --this.count;
|
||||
- final E end = (E)this.references[endIndex];
|
||||
if (index != endIndex) {
|
||||
+ // The removed element was not the last one.
|
||||
+ // Move the element that was at 'endIndex' (the old tail) to 'index'.
|
||||
+ final E end = (E)this.references[endIndex];
|
||||
// not empty after this call
|
||||
this.referenceToIndex.put(end, index); // update index
|
||||
+ this.references[index] = end;
|
||||
}
|
||||
- this.references[index] = end;
|
||||
+ // Null out the slot at 'endIndex'.
|
||||
+ // If 'index == endIndex', this was the slot of the removed element.
|
||||
+ // If 'index != endIndex', this was the original slot of the moved element 'end'.
|
||||
this.references[endIndex] = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
-
|
||||
public boolean add(final E obj) {
|
||||
final int count = this.count;
|
||||
final int currIndex = this.referenceToIndex.putIfAbsent(obj, count);
|
||||
@@ -18,7 +18,6 @@ public class AsyncGoalExecutor {
|
||||
protected final SpscIntQueue queue;
|
||||
protected final SpscIntQueue wake;
|
||||
protected final IntArrayList submit;
|
||||
private final AsyncGoalThread thread;
|
||||
private final ServerLevel world;
|
||||
private long midTickCount = 0L;
|
||||
|
||||
@@ -27,7 +26,6 @@ public class AsyncGoalExecutor {
|
||||
this.queue = new SpscIntQueue(AsyncTargetFinding.queueSize);
|
||||
this.wake = new SpscIntQueue(AsyncTargetFinding.queueSize);
|
||||
this.submit = new IntArrayList();
|
||||
this.thread = thread;
|
||||
}
|
||||
|
||||
boolean wake(int id) {
|
||||
@@ -46,7 +44,18 @@ public class AsyncGoalExecutor {
|
||||
|
||||
public final void tick() {
|
||||
batchSubmit();
|
||||
LockSupport.unpark(thread);
|
||||
while (true) {
|
||||
OptionalInt result = this.wake.recv();
|
||||
if (result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
int id = result.getAsInt();
|
||||
if (poll(id) && !this.queue.send(id)) {
|
||||
do {
|
||||
wake(id);
|
||||
} while (poll(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void batchSubmit() {
|
||||
@@ -67,18 +76,6 @@ public class AsyncGoalExecutor {
|
||||
}
|
||||
|
||||
public final void midTick() {
|
||||
while (true) {
|
||||
OptionalInt result = this.wake.recv();
|
||||
if (result.isEmpty()) {
|
||||
break;
|
||||
}
|
||||
int id = result.getAsInt();
|
||||
if (poll(id) && !this.queue.send(id)) {
|
||||
do {
|
||||
wake(id);
|
||||
} while (poll(id));
|
||||
}
|
||||
}
|
||||
if (AsyncTargetFinding.threshold <= 0L || (midTickCount % AsyncTargetFinding.threshold) == 0L) {
|
||||
batchSubmit();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.dreeam.leaf.async.chunk;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import net.minecraft.Util;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
@@ -14,13 +15,13 @@ public class AsyncChunkSend {
|
||||
public static final ExecutorService POOL = new ThreadPoolExecutor(
|
||||
1, 1, 0L, TimeUnit.MILLISECONDS,
|
||||
new LinkedBlockingQueue<>(),
|
||||
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
.setPriority(Thread.NORM_PRIORITY - 2)
|
||||
new ThreadFactoryBuilder()
|
||||
.setPriority(Thread.NORM_PRIORITY)
|
||||
.setNameFormat("Leaf Async Chunk Send Thread")
|
||||
.setUncaughtExceptionHandler(Util::onThreadException)
|
||||
.setThreadFactory(AsyncChunkSendThread::new)
|
||||
.build(),
|
||||
new ThreadPoolExecutor.DiscardPolicy()
|
||||
new ThreadPoolExecutor.CallerRunsPolicy()
|
||||
);
|
||||
public static final Logger LOGGER = LogManager.getLogger("Leaf Async Chunk Send");
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.pathfinder.Path;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.dreeam.leaf.config.modules.async.AsyncPathfinding;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -29,8 +30,8 @@ public class AsyncPathProcessor {
|
||||
private static long lastWarnMillis = System.currentTimeMillis();
|
||||
private static final ThreadPoolExecutor pathProcessingExecutor = new ThreadPoolExecutor(
|
||||
1,
|
||||
org.dreeam.leaf.config.modules.async.AsyncPathfinding.asyncPathfindingMaxThreads,
|
||||
org.dreeam.leaf.config.modules.async.AsyncPathfinding.asyncPathfindingKeepalive, TimeUnit.SECONDS,
|
||||
AsyncPathfinding.asyncPathfindingMaxThreads,
|
||||
AsyncPathfinding.asyncPathfindingKeepalive, TimeUnit.SECONDS,
|
||||
getQueueImpl(),
|
||||
new ThreadFactoryBuilder()
|
||||
.setNameFormat(THREAD_PREFIX + " Thread - %d")
|
||||
@@ -44,7 +45,7 @@ public class AsyncPathProcessor {
|
||||
public void rejectedExecution(Runnable rejectedTask, ThreadPoolExecutor executor) {
|
||||
BlockingQueue<Runnable> workQueue = executor.getQueue();
|
||||
if (!executor.isShutdown()) {
|
||||
switch (org.dreeam.leaf.config.modules.async.AsyncPathfinding.asyncPathfindingRejectPolicy) {
|
||||
switch (AsyncPathfinding.asyncPathfindingRejectPolicy) {
|
||||
case FLUSH_ALL -> {
|
||||
if (!workQueue.isEmpty()) {
|
||||
List<Runnable> pendingTasks = new ArrayList<>(workQueue.size());
|
||||
@@ -98,7 +99,7 @@ public class AsyncPathProcessor {
|
||||
}
|
||||
|
||||
private static BlockingQueue<Runnable> getQueueImpl() {
|
||||
final int queueCapacity = org.dreeam.leaf.config.modules.async.AsyncPathfinding.asyncPathfindingQueueSize;
|
||||
final int queueCapacity = AsyncPathfinding.asyncPathfindingQueueSize;
|
||||
|
||||
return new LinkedBlockingQueue<>(queueCapacity);
|
||||
}
|
||||
|
||||
@@ -32,15 +32,6 @@ public class MultithreadedTracker {
|
||||
private static long lastWarnMillis = System.currentTimeMillis();
|
||||
private static ThreadPoolExecutor TRACKER_EXECUTOR = null;
|
||||
|
||||
private record SendChanges(Object[] entities, int size) implements Runnable {
|
||||
@Override
|
||||
public void run() {
|
||||
for (int i = 0; i < size; i++) {
|
||||
((ServerEntity) entities[i]).sendDirtyEntityData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private MultithreadedTracker() {
|
||||
}
|
||||
|
||||
@@ -80,7 +71,6 @@ public class MultithreadedTracker {
|
||||
|
||||
// Move tracking to off-main
|
||||
TRACKER_EXECUTOR.execute(() -> {
|
||||
ReferenceArrayList<ServerEntity> sendDirty = new ReferenceArrayList<>();
|
||||
for (final Entity entity : trackerEntitiesRaw) {
|
||||
if (entity == null) continue;
|
||||
|
||||
@@ -88,19 +78,12 @@ public class MultithreadedTracker {
|
||||
|
||||
if (tracker == null) continue;
|
||||
|
||||
// Don't Parallel Tick Tracker of Entity
|
||||
synchronized (tracker.sync) {
|
||||
tracker.moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition()));
|
||||
synchronized (tracker) {
|
||||
var trackedChunk = nearbyPlayers.getChunk(entity.chunkPosition());
|
||||
tracker.moonrise$tick(trackedChunk);
|
||||
tracker.serverEntity.sendChanges();
|
||||
if (tracker.serverEntity.wantSendDirtyEntityData) {
|
||||
tracker.serverEntity.wantSendDirtyEntityData = false;
|
||||
sendDirty.add(tracker.serverEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!sendDirty.isEmpty()) {
|
||||
level.getServer().execute(new SendChanges(sendDirty.elements(), sendDirty.size()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -121,7 +104,7 @@ public class MultithreadedTracker {
|
||||
|
||||
if (tracker == null) continue;
|
||||
|
||||
synchronized (tracker.sync) {
|
||||
synchronized (tracker) {
|
||||
tickTask[index] = tracker.leafTickCompact(nearbyPlayers.getChunk(entity.chunkPosition()));
|
||||
sendChangesTasks[index] = () -> tracker.serverEntity.sendChanges(); // Collect send changes to task array
|
||||
}
|
||||
@@ -140,22 +123,6 @@ public class MultithreadedTracker {
|
||||
|
||||
sendChanges.run();
|
||||
}
|
||||
|
||||
ReferenceArrayList<ServerEntity> sendDirty = new ReferenceArrayList<>();
|
||||
for (final Entity entity : trackerEntitiesRaw) {
|
||||
if (entity == null) continue;
|
||||
|
||||
final ChunkMap.TrackedEntity tracker = ((EntityTrackerEntity) entity).moonrise$getTrackedEntity();
|
||||
|
||||
if (tracker == null) continue;
|
||||
if (tracker.serverEntity.wantSendDirtyEntityData) {
|
||||
tracker.serverEntity.wantSendDirtyEntityData = false;
|
||||
sendDirty.add(tracker.serverEntity);
|
||||
}
|
||||
}
|
||||
if (!sendDirty.isEmpty()) {
|
||||
level.getServer().execute(new SendChanges(sendDirty.elements(), sendDirty.size()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -227,8 +227,12 @@ public class LeafConfig {
|
||||
extraConfigs.addAll(Arrays.asList(existing.split(",")));
|
||||
}
|
||||
|
||||
// Use same way in spark's BukkitServerConfigProvider#getNestedFiles to get all world configs
|
||||
// It may spam in the spark profiler, but it's ok, since spark uses YamlConfigParser.INSTANCE to
|
||||
// get configs defined in extra config flag instead of using SplitYamlConfigParser.INSTANCE
|
||||
for (World world : Bukkit.getWorlds()) {
|
||||
extraConfigs.add(world.getWorldFolder().getName() + "/gale-world.yml"); // Gale world config
|
||||
Path galeWorldFolder = world.getWorldFolder().toPath().resolve("gale-world.yml");
|
||||
extraConfigs.add(galeWorldFolder.toString().replace("\\", "/").replace("./", "")); // Gale world config
|
||||
}
|
||||
|
||||
return extraConfigs;
|
||||
|
||||
@@ -8,15 +8,18 @@ import org.dreeam.leaf.config.annotations.Experimental;
|
||||
public class SparklyPaperParallelWorldTicking extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".parallel-world-tracking";
|
||||
} // TODO: Correct config key when stable
|
||||
return EnumConfigCategory.ASYNC.getBaseKeyName() + ".parallel-world-ticking";
|
||||
}
|
||||
|
||||
@Experimental
|
||||
public static boolean enabled = false;
|
||||
public static int threads = 8;
|
||||
public static boolean logContainerCreationStacktraces = false;
|
||||
public static boolean disableHardThrow = false;
|
||||
@Deprecated
|
||||
public static boolean runAsyncTasksSync = false;
|
||||
// STRICT, BUFFERED, DISABLED
|
||||
public static String asyncUnsafeReadHandling = "BUFFERED";
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
@@ -34,15 +37,30 @@ public class SparklyPaperParallelWorldTicking extends ConfigModules {
|
||||
} else {
|
||||
threads = 0;
|
||||
}
|
||||
|
||||
logContainerCreationStacktraces = config.getBoolean(getBasePath() + ".log-container-creation-stacktraces", logContainerCreationStacktraces);
|
||||
logContainerCreationStacktraces = enabled && logContainerCreationStacktraces;
|
||||
disableHardThrow = config.getBoolean(getBasePath() + ".disable-hard-throw", disableHardThrow);
|
||||
disableHardThrow = enabled && disableHardThrow;
|
||||
runAsyncTasksSync = config.getBoolean(getBasePath() + ".run-async-tasks-sync", runAsyncTasksSync);
|
||||
runAsyncTasksSync = enabled && runAsyncTasksSync;
|
||||
asyncUnsafeReadHandling = config.getString(getBasePath() + ".async-unsafe-read-handling", asyncUnsafeReadHandling).toUpperCase();
|
||||
|
||||
if (!asyncUnsafeReadHandling.equals("STRICT") && !asyncUnsafeReadHandling.equals("BUFFERED") && !asyncUnsafeReadHandling.equals("DISABLED")) {
|
||||
LeafConfig.LOGGER.warn("Invalid value for {}.async-unsafe-read-handling: {}, fallback to STRICT.", getBasePath(), asyncUnsafeReadHandling);
|
||||
asyncUnsafeReadHandling = "STRICT";
|
||||
}
|
||||
if (!enabled) {
|
||||
asyncUnsafeReadHandling = "DISABLED";
|
||||
}
|
||||
|
||||
runAsyncTasksSync = config.getBoolean(getBasePath() + ".run-async-tasks-sync", false); // Default to false now
|
||||
if (runAsyncTasksSync) {
|
||||
LeafConfig.LOGGER.warn("The setting '{}.run-async-tasks-sync' is deprecated. Use 'async-unsafe-read-handling: STRICT' for similar safety checks or 'BUFFERED' for buffered reads.", getBasePath());
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
LeafConfig.LOGGER.info("Using {} threads for Parallel World Ticking", threads);
|
||||
}
|
||||
|
||||
runAsyncTasksSync = enabled && runAsyncTasksSync; // Auto-disable if main feature is off
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package org.dreeam.leaf.config.modules.opt;
|
||||
|
||||
import org.dreeam.leaf.config.ConfigModules;
|
||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||
|
||||
public class OptimizedPoweredRails extends ConfigModules {
|
||||
|
||||
public String getBasePath() {
|
||||
return EnumConfigCategory.PERF.getBaseKeyName() + ".optimized-powered-rails";
|
||||
}
|
||||
|
||||
public static boolean enabled = false;
|
||||
|
||||
@Override
|
||||
public void onLoaded() {
|
||||
enabled = config().getBoolean(getBasePath(), enabled);
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import java.util.*;
|
||||
import java.util.AbstractMap.SimpleEntry;
|
||||
|
||||
// fast array backend map with O(1) get & put & remove
|
||||
public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, AttributeInstance>, Cloneable {
|
||||
public final class AttributeInstanceArrayMap implements Map<Holder<Attribute>, AttributeInstance>, Cloneable {
|
||||
|
||||
private int size = 0;
|
||||
private transient AttributeInstance[] a = new AttributeInstance[32];
|
||||
@@ -46,17 +46,17 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int size() {
|
||||
public int size() {
|
||||
return size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isEmpty() {
|
||||
public boolean isEmpty() {
|
||||
return size == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean containsKey(Object key) {
|
||||
public boolean containsKey(Object key) {
|
||||
if (key instanceof Holder<?> holder && holder.value() instanceof Attribute attribute) {
|
||||
int uid = attribute.uid;
|
||||
return uid >= 0 && uid < a.length && a[uid] != null;
|
||||
@@ -65,22 +65,22 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean containsValue(Object value) {
|
||||
for (final AttributeInstance instance : a) {
|
||||
if (Objects.equals(value, instance)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
public boolean containsValue(Object value) {
|
||||
return value instanceof AttributeInstance val && Objects.equals(getInstance(val.getAttribute().value().uid), val);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AttributeInstance get(Object key) {
|
||||
public AttributeInstance get(Object key) {
|
||||
return key instanceof Holder<?> holder && holder.value() instanceof Attribute attribute ? a[attribute.uid] : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AttributeInstance getInstance(int key) {
|
||||
return a[key];
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AttributeInstance put(@NotNull Holder<Attribute> key, AttributeInstance value) {
|
||||
public AttributeInstance put(@NotNull Holder<Attribute> key, AttributeInstance value) {
|
||||
int uid = key.value().uid;
|
||||
AttributeInstance prev = a[uid];
|
||||
setByIndex(uid, value);
|
||||
@@ -88,7 +88,7 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final AttributeInstance remove(Object key) {
|
||||
public AttributeInstance remove(Object key) {
|
||||
if (!(key instanceof Holder<?> holder) || !(holder.value() instanceof Attribute attribute)) return null;
|
||||
int uid = attribute.uid;
|
||||
AttributeInstance prev = a[uid];
|
||||
@@ -97,7 +97,7 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void putAll(@NotNull Map<? extends Holder<Attribute>, ? extends AttributeInstance> m) {
|
||||
public void putAll(@NotNull Map<? extends Holder<Attribute>, ? extends AttributeInstance> m) {
|
||||
for (AttributeInstance e : m.values()) {
|
||||
if (e != null) {
|
||||
setByIndex(e.getAttribute().value().uid, e);
|
||||
@@ -106,13 +106,13 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void clear() {
|
||||
public void clear() {
|
||||
Arrays.fill(a, null);
|
||||
size = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NotNull Set<Holder<Attribute>> keySet() {
|
||||
public @NotNull Set<Holder<Attribute>> keySet() {
|
||||
if (keys == null) {
|
||||
keys = new KeySet();
|
||||
}
|
||||
@@ -120,7 +120,7 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NotNull Collection<AttributeInstance> values() {
|
||||
public @NotNull Collection<AttributeInstance> values() {
|
||||
if (values == null) {
|
||||
values = new Values();
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NotNull Set<Entry<Holder<Attribute>, AttributeInstance>> entrySet() {
|
||||
public @NotNull Set<Entry<Holder<Attribute>, AttributeInstance>> entrySet() {
|
||||
if (entries == null) {
|
||||
entries = new EntrySet();
|
||||
}
|
||||
@@ -136,13 +136,23 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean equals(Object o) {
|
||||
if (!(o instanceof AttributeInstanceArrayMap that)) return false;
|
||||
return size == that.size && Arrays.equals(a, that.a);
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof Map<?, ?> s)) return false;
|
||||
if (s.size() != size()) return false;
|
||||
if (o instanceof AttributeInstanceArrayMap that) {
|
||||
return Arrays.equals(a, that.a);
|
||||
}
|
||||
for (Entry<?, ?> e : s.entrySet()) {
|
||||
if (!Objects.equals(get(e.getKey()), e.getValue())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int hashCode() {
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(a);
|
||||
}
|
||||
|
||||
@@ -192,7 +202,7 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
currentIndex = nextIndex;
|
||||
nextIndex = findNextOccupied(nextIndex + 1);
|
||||
return BuiltInRegistries.ATTRIBUTE.asHolderIdMap().byIdOrThrow(currentIndex);
|
||||
return BuiltInRegistries.ATTRIBUTE.get(currentIndex).orElseThrow();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -279,7 +289,7 @@ public class AttributeInstanceArrayMap implements Map<Holder<Attribute>, Attribu
|
||||
public Entry<Holder<Attribute>, AttributeInstance> next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
currentIndex = nextIndex;
|
||||
Holder<Attribute> key = BuiltInRegistries.ATTRIBUTE.asHolderIdMap().byIdOrThrow(nextIndex);
|
||||
Holder<Attribute> key = BuiltInRegistries.ATTRIBUTE.get(nextIndex).orElseThrow();
|
||||
AttributeInstance value = a[nextIndex];
|
||||
nextIndex = findNextOccupied(nextIndex + 1);
|
||||
return new SimpleEntry<>(key, value) {
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package org.dreeam.leaf.util.map;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArraySet;
|
||||
import it.unimi.dsi.fastutil.ints.IntSet;
|
||||
import net.minecraft.world.entity.ai.attributes.AttributeInstance;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.*;
|
||||
|
||||
public final class AttributeInstanceSet extends AbstractCollection<AttributeInstance> implements Set<AttributeInstance> {
|
||||
public final IntSet inner;
|
||||
public final AttributeInstanceArrayMap map;
|
||||
|
||||
public AttributeInstanceSet(AttributeInstanceArrayMap map) {
|
||||
this.map = map;
|
||||
inner = new IntArraySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(AttributeInstance instance) {
|
||||
return inner.add(instance.getAttribute().value().uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
return o instanceof AttributeInstance instance && inner.remove(instance.getAttribute().value().uid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Iterator<AttributeInstance> iterator() {
|
||||
return new CloneIterator(inner.toIntArray(), map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return inner.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return inner.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
inner.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o) {
|
||||
if (o instanceof AttributeInstance instance) {
|
||||
return inner.contains(instance.getAttribute().value().uid);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeInstance @NotNull [] toArray() {
|
||||
int[] innerClone = inner.toIntArray();
|
||||
AttributeInstance[] arr = new AttributeInstance[innerClone.length];
|
||||
for (int i = 0; i < arr.length; i++) {
|
||||
arr[i] = map.getInstance(innerClone[i]);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
@Override
|
||||
public <T> T @NotNull [] toArray(T[] a) {
|
||||
if (a == null || (a.getClass() == AttributeInstance[].class && a.length == 0)) {
|
||||
return (T[]) toArray();
|
||||
}
|
||||
if (a.length < size()) {
|
||||
a = (T[]) Array.newInstance(a.getClass().getComponentType(), size());
|
||||
}
|
||||
System.arraycopy((T[]) toArray(), 0, a, 0, size());
|
||||
if (a.length > size()) {
|
||||
a[size()] = null;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
static class CloneIterator implements Iterator<AttributeInstance> {
|
||||
private final int[] array;
|
||||
private int index = 0;
|
||||
private final AttributeInstanceArrayMap map;
|
||||
|
||||
CloneIterator(int[] array, AttributeInstanceArrayMap map) {
|
||||
this.array = array;
|
||||
this.map = map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return index < array.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeInstance next() {
|
||||
if (!hasNext()) throw new NoSuchElementException();
|
||||
return map.getInstance(array[index++]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (!(o instanceof Set<?> s)) return false;
|
||||
if (s.size() != size()) return false;
|
||||
return containsAll(s);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.dreeam.leaf.util.biome;
|
||||
package org.dreeam.leaf.world.biome;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Holder;
|
||||
@@ -0,0 +1,333 @@
|
||||
package org.dreeam.leaf.world.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.PoweredRailBlock;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.RailShape;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import static net.minecraft.world.level.block.Block.*;
|
||||
import static net.minecraft.world.level.block.PoweredRailBlock.POWERED;
|
||||
import static net.minecraft.world.level.block.PoweredRailBlock.SHAPE;
|
||||
|
||||
public class OptimizedPoweredRails {
|
||||
|
||||
private static final Direction[] EAST_WEST_DIR = new Direction[]{Direction.WEST, Direction.EAST};
|
||||
private static final Direction[] NORTH_SOUTH_DIR = new Direction[]{Direction.SOUTH, Direction.NORTH};
|
||||
|
||||
private static final int UPDATE_FORCE_PLACE = UPDATE_MOVE_BY_PISTON | UPDATE_KNOWN_SHAPE | UPDATE_CLIENTS;
|
||||
|
||||
private static int RAIL_POWER_LIMIT = 8;
|
||||
|
||||
private static void giveShapeUpdate(Level level, BlockState state, BlockPos pos, BlockPos fromPos, Direction direction) {
|
||||
BlockState oldState = level.getBlockState(pos);
|
||||
Block.updateOrDestroy(
|
||||
oldState,
|
||||
oldState.updateShape(level, level, pos, direction.getOpposite(), fromPos, state, level.random),
|
||||
level,
|
||||
pos,
|
||||
UPDATE_CLIENTS & -34,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
public static int getRailPowerLimit() {
|
||||
return RAIL_POWER_LIMIT;
|
||||
}
|
||||
|
||||
public static void setRailPowerLimit(int powerLimit) {
|
||||
RAIL_POWER_LIMIT = powerLimit;
|
||||
}
|
||||
|
||||
public static void updateState(PoweredRailBlock self, BlockState state, Level level, BlockPos pos) {
|
||||
boolean shouldBePowered = level.hasNeighborSignal(pos) ||
|
||||
self.findPoweredRailSignal(level, pos, state, true, 0) ||
|
||||
self.findPoweredRailSignal(level, pos, state, false, 0);
|
||||
if (shouldBePowered != state.getValue(POWERED)) {
|
||||
RailShape railShape = state.getValue(SHAPE);
|
||||
if (railShape.isSlope()) {
|
||||
level.setBlock(pos, state.setValue(POWERED, shouldBePowered), 3);
|
||||
level.updateNeighborsAtExceptFromFacing(pos.below(), self, Direction.UP, null);
|
||||
level.updateNeighborsAtExceptFromFacing(pos.above(), self, Direction.DOWN, null); // isSlope
|
||||
} else if (shouldBePowered) {
|
||||
powerLane(self, level, pos, state, railShape);
|
||||
} else {
|
||||
dePowerLane(self, level, pos, state, railShape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean findPoweredRailSignalFaster(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
boolean bl, int distance, RailShape shape,
|
||||
HashMap<BlockPos, Boolean> checkedPos) {
|
||||
BlockState blockState = world.getBlockState(pos);
|
||||
boolean speedCheck = checkedPos.containsKey(pos) && checkedPos.get(pos);
|
||||
if (speedCheck) {
|
||||
return world.hasNeighborSignal(pos) ||
|
||||
findPoweredRailSignalFaster(self, world, pos, blockState, bl, distance + 1, checkedPos);
|
||||
} else {
|
||||
if (blockState.is(self)) {
|
||||
RailShape railShape = blockState.getValue(SHAPE);
|
||||
if (shape == RailShape.EAST_WEST && (
|
||||
railShape == RailShape.NORTH_SOUTH ||
|
||||
railShape == RailShape.ASCENDING_NORTH ||
|
||||
railShape == RailShape.ASCENDING_SOUTH
|
||||
) || shape == RailShape.NORTH_SOUTH && (
|
||||
railShape == RailShape.EAST_WEST ||
|
||||
railShape == RailShape.ASCENDING_EAST ||
|
||||
railShape == RailShape.ASCENDING_WEST
|
||||
)) {
|
||||
return false;
|
||||
} else if (blockState.getValue(POWERED)) {
|
||||
return world.hasNeighborSignal(pos) ||
|
||||
findPoweredRailSignalFaster(self, world, pos, blockState, bl, distance + 1, checkedPos);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean findPoweredRailSignalFaster(PoweredRailBlock self, Level level,
|
||||
BlockPos pos, BlockState state, boolean bl, int distance,
|
||||
HashMap<BlockPos, Boolean> checkedPos) {
|
||||
if (distance >= RAIL_POWER_LIMIT - 1) return false;
|
||||
int i = pos.getX();
|
||||
int j = pos.getY();
|
||||
int k = pos.getZ();
|
||||
boolean bl2 = true;
|
||||
RailShape railShape = state.getValue(SHAPE);
|
||||
switch (railShape.ordinal()) {
|
||||
case 0 -> {
|
||||
if (bl) ++k;
|
||||
else --k;
|
||||
}
|
||||
case 1 -> {
|
||||
if (bl) --i;
|
||||
else ++i;
|
||||
}
|
||||
case 2 -> {
|
||||
if (bl) {
|
||||
--i;
|
||||
} else {
|
||||
++i;
|
||||
++j;
|
||||
bl2 = false;
|
||||
}
|
||||
railShape = RailShape.EAST_WEST;
|
||||
}
|
||||
case 3 -> {
|
||||
if (bl) {
|
||||
--i;
|
||||
++j;
|
||||
bl2 = false;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
railShape = RailShape.EAST_WEST;
|
||||
}
|
||||
case 4 -> {
|
||||
if (bl) {
|
||||
++k;
|
||||
} else {
|
||||
--k;
|
||||
++j;
|
||||
bl2 = false;
|
||||
}
|
||||
railShape = RailShape.NORTH_SOUTH;
|
||||
}
|
||||
case 5 -> {
|
||||
if (bl) {
|
||||
++k;
|
||||
++j;
|
||||
bl2 = false;
|
||||
} else {
|
||||
--k;
|
||||
}
|
||||
railShape = RailShape.NORTH_SOUTH;
|
||||
}
|
||||
}
|
||||
return findPoweredRailSignalFaster(
|
||||
self, level, new BlockPos(i, j, k),
|
||||
bl, distance, railShape, checkedPos
|
||||
) ||
|
||||
(bl2 && findPoweredRailSignalFaster(
|
||||
self, level, new BlockPos(i, j - 1, k),
|
||||
bl, distance, railShape, checkedPos
|
||||
));
|
||||
}
|
||||
|
||||
private static void powerLane(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
BlockState mainState, RailShape railShape) {
|
||||
world.setBlock(pos, mainState.setValue(POWERED, true), UPDATE_FORCE_PLACE);
|
||||
HashMap<BlockPos, Boolean> checkedPos = new HashMap<>();
|
||||
checkedPos.put(pos, true);
|
||||
int[] count = new int[2];
|
||||
if (railShape == RailShape.NORTH_SOUTH) { // Order: +z, -z
|
||||
for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) {
|
||||
setRailPositionsPower(self, world, pos, checkedPos, count, i, NORTH_SOUTH_DIR[i]);
|
||||
}
|
||||
updateRails(self, false, world, pos, mainState, count);
|
||||
} else if (railShape == RailShape.EAST_WEST) { // Order: -x, +x
|
||||
for (int i = 0; i < EAST_WEST_DIR.length; ++i) {
|
||||
setRailPositionsPower(self, world, pos, checkedPos, count, i, EAST_WEST_DIR[i]);
|
||||
}
|
||||
updateRails(self, true, world, pos, mainState, count);
|
||||
}
|
||||
}
|
||||
|
||||
private static void dePowerLane(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
BlockState mainState, RailShape railShape) {
|
||||
world.setBlock(pos, mainState.setValue(POWERED, false), UPDATE_FORCE_PLACE);
|
||||
int[] count = new int[2];
|
||||
if (railShape == RailShape.NORTH_SOUTH) { // Order: +z, -z
|
||||
for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) {
|
||||
setRailPositionsDePower(self, world, pos, count, i, NORTH_SOUTH_DIR[i]);
|
||||
}
|
||||
updateRails(self, false, world, pos, mainState, count);
|
||||
} else if (railShape == RailShape.EAST_WEST) { // Order: -x, +x
|
||||
for (int i = 0; i < EAST_WEST_DIR.length; ++i) {
|
||||
setRailPositionsDePower(self, world, pos, count, i, EAST_WEST_DIR[i]);
|
||||
}
|
||||
updateRails(self, true, world, pos, mainState, count);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setRailPositionsPower(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
HashMap<BlockPos, Boolean> checkedPos, int[] count, int i, Direction dir) {
|
||||
for (int z = 1; z < RAIL_POWER_LIMIT; z++) {
|
||||
BlockPos newPos = pos.relative(dir, z);
|
||||
BlockState state = world.getBlockState(newPos);
|
||||
if (checkedPos.containsKey(newPos)) {
|
||||
if (!checkedPos.get(newPos)) break;
|
||||
count[i]++;
|
||||
} else if (!state.is(self) || state.getValue(POWERED) || !(
|
||||
world.hasNeighborSignal(newPos) ||
|
||||
findPoweredRailSignalFaster(self, world, newPos, state, true, 0, checkedPos) ||
|
||||
findPoweredRailSignalFaster(self, world, newPos, state, false, 0, checkedPos)
|
||||
)) {
|
||||
checkedPos.put(newPos, false);
|
||||
break;
|
||||
} else {
|
||||
checkedPos.put(newPos, true);
|
||||
world.setBlock(newPos, state.setValue(POWERED, true), UPDATE_FORCE_PLACE);
|
||||
count[i]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setRailPositionsDePower(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
int[] count, int i, Direction dir) {
|
||||
for (int z = 1; z < RAIL_POWER_LIMIT; z++) {
|
||||
BlockPos newPos = pos.relative(dir, z);
|
||||
BlockState state = world.getBlockState(newPos);
|
||||
if (!state.is(self) || !state.getValue(POWERED) || world.hasNeighborSignal(newPos) ||
|
||||
self.findPoweredRailSignal(world, newPos, state, true, 0) ||
|
||||
self.findPoweredRailSignal(world, newPos, state, false, 0)) break;
|
||||
world.setBlock(newPos, state.setValue(POWERED, false), UPDATE_FORCE_PLACE);
|
||||
count[i]++;
|
||||
}
|
||||
}
|
||||
|
||||
private static void shapeUpdateEnd(PoweredRailBlock self, Level world, BlockPos pos, BlockState mainState,
|
||||
int endPos, Direction direction, int currentPos, BlockPos blockPos) {
|
||||
if (currentPos == endPos) {
|
||||
BlockPos newPos = pos.relative(direction, currentPos + 1);
|
||||
giveShapeUpdate(world, mainState, newPos, pos, direction);
|
||||
BlockState state = world.getBlockState(blockPos);
|
||||
if (state.is(self) && state.getValue(SHAPE).isSlope()) giveShapeUpdate(world, mainState, newPos.above(), pos, direction);
|
||||
}
|
||||
}
|
||||
|
||||
private static void neighborUpdateEnd(PoweredRailBlock self, Level world, BlockPos pos, int endPos,
|
||||
Direction direction, Block block, int currentPos, BlockPos blockPos) {
|
||||
if (currentPos == endPos) {
|
||||
BlockPos newPos = pos.relative(direction, currentPos + 1);
|
||||
world.neighborChanged(newPos, block, null);
|
||||
BlockState state = world.getBlockState(blockPos);
|
||||
if (state.is(self) && state.getValue(SHAPE).isSlope()) world.neighborChanged(newPos.above(), block, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static void updateRailsSectionEastWestShape(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
int c, BlockState mainState, Direction dir,
|
||||
int[] count, int countAmt) {
|
||||
BlockPos pos1 = pos.relative(dir, c);
|
||||
if (c == 0 && count[1] == 0) giveShapeUpdate(world, mainState, pos1.relative(dir.getOpposite()), pos, dir.getOpposite());
|
||||
shapeUpdateEnd(self, world, pos, mainState, countAmt, dir, c, pos1);
|
||||
giveShapeUpdate(world, mainState, pos1.below(), pos, Direction.DOWN);
|
||||
giveShapeUpdate(world, mainState, pos1.above(), pos, Direction.UP);
|
||||
giveShapeUpdate(world, mainState, pos1.north(), pos, Direction.NORTH);
|
||||
giveShapeUpdate(world, mainState, pos1.south(), pos, Direction.SOUTH);
|
||||
}
|
||||
|
||||
private static void updateRailsSectionNorthSouthShape(PoweredRailBlock self, Level world, BlockPos pos,
|
||||
int c, BlockState mainState, Direction dir,
|
||||
int[] count, int countAmt) {
|
||||
BlockPos pos1 = pos.relative(dir, c);
|
||||
giveShapeUpdate(world, mainState, pos1.west(), pos, Direction.WEST);
|
||||
giveShapeUpdate(world, mainState, pos1.east(), pos, Direction.EAST);
|
||||
giveShapeUpdate(world, mainState, pos1.below(), pos, Direction.DOWN);
|
||||
giveShapeUpdate(world, mainState, pos1.above(), pos, Direction.UP);
|
||||
shapeUpdateEnd(self, world, pos, mainState, countAmt, dir, c, pos1);
|
||||
if (c == 0 && count[1] == 0) giveShapeUpdate(world, mainState, pos1.relative(dir.getOpposite()), pos, dir.getOpposite());
|
||||
}
|
||||
|
||||
private static void updateRails(PoweredRailBlock self, boolean eastWest, Level world,
|
||||
BlockPos pos, BlockState mainState, int[] count) {
|
||||
if (eastWest) {
|
||||
for (int i = 0; i < EAST_WEST_DIR.length; ++i) {
|
||||
int countAmt = count[i];
|
||||
if (i == 1 && countAmt == 0) continue;
|
||||
Direction dir = EAST_WEST_DIR[i];
|
||||
Block block = mainState.getBlock();
|
||||
for (int c = countAmt; c >= i; c--) {
|
||||
BlockPos p = pos.relative(dir, c);
|
||||
if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()), block, null);
|
||||
neighborUpdateEnd(self, world, pos, countAmt, dir, block, c, p);
|
||||
world.neighborChanged(p.below(), block, null);
|
||||
world.neighborChanged(p.above(), block, null);
|
||||
world.neighborChanged(p.north(), block, null);
|
||||
world.neighborChanged(p.south(), block, null);
|
||||
BlockPos pos2 = pos.relative(dir, c).below();
|
||||
world.neighborChanged(pos2.below(), block, null);
|
||||
world.neighborChanged(pos2.north(), block, null);
|
||||
world.neighborChanged(pos2.south(), block, null);
|
||||
if (c == countAmt) world.neighborChanged(pos.relative(dir, c + 1).below(), block, null);
|
||||
if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()).below(), block, null);
|
||||
}
|
||||
for (int c = countAmt; c >= i; c--)
|
||||
updateRailsSectionEastWestShape(self, world, pos, c, mainState, dir, count, countAmt);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < NORTH_SOUTH_DIR.length; ++i) {
|
||||
int countAmt = count[i];
|
||||
if (i == 1 && countAmt == 0) continue;
|
||||
Direction dir = NORTH_SOUTH_DIR[i];
|
||||
Block block = mainState.getBlock();
|
||||
for (int c = countAmt; c >= i; c--) {
|
||||
BlockPos p = pos.relative(dir, c);
|
||||
world.neighborChanged(p.west(), block, null);
|
||||
world.neighborChanged(p.east(), block, null);
|
||||
world.neighborChanged(p.below(), block, null);
|
||||
world.neighborChanged(p.above(), block, null);
|
||||
neighborUpdateEnd(self, world, pos, countAmt, dir, block, c, p);
|
||||
if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()), block, null);
|
||||
BlockPos pos2 = pos.relative(dir, c).below();
|
||||
world.neighborChanged(pos2.west(), block, null);
|
||||
world.neighborChanged(pos2.east(), block, null);
|
||||
world.neighborChanged(pos2.below(), block, null);
|
||||
if (c == countAmt) world.neighborChanged(pos.relative(dir, c + 1).below(), block, null);
|
||||
if (c == 0 && count[1] == 0) world.neighborChanged(p.relative(dir.getOpposite()).below(), block, null);
|
||||
}
|
||||
for (int c = countAmt; c >= i; c--)
|
||||
updateRailsSectionNorthSouthShape(self, world, pos, c, mainState, dir, count, countAmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
2
todos.md
2
todos.md
@@ -13,4 +13,4 @@
|
||||
- [ ] Check Purpur's Projectile offset config, in BowItem shoot
|
||||
- [ ] Remove Gale's attribute patch
|
||||
- [ ] Check SparklyPaper's mapitem update skip
|
||||
- [ ] Update from Leaf 1.21.4 (curr commit: `a022d84c5b5b52f7e8a62f6bff774d0c23176ed5`)
|
||||
- [ ] Update from Leaf 1.21.4 (curr commit: `12711630d4ca8788366f8abd47275c4c262ff13f`)
|
||||
|
||||
Reference in New Issue
Block a user