9
0
mirror of https://github.com/Winds-Studio/Leaf.git synced 2025-12-19 15:09:25 +00:00
Files
Leaf/leaf-server/minecraft-patches/features/0085-Multithreaded-Tracker.patch
Dreeam d801e88a2a Updated Upstream (Paper/Gale/Purpur)
Upstream has released updates that appear to apply and compile correctly

Paper Changes:
PaperMC/Paper@5e2a3bc0 Call EntityChangeBlockEvent with correct block when waxing (#12154)
PaperMC/Paper@ab984a07 Always pass event block to damage source (#12158)
PaperMC/Paper@7b4d44f5 Revert "Always pass event block to damage source (#12158)"
PaperMC/Paper@e5a8ee84 Hide soul speed particles for vanished players (#12152)
PaperMC/Paper@fcb2e815 Clear lastSection on game event listener removal
PaperMC/Paper@636ae0cd Add missing Paper comments to player movement patch
PaperMC/Paper@9be4e07a Pin snapshot dependencies (#12185)
PaperMC/Paper@f12d33f0 Track codec writing
PaperMC/Paper@1d9b3994 Add config option for failed beehive release cooldowns (#12186)
PaperMC/Paper@5f2ee83e Fix first execution of async delayed/repeating tasks being sync (#12166)
PaperMC/Paper@b00875f8 Add a method on Registry to get the size (#12182)
PaperMC/Paper@ca261090 Don't process empty rcon commands (#12188)
PaperMC/Paper@a501c459 Deprecate server config getters (#12189)
PaperMC/Paper@7f3d3591 Use MiniMessage#deserialize(String, Pointered) in sendRichMessage for send messages (#12177)
PaperMC/Paper@9b9f046f Remove broken code (#12171)
PaperMC/Paper@fc56c728 Add methods for Creaking (#12094)
PaperMC/Paper@f63dbeaf Fix cancelled HangingPlaceEvent inventory desync (#12161)
PaperMC/Paper@9421f223 Make CustomArgumentType use parse(reader,source) (#12191)
PaperMC/Paper@0a6e7435 Fix invulnerability damage and armour (#12190)

Gale Changes:
Dreeam-qwq/Gale@b2c11564 Updated Upstream (Paper)
Dreeam-qwq/Gale@a9e4baae Updated Upstream (Paper)
Dreeam-qwq/Gale@32a291bc [ci/skip] Update comment

Purpur Changes:
PurpurMC/Purpur@62cbd47a Updated Upstream (Paper)
PurpurMC/Purpur@d41aaca1 Updated Upstream (Paper)
PurpurMC/Purpur@3f8e6134 Fix EntityTameEvent not being called when `always-tame-in-creative` option is enabled (#1645)
PurpurMC/Purpur@b34d675f fix `zombie_horse.spawn-chance` option not working
2025-02-27 06:03:30 -05:00

286 lines
18 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: peaches94 <peachescu94@gmail.com>
Date: Sat, 2 Jul 2022 00:35:56 -0500
Subject: [PATCH] Multithreaded Tracker
Original license: GPL v3
Original project: https://github.com/Bloom-host/Petal
Original license: GPL v3
Original project: https://github.com/TECHNOVE/Airplane-Experimental
Co-authored-by: Paul Sauve <paul@technove.co>
Co-authored-by: Kevin Raneri <kevin.raneri@gmail.com>
Co-authored-by: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com>
This patch refactored from original multithreaded tracker (Petal version),
and is derived from the Airplane fork by Paul Sauve, the tree is like:
Airplane -> Pufferfish? -> Petal -> Leaf
We made much of tracking logic asynchronously, and fixed visible issue
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/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index dd2509996bfd08e8c3f9f2be042229eac6d7692d..a35e9fae8f8da0c42f0616c4f78dc396492673aa 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -342,7 +342,7 @@ public final class RegionizedPlayerChunkLoader {
private boolean canGenerateChunks = true;
private final ArrayDeque<ChunkHolderManager.TicketOperation<?, ?>> delayedTicketOps = new ArrayDeque<>();
- private final LongOpenHashSet sentChunks = new LongOpenHashSet();
+ private final LongOpenHashSet sentChunks = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled && !org.dreeam.leaf.config.modules.async.MultithreadedTracker.compatModeEnabled ? new org.dreeam.leaf.util.map.ConcurrentLongHashSet() : new LongOpenHashSet(); // Leaf - Multithreaded tracker
private static final byte CHUNK_TICKET_STAGE_NONE = 0;
private static final byte CHUNK_TICKET_STAGE_LOADING = 1;
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 5d9d233e3a568aa6297ed9c703fa450f98158602..8986c059e7aadb58ae8d9ab7b848de10f9faa6b2 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -248,6 +248,15 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
+ // Leaf start - Multithreaded tracker
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled)
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ final ServerPlayer player = backingSet[i];
+ if (player == null) continue;
+ ++(player.mobCounts[index]);
+ }
+ else
+ // Leaf end - Multithreaded tracker
for (int i = 0, len = inRange.size(); i < len; i++) {
++(backingSet[i].mobCounts[index]);
}
@@ -951,6 +960,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper end - optimise entity tracker
protected void tick() {
+ // Leaf start - Multithreaded tracker
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled) {
+ final ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel level = this.level;
+ org.dreeam.leaf.async.tracker.MultithreadedTracker.tick(level);
+ return;
+ }
+ // Leaf end - Multithreaded tracker
// Paper start - optimise entity tracker
if (true) {
this.newTrackerTick();
@@ -1073,7 +1089,7 @@ 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
+ public final Set<ServerPlayerConnection> seenBy = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl // Leaf - petal - Multithreaded tracker
// Paper start - optimise entity tracker
private long lastChunkUpdate = -1L;
@@ -1100,7 +1116,39 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.lastTrackedChunk = chunk;
final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
+ final int playersLen = players.size(); // Ensure length won't change in the future tasks
+
+ // Leaf start - Multithreaded tracker
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled && org.dreeam.leaf.config.modules.async.MultithreadedTracker.compatModeEnabled) {
+ final boolean isServerPlayer = this.entity instanceof ServerPlayer;
+ final boolean isRealPlayer = isServerPlayer && ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer) this.entity).moonrise$isRealPlayer();
+ Runnable updatePlayerTasks = () -> {
+ for (int i = 0; i < playersLen; ++i) {
+ final ServerPlayer player = playersRaw[i];
+ this.updatePlayer(player);
+ }
+ if (lastChunkUpdate != currChunkUpdate || lastTrackedChunk != chunk) {
+ // need to purge any players possible not in the chunk list
+ for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
+ final ServerPlayer player = conn.getPlayer();
+ if (!players.contains(player)) {
+ this.removePlayer(player);
+ }
+ }
+ }
+ };
+
+ // Only update asynchronously for real player, and sync update for fake players
+ // This can fix compatibility issue with NPC plugins using real entity type, like Citizens
+ // To prevent visible issue with player type NPCs
+ // btw, still recommend to use packet based NPC plugins, like ZNPC Plus, Adyeshach, Fancy NPC, etc.
+ if (isRealPlayer || !isServerPlayer) {
+ org.dreeam.leaf.async.tracker.MultithreadedTracker.getTrackerExecutor().execute(updatePlayerTasks);
+ } else {
+ updatePlayerTasks.run();
+ }
+ } else {
for (int i = 0, len = players.size(); i < len; ++i) {
final ServerPlayer player = playersRaw[i];
this.updatePlayer(player);
@@ -1115,6 +1163,8 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
}
}
+ }
+ // Leaf end - Multithreaded tracker
}
@Override
@@ -1176,7 +1226,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public void broadcast(Packet<?> packet) {
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) {// Leaf - petal - Multithreaded tracker
serverPlayerConnection.send(packet);
}
}
@@ -1189,21 +1239,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public void broadcastRemoved() {
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) {// Leaf - petal - Multithreaded tracker
this.serverEntity.removePairing(serverPlayerConnection.getPlayer());
}
}
public void removePlayer(ServerPlayer player) {
- org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
+ //org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot // Leaf - petal - Multithreaded tracker - We can remove async too
if (this.seenBy.remove(player.connection)) {
this.serverEntity.removePairing(player);
}
}
public void updatePlayer(ServerPlayer player) {
- org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
+ //org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot // Leaf - petal - Multithreaded tracker - We can update async
if (player != this.entity) {
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled && player == null) return; // Leaf - Multithreaded tracker
// Paper start - remove allocation of Vec3D here
// Vec3 vec3 = player.position().subtract(this.entity.position());
double vec3_dx = player.getX() - this.entity.getX();
diff --git a/net/minecraft/server/level/ServerBossEvent.java b/net/minecraft/server/level/ServerBossEvent.java
index f106373ef3ac4a8685c2939c9e8361688a285913..51ae390c68e7a3aa193329cc3bc47ca675930ff2 100644
--- a/net/minecraft/server/level/ServerBossEvent.java
+++ b/net/minecraft/server/level/ServerBossEvent.java
@@ -13,7 +13,7 @@ import net.minecraft.util.Mth;
import net.minecraft.world.BossEvent;
public class ServerBossEvent extends BossEvent {
- private final Set<ServerPlayer> players = Sets.newHashSet();
+ private final Set<ServerPlayer> players = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled ? Sets.newConcurrentHashSet() : Sets.newHashSet(); // Leaf - petal - Multithreaded tracker - players can be removed in async tracking
private final Set<ServerPlayer> unmodifiablePlayers = Collections.unmodifiableSet(this.players);
public boolean visible = true;
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
index d8298c7925e3bcea07ead4d438478cc51abcfa16..75670751064add901c2628d53d8028350f966c5d 100644
--- a/net/minecraft/server/level/ServerEntity.java
+++ b/net/minecraft/server/level/ServerEntity.java
@@ -110,8 +110,16 @@ public class ServerEntity {
.forEach(
removedPassenger -> {
if (removedPassenger instanceof ServerPlayer serverPlayer1) {
- serverPlayer1.connection
- .teleport(serverPlayer1.getX(), serverPlayer1.getY(), serverPlayer1.getZ(), serverPlayer1.getYRot(), serverPlayer1.getXRot());
+ // Leaf start - Multithreaded tracker - Ensure teleport is executed on server thread
+ if (org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled && Thread.currentThread() instanceof org.dreeam.leaf.async.tracker.MultithreadedTracker.MultithreadedTrackerThread) {
+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> serverPlayer1.connection
+ .teleport(serverPlayer1.getX(), serverPlayer1.getY(), serverPlayer1.getZ(), serverPlayer1.getYRot(), serverPlayer1.getXRot())
+ );
+ } else {
+ serverPlayer1.connection
+ .teleport(serverPlayer1.getX(), serverPlayer1.getY(), serverPlayer1.getZ(), serverPlayer1.getYRot(), serverPlayer1.getXRot());
+ }
+ // Leaf end - Multithreaded tracker - Ensure teleport is executed on server thread
}
}
);
@@ -435,12 +443,15 @@ public class ServerEntity {
if (this.entity instanceof LivingEntity) {
Set<AttributeInstance> attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync();
if (!attributesToSync.isEmpty()) {
+ // Leaf start - petal - Multithreaded tracker - send in main thread
+ final Set<AttributeInstance> copy = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(attributesToSync);
// CraftBukkit start - Send scaled max health
if (this.entity instanceof ServerPlayer serverPlayer) {
- serverPlayer.getBukkitEntity().injectScaledMaxHealth(attributesToSync, false);
+ serverPlayer.getBukkitEntity().injectScaledMaxHealth(copy, false);
}
// CraftBukkit end
- this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync));
+ this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy));
+ // Leaf end - petal - Multithreaded tracker - send in main thread
}
attributesToSync.clear();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 34276e9a114ae70bc109d68d44b2f545cd10db88..5423d8228c1da56135ae32b958f432d5b94707ed 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -2496,7 +2496,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public LevelEntityGetter<Entity> getEntities() {
- org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
+ //org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot // Leaf - Multithreaded tracker
return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system
}
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 74e2435f09f12f20ce9ad61c7688ac93a06846d5..7c3043961540eb4c4acbc705c62e7cb6996a512f 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1816,7 +1816,7 @@ public class ServerGamePacketListenerImpl
}
public void internalTeleport(PositionMoveRotation posMoveRotation, Set<Relative> relatives) {
- org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper
+ //org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper // Leaf - Multithreaded tracker
// 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/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
index 8013594bb4844e7a8abf28123958e7f632d39341..ceff383d565267edd13a6d9006030b8e1f8053e3 100644
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
@@ -24,8 +24,11 @@ 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 boolean multiThreadedTrackingEnabled = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled;
+ private final Map<ResourceLocation, AttributeModifier> modifierById = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new Object2ObjectArrayMap<>();
+ private final Map<ResourceLocation, AttributeModifier> permanentModifiers = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new Object2ObjectArrayMap<>();
+ // Leaf end - Multithreaded tracker
private double baseValue;
private boolean dirty = true;
private double cachedValue;
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
index 89f4c5b2d61e27acd48063f9f24ce9ea91898b8b..371dd51c62c9a109014851c8a1562a5cb78b18b6 100644
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
@@ -19,11 +19,14 @@ import org.slf4j.Logger;
public class AttributeMap {
private static final Logger LOGGER = LogUtils.getLogger();
+ // Leaf start - Multithreaded tracker
+ private final boolean multiThreadedTrackingEnabled = org.dreeam.leaf.config.modules.async.MultithreadedTracker.enabled;
// 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);
+ private final Map<Holder<Attribute>, AttributeInstance> attributes = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
+ private final Set<AttributeInstance> attributesToSync = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
+ private final Set<AttributeInstance> attributesToUpdate = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
// Gale end - Lithium - replace AI attributes with optimized collections
+ // Leaf end - Multithreaded tracker
private final AttributeSupplier supplier;
private final java.util.function.Function<Holder<Attribute>, AttributeInstance> createInstance; // Gale - Airplane - reduce entity allocations
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables