Compare commits

...

2 Commits

Author SHA1 Message Date
Helvetica Volubi 42a4d18717 refactor: deprecated tickCount 2025-10-27 21:40:42 +08:00
Helvetica Volubi 2d8d7f5784 refactor: prepare to drop reuse tickCount 2025-10-27 21:11:51 +08:00
29 changed files with 40 additions and 98 deletions
@@ -1,63 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Helvetica Volubi <suisuroru@blue-millennium.fun>
Date: Sun, 28 Sep 2025 13:21:30 +0800
Subject: [PATCH] Rewrite tickCount support
diff --git a/io/papermc/paper/threadedregions/TickRegionScheduler.java b/io/papermc/paper/threadedregions/TickRegionScheduler.java
index b957585cf7cf7f845e20f59c7b355722880f3b4e..9b279d003eb9f780ed2723c98b28d9f4d6e3a281 100644
--- a/io/papermc/paper/threadedregions/TickRegionScheduler.java
+++ b/io/papermc/paper/threadedregions/TickRegionScheduler.java
@@ -412,6 +412,8 @@ public final class TickRegionScheduler {
}
// Luminol end - Add tick command support
+ MinecraftServer.getServer().handleTickCount(tickCount); // Lophine - reuse tick count
+
if (!this.tryMarkTicking()) {
if (!this.cancelled.get()) {
throw new IllegalStateException("Scheduled region should be acquirable");
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index b156b5c635f931a3d4abc0584591f90476d011a6..0c2b7aafa8ddee36d38fabd3561e6f97fce828f9 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -305,6 +305,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Folia start - regionised ticking
public final io.papermc.paper.threadedregions.RegionizedServer regionizedServer = new io.papermc.paper.threadedregions.RegionizedServer();
+ private int tickCount; // Lophine - reuse tick count
+ private final ThreadLocal<Integer> lastTickCount = ThreadLocal.withInitial(() -> 0); // Lophine - reuse tick count
@Override
public <V> CompletableFuture<V> submit(java.util.function.Supplier<V> task) {
@@ -2227,9 +2229,29 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return false;
}
+ // Lophine start - reuse tick count
public int getTickCount() {
- throw new UnsupportedOperationException(); // Folia - region threading
+ return this.tickCount;
+ }
+
+ public boolean checkTickCount(int period) {
+ return this.checkTickCount(period, this.lastTickCount.get());
+ }
+
+ public boolean checkTickCount(int period, int lastTickCount) {
+ if (this.tickCount % period == 0) {
+ return true;
+ }
+
+ int nextPeriodTick = ((lastTickCount / period) + 1) * period;
+ return nextPeriodTick < this.tickCount;
+ }
+
+ public void handleTickCount(int deltaTicks) {
+ this.lastTickCount.set(this.getTickCount());
+ this.tickCount += deltaTicks;
}
+ // Lophine end - reuse tick count
public int getSpawnProtectionRadius() {
return 16;
@@ -33,10 +33,10 @@ index 66ec0424a46dcd49cf44467357d80b1a2d84d3b2..04ae8de63af0a8abe578f14c8ef85fd4
private DisconnectionDetails disconnectionDetails;
private boolean encrypted;
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 0c2b7aafa8ddee36d38fabd3561e6f97fce828f9..e5fc1969b8af692d785214731b3f8cc47df2aa78 100644
index b156b5c635f931a3d4abc0584591f90476d011a6..81726e5782d25ff35a2bea8820a62786e46148b1 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -349,6 +349,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -347,6 +347,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
// Folia end - regionised ticking
@@ -45,7 +45,7 @@ index 0c2b7aafa8ddee36d38fabd3561e6f97fce828f9..e5fc1969b8af692d785214731b3f8cc4
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
AtomicReference<S> atomicReference = new AtomicReference<>();
@@ -1040,6 +1042,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1038,6 +1040,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Folia end - region threading
public void stopServer() {
@@ -57,7 +57,7 @@ index 0c2b7aafa8ddee36d38fabd3561e6f97fce828f9..e5fc1969b8af692d785214731b3f8cc4
// Folia start - region threading
// halt scheduler
// don't wait, we may be on a scheduler thread
@@ -1590,7 +1597,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1588,7 +1595,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
int i = this.pauseWhileEmptySeconds() * 20;
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
if (false && i > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
@@ -66,7 +66,7 @@ index 0c2b7aafa8ddee36d38fabd3561e6f97fce828f9..e5fc1969b8af692d785214731b3f8cc4
this.emptyTicks++;
} else {
this.emptyTicks = 0;
@@ -1914,6 +1921,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1912,6 +1919,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public void tickConnection() {
this.getConnection().tick();
@@ -74,7 +74,7 @@ index 0c2b7aafa8ddee36d38fabd3561e6f97fce828f9..e5fc1969b8af692d785214731b3f8cc4
}
private void synchronizeTime(ServerLevel level) {
@@ -3005,6 +3013,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2983,6 +2991,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
return 0;
}
@@ -9,7 +9,6 @@ import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.DyeColor;
import org.bukkit.command.CommandSender;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.command.ArgumentNode;
import org.leavesmc.leaves.command.CommandContext;
@@ -9,7 +9,6 @@ import fun.bm.lophine.command.counter.CounterSubCommand;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.JoinConfiguration;
import net.kyori.adventure.text.format.TextColor;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.item.DyeColor;
import org.jetbrains.annotations.NotNull;
import org.leavesmc.leaves.command.ArgumentNode;
@@ -154,7 +154,7 @@ public class ServerBot extends ServerPlayer {
this.notSleepTicks++;
}
if (FakeplayerConfig.regenAmount > 0.0 && getServer().checkTickCount(20)) {
if (FakeplayerConfig.regenAmount > 0.0 && this.tickCount % 20 == 0) {
float regenAmount = (float) (FakeplayerConfig.regenAmount * 20);
this.setHealth(Math.min(this.getHealth() + regenAmount, this.getMaxHealth()));
}
@@ -24,7 +24,6 @@ import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerPlayer;
import org.leavesmc.leaves.protocol.core.invoker.*;
import org.slf4j.Logger;
@@ -66,6 +65,8 @@ public class LeavesProtocolManager {
private static final List<EmptyInvokerHolder<ProtocolHandler.ReloadServer>> RELOAD_SERVER = new ArrayList<>();
private static final List<EmptyInvokerHolder<ProtocolHandler.ReloadDataPack>> RELOAD_DATAPACK = new ArrayList<>();
private static long lastAcceptTime = 0;
@SuppressWarnings("unchecked")
public static void init() {
for (Class<?> clazz : getClasses("org.leavesmc.leaves.protocol")) {
@@ -253,8 +254,11 @@ public class LeavesProtocolManager {
}
public static void handleTick() {
long currentTime = System.currentTimeMillis() / 50;
if (currentTime == lastAcceptTime) return;
lastAcceptTime = currentTime;
for (var tickerInfo : TICKERS) {
if (MinecraftServer.getServer().checkTickCount(tickerInfo.owner().tickerInterval(tickerInfo.handler().tickerId()))) {
if (currentTime % tickerInfo.owner().tickerInterval(tickerInfo.handler().tickerId()) == 0) {
tickerInfo.invoke();
}
}
@@ -72,12 +72,12 @@ public class ItemCollector<T> {
return null;
}
long currentVersion = iterator.getVersion(container);
long gameTime = request.getLevel().getServer().getTickCount();
long gameTimeReforged = System.currentTimeMillis() / 50;
if (mergedResult != null && iterator.isFinished()) {
if (version == currentVersion) {
return mergedResult; // content not changed
}
if (lastTimeFinished + 5 > gameTime) {
if (lastTimeFinished + 5 > gameTimeReforged) {
return mergedResult; // avoid update too frequently
}
iterator.reset();
@@ -104,7 +104,7 @@ public class ItemCollector<T> {
mergedResult = groups;
lastTimeIsEmpty = mergedResult.getFirst().views.isEmpty();
version = currentVersion;
lastTimeFinished = gameTime;
lastTimeFinished = gameTimeReforged;
items.clear();
}
return groups;
@@ -98,13 +98,13 @@ public class REIServerProtocol implements LeavesProtocol {
new ArrayBlockingQueue<>(1),
new ThreadPoolExecutor.DiscardOldestPolicy()
);
private static int minecraftRecipeVer = 0;
private static int nextReiRecipeVer = -1;
private static long minecraftRecipeVer = 0;
private static long nextReiRecipeVer = -1;
private static ImmutableList<CustomPacketPayload> cachedPayloads;
@ProtocolHandler.ReloadDataPack
public static void onRecipeReload() {
minecraftRecipeVer = MinecraftServer.getServer().getTickCount();
minecraftRecipeVer = System.currentTimeMillis() / 50;
}
@Contract("_ -> new")
@@ -138,7 +138,7 @@ public class REIServerProtocol implements LeavesProtocol {
}
@SuppressWarnings({"unchecked", "rawtypes"})
private static void reloadRecipe(int reiRecipeVer) {
private static void reloadRecipe(long reiRecipeVer) {
ImmutableList.Builder<Display> builder = ImmutableList.builder();
MinecraftServer server = MinecraftServer.getServer();
RecipeMap recipeMap = server.getRecipeManager().recipes;
@@ -61,6 +61,7 @@ public class ServuxHudDataProtocol implements LeavesProtocol {
private static final Table<DataLogger.Type, ServerPlayer, Tag> DATA = HashBasedTable.create();
public static boolean refreshSpawnMetadata = false;
private long lastAcceptTime = 0;
@ProtocolHandler.Init
private static void initializeLoggers() {
@@ -238,9 +239,12 @@ public class ServuxHudDataProtocol implements LeavesProtocol {
return;
}
MinecraftServer server = MinecraftServer.getServer();
long currentTime = System.currentTimeMillis() / 50;
if (currentTime == lastAcceptTime) return;
lastAcceptTime = currentTime;
if (server.checkTickCount(ServuxProtocolConfig.hudUpdateInterval)) {
if (currentTime % ServuxProtocolConfig.hudUpdateInterval == 0) {
MinecraftServer server = MinecraftServer.getServer();
LOGGERS.forEach((type, logger) -> {
if (!isLoggerTypeEnabled(type)) {
return;
@@ -84,7 +84,7 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
@ProtocolHandler.Ticker
public static void tick() {
MinecraftServer server = MinecraftServer.getServer();
int tickCounter = server.getTickCount();
long tickCounter = System.currentTimeMillis() / 50;
retainDistance = server.getPlayerList().getViewDistance() + 2;
for (ServerPlayer player : players.values()) {
// TODO DimensionChange
@@ -95,11 +95,11 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
public static void onStartedWatchingChunk(ServerPlayer player, LevelChunk chunk) {
MinecraftServer server = player.getServer();
if (players.containsKey(player.getId()) && server != null) {
addChunkTimeoutIfHasReferences(player.getUUID(), chunk, server.getTickCount());
addChunkTimeoutIfHasReferences(player.getUUID(), chunk, System.currentTimeMillis() / 50);
}
}
private static void addChunkTimeoutIfHasReferences(final UUID uuid, LevelChunk chunk, final int tickCounter) {
private static void addChunkTimeoutIfHasReferences(final UUID uuid, LevelChunk chunk, final long tickCounter) {
final ChunkPos pos = chunk.getPos();
if (chunkHasStructureReferences(pos.x, pos.z, chunk.getLevel())) {
@@ -135,7 +135,7 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
MinecraftServer server = MinecraftServer.getServer();
sendMetaData(player);
initialSyncStructures(player, player.moonrise$getViewDistanceHolder().getViewDistances().sendViewDistance() + 2, server.getTickCount());
initialSyncStructures(player, player.moonrise$getViewDistanceHolder().getViewDistances().sendViewDistance() + 2, System.currentTimeMillis() / 50);
}
private static void sendMetaData(ServerPlayer player) {
@@ -149,7 +149,7 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
sendPacket(player, new StructuresPayload(StructuresPayloadType.PACKET_S2C_METADATA, tag));
}
public static void initialSyncStructures(ServerPlayer player, int chunkRadius, int tickCounter) {
public static void initialSyncStructures(ServerPlayer player, int chunkRadius, long tickCounter) {
UUID uuid = player.getUUID();
ChunkPos center = player.getLastSectionPos().chunk();
Map<Structure, LongSet> references = getStructureReferences(player.level(), center, chunkRadius);
@@ -195,7 +195,7 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
}
}
public static void sendStructures(ServerPlayer player, Map<Structure, LongSet> references, int tickCounter) {
public static void sendStructures(ServerPlayer player, Map<Structure, LongSet> references, long tickCounter) {
ServerLevel world = player.level();
Map<ChunkPos, StructureStart> starts = getStructureStarts(world, references);
@@ -254,7 +254,7 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
return starts;
}
public static void refreshTrackedChunks(ServerPlayer player, int tickCounter) {
public static void refreshTrackedChunks(ServerPlayer player, long tickCounter) {
UUID uuid = player.getUUID();
Map<ChunkPos, Timeout> map = timeouts.get(uuid);
@@ -263,7 +263,7 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
}
}
public static void sendAndRefreshExpiredStructures(ServerPlayer player, Map<ChunkPos, Timeout> map, int tickCounter) {
public static void sendAndRefreshExpiredStructures(ServerPlayer player, Map<ChunkPos, Timeout> map, long tickCounter) {
Set<ChunkPos> positionsToUpdate = new HashSet<>();
for (Map.Entry<ChunkPos, Timeout> entry : map.entrySet()) {
@@ -303,7 +303,7 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
return Math.abs(pos.x - center.x) > retainDistance || Math.abs(pos.z - center.z) > retainDistance;
}
public static void addOrRefreshTimeouts(final UUID uuid, final Map<Structure, LongSet> references, final int tickCounter) {
public static void addOrRefreshTimeouts(final UUID uuid, final Map<Structure, LongSet> references, final long tickCounter) {
Map<ChunkPos, Timeout> map = timeouts.computeIfAbsent(uuid, (u) -> new HashMap<>());
for (LongSet chunks : references.values()) {
@@ -402,18 +402,17 @@ public class ServuxStructuresProtocol implements LeavesProtocol {
}
public static class Timeout {
private int lastSync;
private long lastSync;
public Timeout(int currentTick) {
public Timeout(long currentTick) {
this.lastSync = currentTick;
}
public boolean needsUpdate(int currentTick, int timeout) {
if (timeout == -1 || currentTick - this.lastSync >= timeout) return true;
return MinecraftServer.getServer().checkTickCount(timeout);
public boolean needsUpdate(int timeout, long currentTick) {
return timeout == -1 || currentTick - this.lastSync >= timeout;
}
public void setLastSync(int tickCounter) {
public void setLastSync(long tickCounter) {
this.lastSync = tickCounter;
}
}