diff --git a/patches/server/0061-Hearse-Parallel-world-ticking.patch b/patches/server/0061-Hearse-Parallel-world-ticking.patch new file mode 100644 index 00000000..5a776ea3 --- /dev/null +++ b/patches/server/0061-Hearse-Parallel-world-ticking.patch @@ -0,0 +1,223 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: wangxyper +Date: Thu, 12 Jan 2023 13:04:01 +0800 +Subject: [PATCH] Hearse: Parallel world ticking + +Original license: MIT +Original project: https://github.com/NaturalCodeClub/HearseRewrite + +diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java +index 443ac5267245c20830692b37802afd6ebdf8813b..c26511c26bd02320a55a01168f342b4b051ffdfd 100644 +--- a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java ++++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java +@@ -8,14 +8,16 @@ import java.util.concurrent.atomic.AtomicInteger; + public class DefaultWorkerFactory implements WorkerThreadFactory { + private static final AtomicInteger poolId = new AtomicInteger(); + private final AtomicInteger threadId = new AtomicInteger(); ++ private final String bound; + +- public DefaultWorkerFactory(){ ++ public DefaultWorkerFactory(String bound){ + poolId.getAndIncrement(); ++ this.bound = bound; + } + + @Override + public WorkerThread getNewThread(Runnable task) { +- final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()); ++ final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound); + if (workerThread.isDaemon()){ + workerThread.setDaemon(false); + } +diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java +index fd7912df03ae39347206fe8db2efa7a8a0e516c8..9d26ff7d07f1e972f1720f5b2d0e66d4c9c3f1e5 100644 +--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java ++++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java +@@ -18,7 +18,7 @@ import java.util.concurrent.atomic.AtomicInteger; + public class ServerEntityTickHook { + private static final Logger logger = LogManager.getLogger(); + private static volatile boolean firstTick = false; +- private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory(); ++ private static final WorkerThreadFactory defFactory = new DefaultWorkerFactory("entity"); + private static final AtomicInteger threadId = new AtomicInteger(); + private static WorkerThreadPoolExecutor worker; + private static boolean asyncEntityEnabled; +diff --git a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5670fdae5d16cbbdf605df048ae253208e49a82c +--- /dev/null ++++ b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java +@@ -0,0 +1,70 @@ ++package co.earthme.hearse.server; ++ ++import co.earthme.hearse.Hearse; ++import co.earthme.hearse.HearseConfig; ++import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor; ++import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory; ++import net.minecraft.CrashReport; ++import net.minecraft.ReportedException; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; ++ ++import java.util.concurrent.LinkedBlockingQueue; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.atomic.AtomicInteger; ++import java.util.concurrent.locks.LockSupport; ++import java.util.function.BooleanSupplier; ++ ++public class ServerLevelTickHook { ++ private static final DefaultWorkerFactory workerFactory = new DefaultWorkerFactory("world"); ++ private static WorkerThreadPoolExecutor worker; ++ private static boolean enabledParaWorld; ++ private static volatile boolean inited = false; ++ private static final AtomicInteger activeTaskCount = new AtomicInteger(); ++ ++ public static void initWorker(){ ++ enabledParaWorld = HearseConfig.getBoolean("optimizations.enableparallelworldtick",true); ++ if (enabledParaWorld){ ++ worker = new WorkerThreadPoolExecutor( ++ MinecraftServer.getServer().levels.size(), ++ MinecraftServer.getServer().levels.size(), ++ 0, ++ TimeUnit.MILLISECONDS, ++ new LinkedBlockingQueue<>(), ++ workerFactory ++ ); ++ worker.prestartAllCoreThreads(); ++ Hearse.getWorkerManager().addWorker("world",worker); ++ } ++ inited = true; ++ } ++ ++ public static boolean isInited(){ ++ return inited; ++ } ++ ++ public static void callWorldTick(ServerLevel worldserver, BooleanSupplier shouldKeepTicking){ ++ activeTaskCount.getAndIncrement(); ++ worker.execute(()->{ ++ try { ++ try { ++ worldserver.tick(shouldKeepTicking); ++ for (final io.papermc.paper.chunk.SingleThreadChunkRegionManager regionManager : worldserver.getChunkSource().chunkMap.regionManagers) { ++ regionManager.recalculateRegions(); ++ } ++ } catch (Throwable throwable) { ++ throwable.printStackTrace(); ++ } ++ worldserver.explosionDensityCache.clear(); ++ }finally { ++ activeTaskCount.getAndDecrement(); ++ } ++ }); ++ } ++ ++ public static void awaitWorldTicKTasks(){ ++ while (activeTaskCount.get() > 0){ ++ LockSupport.parkNanos("Await world ticking",1000000); ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index fe47aff8654283aa6a17a36226aa9fc7f18f9886..57bae261ee1d6db734b38dd5f67dbce98c41fc1c 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -3,6 +3,7 @@ package net.minecraft.server; + import co.earthme.hearse.Hearse; + import co.earthme.hearse.HearseConfig; + import co.earthme.hearse.server.ServerEntityTickHook; ++import co.earthme.hearse.server.ServerLevelTickHook; + import com.google.common.base.Splitter; + import com.google.common.collect.ImmutableList; + import com.google.common.collect.Lists; +@@ -223,7 +224,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop registries; +- private Map, ServerLevel> levels; ++ public Map, ServerLevel> levels; + private PlayerList playerList; + private volatile boolean running; + private volatile boolean isRestarting = false; // Paper - flag to signify we're attempting to restart +@@ -1121,6 +1122,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0; // Paper +- worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper ++ for (ServerLevel worldserver : this.getAllLevels()) { ++ worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper ++ worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper + net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper + + /*this.profiler.push(() -> { // Purpur +@@ -1534,35 +1534,9 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions ++ public final Map explosionDensityCache = Maps.newConcurrentMap(); // Paper - Optimize explosions + public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Move from Map in BlockRedstoneTorch to here + + // Paper start - fix and optimise world upgrading diff --git a/patches/server/0062-Hearse-Print-world-worker-thread-names-when-server-s.patch b/patches/server/0062-Hearse-Print-world-worker-thread-names-when-server-s.patch new file mode 100644 index 00000000..6a36fa67 --- /dev/null +++ b/patches/server/0062-Hearse-Print-world-worker-thread-names-when-server-s.patch @@ -0,0 +1,102 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: wangxyper +Date: Thu, 12 Jan 2023 13:58:20 +0800 +Subject: [PATCH] Hearse: Print world worker thread names when server started + +Original license: MIT +Original project: https://github.com/NaturalCodeClub/HearseRewrite + +diff --git a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java +index c26511c26bd02320a55a01168f342b4b051ffdfd..03a29509821a17faac2dc8ab810a2693b03bfbc6 100644 +--- a/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java ++++ b/src/main/java/co/earthme/hearse/concurrent/threadfactory/DefaultWorkerFactory.java +@@ -2,25 +2,38 @@ package co.earthme.hearse.concurrent.threadfactory; + + import co.earthme.hearse.concurrent.WorkerThread; + import co.earthme.hearse.concurrent.WorkerThreadFactory; ++import it.unimi.dsi.fastutil.objects.ObjectArrayList; ++import it.unimi.dsi.fastutil.objects.ObjectLists; + import net.minecraft.server.MinecraftServer; ++ ++import java.util.List; + import java.util.concurrent.atomic.AtomicInteger; + + public class DefaultWorkerFactory implements WorkerThreadFactory { + private static final AtomicInteger poolId = new AtomicInteger(); + private final AtomicInteger threadId = new AtomicInteger(); + private final String bound; ++ private final List createdThreads = ObjectLists.synchronize(new ObjectArrayList<>()); + + public DefaultWorkerFactory(String bound){ + poolId.getAndIncrement(); + this.bound = bound; + } + ++ public List getCreatedThreads() { ++ return this.createdThreads; ++ } ++ + @Override + public WorkerThread getNewThread(Runnable task) { +- final WorkerThread workerThread = new WorkerThread(task,"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound); +- if (workerThread.isDaemon()){ +- workerThread.setDaemon(false); +- } ++ final WorkerThread workerThread = new WorkerThread(()->{ ++ try { ++ task.run(); ++ }finally { ++ this.createdThreads.remove(Thread.currentThread()); ++ } ++ },"pool-"+poolId.get()+"-worker-"+threadId.getAndIncrement()+"-bound-"+this.bound); ++ this.createdThreads.add(workerThread); + workerThread.setDaemon(true); + workerThread.setPriority(Thread.NORM_PRIORITY - 2); + workerThread.setContextClassLoader(MinecraftServer.class.getClassLoader()); +diff --git a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java +index 5670fdae5d16cbbdf605df048ae253208e49a82c..8085eb700d8e5c20ebb5bfeceb78198c6e973019 100644 +--- a/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java ++++ b/src/main/java/co/earthme/hearse/server/ServerLevelTickHook.java +@@ -2,12 +2,15 @@ package co.earthme.hearse.server; + + import co.earthme.hearse.Hearse; + import co.earthme.hearse.HearseConfig; ++import co.earthme.hearse.concurrent.WorkerThread; + import co.earthme.hearse.concurrent.WorkerThreadPoolExecutor; + import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory; + import net.minecraft.CrashReport; + import net.minecraft.ReportedException; + import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.ServerLevel; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; + + import java.util.concurrent.LinkedBlockingQueue; + import java.util.concurrent.TimeUnit; +@@ -21,6 +24,7 @@ public class ServerLevelTickHook { + private static boolean enabledParaWorld; + private static volatile boolean inited = false; + private static final AtomicInteger activeTaskCount = new AtomicInteger(); ++ private static final Logger logger = LogManager.getLogger(); + + public static void initWorker(){ + enabledParaWorld = HearseConfig.getBoolean("optimizations.enableparallelworldtick",true); +@@ -28,13 +32,17 @@ public class ServerLevelTickHook { + worker = new WorkerThreadPoolExecutor( + MinecraftServer.getServer().levels.size(), + MinecraftServer.getServer().levels.size(), +- 0, ++ Long.MAX_VALUE, + TimeUnit.MILLISECONDS, + new LinkedBlockingQueue<>(), + workerFactory + ); ++ worker.allowCoreThreadTimeOut(true); + worker.prestartAllCoreThreads(); + Hearse.getWorkerManager().addWorker("world",worker); ++ for (Thread worker : workerFactory.getCreatedThreads()){ ++ logger.warn("World worker name:{}.This can help you to slove the lag problems when you using parallel world ticking",worker.getName()); ++ } + } + inited = true; + } diff --git a/patches/server/0061-Hearse-Fix-some-NPE-errors.patch b/patches/server/0063-Hearse-Fix-some-NPE-errors.patch similarity index 100% rename from patches/server/0061-Hearse-Fix-some-NPE-errors.patch rename to patches/server/0063-Hearse-Fix-some-NPE-errors.patch diff --git a/patches/server/0062-Hearse-Move-player-ticking-to-main-thread-and-add-lo.patch b/patches/server/0064-Hearse-Move-player-ticking-to-main-thread-and-add-lo.patch similarity index 99% rename from patches/server/0062-Hearse-Move-player-ticking-to-main-thread-and-add-lo.patch rename to patches/server/0064-Hearse-Move-player-ticking-to-main-thread-and-add-lo.patch index c53c33a5..48f00062 100644 --- a/patches/server/0062-Hearse-Move-player-ticking-to-main-thread-and-add-lo.patch +++ b/patches/server/0064-Hearse-Move-player-ticking-to-main-thread-and-add-lo.patch @@ -8,7 +8,7 @@ Original license: MIT Original project: https://github.com/NaturalCodeClub/HearseRewrite diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java -index fd7912df03ae39347206fe8db2efa7a8a0e516c8..85f92f20718ae21bffd687e00614588c771cc940 100644 +index 9d26ff7d07f1e972f1720f5b2d0e66d4c9c3f1e5..86f8afd54c0cbb449403c3f43e6880ade13cfecc 100644 --- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java +++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java @@ -8,6 +8,7 @@ import co.earthme.hearse.concurrent.threadfactory.DefaultWorkerFactory; diff --git a/patches/server/0063-Hearse-Remove-some-lock-in-ChunkEntitySlices.patch b/patches/server/0065-Hearse-Remove-some-lock-in-ChunkEntitySlices.patch similarity index 100% rename from patches/server/0063-Hearse-Remove-some-lock-in-ChunkEntitySlices.patch rename to patches/server/0065-Hearse-Remove-some-lock-in-ChunkEntitySlices.patch diff --git a/patches/server/0064-Hearse-Fix-a-dead-lock.patch b/patches/server/0066-Hearse-Fix-a-dead-lock.patch similarity index 100% rename from patches/server/0064-Hearse-Fix-a-dead-lock.patch rename to patches/server/0066-Hearse-Fix-a-dead-lock.patch diff --git a/patches/server/0065-Hearse-Fix-a-concurrent-problem.patch b/patches/server/0067-Hearse-Fix-a-concurrent-problem.patch similarity index 100% rename from patches/server/0065-Hearse-Fix-a-concurrent-problem.patch rename to patches/server/0067-Hearse-Fix-a-concurrent-problem.patch diff --git a/patches/server/0068-Hearse-Remove-a-NPE-fix.patch b/patches/server/0068-Hearse-Remove-a-NPE-fix.patch new file mode 100644 index 00000000..35ef2f31 --- /dev/null +++ b/patches/server/0068-Hearse-Remove-a-NPE-fix.patch @@ -0,0 +1,25 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: wangxyper +Date: Fri, 13 Jan 2023 15:22:42 +0800 +Subject: [PATCH] Hearse: Remove a NPE fix + +Original license: MIT +Original project: https://github.com/NaturalCodeClub/HearseRewrite + +diff --git a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +index d6951b05128fea7eb5f1b40837cea77e0c209165..26e1b4060f2a93cb659170f83e6ce64086e0eb0c 100644 +--- a/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java ++++ b/src/main/java/io/papermc/paper/chunk/system/entity/EntityLookup.java +@@ -423,10 +423,8 @@ public final class EntityLookup implements LevelEntityGetter { + final ChunkEntitySlices old = this.getChunk(entity.sectionX, entity.sectionZ); + final ChunkEntitySlices slices = this.getOrCreateChunk(newSectionX, newSectionZ); + +- if (old!=null){ +- if (!old.removeEntity(entity, entity.sectionY)) { +- LOGGER.warn("Could not remove entity " + entity + " from its old chunk section (" + entity.sectionX + "," + entity.sectionY + "," + entity.sectionZ + ") since it was not contained in the section"); +- } ++ if (!old.removeEntity(entity, entity.sectionY)) { ++ LOGGER.warn("Could not remove entity " + entity + " from its old chunk section (" + entity.sectionX + "," + entity.sectionY + "," + entity.sectionZ + ") since it was not contained in the section"); + } + + if (!slices.addEntity(entity, newSectionY)) { diff --git a/patches/server/0069-Hearse-Change-something.patch b/patches/server/0069-Hearse-Change-something.patch new file mode 100644 index 00000000..33fe3d34 --- /dev/null +++ b/patches/server/0069-Hearse-Change-something.patch @@ -0,0 +1,21 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: wangxyper +Date: Fri, 13 Jan 2023 15:25:47 +0800 +Subject: [PATCH] Hearse: Change something + +Original license: MIT +Original project: https://github.com/NaturalCodeClub/HearseRewrite + +diff --git a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java +index 86f8afd54c0cbb449403c3f43e6880ade13cfecc..c0e7a9cf79ddf00827daba0aa9c7a32fa76b0c7c 100644 +--- a/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java ++++ b/src/main/java/co/earthme/hearse/server/ServerEntityTickHook.java +@@ -88,7 +88,7 @@ public class ServerEntityTickHook { + } + } + }; +- if (!asyncEntityEnabled || entity instanceof Player){ ++ if (!asyncEntityEnabled){ + task.run(); + return; + } diff --git a/patches/server/0070-Hearse-Add-new-command.patch b/patches/server/0070-Hearse-Add-new-command.patch new file mode 100644 index 00000000..c077366a --- /dev/null +++ b/patches/server/0070-Hearse-Add-new-command.patch @@ -0,0 +1,82 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: wangxyper +Date: Fri, 13 Jan 2023 15:49:11 +0800 +Subject: [PATCH] Hearse: Add new command + +Original license: MIT +Original project: https://github.com/NaturalCodeClub/HearseRewrite + +diff --git a/src/main/java/co/earthme/hearse/Hearse.java b/src/main/java/co/earthme/hearse/Hearse.java +index 79116449c221e0748e938f40366af03f93a4ab9f..692fef51b2f15dd1ddc28773a381b9da3b42725e 100644 +--- a/src/main/java/co/earthme/hearse/Hearse.java ++++ b/src/main/java/co/earthme/hearse/Hearse.java +@@ -1,5 +1,6 @@ + package co.earthme.hearse; + ++import co.earthme.hearse.commands.EntityCountCommand; + import co.earthme.hearse.commands.WorkerCommand; + import co.earthme.hearse.server.ServerEntityTickHook; + import co.earthme.hearse.workers.WorkerThreadPoolManager; +@@ -12,6 +13,7 @@ public class Hearse { + HearseConfig.init(); + ServerEntityTickHook.init(); + MinecraftServer.getServer().server.getCommandMap().register("workers","hearse",new WorkerCommand()); ++ MinecraftServer.getServer().server.getCommandMap().register("entitycount","hearse",new EntityCountCommand()); + } + + public static void onServerStop(){ +diff --git a/src/main/java/co/earthme/hearse/commands/EntityCountCommand.java b/src/main/java/co/earthme/hearse/commands/EntityCountCommand.java +new file mode 100644 +index 0000000000000000000000000000000000000000..563485b8c657a7a96ff3a391c8fa19159e6dd8f6 +--- /dev/null ++++ b/src/main/java/co/earthme/hearse/commands/EntityCountCommand.java +@@ -0,0 +1,36 @@ ++package co.earthme.hearse.commands; ++ ++import com.google.common.collect.Maps; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.world.entity.Entity; ++import org.bukkit.ChatColor; ++import org.bukkit.command.Command; ++import org.bukkit.command.CommandSender; ++import org.jetbrains.annotations.NotNull; ++import java.util.Map; ++ ++public class EntityCountCommand extends Command { ++ public EntityCountCommand() { ++ super("entitycount"); ++ } ++ ++ @Override ++ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, @NotNull String[] args) { ++ final Map counts = Maps.newHashMap(); ++ for (ServerLevel level : MinecraftServer.getServer().getAllLevels()){ ++ for (Entity entity : level.entityTickList.entities){ ++ final String name = entity.getType().getName(); ++ if (!counts.containsKey(name)){ ++ counts.put(name,0); ++ } ++ counts.replace(name,counts.get(name)); ++ } ++ } ++ sender.sendMessage("Exists entity Counts:"); ++ for (Map.Entry entry : counts.entrySet()){ ++ sender.sendMessage(ChatColor.BLUE+String.format("%s:%s",entry.getKey(),entry.getValue())); ++ } ++ return true; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index ac92d1b36590bcc491d56a1eb442477c8f6e2d11..39c3aaf91514bd8a2f9f04496e25a6253442939f 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -146,7 +146,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + public final ServerChunkCache chunkSource; + private final MinecraftServer server; + public final PrimaryLevelData serverLevelData; // CraftBukkit - type +- final EntityTickList entityTickList; ++ public final EntityTickList entityTickList; + //public final PersistentEntitySectionManager entityManager; // Paper - rewrite chunk system + private final GameEventDispatcher gameEventDispatcher; + public boolean noSave;