From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: wangxyper Date: Mon, 9 Jan 2023 09:26:38 +0800 Subject: [PATCH] Hearse: Update codes Original license: MIT Original project: https://github.com/NaturalCodeClub/HearseRewrite diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java index 06f55f26eb63e356b3558622bf68711f18cda1c6..2a43625d13d7aa253c15aba8092ac9361785a5f0 100644 --- a/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java +++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThread.java @@ -3,8 +3,11 @@ package co.earthme.hearse.concurrent; import io.papermc.paper.util.TickThread; public class WorkerThread extends TickThread { + public WorkerThread(String name) { super(name); + this.setDaemon(true); + this.setPriority(Thread.NORM_PRIORITY - 2); } public static boolean isWorker(){ diff --git a/src/main/java/co/earthme/hearse/concurrent/WorkerThreadFactory.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..e65b1eba68003a9f7ce5080d07a521817831ff48 --- /dev/null +++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadFactory.java @@ -0,0 +1,5 @@ +package co.earthme.hearse.concurrent; + +public interface WorkerThreadFactory { + WorkerThread getNewThread(Runnable task); +} diff --git a/src/main/java/co/earthme/hearse/concurrent/ThreadPool.java b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java similarity index 62% rename from src/main/java/co/earthme/hearse/concurrent/ThreadPool.java rename to src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java index 3fbc81cb880cf6d38bb4c940b4cc1fa828c2ef17..f7ca6d650d9089b65137d61acca64c89e5b4db22 100644 --- a/src/main/java/co/earthme/hearse/concurrent/ThreadPool.java +++ b/src/main/java/co/earthme/hearse/concurrent/WorkerThreadPoolExecutor.java @@ -6,25 +6,17 @@ import java.util.Queue; import java.util.concurrent.*; import java.util.concurrent.locks.LockSupport; -public class ThreadPool extends ThreadPoolExecutor { - public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); - } - - public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue, @NotNull ThreadFactory threadFactory) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory); - } +public class WorkerThreadPoolExecutor extends ThreadPoolExecutor { + private final Queue taskEntries = new ConcurrentLinkedQueue<>(); - public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue, @NotNull RejectedExecutionHandler handler) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler); + public WorkerThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue, @NotNull WorkerThreadFactory workerThreadFactory) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,r->workerThreadFactory.getNewThread(r)); } - public ThreadPool(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue, @NotNull ThreadFactory threadFactory, @NotNull RejectedExecutionHandler handler) { - super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); + public WorkerThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, @NotNull TimeUnit unit, @NotNull BlockingQueue workQueue, @NotNull WorkerThreadFactory workerThreadFactory, @NotNull RejectedExecutionHandler handler) { + super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,r->workerThreadFactory.getNewThread(r), handler); } - private final Queue taskEntries = new ConcurrentLinkedQueue<>(); - public void executeWithSubTask(Runnable mainTask,Runnable subTask){ final TaskEntry wrapped = new TaskEntry(subTask,mainTask); this.taskEntries.offer(wrapped); diff --git a/src/main/java/co/earthme/hearse/server/ServerHook.java b/src/main/java/co/earthme/hearse/server/ServerHook.java new file mode 100644 index 0000000000000000000000000000000000000000..22260735664d986fed6bf82e4016b647417e1932 --- /dev/null +++ b/src/main/java/co/earthme/hearse/server/ServerHook.java @@ -0,0 +1,66 @@ +package co.earthme.hearse.server; + +import co.earthme.hearse.concurrent.WorkerThread; +import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.Entity; +import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +public class ServerHook { + private static volatile boolean firstTick = false; + private static final AtomicInteger threadId = new AtomicInteger(); + private static final WorkerThreadPoolExecutor worker = new WorkerThreadPoolExecutor( + Runtime.getRuntime().availableProcessors(), + Runtime.getRuntime().availableProcessors(), + 100, + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), + task -> { + WorkerThread workerThread = new WorkerThread("Hearse-Worker-Thread # "+threadId.getAndIncrement()); + return workerThread; + } + ); + + public static void executeAsyncTask(Runnable task){ + worker.execute(task); + } + + public static void executeAsyncTaskWithMainThreadCallback(Runnable task,Runnable callBack){ + worker.executeWithSubTask(task,callBack); + } + + public static void callPostTick(){ + if (!firstTick){ + firstTick = true; + return; + } + worker.runAllSubTasks(); + } + + public static void callAsyncEntityTick(Entity entity, ServerLevel level){ + MinecraftServer.getServer().executeMidTickTasks(); + worker.execute(()->{ + entity.activatedPriorityReset = false; + if (!entity.isRemoved()) { + entity.checkDespawn(); + Entity entity1 = entity.getVehicle(); + if (entity1 != null) { + if (!entity1.isRemoved() && entity1.hasPassenger(entity)) { + return; + } + entity.stopRiding(); + } + try { + level.tickNonPassenger(entity); + } catch (Throwable throwable) { + if (throwable instanceof ThreadDeath) throw throwable; + level.getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(throwable.getMessage(), throwable))); + throwable.printStackTrace(); + } + } + }); + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java index 3b7e4b724e86518ea57f5ed5ef0b8b3741d10f6f..e0e169a4403926ff6be004de1bf5ec2079acb440 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1,5 +1,6 @@ package net.minecraft.server; +import co.earthme.hearse.server.ServerHook; import com.google.common.base.Splitter; import com.google.common.collect.ImmutableList; import co.aikar.timings.Timings; @@ -1407,6 +1408,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop= 5000000000L) { this.lastServerStatus = i; this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount())); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java index a2935994edc279d880ff26dd5cc4e33f1105acc8..81697ea6d00967852556c3bb741317db030c24db 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -833,12 +833,10 @@ public class ServerChunkCache extends ChunkSource { if (chunkMap.playerMobDistanceMap != null && _pufferfish_spawnCountsReady.getAndSet(false)) { net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> { int mapped = distanceManager.getNaturalSpawnChunkCount(); - io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator objectiterator = - level.entityTickList.entities.iterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); + Iterator objectiterator = level.entityTickList.entities.iterator(); gg.pufferfish.pufferfish.util.IterableWrapper wrappedIterator = new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator); lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true); - objectiterator.finishedIterating(); _pufferfish_spawnCountsReady.set(true); }); } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 6074956d677542a46066dc45ceda9d73a2e09d27..125e5fb54acb68d58ea9fb973894b02facb04edc 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -1,6 +1,8 @@ package net.minecraft.server.level; import co.aikar.timings.TimingHistory; +import co.earthme.hearse.concurrent.WorkerThread; +import co.earthme.hearse.server.ServerHook; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Lists; import com.google.common.collect.Sets; @@ -221,7 +223,7 @@ public class ServerLevel extends Level implements WorldGenLevel { public final void loadChunksForMoveAsync(AABB axisalignedbb, ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority priority, java.util.function.Consumer> onLoad) { - if (Thread.currentThread() != this.thread) { + if (Thread.currentThread() != this.thread && !WorkerThread.isWorker()) { this.getChunkSource().mainThreadProcessor.execute(() -> { this.loadChunksForMoveAsync(axisalignedbb, priority, onLoad); }); @@ -643,71 +645,15 @@ public class ServerLevel extends Level implements WorldGenLevel { //timings.doSounds.stopTiming(); // Spigot // Purpur this.handlingTick = false; //gameprofilerfiller.pop(); // Purpur - boolean flag = true || !this.players.isEmpty() || !this.getForcedChunks().isEmpty(); // CraftBukkit - this prevents entity cleanup, other issues on servers with no players - - if (flag) { - this.resetEmptyTime(); - } - - if (flag || this.emptyTime++ < 300) { - //gameprofilerfiller.push("entities"); // Purpur - //timings.tickEntities.startTiming(); // Spigot // Purpur - if (this.dragonFight != null) { - //gameprofilerfiller.push("dragonFight"); // Purpur - this.dragonFight.tick(); - //gameprofilerfiller.pop(); // Purpur - } - - org.spigotmc.ActivationRange.activateEntities(this); // Spigot - //timings.entityTick.startTiming(); // Spigot // Purpur - this.entityTickList.forEach((entity) -> { - entity.activatedPriorityReset = false; // Pufferfish - DAB - if (!entity.isRemoved()) { - if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed - entity.discard(); - } else { - //gameprofilerfiller.push("checkDespawn"); // Purpur - entity.checkDespawn(); - //gameprofilerfiller.pop(); // Purpur - if (true || this.chunkSource.chunkMap.getDistanceManager().inEntityTickingRange(entity.chunkPosition().toLong())) { // Paper - now always true if in the ticking list - Entity entity1 = entity.getVehicle(); - - if (entity1 != null) { - if (!entity1.isRemoved() && entity1.hasPassenger(entity)) { - return; - } - - entity.stopRiding(); - } - - //gameprofilerfiller.push("tick"); // Purpur - // Pufferfish start - copied from this.guardEntityTick - try { - this.tickNonPassenger(entity); // Pufferfish - changed - MinecraftServer.getServer().executeMidTickTasks(); // Tuinity - execute chunk tasks mid tick - } catch (Throwable throwable) { - if (throwable instanceof ThreadDeath) throw throwable; // Paper - // Paper start - Prevent tile entity and entity crashes - final String msg = String.format("Entity threw exception at %s:%s,%s,%s", entity.level.getWorld().getName(), entity.getX(), entity.getY(), entity.getZ()); - MinecraftServer.LOGGER.error(msg, throwable); - getCraftServer().getPluginManager().callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerInternalException(msg, throwable))); - entity.discard(); - // Paper end - } - // Pufferfish end - //gameprofilerfiller.pop(); // Purpur - } - } - } - }); - //timings.entityTick.stopTiming(); // Spigot // Purpur - //timings.tickEntities.stopTiming(); // Spigot // Purpur - //gameprofilerfiller.pop(); // Purpur - this.tickBlockEntities(); + this.resetEmptyTime(); + if (this.dragonFight != null) { + this.dragonFight.tick(); } - - //gameprofilerfiller.push("entityManagement"); // Purpur - //this.entityManager.tick(); // Paper - rewrite chunk system + org.spigotmc.ActivationRange.activateEntities(this); // Spigot + this.entityTickList.forEach((entity) -> { + ServerHook.callAsyncEntityTick(entity,this); + }); + this.tickBlockEntities(); } @Override @@ -746,7 +692,7 @@ public class ServerLevel extends Level implements WorldGenLevel { } - private boolean shouldDiscardEntity(Entity entity) { + public boolean shouldDiscardEntity(Entity entity) { return !this.server.isSpawningAnimals() && (entity instanceof Animal || entity instanceof WaterAnimal) ? true : !this.server.areNpcsEnabled() && entity instanceof Npc; } diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java index 958e0ee29915bddde2cb8ebfd578448b83e2b149..de78c5bdde53b4adfed9fda4d473560849bdb5aa 100644 --- a/src/main/java/net/minecraft/world/level/Level.java +++ b/src/main/java/net/minecraft/world/level/Level.java @@ -2,6 +2,7 @@ package net.minecraft.world.level; import co.aikar.timings.Timing; import co.aikar.timings.Timings; +import co.earthme.hearse.concurrent.WorkerThread; import com.destroystokyo.paper.event.server.ServerExceptionEvent; import com.destroystokyo.paper.exception.ServerInternalException; import com.google.common.base.MoreObjects; @@ -1116,7 +1117,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable { } // Paper end // CraftBukkit end - return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system + return this.isOutsideBuildHeight(blockposition) ? null : (!this.isClientSide && !io.papermc.paper.util.TickThread.isTickThread() && !WorkerThread.isWorker() ? null : this.getChunkAt(blockposition).getBlockEntity(blockposition, LevelChunk.EntityCreationType.IMMEDIATE)); // Paper - rewrite chunk system } public void setBlockEntity(BlockEntity blockEntity) {