diff --git a/docs/MODIFICATION.md b/docs/MODIFICATION.md index 27849a42..c9dc5c6c 100644 --- a/docs/MODIFICATION.md +++ b/docs/MODIFICATION.md @@ -24,3 +24,9 @@ Leaves Modification - Spectator don't get Advancement - Use stick and shift to ArmorStand can modify ArmorStand's arm status - Remove Player Chat sign + +## Performance + +> All of it will have configuration + +- Optimize mob spawning (Powered by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish)) \ No newline at end of file diff --git a/docs/MODIFICATION_cn.md b/docs/MODIFICATION_cn.md index 55a899d4..3739e9cd 100644 --- a/docs/MODIFICATION_cn.md +++ b/docs/MODIFICATION_cn.md @@ -24,3 +24,9 @@ Leaves Modification - 观察者不会获得进度 - 对盔甲架下蹲使用木棍可以修改盔甲架的手臂状态 - 删除玩家聊天内的签名 + +## 性能 + +> 所有的性能内容都会存在配置项 + +- 生物生成优化 (Powered by [Pufferfish](https://github.com/pufferfish-gg/Pufferfish)) \ No newline at end of file diff --git a/patches/server/0001-Build-changes.patch b/patches/server/0001-Build-changes.patch index 61cbf8de..482d9756 100644 --- a/patches/server/0001-Build-changes.patch +++ b/patches/server/0001-Build-changes.patch @@ -70,8 +70,34 @@ index 7b1843e16745ca8db2244e17490d291401f22679..0ac8bcb0a4b7d1da3d0e016617db7a81 metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> { Map> map = new HashMap<>(); +diff --git a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java +index c89f6986eda5a132a948732ea1b6923370685317..5a0655dabc032a29062dfdd9f9d3fc9e8d25f6b7 100644 +--- a/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java ++++ b/src/main/java/com/destroystokyo/paper/util/misc/AreaMap.java +@@ -26,7 +26,7 @@ public abstract class AreaMap { + + // we use linked for better iteration. + // map of: coordinate to set of objects in coordinate +- protected final Long2ObjectOpenHashMap> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); ++ protected Long2ObjectOpenHashMap> areaMap = new Long2ObjectOpenHashMap<>(1024, 0.7f); // Leaves - not final + protected final PooledLinkedHashSets pooledHashSets; + + protected final ChangeCallback addCallback; +diff --git a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java +index 46954db7ecd35ac4018fdf476df7c8020d7ce6c8..044c51ebb058fc36074fd178929e3279335f6c99 100644 +--- a/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java ++++ b/src/main/java/com/destroystokyo/paper/util/misc/PlayerAreaMap.java +@@ -5,7 +5,7 @@ import net.minecraft.server.level.ServerPlayer; + /** + * @author Spottedleaf + */ +-public final class PlayerAreaMap extends AreaMap { ++public class PlayerAreaMap extends AreaMap { // Leaves - not final + + public PlayerAreaMap() { + super(); diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 35a5cc8ed861401d3dd28b08ebc5d40aad82b0df..e137e18cdca9fd3d1add500a178459a93465e789 100644 +index f23be38ef96a81ce3867a3b6fdccf632fe285f31..7301c552ab695b81560eeefa44b2f29d4f4ac258 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1655,7 +1655,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop jobs = Queues.newConcurrentLinkedQueue(); ++ private final Thread thread; ++ private final BooleanSupplier shouldRun; ++ private volatile boolean killswitch = false; ++ ++ public AsyncExecutor(String threadName, BooleanSupplier shouldRun) { ++ this.thread = new Thread(this, threadName); ++ this.shouldRun = shouldRun; ++ } ++ ++ public void start() { ++ thread.start(); ++ } ++ ++ public void kill() { ++ killswitch = true; ++ } ++ ++ public void submit(Runnable runnable) { ++ jobs.offer(runnable); ++ } ++ ++ @Override ++ public void run() { ++ while (!killswitch) { ++ if (shouldRun.getAsBoolean()) { ++ try { ++ Runnable runnable; ++ while ((runnable = jobs.poll()) != null) { ++ runnable.run(); ++ } ++ } catch (Exception e) { ++ LeavesLogger.LOGGER.log(Level.SEVERE, e, () -> "Failed to execute async job for thread " + thread.getName()); ++ } ++ } ++ LockSupport.parkNanos("executing tasks", 1000L); ++ } ++ } ++} +diff --git a/src/main/java/top/leavesmc/leaves/util/AsyncPlayerAreaMap.java b/src/main/java/top/leavesmc/leaves/util/AsyncPlayerAreaMap.java +new file mode 100644 +index 0000000000000000000000000000000000000000..4ccc1b3b29e9d62526b2d7c56ef06db77704bf80 +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/util/AsyncPlayerAreaMap.java +@@ -0,0 +1,32 @@ ++package top.leavesmc.leaves.util; ++ ++import com.destroystokyo.paper.util.misc.PlayerAreaMap; ++import com.destroystokyo.paper.util.misc.PooledLinkedHashSets; ++import net.minecraft.server.level.ServerPlayer; ++ ++import java.util.concurrent.ConcurrentHashMap; ++ ++// Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) ++public class AsyncPlayerAreaMap extends PlayerAreaMap { ++ ++ public AsyncPlayerAreaMap() { ++ super(); ++ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); ++ } ++ ++ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets) { ++ super(pooledHashSets); ++ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); ++ } ++ ++ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, ++ final ChangeCallback removeCallback) { ++ this(pooledHashSets, addCallback, removeCallback, null); ++ } ++ ++ public AsyncPlayerAreaMap(final PooledLinkedHashSets pooledHashSets, final ChangeCallback addCallback, ++ final ChangeCallback removeCallback, final ChangeSourceCallback changeSourceCallback) { ++ super(pooledHashSets, addCallback, removeCallback, changeSourceCallback); ++ this.areaMap = new Long2ObjectOpenHashMapWrapper<>(new ConcurrentHashMap<>(1024, 0.7f)); ++ } ++} +diff --git a/src/main/java/top/leavesmc/leaves/util/IterableWrapper.java b/src/main/java/top/leavesmc/leaves/util/IterableWrapper.java +new file mode 100644 +index 0000000000000000000000000000000000000000..0dc58b78c84a825ec7025534cd0fc7be9c4610ad +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/util/IterableWrapper.java +@@ -0,0 +1,21 @@ ++package top.leavesmc.leaves.util; ++ ++import org.jetbrains.annotations.NotNull; ++ ++import java.util.Iterator; ++ ++// Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) ++public class IterableWrapper implements Iterable { ++ ++ private final Iterator iterator; ++ ++ public IterableWrapper(Iterator iterator) { ++ this.iterator = iterator; ++ } ++ ++ @NotNull ++ @Override ++ public Iterator iterator() { ++ return iterator; ++ } ++} +diff --git a/src/main/java/top/leavesmc/leaves/util/Long2ObjectOpenHashMapWrapper.java b/src/main/java/top/leavesmc/leaves/util/Long2ObjectOpenHashMapWrapper.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b684d8f576acbc5de8d06b0ff779c257198bc32d +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/util/Long2ObjectOpenHashMapWrapper.java +@@ -0,0 +1,41 @@ ++package top.leavesmc.leaves.util; ++ ++import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; ++import org.jetbrains.annotations.Nullable; ++ ++import java.util.Map; ++ ++public class Long2ObjectOpenHashMapWrapper extends Long2ObjectOpenHashMap { ++ ++ private final Map backingMap; ++ ++ public Long2ObjectOpenHashMapWrapper(Map map) { ++ backingMap = map; ++ } ++ ++ @Override ++ public V put(Long key, V value) { ++ return backingMap.put(key, value); ++ } ++ ++ @Override ++ public V get(Object key) { ++ return backingMap.get(key); ++ } ++ ++ @Override ++ public V remove(Object key) { ++ return backingMap.remove(key); ++ } ++ ++ @Nullable ++ @Override ++ public V putIfAbsent(Long key, V value) { ++ return backingMap.putIfAbsent(key, value); ++ } ++ ++ @Override ++ public int size() { ++ return backingMap.size(); ++ } ++} diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png index a7d785f60c884ee4ee487cc364402d66c3dc2ecc..68e9ac07245a9e4607b5e57c3511121a5651ad43 100644 GIT binary patch diff --git a/patches/server/0003-Leaves-Server-Config.patch b/patches/server/0003-Leaves-Server-Config.patch index 150162e2..6bcfed00 100644 --- a/patches/server/0003-Leaves-Server-Config.patch +++ b/patches/server/0003-Leaves-Server-Config.patch @@ -119,7 +119,7 @@ index 95f296ef42cb9f1d486962a0a31da9aa436967c7..e40978698bd76132b56d5a1bc9791f05 .withRequiredArg() diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java new file mode 100644 -index 0000000000000000000000000000000000000000..1f6bba371f827c1151984f8dc89cc461973988b9 +index 0000000000000000000000000000000000000000..ec35e33ecbba6f2cb1dcc2e739841b7e6612c9ea --- /dev/null +++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java @@ -0,0 +1,289 @@ @@ -139,7 +139,7 @@ index 0000000000000000000000000000000000000000..1f6bba371f827c1151984f8dc89cc461 +import java.util.List; +import java.util.logging.Level; + -+// Copy form Tuinity(https://github.com/Tuinity/Tuinity) ++// Powered by Tuinity(https://github.com/Tuinity/Tuinity) + +public final class LeavesConfig { + diff --git a/patches/server/0008-Add-Leaves-Command.patch b/patches/server/0008-Add-Leaves-Command.patch index a971b9aa..b61ea791 100644 --- a/patches/server/0008-Add-Leaves-Command.patch +++ b/patches/server/0008-Add-Leaves-Command.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Add Leaves Command diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 2294294bd192d380d99189a1884db7f2be885d04..026d79fb66cf96883a28e7a33707fb3116f80ab9 100644 +index 7ad3569628fd6c6ac0038394e7d88979b29935a0..d27f115b74fe00623985255d1027656166c1c459 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java @@ -228,6 +228,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -17,7 +17,7 @@ index 2294294bd192d380d99189a1884db7f2be885d04..026d79fb66cf96883a28e7a33707fb31 this.setPvpAllowed(dedicatedserverproperties.pvp); this.setFlightAllowed(dedicatedserverproperties.allowFlight); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 244c76dc3d91e4240b072c1d3077a8e0aa4dc47d..6ee113a83b3aa6668c01b0496b4097733b7ad63e 100644 +index 599ad9516e9642f774c4f8b1d60b453a775b172a..9e21aa4d6464b86923f4ccc4cdec9e3b663dd268 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -991,6 +991,7 @@ public final class CraftServer implements Server { @@ -29,7 +29,7 @@ index 244c76dc3d91e4240b072c1d3077a8e0aa4dc47d..6ee113a83b3aa6668c01b0496b409773 this.ignoreVanillaPermissions = this.commandsConfiguration.getBoolean("ignore-vanilla-permissions"); diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java -index 8999a852440c5c15dec5adf892eb60674500f70e..a85a5de7d85cf6c5e19c0245c40e6106e6623007 100644 +index b82efc14c0e7aa33260cffcfc20fa42d24e61192..393ced680a790cb6e6abf448a6c60f413ac97551 100644 --- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java +++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java @@ -4,6 +4,7 @@ import com.destroystokyo.paper.util.SneakyThrow; @@ -49,7 +49,7 @@ index 8999a852440c5c15dec5adf892eb60674500f70e..a85a5de7d85cf6c5e19c0245c40e6106 +import java.util.Map; import java.util.logging.Level; - // Copy form Tuinity(https://github.com/Tuinity/Tuinity) + // Powered by Tuinity(https://github.com/Tuinity/Tuinity) @@ -27,6 +30,7 @@ public final class LeavesConfig { public static YamlConfiguration config; private static int configVersion; diff --git a/patches/server/0019-Optimize-mob-spawning.patch b/patches/server/0019-Optimize-mob-spawning.patch new file mode 100644 index 00000000..c4141248 --- /dev/null +++ b/patches/server/0019-Optimize-mob-spawning.patch @@ -0,0 +1,170 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Sat, 13 Aug 2022 17:27:18 +0800 +Subject: [PATCH] Optimize mob spawning + +This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish) + +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index c0b82c838364b94e45138ff71b6e63bb0018287c..c754b8d88fa258e3fccd25e41a7501fc1d0b3e34 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -301,6 +301,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop true); // Leaves - optimize mob spawning ++ + public static S spin(Function serverFactory) { + AtomicReference atomicreference = new AtomicReference(); + Thread thread = new Thread(() -> { +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index b5d5c2346cad59dabffc0c378b4f9fdae90bd48e..4da748a4f6963dea6e33332fe6daf411270a0b80 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -341,6 +341,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + DedicatedServer.LOGGER.info("JMX monitoring enabled"); + } + ++ // Leaves start - optimize mob spawning ++ if (top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) { ++ mobSpawnExecutor.start(); ++ } ++ // Leaves end - optimize mob spawning + return true; + } + } +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 77c89376495d90d0e7cbf6cd02c9a1c8d9a4340b..a273dfe889ad09b733a696649c675812fa7b2db0 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -471,7 +471,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); + this.regionManagers.add(this.dataRegionManager); + // Paper end +- this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper ++ this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new top.leavesmc.leaves.util.AsyncPlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper // Leaves - optimize mob spawning(actually not use) + // Paper start - use distance map to optimise entity tracker + this.playerEntityTrackerTrackMaps = new com.destroystokyo.paper.util.misc.PlayerAreaMap[TRACKING_RANGE_TYPES.length]; + this.entityTrackerTrackRanges = new int[TRACKING_RANGE_TYPES.length]; +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index 59acbf6249f8f5285504c0ddea448a3433d1d68d..bcc24c563cc8d35bffb594b11954e916711ce971 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -76,6 +76,11 @@ public class ServerChunkCache extends ChunkSource { + + private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4]; + ++ // Leaves start - optimize countmobs ++ public boolean firstRunSpawnCounts = true; ++ public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false); ++ // Leaves end - optimize countmobs ++ + private static int getChunkCacheKey(int x, int z) { + return x & 3 | ((z & 3) << 2); + } +@@ -971,18 +976,25 @@ public class ServerChunkCache extends ChunkSource { + // Paper start - per player mob spawning + NaturalSpawner.SpawnState spawnercreature_d; // moved down + if ((this.spawnFriendlies || this.spawnEnemies) && this.chunkMap.playerMobDistanceMap != null) { // don't count mobs when animals and monsters are disabled +- // re-set mob counts +- for (ServerPlayer player : this.level.players) { +- Arrays.fill(player.mobCounts, 0); ++ // Leaves start - moved down when async processing ++ if (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) { ++ // re-set mob counts ++ for (ServerPlayer player : this.level.players) { ++ Arrays.fill(player.mobCounts, 0); ++ } ++ lastSpawnState = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true); + } +- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true); ++ // Leaves end - moved down when async processing + } else { +- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, this.chunkMap.playerMobDistanceMap == null ? new LocalMobCapCalculator(this.chunkMap) : null, false); ++ // Leaves start - this is only implemented for per-player mob spawning so this makes everything work if this setting is disabled (actually not use) ++ lastSpawnState = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, this.chunkMap.playerMobDistanceMap == null ? new LocalMobCapCalculator(this.chunkMap) : null, false); ++ spawnCountsReady.set(true); ++ // Leaves end - this is only implemented for per-player mob spawning so this makes everything work if this setting is disabled (actually not use) + } + // Paper end + this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings + +- this.lastSpawnState = spawnercreature_d; ++ // this.lastSpawnState = spawnercreature_d; // Leaves - asynchronously + gameprofilerfiller.popPush("filteringLoadedChunks"); + // Paper - moved down + this.level.timings.chunkTicks.startTiming(); // Paper +@@ -1020,8 +1032,8 @@ public class ServerChunkCache extends ChunkSource { + + if ((true || this.level.isNaturalSpawningAllowed(chunkcoordintpair)) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning // Paper - replace player chunk loader system + chunk1.incrementInhabitedTime(j); +- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration +- NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1); ++ if (flag2 && (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning || spawnCountsReady.get()) && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration // Leaves - optimize mob spawning ++ NaturalSpawner.spawnForChunk(this.level, chunk1, lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1); // Leaves - optimize mob spawning + } + + if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - replace player chunk loader system +@@ -1082,6 +1094,30 @@ public class ServerChunkCache extends ChunkSource { + } + } + // Paper end - controlled flush for entity tracker packets ++ ++ // Leaves start - optimize mob spawning ++ if (top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) { ++ for (ServerPlayer player : this.level.players) { ++ Arrays.fill(player.mobCounts, 0); ++ } ++ if (firstRunSpawnCounts) { ++ firstRunSpawnCounts = false; ++ spawnCountsReady.set(true); ++ } ++ if (chunkMap.playerMobDistanceMap != null && 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); ++ top.leavesmc.leaves.util.IterableWrapper wrappedIterator = ++ new top.leavesmc.leaves.util.IterableWrapper(objectiterator); ++ lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true); ++ objectiterator.finishedIterating(); ++ spawnCountsReady.set(true); ++ }); ++ } ++ } ++ // Leaves end - optimize mob spawning + } + } + +diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java +index 4cdfc433df67afcd455422e9baf56f167dd712ae..a6e0f5dab21d806e0c7744b2a337cded2739d870 100644 +--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java ++++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java +@@ -8,7 +8,7 @@ import javax.annotation.Nullable; + import net.minecraft.world.entity.Entity; + + public class EntityTickList { +- private final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? ++ public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? // Leaves - private -> public + + private void ensureActiveIsNotIterated() { + // Paper - replace with better logic, do not delay removals +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index bc16e5f273d570002dd6bdfb152c5a08658e47a7..f380cd6a9849391f753a1c3d9a55e6b633781425 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -190,7 +190,12 @@ public final class LeavesConfig { + private static void noChatSign() { + noChatSign = getBoolean("settings.no-chat-sign", noChatSign); + } +- ++ ++ public static boolean asyncMobSpawning = true; ++ private static void asyncMobSpawning() { ++ asyncMobSpawning = getBoolean("settings.performance.async-mob-spawning", asyncMobSpawning); ++ } ++ + public static final class WorldConfig { + + public final String worldName; diff --git a/patches/server/0020-LeavesConfig-V2.patch b/patches/server/0020-LeavesConfig-V2.patch new file mode 100644 index 00000000..9207c59b --- /dev/null +++ b/patches/server/0020-LeavesConfig-V2.patch @@ -0,0 +1,258 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: violetc <58360096+s-yh-china@users.noreply.github.com> +Date: Sat, 13 Aug 2022 17:54:19 +0800 +Subject: [PATCH] LeavesConfig V2 + + +diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +index f380cd6a9849391f753a1c3d9a55e6b633781425..c232766bda8b253988b02bc14d4659f4b5553d96 100644 +--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java ++++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java +@@ -24,7 +24,7 @@ import java.util.logging.Level; + public final class LeavesConfig { + + public static final String CONFIG_HEADER = "Configuration file for Leaves."; +- public static final int CURRENT_CONFIG_VERSION = 1; ++ public static final int CURRENT_CONFIG_VERSION = 2; + + private static final Object[] EMPTY = new Object[0]; + +@@ -59,12 +59,13 @@ public final class LeavesConfig { + if (config.contains("config-version-please-do-not-modify-me")) { + LeavesConfig.set("config-version-please-do-not-modify-me", null); + } +- LeavesConfig.configVersion = LeavesConfig.getInt("config-version", CURRENT_CONFIG_VERSION); ++ LeavesConfig.configVersion = LeavesConfig.getInt("config-version", CURRENT_CONFIG_VERSION); + LeavesConfig.set("config-version", CURRENT_CONFIG_VERSION); + +- LeavesConfig.load(config); ++ updateConfigVersion(config); ++ LeavesConfig.load(config); + +- commands = new HashMap<>(); ++ commands = new HashMap<>(); + + if (top.leavesmc.leaves.LeavesConfig.fakeplayerSupport) { + commands.put("bot", new BotCommand("bot")); +@@ -73,20 +74,20 @@ public final class LeavesConfig { + } + + public static void load(final YamlConfiguration config) { +- for (Method method : LeavesConfig.class.getDeclaredMethods()) { +- if (Modifier.isPrivate(method.getModifiers())) { +- if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { +- try { +- method.setAccessible(true); +- method.invoke(null); +- } catch (InvocationTargetException ex) { +- throw Throwables.propagate(ex.getCause()); +- } catch (Exception ex) { +- Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); +- } +- } +- } +- } ++ for (Method method : LeavesConfig.class.getDeclaredMethods()) { ++ if (Modifier.isPrivate(method.getModifiers())) { ++ if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) { ++ try { ++ method.setAccessible(true); ++ method.invoke(null); ++ } catch (InvocationTargetException ex) { ++ throw Throwables.propagate(ex.getCause()); ++ } catch (Exception ex) { ++ Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex); ++ } ++ } ++ } ++ } + + /* We re-save to add new options */ + try { +@@ -137,58 +138,79 @@ public final class LeavesConfig { + return (List) LeavesConfig.config.getList(path, config.getList(path)); + } + ++ private static void updateConfigVersion(final YamlConfiguration config) { ++ if (configVersion < CURRENT_CONFIG_VERSION) { ++ playerCanEditSign = config.getBoolean("settings.player-can-edit-sign", playerCanEditSign); ++ snowballAndEggCanKnockback = config.getBoolean("settings.snowball-and-egg-can-knockback-player", snowballAndEggCanKnockback); ++ fakeplayerSupport = config.getBoolean("settings.fakeplayer.enable", fakeplayerSupport); ++ unableFakeplayerNames = (List) config.getList("settings.fakeplayer.unable-fakeplayer-names", Arrays.asList("player-name")); ++ shearsInDispenserCanZeroAmount = config.getBoolean("settings.shears-in-dispenser-can-zero-amount", shearsInDispenserCanZeroAmount); ++ redstoneShearsWrench = config.getBoolean("settings.redstone-shears-wrench", redstoneShearsWrench); ++ buddingAmethystCanPushByPiston = config.getBoolean("settings.budding-amethyst-can-push-by-piston", buddingAmethystCanPushByPiston); ++ spectatorDontGetAdvancement = config.getBoolean("settings.spectator-dont-get-advancement", spectatorDontGetAdvancement); ++ stickChangeArmorStandArmStatus = config.getBoolean("settings.stick-change-armorstand-arm-status", stickChangeArmorStandArmStatus); ++ noChatSign = config.getBoolean("settings.no-chat-sign", noChatSign); ++ ++ config.set("settings.player-can-edit-sign", null); ++ config.set("settings.snowball-and-egg-can-knockback-player", null); ++ config.set("settings.fakeplayer", null); ++ config.set("settings.shears-in-dispenser-can-zero-amount", null); ++ config.set("settings.redstone-shears-wrench", null); ++ config.set("settings.budding-amethyst-can-push-by-piston", null); ++ config.set("settings.spectator-dont-get-advancement", null); ++ config.set("settings.stick-change-armorstand-arm-status", null); ++ config.set("settings.no-chat-sign", null); ++ } ++ } ++ + public static boolean playerCanEditSign = true; + private static void playerCanEditSign() { +- playerCanEditSign = getBoolean("settings.player-can-edit-sign", playerCanEditSign); ++ playerCanEditSign = getBoolean("settings.modify.player-can-edit-sign", playerCanEditSign); + } + + public static boolean snowballAndEggCanKnockback = true; + private static void snowballAndEggCanKnockback() { +- snowballAndEggCanKnockback = getBoolean("settings.snowball-and-egg-can-knockback-player", snowballAndEggCanKnockback); ++ snowballAndEggCanKnockback = getBoolean("settings.modify.snowball-and-egg-can-knockback-player", snowballAndEggCanKnockback); + } + + public static boolean fakeplayerSupport = true; + private static void fakeplayerSupport() { +- if (config.contains("settings.fakeplayer-support")) { +- fakeplayerSupport = LeavesConfig.config.getBoolean("settings.fakeplayer-support", fakeplayerSupport); +- LeavesConfig.config.set("settings.fakeplayer-support", null); +- } +- fakeplayerSupport = getBoolean("settings.fakeplayer.enable", fakeplayerSupport); ++ fakeplayerSupport = getBoolean("settings.modify.fakeplayer.enable", fakeplayerSupport); + } + +- public static List unableFakeplayerNames; ++ public static List unableFakeplayerNames = List.of("player-name"); + private static void unableFakeplayerNames() { +- unableFakeplayerNames = getList("settings.fakeplayer.unable-fakeplayer-names", Arrays.asList("player-name")); ++ unableFakeplayerNames = getList("settings.modify.fakeplayer.unable-fakeplayer-names", unableFakeplayerNames); + } + + public static boolean shearsInDispenserCanZeroAmount = false; + private static void shearsInDispenserCanZeroAmount() { +- shearsInDispenserCanZeroAmount = getBoolean("settings.shears-in-dispenser-can-zero-amount", shearsInDispenserCanZeroAmount); ++ shearsInDispenserCanZeroAmount = getBoolean("settings.modify.shears-in-dispenser-can-zero-amount", shearsInDispenserCanZeroAmount); + } + + public static boolean redstoneShearsWrench = true; + private static void redstoneShearsWrench() { +- redstoneShearsWrench = getBoolean("settings.redstone-shears-wrench", redstoneShearsWrench); ++ redstoneShearsWrench = getBoolean("settings.modify.redstone-shears-wrench", redstoneShearsWrench); + } + + public static boolean buddingAmethystCanPushByPiston = false; + private static void buddingAmethystCanPushByPiston() { +- buddingAmethystCanPushByPiston = getBoolean("settings.budding-amethyst-can-push-by-piston", buddingAmethystCanPushByPiston); ++ buddingAmethystCanPushByPiston = getBoolean("settings.modify.budding-amethyst-can-push-by-piston", buddingAmethystCanPushByPiston); + } + + public static boolean spectatorDontGetAdvancement = false; +- private static void spectatorDontGetAdvancement() { +- spectatorDontGetAdvancement = getBoolean("settings.spectator-dont-get-advancement", spectatorDontGetAdvancement); ++ private static void spectatorDontGetAdvancement() { ++ spectatorDontGetAdvancement = getBoolean("settings.modify.spectator-dont-get-advancement", spectatorDontGetAdvancement); + } + + public static boolean stickChangeArmorStandArmStatus = true; +- private static void stickChangeArmorStandHasArm() { +- stickChangeArmorStandArmStatus = getBoolean("settings.stick-change-armorstand-arm-status", stickChangeArmorStandArmStatus); ++ private static void stickChangeArmorStandHasArm() { ++ stickChangeArmorStandArmStatus = getBoolean("settings.modify.stick-change-armorstand-arm-status", stickChangeArmorStandArmStatus); + } + + public static boolean noChatSign = true; + private static void noChatSign() { +- noChatSign = getBoolean("settings.no-chat-sign", noChatSign); ++ noChatSign = getBoolean("settings.modify.no-chat-sign", noChatSign); + } + + public static boolean asyncMobSpawning = true; +@@ -213,7 +235,7 @@ public final class LeavesConfig { + this.worldDefaults = LeavesConfig.config.createSection("world-settings.default"); + } + +- String worldSectionPath = LeavesConfig.configVersion < 0 ? this.worldName : "world-settings.".concat(this.worldName); ++ String worldSectionPath = LeavesConfig.configVersion < CURRENT_CONFIG_VERSION ? this.worldName : "world-settings.".concat(this.worldName); + ConfigurationSection section = LeavesConfig.config.getConfigurationSection(worldSectionPath); + this.configPath = worldSectionPath; + if (LeavesConfig.createWorldSections) { +@@ -242,7 +264,7 @@ public final class LeavesConfig { + } + } + +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + ConfigurationSection oldSection = LeavesConfig.config.getConfigurationSection(this.worldName); + LeavesConfig.config.set("world-settings.".concat(this.worldName), oldSection); + LeavesConfig.config.set(this.worldName, null); +@@ -267,7 +289,7 @@ public final class LeavesConfig { + boolean getBoolean(final String path, final boolean dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); + this.worldDefaults.addDefault(path, Boolean.valueOf(dfl)); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getBoolean(path) == dfl) { + config.set(path, null); + } +@@ -277,7 +299,7 @@ public final class LeavesConfig { + + boolean getBooleanRaw(final String path, final boolean dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getBoolean(path) == dfl) { + config.set(path, null); + } +@@ -288,7 +310,7 @@ public final class LeavesConfig { + int getInt(final String path, final int dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); + this.worldDefaults.addDefault(path, Integer.valueOf(dfl)); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getInt(path) == dfl) { + config.set(path, null); + } +@@ -298,7 +320,7 @@ public final class LeavesConfig { + + int getIntRaw(final String path, final int dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getInt(path) == dfl) { + config.set(path, null); + } +@@ -309,7 +331,7 @@ public final class LeavesConfig { + long getLong(final String path, final long dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); + this.worldDefaults.addDefault(path, Long.valueOf(dfl)); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getLong(path) == dfl) { + config.set(path, null); + } +@@ -319,7 +341,7 @@ public final class LeavesConfig { + + long getLongRaw(final String path, final long dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getLong(path) == dfl) { + config.set(path, null); + } +@@ -330,7 +352,7 @@ public final class LeavesConfig { + double getDouble(final String path, final double dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); + this.worldDefaults.addDefault(path, Double.valueOf(dfl)); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getDouble(path) == dfl) { + config.set(path, null); + } +@@ -340,7 +362,7 @@ public final class LeavesConfig { + + double getDoubleRaw(final String path, final double dfl) { + final ConfigurationSection config = LeavesConfig.config.getConfigurationSection(this.configPath); +- if (LeavesConfig.configVersion < 1) { ++ if (LeavesConfig.configVersion < CURRENT_CONFIG_VERSION) { + if (config != null && config.getDouble(path) == dfl) { + config.set(path, null); + }