From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 Date: Sat, 27 Apr 2024 12:36:55 +0000 Subject: [PATCH] KioCG Chunk API diff --git a/src/main/java/com/kiocg/ChunkHot.java b/src/main/java/com/kiocg/ChunkHot.java new file mode 100644 index 0000000000000000000000000000000000000000..53b4397997bc9b9b9d88e48304b37a2590161906 --- /dev/null +++ b/src/main/java/com/kiocg/ChunkHot.java @@ -0,0 +1,90 @@ +package com.kiocg; + +import java.util.Arrays; + +public class ChunkHot { + // 热度统计总区间数量 + private static final int TIMES_LENGTH = 10; + // 当前统计区间下标 + private int index = -1; + + // 热度统计区间 + private final long[] times = new long[TIMES_LENGTH]; + // 存放临时的区间数值 + // 用于修正正在统计的当前区间热度没有计入总值的问题 + private long temp; + // 所有区间的热度总值 + private long total; + + // 用于每个具体统计的计算 + private long nanos; + // 当前统计是否进行中 + private volatile boolean started = false; + + /** + * 更新区间下标 + */ + public void nextTick() { + this.index = ++this.index % TIMES_LENGTH; + } + + /** + * 开始统计一个新区间 + */ + public void start() { + started = true; + temp = times[this.index]; + times[this.index] = 0L; + } + + public boolean isStarted(){ + return this.started; + } + + /** + * 结束当前区间的统计 + * 将统计值更新入热度总值 + */ + public void stop() { + started = false; + total -= temp; + total += times[this.index]; + } + + /** + * 开始一个具体统计 + */ + public void startTicking() { + if (!started) return; + nanos = System.nanoTime(); + } + + /** + * 结束一个具体统计 + * 将统计值计入当前热度区间 + */ + public void stopTickingAndCount() { + if (!started) return; + // 定义一个具体统计的最大值为 1,000,000 + // 有时候某个具体统计的计算值会在某1刻飙升,可能是由于保存数据到磁盘? + times[this.index] += Math.min(System.nanoTime() - nanos, 1000000L); + } + + /** + * 清空统计 (当区块卸载时) + */ + public void clear() { + started = false; + Arrays.fill(times, 0L); + temp = 0L; + total = 0L; + nanos = 0L; + } + + /** + * @return 获取区块热度平均值 + */ + public long getAverage() { + return total / ((long) TIMES_LENGTH * 20L); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 8ea86315e09a6b182bab03ee902ef92c5e18d962..d933895e833bea1720cc32256e98e0fe3638f4eb 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1654,6 +1654,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop chunkIterator = region.world.getCurrentWorldData().getChunks().unsafeIterator(); + while (chunkIterator.hasNext()){ + final net.minecraft.world.level.chunk.LevelChunk targetChunk = chunkIterator.next(); + + targetChunk.getChunkHot().nextTick(); + targetChunk.getChunkHot().start(); + } + } + //KioCG end // Folia - region threading if (region == null) this.tickRateManager.tick(); // Folia - region threading this.tickChildren(shouldKeepTicking, region); // Folia - region threading @@ -1663,6 +1674,20 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop chunkIterator = region.world.getCurrentWorldData().getChunks().unsafeIterator(); + while (chunkIterator.hasNext()){ + final net.minecraft.world.level.chunk.LevelChunk targetChunk = chunkIterator.next(); + + if (!targetChunk.getChunkHot().isStarted()){ + continue; + } + + targetChunk.getChunkHot().stop(); + } + } + //KioCG end // Paper start - Incremental chunk and player saving int playerSaveInterval = io.papermc.paper.configuration.GlobalConfiguration.get().playerAutoSave.rate; if (playerSaveInterval < 0) { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 3f394934e64df09e65b86d61a1dcabd3c6031a38..ba33c107cfbe9920fc33375daf8e6b62cc794d98 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1542,6 +1542,8 @@ public class ServerLevel extends Level implements WorldGenLevel { final int timerId = isActive ? entity.getType().tickTimerId : entity.getType().inactiveTickTimerId; final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); profiler.startTimer(timerId); + LevelChunk levelChunk = entity.shouldTickHot() ? this.getChunkIfLoaded(entity.sectionX,entity.sectionZ) : null; // KioCG + if (levelChunk != null) levelChunk.getChunkHot().startTicking(); try { // KioCG // Folia end - timer try { // Paper end - timings @@ -1569,6 +1571,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } else { entity.inactiveTick(); } // Paper - EAR 2 this.getProfiler().pop(); } finally { timer.stopTiming(); profiler.stopTimer(timerId); } // Paper - timings // Folia - timer + } finally { if (levelChunk != null) levelChunk.getChunkHot().stopTickingAndCount(); } // KioCG Iterator iterator = entity.getPassengers().iterator(); while (iterator.hasNext()) { @@ -1597,6 +1600,8 @@ public class ServerLevel extends Level implements WorldGenLevel { final ca.spottedleaf.leafprofiler.RegionizedProfiler.Handle profiler = io.papermc.paper.threadedregions.TickRegionScheduler.getProfiler(); profiler.startTimer(timerId); // Folia end - timer + LevelChunk levelChunk = !(passenger instanceof Player) ? this.getChunkIfLoaded(passenger.blockPosition()) : null; // KioCG + if (levelChunk != null) levelChunk.getChunkHot().startTicking(); try { // KioCG try { // Paper end passenger.setOldPosAndRot(); @@ -1637,6 +1642,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } } finally { timer.stopTiming(); profiler.stopTimer(timerId); }// Paper - EAR2 timings // Folia - timer + } finally { if (levelChunk != null) levelChunk.getChunkHot().stopTickingAndCount(); } // KioCG } } else { passenger.stopRiding(); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java index 6357440e89ffddfc61de767e4a1bfdbbb9d854b3..c25261e2c5313aedeae813b5f439a5b29a0ffcbb 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -335,6 +335,25 @@ public class ServerPlayer extends Player { public boolean handlingMoveEvent = false; //Luminol end + // KioCG start - ChunkHot + private long nearbyChunkHot = 0; + + public long getNearbyChunkHot() { return this.nearbyChunkHot; } + + private long refreshNearbyChunkHot() { + long total = 0L; + for (int i = this.sectionX - 4; i <= this.sectionX + 4; ++i) { + for (int j = this.sectionZ - 4; j <= this.sectionZ + 4; ++j) { + net.minecraft.world.level.chunk.LevelChunk targetChunk = this.level().getChunkIfLoaded(i, j); + if (targetChunk != null) { + total += targetChunk.getChunkHot().getAverage(); + } + } + } + return total; + } + // KioCG end + public ServerPlayer(MinecraftServer server, ServerLevel world, GameProfile profile, ClientInformation clientOptions) { super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); this.chatVisibility = ChatVisiblity.FULL; @@ -873,6 +892,12 @@ public class ServerPlayer extends Player { this.trackStartFallingPosition(); this.trackEnteredOrExitedLavaOnVehicle(); this.advancements.flushDirty(this); + + // KioCG start - ChunkHot + if (this.tickCount % 20 == 0){ + this.nearbyChunkHot = this.refreshNearbyChunkHot(); + } + // KioCG end } public void doTick() { diff --git a/src/main/java/net/minecraft/world/entity/AreaEffectCloud.java b/src/main/java/net/minecraft/world/entity/AreaEffectCloud.java index 094ab43e5a209ea848bf0994db9018281c64e08d..e2084013770e78d006ddd9547f6c9040aceb22c9 100644 --- a/src/main/java/net/minecraft/world/entity/AreaEffectCloud.java +++ b/src/main/java/net/minecraft/world/entity/AreaEffectCloud.java @@ -498,4 +498,11 @@ public class AreaEffectCloud extends Entity implements TraceableEntity { public EntityDimensions getDimensions(Pose pose) { return EntityDimensions.scalable(this.getRadius() * 2.0F, 0.5F); } + + // KioCG start + @Override + public boolean shouldTickHot() { + return false; + } + // KioCG end } diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java index 82ffe6571b06a482296fb28e37aa148daf6a0ce6..9293fb2dec97e6c6bf5abe5eb7d1878bb7f200d1 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -5898,4 +5898,6 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S return ((net.minecraft.server.level.ServerChunkCache) level.getChunkSource()).isPositionTicking(this); } // Paper end - Expose entity id counter + + public boolean shouldTickHot() { return this.tickCount > 20 * 10 && this.isAlive(); } // KioCG } diff --git a/src/main/java/net/minecraft/world/entity/LightningBolt.java b/src/main/java/net/minecraft/world/entity/LightningBolt.java index 0a8a53710c693a220e9475f6f3112b91d8209c00..5053852c72b68db41a2f51a72fffa1f8fe09b8da 100644 --- a/src/main/java/net/minecraft/world/entity/LightningBolt.java +++ b/src/main/java/net/minecraft/world/entity/LightningBolt.java @@ -287,4 +287,11 @@ public class LightningBolt extends Entity { public Stream getHitEntities() { return this.hitEntities.stream().filter(Entity::isAlive); } + + // KioCG start + @Override + public boolean shouldTickHot() { + return false; + } + // KioCG end } diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java index b3ab33fb1e77cd1f95e4669fc7c7c2a188e813ca..4c26749515f7d4508f749caf4ae90607131bed4e 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -1831,4 +1831,11 @@ public abstract class Mob extends LivingEntity implements Targeting { return itemmonsteregg == null ? null : new ItemStack(itemmonsteregg); } + + // KioCG start + @Override + public boolean shouldTickHot() { + return super.shouldTickHot() && (!this.removeWhenFarAway(0.0) || this.isPersistenceRequired() || this.requiresCustomPersistence()); + } + // KioCG end } diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java index 038de19633002e8f7c4b1ead7438cef0163456ce..c33da6894f81cc9c6641885969532633fb845594 100644 --- a/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java +++ b/src/main/java/net/minecraft/world/entity/animal/horse/TraderLlama.java @@ -166,4 +166,11 @@ public class TraderLlama extends Llama { super.start(); } } + + // KioCG start + @Override + public boolean shouldTickHot() { + return super.shouldTickHot() && !this.canDespawn(); + } + // KioCG end } diff --git a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java index 8d1cc1a644415be251f469ab1cb2ebc09fe5c3eb..32b128e4ea8fdeb55ba568f8af09abf9e80f7c42 100644 --- a/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java +++ b/src/main/java/net/minecraft/world/entity/npc/WanderingTrader.java @@ -327,4 +327,12 @@ public class WanderingTrader extends net.minecraft.world.entity.npc.AbstractVill return !pos.closerToCenterThan(this.trader.position(), proximityDistance); } } + + + // KioCG start + @Override + public boolean shouldTickHot() { + return false; + } + // KioCG end } diff --git a/src/main/java/net/minecraft/world/entity/player/Player.java b/src/main/java/net/minecraft/world/entity/player/Player.java index 579eb5a81281ca36c145153d8c24a517242ffe18..a758081a3058bee62721a0b73adbce511dcebe51 100644 --- a/src/main/java/net/minecraft/world/entity/player/Player.java +++ b/src/main/java/net/minecraft/world/entity/player/Player.java @@ -2426,4 +2426,12 @@ public abstract class Player extends LivingEntity { return this.message; } } + + + // KioCG start + @Override + public boolean shouldTickHot() { + return false; + } + // KioCG end } diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java index 11dfac223d36b0a8cbd865b3a29de15b4268eeb0..2dcfcb226bef8ca0f60ade043dcde1acc8a0811c 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java @@ -351,4 +351,11 @@ public abstract class Projectile extends Entity implements TraceableEntity { public boolean mayBreak(Level world) { return this.getType().is(EntityTypeTags.IMPACT_PROJECTILES) && world.getGameRules().getBoolean(GameRules.RULE_PROJECTILESCANBREAKBLOCKS); } + + // KioCG start + @Override + public boolean shouldTickHot() { + return false; + } + // KioCG end } diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java index 8c6ade7cf14e367d6390849ef1b2a1bfef0d52ac..a484970c122fb190155e15109781b17155f9a499 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -92,6 +92,7 @@ public class LevelChunk extends ChunkAccess { private final LevelChunkTicks blockTicks; private final LevelChunkTicks fluidTicks; public volatile FullChunkStatus chunkStatus = FullChunkStatus.INACCESSIBLE; // Paper - rewrite chunk system + private final com.kiocg.ChunkHot chunkHot = new com.kiocg.ChunkHot(); public com.kiocg.ChunkHot getChunkHot() { return this.chunkHot; } // KioCG public LevelChunk(Level world, ChunkPos pos) { this(world, pos, UpgradeData.EMPTY, new LevelChunkTicks<>(), new LevelChunkTicks<>(), 0L, (LevelChunkSection[]) null, (LevelChunk.PostLoadProcessor) null, (BlendingData) null); @@ -762,6 +763,7 @@ public class LevelChunk extends ChunkAccess { } public void onChunkNotTicking(io.papermc.paper.chunk.system.scheduling.NewChunkHolder chunkHolder) { + this.chunkHot.clear(); // KioCG io.papermc.paper.chunk.system.ChunkSystem.onChunkNotTicking(this, chunkHolder.vanillaChunkHolder); } @@ -1188,6 +1190,7 @@ public class LevelChunk extends ChunkAccess { gameprofilerfiller.push(this::getType); this.blockEntity.tickTimer.startTiming(); // Spigot + LevelChunk.this.chunkHot.startTicking(); // KioCG profiler.startTimer(timerId); try { // Folia - profiler BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); @@ -1218,6 +1221,7 @@ public class LevelChunk extends ChunkAccess { } finally { this.blockEntity.tickTimer.stopTiming(); // Spigot end + LevelChunk.this.chunkHot.stopTickingAndCount(); // KioCG } } } diff --git a/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java index 19faa8f5f891c1ffbed0af8391dee8202433c447..a3503375133e5ed14dc7092bd403f2266fffa628 100644 --- a/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java +++ b/src/main/java/net/minecraft/world/level/redstone/NeighborUpdater.java @@ -63,7 +63,10 @@ public interface NeighborUpdater { } } // CraftBukkit end + net.minecraft.world.level.chunk.LevelChunk levelChunk = world.getChunkIfLoaded(pos); // KioCG + if (levelChunk != null) levelChunk.getChunkHot().startTicking(); try { // KioCG state.neighborChanged(world, pos, sourceBlock, sourcePos, notify); + } finally { if (levelChunk != null) levelChunk.getChunkHot().stopTickingAndCount(); } // KioCG // Spigot Start } catch (StackOverflowError ex) { world.lastPhysicsProblem = new BlockPos(pos); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java index dca5f25cf331b5550e9be491b4e8a3466531e021..0dee50f136b81f788f84beeb1ad8720007736517 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java @@ -22,13 +22,7 @@ import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LightLayer; import net.minecraft.world.level.biome.Biomes; import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.chunk.ChunkAccess; -import net.minecraft.world.level.chunk.ChunkStatus; -import net.minecraft.world.level.chunk.DataLayer; -import net.minecraft.world.level.chunk.ImposterProtoChunk; -import net.minecraft.world.level.chunk.LevelChunkSection; -import net.minecraft.world.level.chunk.PalettedContainer; -import net.minecraft.world.level.chunk.PalettedContainerRO; +import net.minecraft.world.level.chunk.*; import net.minecraft.world.level.chunk.storage.ChunkSerializer; import net.minecraft.world.level.chunk.storage.EntityStorage; import net.minecraft.world.level.entity.PersistentEntitySectionManager; @@ -428,4 +422,12 @@ public class CraftChunk implements Chunk { static { Arrays.fill(FULL_LIGHT, (byte) 0xFF); } + + // KioCG start - ChunkHot + @Override + public long getChunkHotAvg() { + final LevelChunk target = this.worldServer.getChunkIfLoaded(this.x,this.z); + return target == null ? -1 : target.getChunkHot().getAverage(); + } + // KioCG end } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java index 2a5e76b1cee25b05189bb75daad4ced939bbb343..51caaac770b063a4be432b06030e325047651e91 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -3481,4 +3481,11 @@ public class CraftPlayer extends CraftHumanEntity implements Player { public void setSendViewDistance(final int viewDistance) { this.getHandle().setSendViewDistance(viewDistance); } + + // KioCG start - ChunkHot + @Override + public long getNearbyChunkHot() { + return this.getHandle().getNearbyChunkHot(); + } + // KioCG end } diff --git a/src/main/java/top/leavesmc/leaves/entity/CraftPhotographer.java b/src/main/java/top/leavesmc/leaves/entity/CraftPhotographer.java index 4f58b6623a6b5c726d718ced6ab106af3e665e35..3941f2d37bca6482e5db2d2fbe248f0faa8133ce 100644 --- a/src/main/java/top/leavesmc/leaves/entity/CraftPhotographer.java +++ b/src/main/java/top/leavesmc/leaves/entity/CraftPhotographer.java @@ -70,4 +70,11 @@ public class CraftPhotographer extends CraftPlayer implements Photographer { public String toString() { return "CraftPhotographer{" + "name=" + getName() + '}'; } + + // KioCG start - ChunkHot + @Override + public long getNearbyChunkHot() { + return this.getHandle().getNearbyChunkHot(); + } + // KioCG end }