9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-19 14:59:25 +00:00

Merge branch 'master' into dev/1.21.5

# Conflicts:
#	divinemc-server/build.gradle.kts.patch
#	gradle.properties
This commit is contained in:
NONPLAYT
2025-04-21 16:59:22 +03:00
94 changed files with 8695 additions and 4050 deletions

View File

@@ -1,47 +0,0 @@
name: Upstream Purpur
on:
workflow_dispatch: {}
schedule:
- cron: "0 0 */3 * *"
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout DivineMC Repository
uses: actions/checkout@v3
with:
path: 'DivineMC'
token: ${{ secrets.GITHUB_TOKEN }}
- name: Checkout Purpur Repository
uses: actions/checkout@v3
with:
path: 'Purpur'
repository: "PurpurMC/Purpur"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Get Purpur Latest Commit Hash
id: purpurRef
run: |
ls
cd Purpur
echo "::set-output name=purpurRef::$(git rev-parse HEAD)"
cd ..
- name: Update purpurRef in DivineMC
run: |
cd DivineMC
sed -i "s/\(purpurRef\s*=\s*\).*/\1$PAPER_REF/" gradle.properties
env:
PAPER_REF: ${{ steps.purpurRef.outputs.purpurRef }}
- name: Check for changes and Write to repository
run: |
cd DivineMC
if ! git diff --quiet; then
git add gradle.properties
git config --global user.email "action@github.com" && git config --global user.name "Github Action"
git commit -m "Updated Upstream (Purpur)"
git push
else
echo "No changes to commit."
fi

View File

@@ -16,10 +16,10 @@ DivineMC is a high-performance [Purpur](https://github.com/PurpurMC/Purpur) fork
## ⚙️ Features ## ⚙️ Features
- **Based on [Purpur](https://github.com/PurpurMC/Purpur)** that adds a high customization level to the server. - **Based on [Purpur](https://github.com/PurpurMC/Purpur)** that adds a high customization level to the server.
- All worlds **are ticked in parallel**, so the server can take full advantage of multicore processors. - Implemented **Parallel world ticking** feature, that allows to server take advantage of multiple CPU cores to tick worlds.
- **Implemented Secure Seed mod** that changes default 64-bit seed to a 1024-bit seed, making it almost impossible to crack the seed. - Implemented **Secure Seed** mod that changes default 64-bit seed to a 1024-bit seed, making it almost impossible to crack the seed.
- **Optimized chunk generation** that can generate chunks up to 70% faster than vanilla. - **Optimized chunk generation** that can generate chunks up to 70% faster than vanilla.
- **Async** pathfinding, mob spawning and entity tracker - **Async** pathfinding, entity tracker, mob spawning and chunk sending.
- Implemented **Linear region file format** - Implemented **Linear region file format**
- **Fully compatible** with Bukkit, Spigot and Paper plugins - **Fully compatible** with Bukkit, Spigot and Paper plugins
- **Fixes** some Minecraft bugs - **Fixes** some Minecraft bugs
@@ -29,7 +29,7 @@ DivineMC is a high-performance [Purpur](https://github.com/PurpurMC/Purpur) fork
## 📥 Downloading & Installing ## 📥 Downloading & Installing
If you want to install DivineMC, you can read our [installation documentation](https://bxteam.org/docs/divinemc/getting-started/installation). If you want to install DivineMC, you can read our [installation documentation](https://bxteam.org/docs/divinemc/getting-started/installation).
You can find the latest successful build in [GitHub Action](https://github.com/BX-Team/DivineMC/actions) or [Releases](https://github.com/BX-Team/DivineMC/releases) You can find the latest successful build in [Releases](https://github.com/BX-Team/DivineMC/releases) or you can use [MCJars](https://mcjars.app/DIVINEMC/versions) website.
## 📈 bStats ## 📈 bStats
[![bStats](https://bstats.org/signatures/server-implementation/DivineMC.svg)](https://bstats.org/plugin/server-implementation/DivineMC) [![bStats](https://bstats.org/signatures/server-implementation/DivineMC.svg)](https://bstats.org/plugin/server-implementation/DivineMC)

View File

@@ -6,6 +6,17 @@ private-f net.minecraft.world.level.levelgen.NoiseChunk$FlatCache noiseFiller
private-f net.minecraft.world.level.levelgen.NoiseChunk$NoiseInterpolator noiseFiller private-f net.minecraft.world.level.levelgen.NoiseChunk$NoiseInterpolator noiseFiller
private-f net.minecraft.world.level.levelgen.RandomState router private-f net.minecraft.world.level.levelgen.RandomState router
private-f net.minecraft.world.level.levelgen.RandomState sampler private-f net.minecraft.world.level.levelgen.RandomState sampler
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor.RadiusAwarePrioritisedExecutor$Task
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor.RadiusAwarePrioritisedExecutor$Task chunkX
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor.RadiusAwarePrioritisedExecutor$Task chunkZ
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask chunkX
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask chunkZ
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask world
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask chunkX
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask chunkZ
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask world
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask$ProcessOffMainTask
public ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask$ProcessOnMainTask
public net.minecraft.util.Mth SIN public net.minecraft.util.Mth SIN
public net.minecraft.world.entity.ai.Brain sensors public net.minecraft.world.entity.ai.Brain sensors
public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfSightTest public net.minecraft.world.entity.ai.memory.NearestVisibleLivingEntities lineOfSightTest
@@ -55,6 +66,7 @@ public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedHi
public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedLo public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedLo
public net.minecraft.world.level.levelgen.XoroshiroRandomSource randomNumberGenerator public net.minecraft.world.level.levelgen.XoroshiroRandomSource randomNumberGenerator
public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool rawTemplates public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool rawTemplates
public net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionPieces$SimpleGrid
public net.minecraft.world.level.levelgen.synth.BlendedNoise mainNoise public net.minecraft.world.level.levelgen.synth.BlendedNoise mainNoise
public net.minecraft.world.level.levelgen.synth.BlendedNoise maxLimitNoise public net.minecraft.world.level.levelgen.synth.BlendedNoise maxLimitNoise
public net.minecraft.world.level.levelgen.synth.BlendedNoise minLimitNoise public net.minecraft.world.level.levelgen.synth.BlendedNoise minLimitNoise
@@ -72,3 +84,4 @@ public net.minecraft.world.level.levelgen.synth.PerlinNoise lowestFreqValueFacto
public net.minecraft.world.level.levelgen.synth.PerlinNoise noiseLevels public net.minecraft.world.level.levelgen.synth.PerlinNoise noiseLevels
public net.minecraft.world.level.levelgen.synth.SimplexNoise p public net.minecraft.world.level.levelgen.synth.SimplexNoise p
public net.minecraft.world.level.pathfinder.SwimNodeEvaluator allowBreaching public net.minecraft.world.level.pathfinder.SwimNodeEvaluator allowBreaching
public-f ca.spottedleaf.moonrise.paper.PaperHooks

View File

@@ -17,25 +17,6 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f
public CrashReport(String title, Throwable exception) { public CrashReport(String title, Throwable exception) {
io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
index 1485186d4989874ef89c4e83830f26358a43759c..b48fc9e0b95fe6c8f72c5501b8de374e6ac2e5d6 100644
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
@@ -62,6 +62,14 @@ import org.slf4j.Logger;
public class Main {
private static final Logger LOGGER = LogUtils.getLogger();
+ // DivineMC start - Log experimental warning
+ static {
+ io.papermc.paper.ServerBuildInfo info = io.papermc.paper.ServerBuildInfo.buildInfo();
+ if (io.papermc.paper.ServerBuildInfoImpl.IS_EXPERIMENTAL) {
+ LOGGER.warn("Running an experimental version of {}, please proceed with caution.", info.brandName());
+ }
+ }
+ // DivineMC end - Log experimental warning
@SuppressForbidden(
reason = "System.out needed before bootstrap"
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 781030cb2e0316151c20351f04347c8db63f43e1..6bb8afb3b0e92c374474c92fa44dc7b80af0bd73 100644 index 781030cb2e0316151c20351f04347c8db63f43e1..6bb8afb3b0e92c374474c92fa44dc7b80af0bd73 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java

View File

@@ -1293,7 +1293,7 @@ index 6540b2d6a1062d883811ce240c49d30d1925b291..8055b8552b40160732953b15876dda79
} }
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a26a598f6e 100644 index eb6286d34a68bf6eb57877a9cfc2be09615c7e83..f4b1f45f1dc86bd077860f088cdd6da78ecc6020 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -77,8 +77,6 @@ import net.minecraft.util.ProgressListener; @@ -77,8 +77,6 @@ import net.minecraft.util.ProgressListener;
@@ -1437,7 +1437,7 @@ index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a2
} }
@VisibleForTesting @VisibleForTesting
@@ -1330,17 +1296,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1356,17 +1322,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
} }
// Paper end - log detailed entity tick information // Paper end - log detailed entity tick information
entity.setOldPosAndRot(); entity.setOldPosAndRot();
@@ -1455,7 +1455,7 @@ index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a2
for (Entity entity1 : entity.getPassengers()) { for (Entity entity1 : entity.getPassengers()) {
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2 this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
@@ -1361,9 +1323,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1387,9 +1349,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
passengerEntity.setOldPosAndRot(); passengerEntity.setOldPosAndRot();
passengerEntity.tickCount++; passengerEntity.tickCount++;
passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities passengerEntity.totalEntityAge++; // Paper - age-like counter for all entities
@@ -1465,7 +1465,7 @@ index 3c3e8e58cd2761ab2f0652e63f944a5c9a95dca8..3980e0dfb08a357384ea33670fb282a2
// Paper start - EAR 2 // Paper start - EAR 2
if (isActive) { if (isActive) {
passengerEntity.rideTick(); passengerEntity.rideTick();
@@ -1375,7 +1334,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -1401,7 +1360,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
ridingEntity.positionRider(passengerEntity); ridingEntity.positionRider(passengerEntity);
} }
// Paper end - EAR 2 // Paper end - EAR 2
@@ -1510,7 +1510,7 @@ index a9f723528dd05cb9583319edcb14143b784a2fd7..21d41b477cc0e8d2476d1e3141bdf23d
this.stopUsingItem(); this.stopUsingItem();
this.connection.send(new ClientboundPlayerAbilitiesPacket(this.getAbilities())); this.connection.send(new ClientboundPlayerAbilitiesPacket(this.getAbilities()));
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
index 398c1733824b689520170de0be94006731afa5cd..0c499eca39371993c46d510fa45298efdd67d20c 100644 index c089a01765945277aafc62cb3566d81162c40c1d..801dd76a2c7f76fc6fdb7167cbf3ab1310be36c9 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java --- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -24,7 +24,6 @@ import net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket; @@ -24,7 +24,6 @@ import net.minecraft.network.protocol.cookie.ServerboundCookieResponsePacket;
@@ -1521,7 +1521,7 @@ index 398c1733824b689520170de0be94006731afa5cd..0c499eca39371993c46d510fa45298ef
import org.slf4j.Logger; import org.slf4j.Logger;
public abstract class ServerCommonPacketListenerImpl implements ServerCommonPacketListener, org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection { // CraftBukkit public abstract class ServerCommonPacketListenerImpl implements ServerCommonPacketListener, org.bukkit.craftbukkit.entity.CraftPlayer.TransferCookieConnection { // CraftBukkit
@@ -252,7 +251,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -256,7 +255,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
} }
protected void keepConnectionAlive() { protected void keepConnectionAlive() {
@@ -1529,7 +1529,7 @@ index 398c1733824b689520170de0be94006731afa5cd..0c499eca39371993c46d510fa45298ef
long millis = Util.getMillis(); long millis = Util.getMillis();
// Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings // Paper start - give clients a longer time to respond to pings as per pre 1.12.2 timings
// This should effectively place the keepalive handling back to "as it was" before 1.12.2 // This should effectively place the keepalive handling back to "as it was" before 1.12.2
@@ -286,8 +284,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -290,8 +288,6 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge)); this.send(new ClientboundKeepAlivePacket(this.keepAliveChallenge));
} }
} }

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Multithreaded Tracker
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index 8ffe79b81777015ff807538e461ec68463225557..b28083be4384d6c5efbdce898a0e9d7a2f5bd3d3 100644 index dd2509996bfd08e8c3f9f2be042229eac6d7692d..8ef5a1aaac9c27873ce746eb281f77bb318a3c69 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -342,7 +342,11 @@ public final class RegionizedPlayerChunkLoader { @@ -342,7 +342,11 @@ public final class RegionizedPlayerChunkLoader {
@@ -22,32 +22,10 @@ index 8ffe79b81777015ff807538e461ec68463225557..b28083be4384d6c5efbdce898a0e9d7a
private static final byte CHUNK_TICKET_STAGE_NONE = 0; private static final byte CHUNK_TICKET_STAGE_NONE = 0;
private static final byte CHUNK_TICKET_STAGE_LOADING = 1; private static final byte CHUNK_TICKET_STAGE_LOADING = 1;
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 72f019e3034d3268cf5526237ff0927eccc0c5bb..34c37abfe6c33ca1073450c8925f553d34be87a0 100644 index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..965899a98223b15bd770378c202873cbf15b714d 100644
--- a/net/minecraft/server/level/ChunkMap.java --- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java
@@ -262,9 +262,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -951,6 +951,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
- for (int i = 0, len = inRange.size(); i < len; i++) {
- ++(backingSet[i].mobCounts[index]);
+ // DivineMC start - Multithreaded tracker
+ if (org.bxteam.divinemc.DivineConfig.multithreadedEnabled) {
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ final ServerPlayer player = backingSet[i];
+ if (player == null) continue;
+ ++(player.mobCounts[index]);
+ }
+ } else {
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ ++(backingSet[i].mobCounts[index]);
+ }
}
+ // DivineMC end - Multithreaded tracker
}
// Paper start - per player mob count backoff
@@ -965,6 +975,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
// Paper end - optimise entity tracker // Paper end - optimise entity tracker
protected void tick() { protected void tick() {
@@ -61,7 +39,7 @@ index 72f019e3034d3268cf5526237ff0927eccc0c5bb..34c37abfe6c33ca1073450c8925f553d
// Paper start - optimise entity tracker // Paper start - optimise entity tracker
if (true) { if (true) {
this.newTrackerTick(); this.newTrackerTick();
@@ -1087,7 +1104,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -1073,7 +1080,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
final Entity entity; final Entity entity;
private final int range; private final int range;
SectionPos lastSectionPos; SectionPos lastSectionPos;
@@ -74,7 +52,7 @@ index 72f019e3034d3268cf5526237ff0927eccc0c5bb..34c37abfe6c33ca1073450c8925f553d
// Paper start - optimise entity tracker // Paper start - optimise entity tracker
private long lastChunkUpdate = -1L; private long lastChunkUpdate = -1L;
@@ -1114,21 +1135,55 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -1100,21 +1111,55 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.lastTrackedChunk = chunk; this.lastTrackedChunk = chunk;
final ServerPlayer[] playersRaw = players.getRawDataUnchecked(); final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
@@ -140,7 +118,7 @@ index 72f019e3034d3268cf5526237ff0927eccc0c5bb..34c37abfe6c33ca1073450c8925f553d
} }
@Override @Override
@@ -1190,7 +1245,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -1176,7 +1221,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
} }
public void broadcast(Packet<?> packet) { public void broadcast(Packet<?> packet) {
@@ -149,7 +127,7 @@ index 72f019e3034d3268cf5526237ff0927eccc0c5bb..34c37abfe6c33ca1073450c8925f553d
serverPlayerConnection.send(packet); serverPlayerConnection.send(packet);
} }
} }
@@ -1203,21 +1258,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -1189,21 +1234,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
} }
public void broadcastRemoved() { public void broadcastRemoved() {
@@ -230,10 +208,10 @@ index 0fb253aa55a24b56b17f524b3261c5b75c7d7e59..b6053158f5d9b6ad325ea075ab7c60f9
attributesToSync.clear(); attributesToSync.clear();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 9afd448ede87c9192dc576f66e08676a68b34d98..6e1ed33463c6280159d7f8187b9a9210d6b85e0c 100644 index c229d69ce3d007e4cb57e559611b3fca7a03562f..ba5ca5213fafd60b2257409f334a7c6b28fe918a 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -2471,7 +2471,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -2497,7 +2497,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override @Override
public LevelEntityGetter<Entity> getEntities() { public LevelEntityGetter<Entity> getEntities() {
@@ -242,8 +220,17 @@ index 9afd448ede87c9192dc576f66e08676a68b34d98..6e1ed33463c6280159d7f8187b9a9210
return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system
} }
@@ -2724,7 +2724,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
map.carriedByPlayers.remove(player);
- if (map.carriedBy.removeIf(holdingPlayer -> holdingPlayer.player == player)) {
+ if (map.carriedBy.removeIf(holdingPlayer -> holdingPlayer != null && holdingPlayer.player == player)) { // DivineMC - Multithreaded tracker
map.decorations.remove(player.getName().getString());
}
}
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 420c9993df062466b85d60fe3fcc915e24d3da2a..19c7802969aa9d1e15b4c67ee5c97e73daf0a460 100644 index 56a22d19a82a937c08cb4527b0f67f219a6bb8a0..f8c76bb2c9fa625e191036dc58ef3dfb1d4ee930 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1822,7 +1822,7 @@ public class ServerGamePacketListenerImpl @@ -1822,7 +1822,7 @@ public class ServerGamePacketListenerImpl
@@ -293,3 +280,15 @@ index a25d74592e89e3d6339479c6dc2b6f45d1932cfc..621b183211b8148bb8db256d2119c82f
private final AttributeSupplier supplier; private final AttributeSupplier supplier;
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index 681dec447486138088fe5f705ef4fadab531139f..3d6aad86519be3e1449d3288369a41aebb924c90 100644
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -279,6 +279,7 @@ public class MapItemSavedData extends SavedData {
for (int i = 0; i < this.carriedBy.size(); i++) {
MapItemSavedData.HoldingPlayer holdingPlayer1 = this.carriedBy.get(i);
+ if (holdingPlayer1 == null) continue; // DivineMC - Multithreaded tracker
Player player1 = holdingPlayer1.player;
String string = player1.getName().getString();
if (!player1.isRemoved() && (player1.getInventory().contains(predicate) || mapStack.isFramed())) {

View File

@@ -1,40 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Tue, 28 Jan 2025 01:14:58 +0300
Subject: [PATCH] Threaded light engine
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..72f019e3034d3268cf5526237ff0927eccc0c5bb 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -210,7 +210,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
ConsecutiveExecutor consecutiveExecutor = new ConsecutiveExecutor(dispatcher, "worldgen");
this.progressListener = progressListener;
this.chunkStatusListener = chunkStatusListener;
- ConsecutiveExecutor consecutiveExecutor1 = new ConsecutiveExecutor(dispatcher, "light");
+ ConsecutiveExecutor consecutiveExecutor1 = onLightExecutorInit(ConsecutiveExecutor::new); // DivineMC - Threaded light engine
// Paper - rewrite chunk system
this.lightEngine = new ThreadedLevelLightEngine(
lightChunk, this, this.level.dimensionType().hasSkyLight(), consecutiveExecutor1, null // Paper - rewrite chunk system
@@ -230,6 +230,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.worldGenContext = new WorldGenContext(level, generator, structureManager, this.lightEngine, null, this::setChunkUnsaved); // Paper - rewrite chunk system
}
+ // DivineMC start - Threaded light engine
+ private java.util.concurrent.ExecutorService lightThread = null;
+
+ private ConsecutiveExecutor onLightExecutorInit(java.util.function.BiFunction<java.util.concurrent.Executor, String, net.minecraft.util.thread.ConsecutiveExecutor> original) {
+ lightThread = new java.util.concurrent.ThreadPoolExecutor(
+ 1, 1,
+ 0, java.util.concurrent.TimeUnit.SECONDS,
+ new java.util.concurrent.LinkedBlockingQueue<>(),
+ new com.google.common.util.concurrent.ThreadFactoryBuilder().setPriority(Thread.NORM_PRIORITY - 1).setDaemon(true).setNameFormat(String.format("%s - Light", level.dimension().location().toDebugFileName())).build()
+ );
+ return original.apply(lightThread, "light");
+ }
+ // DivineMC end - Threaded light engine
+
private void setChunkUnsaved(ChunkPos chunkPos) {
// Paper - rewrite chunk system
}

View File

@@ -1,11 +1,11 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 15:59:29 +0300 Date: Fri, 31 Jan 2025 21:50:46 +0300
Subject: [PATCH] Some optimizations Subject: [PATCH] Misc Optimizations
diff --git a/com/mojang/brigadier/tree/CommandNode.java b/com/mojang/brigadier/tree/CommandNode.java diff --git a/com/mojang/brigadier/tree/CommandNode.java b/com/mojang/brigadier/tree/CommandNode.java
index 2ae5b80338282ac73c74765fc0729af2d54f6d6c..59c93bbf431836fd29101ff9e7e467d9ea3f5df9 100644 index 2ae5b80338282ac73c74765fc0729af2d54f6d6c..00a63a6a5983e6a25f2a9014a2f9eefeda468cdf 100644
--- a/com/mojang/brigadier/tree/CommandNode.java --- a/com/mojang/brigadier/tree/CommandNode.java
+++ b/com/mojang/brigadier/tree/CommandNode.java +++ b/com/mojang/brigadier/tree/CommandNode.java
@@ -24,7 +24,7 @@ import java.util.concurrent.CompletableFuture; @@ -24,7 +24,7 @@ import java.util.concurrent.CompletableFuture;
@@ -13,10 +13,42 @@ index 2ae5b80338282ac73c74765fc0729af2d54f6d6c..59c93bbf431836fd29101ff9e7e467d9
public abstract class CommandNode<S> implements Comparable<CommandNode<S>> { public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
- private final Map<String, CommandNode<S>> children = new LinkedHashMap<>(); - private final Map<String, CommandNode<S>> children = new LinkedHashMap<>();
+ private final Map<String, CommandNode<S>> children = Collections.synchronizedMap(new LinkedHashMap<>()); // DivineMC - Some optimizations + private final Map<String, CommandNode<S>> children = Collections.synchronizedMap(new LinkedHashMap<>()); // DivineMC - Misc Optimizations
private final Map<String, LiteralCommandNode<S>> literals = new LinkedHashMap<>(); private final Map<String, LiteralCommandNode<S>> literals = new LinkedHashMap<>();
private final Map<String, ArgumentCommandNode<S, ?>> arguments = new LinkedHashMap<>(); private final Map<String, ArgumentCommandNode<S, ?>> arguments = new LinkedHashMap<>();
public Predicate<S> requirement; // Paper - public-f public Predicate<S> requirement; // Paper - public-f
diff --git a/com/mojang/math/OctahedralGroup.java b/com/mojang/math/OctahedralGroup.java
index 11902e7427761746ee098fea3276a34fef0096ba..3ba23fa243f7af712a41316066ca554f1c23b495 100644
--- a/com/mojang/math/OctahedralGroup.java
+++ b/com/mojang/math/OctahedralGroup.java
@@ -112,6 +112,7 @@ public enum OctahedralGroup implements StringRepresentable {
this.transformation = new Matrix3f().scaling(invertX ? -1.0F : 1.0F, invertY ? -1.0F : 1.0F, invertZ ? -1.0F : 1.0F);
this.transformation.mul(permutation.transformation());
this.initializeRotationDirections(); // Paper - Avoid Lazy Initialization for Enum Fields
+ this.rotate(Direction.UP); // DivineMC - Math Optimizations
}
private BooleanList packInversions() {
diff --git a/com/mojang/math/Transformation.java b/com/mojang/math/Transformation.java
index aa755b8b7f8bc5910322e0c5b520f603da06a85a..e781dea43279aa77cc40a7afd2281c32cc8347a9 100644
--- a/com/mojang/math/Transformation.java
+++ b/com/mojang/math/Transformation.java
@@ -51,6 +51,7 @@ public final class Transformation {
} else {
this.matrix = matrix;
}
+ ensureDecomposed(); // DivineMC - Math Optimizations
}
public Transformation(@Nullable Vector3f translation, @Nullable Quaternionf leftRotation, @Nullable Vector3f scale, @Nullable Quaternionf rightRotation) {
@@ -60,6 +61,7 @@ public final class Transformation {
this.scale = scale != null ? scale : new Vector3f(1.0F, 1.0F, 1.0F);
this.rightRotation = rightRotation != null ? rightRotation : new Quaternionf();
this.decomposed = true;
+ ensureDecomposed(); // DivineMC - Math Optimizations
}
public static Transformation identity() {
diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java
index 5f752603aa5611ce9d3dd44cc5b70c27ac46a86e..332122c0b700fb743f91f3fed16aade41dceec28 100644 index 5f752603aa5611ce9d3dd44cc5b70c27ac46a86e..332122c0b700fb743f91f3fed16aade41dceec28 100644
--- a/net/minecraft/core/MappedRegistry.java --- a/net/minecraft/core/MappedRegistry.java
@@ -62,7 +94,7 @@ index bee90335677f7d8b01589ce5cfd81a40fd422886..a5e488d14fd2016ee188b114d0e68156
public record Positioned(ChunkPos center, int viewDistance) implements ChunkTrackingView { public record Positioned(ChunkPos center, int viewDistance) implements ChunkTrackingView {
diff --git a/net/minecraft/util/ClassInstanceMultiMap.java b/net/minecraft/util/ClassInstanceMultiMap.java diff --git a/net/minecraft/util/ClassInstanceMultiMap.java b/net/minecraft/util/ClassInstanceMultiMap.java
index 2a708ae0d5bb209650b525e3c56051f8b5655074..762cba15597623f95a242bdd44742d9b892ad042 100644 index 2a708ae0d5bb209650b525e3c56051f8b5655074..4c7670224f0c90c1d0d833ff0b3d908846133b4a 100644
--- a/net/minecraft/util/ClassInstanceMultiMap.java --- a/net/minecraft/util/ClassInstanceMultiMap.java
+++ b/net/minecraft/util/ClassInstanceMultiMap.java +++ b/net/minecraft/util/ClassInstanceMultiMap.java
@@ -14,9 +14,9 @@ import java.util.Map.Entry; @@ -14,9 +14,9 @@ import java.util.Map.Entry;
@@ -70,10 +102,10 @@ index 2a708ae0d5bb209650b525e3c56051f8b5655074..762cba15597623f95a242bdd44742d9b
public class ClassInstanceMultiMap<T> extends AbstractCollection<T> { public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
- private final Map<Class<?>, List<T>> byClass = Maps.newHashMap(); - private final Map<Class<?>, List<T>> byClass = Maps.newHashMap();
+ private final Map<Class<?>, List<T>> byClass = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // DivineMC - Some optimizations + private final Map<Class<?>, List<T>> byClass = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // DivineMC - Misc Optimizations
private final Class<T> baseClass; private final Class<T> baseClass;
- private final List<T> allInstances = Lists.newArrayList(); - private final List<T> allInstances = Lists.newArrayList();
+ private final List<T> allInstances = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // DivineMC - Some optimizations + private final List<T> allInstances = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // DivineMC - Misc Optimizations
public ClassInstanceMultiMap(Class<T> baseClass) { public ClassInstanceMultiMap(Class<T> baseClass) {
this.baseClass = baseClass; this.baseClass = baseClass;
@@ -109,7 +141,7 @@ index 2a708ae0d5bb209650b525e3c56051f8b5655074..762cba15597623f95a242bdd44742d9b
@Override @Override
diff --git a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java diff --git a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
index f28fbf81a417a678726d3f77b3999054676d522e..fbf17cc11fa8e56c5ada2f0f60c944b6b22591a5 100644 index f28fbf81a417a678726d3f77b3999054676d522e..7ff32b1f93b31fafd13f4e0857d14d85ef1f28c7 100644
--- a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java --- a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
+++ b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java +++ b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
@@ -52,23 +52,23 @@ public class CrudeIncrementalIntIdentityHashBiMap<K> implements IdMap<K>, ca.spo @@ -52,23 +52,23 @@ public class CrudeIncrementalIntIdentityHashBiMap<K> implements IdMap<K>, ca.spo
@@ -117,27 +149,27 @@ index f28fbf81a417a678726d3f77b3999054676d522e..fbf17cc11fa8e56c5ada2f0f60c944b6
@Nullable @Nullable
@Override @Override
- public K byId(int value) { - public K byId(int value) {
+ public synchronized K byId(int value) { // DivineMC - Some optimizations + public synchronized K byId(int value) { // DivineMC - Misc Optimizations
return value >= 0 && value < this.byId.length ? this.byId[value] : null; return value >= 0 && value < this.byId.length ? this.byId[value] : null;
} }
- private int getValue(int key) { - private int getValue(int key) {
+ private synchronized int getValue(int key) { // DivineMC - Some optimizations + private synchronized int getValue(int key) { // DivineMC - Misc Optimizations
return key == -1 ? -1 : this.values[key]; return key == -1 ? -1 : this.values[key];
} }
- public boolean contains(K value) { - public boolean contains(K value) {
+ public synchronized boolean contains(K value) { // DivineMC - Some optimizations + public synchronized boolean contains(K value) { // DivineMC - Misc Optimizations
return this.getId(value) != -1; return this.getId(value) != -1;
} }
- public boolean contains(int value) { - public boolean contains(int value) {
+ public synchronized boolean contains(int value) { // DivineMC - Some optimizations + public synchronized boolean contains(int value) { // DivineMC - Misc Optimizations
return this.byId(value) != null; return this.byId(value) != null;
} }
- public int add(K object) { - public int add(K object) {
+ public synchronized int add(K object) { // DivineMC - Some optimizations + public synchronized int add(K object) { // DivineMC - Misc Optimizations
int i = this.nextId(); int i = this.nextId();
this.addMapping(object, i); this.addMapping(object, i);
return i; return i;
@@ -146,7 +178,7 @@ index f28fbf81a417a678726d3f77b3999054676d522e..fbf17cc11fa8e56c5ada2f0f60c944b6
} }
- public void addMapping(K object, int intKey) { - public void addMapping(K object, int intKey) {
+ public synchronized void addMapping(K object, int intKey) { // DivineMC - Some optimizations + public synchronized void addMapping(K object, int intKey) { // DivineMC - Misc Optimizations
int max = Math.max(intKey, this.size + 1); int max = Math.max(intKey, this.size + 1);
if (max >= this.keys.length * 0.8F) { if (max >= this.keys.length * 0.8F) {
int i = this.keys.length << 1; int i = this.keys.length << 1;
@@ -155,12 +187,12 @@ index f28fbf81a417a678726d3f77b3999054676d522e..fbf17cc11fa8e56c5ada2f0f60c944b6
@Override @Override
- public Iterator<K> iterator() { - public Iterator<K> iterator() {
+ public synchronized Iterator<K> iterator() { // DivineMC - Some optimizations + public synchronized Iterator<K> iterator() { // DivineMC - Misc Optimizations
return Iterators.filter(Iterators.forArray(this.byId), Predicates.notNull()); return Iterators.filter(Iterators.forArray(this.byId), Predicates.notNull());
} }
- public void clear() { - public void clear() {
+ public synchronized void clear() { // DivineMC - Some optimizations + public synchronized void clear() { // DivineMC - Misc Optimizations
Arrays.fill(this.keys, null); Arrays.fill(this.keys, null);
Arrays.fill(this.byId, null); Arrays.fill(this.byId, null);
this.nextId = 0; this.nextId = 0;
@@ -264,8 +296,110 @@ index f36f8f2d49d4eba5c80eb243883749d6f831eb8a..5abd899c88683cb79bb8f02e43c4bfbe
+ // DivineMC end - Some optimizations + // DivineMC end - Some optimizations
} }
} }
diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java
index ab3a221c115992d0f4ea921aa92cf0976b815ff4..076a931341da486162f289a5f19d3d6736df7768 100644
--- a/net/minecraft/util/Mth.java
+++ b/net/minecraft/util/Mth.java
@@ -46,11 +46,11 @@ public class Mth {
private static final double[] COS_TAB = new double[257];
public static float sin(float value) {
- return SIN[(int)(value * 10430.378F) & 65535];
+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.sin(value); // DivineMC - Math Optimizations
}
public static float cos(float value) {
- return SIN[(int)(value * 10430.378F + 16384.0F) & 65535];
+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.cos(value); // DivineMC - Math Optimizations
}
public static float sqrt(float value) {
@@ -58,18 +58,15 @@ public class Mth {
}
public static int floor(float value) {
- int i = (int)value;
- return value < i ? i - 1 : i;
+ return (int) Math.floor(value); // DivineMC - Math Optimizations
}
public static int floor(double value) {
- int i = (int)value;
- return value < i ? i - 1 : i;
+ return (int) Math.floor(value); // DivineMC - Math Optimizations
}
public static long lfloor(double value) {
- long l = (long)value;
- return value < l ? l - 1L : l;
+ return (long) Math.floor(value); // DivineMC - Math Optimizations
}
public static float abs(float value) {
@@ -81,13 +78,11 @@ public class Mth {
}
public static int ceil(float value) {
- int i = (int)value;
- return value > i ? i + 1 : i;
+ return (int) Math.ceil(value); // DivineMC - Math Optimizations
}
public static int ceil(double value) {
- int i = (int)value;
- return value > i ? i + 1 : i;
+ return (int) Math.ceil(value); // DivineMC - Math Optimizations
}
public static int clamp(int value, int min, int max) {
@@ -123,15 +118,7 @@ public class Mth {
}
public static double absMax(double x, double y) {
- if (x < 0.0) {
- x = -x;
- }
-
- if (y < 0.0) {
- y = -y;
- }
-
- return Math.max(x, y);
+ return Math.max(Math.abs(x), Math.abs(y)); // DivineMC - Math Optimizations
}
public static int floorDiv(int dividend, int divisor) {
@@ -162,14 +149,26 @@ public class Mth {
return Math.floorMod(x, y);
}
- public static float positiveModulo(float numerator, float denominator) {
+ public static float positiveModuloForAnyDenominator(float numerator, float denominator) { // DivineMC - Math Optimizations
return (numerator % denominator + denominator) % denominator;
}
- public static double positiveModulo(double numerator, double denominator) {
+ public static double positiveModuloForAnyDenominator(double numerator, double denominator) { // DivineMC - Math Optimizations
return (numerator % denominator + denominator) % denominator;
}
+ // DivineMC start - Math Optimizations
+ public static float positiveModuloForPositiveIntegerDenominator(float numerator, float denominator) {
+ var modulo = numerator % denominator;
+ return modulo < 0 ? modulo + denominator : modulo;
+ }
+
+ public static double positiveModuloForPositiveIntegerDenominator(double numerator, double denominator) {
+ var modulo = numerator % denominator;
+ return modulo < 0 ? modulo + denominator : modulo;
+ }
+ // DivineMC end - Math Optimizations
+
public static boolean isMultipleOf(int number, int multiple) {
return number % multiple == 0;
}
diff --git a/net/minecraft/util/RandomSource.java b/net/minecraft/util/RandomSource.java diff --git a/net/minecraft/util/RandomSource.java b/net/minecraft/util/RandomSource.java
index 98a54bc4de251014342cda6d0951b7fea79ce553..cd17a4c7f02abf16fcb3b793c10d8b86d47b7974 100644 index 98a54bc4de251014342cda6d0951b7fea79ce553..663edee4dfa660e3d3a04c728fd764258867916d 100644
--- a/net/minecraft/util/RandomSource.java --- a/net/minecraft/util/RandomSource.java
+++ b/net/minecraft/util/RandomSource.java +++ b/net/minecraft/util/RandomSource.java
@@ -12,7 +12,7 @@ public interface RandomSource { @@ -12,7 +12,7 @@ public interface RandomSource {
@@ -273,7 +407,7 @@ index 98a54bc4de251014342cda6d0951b7fea79ce553..cd17a4c7f02abf16fcb3b793c10d8b86
static RandomSource create() { static RandomSource create() {
- return create(RandomSupport.generateUniqueSeed()); - return create(RandomSupport.generateUniqueSeed());
+ return createThreadSafe(); // DivineMC - Some optimizations + return createThreadSafe(); // DivineMC - Misc Optimizations
} }
@Deprecated @Deprecated
@@ -282,12 +416,12 @@ index 98a54bc4de251014342cda6d0951b7fea79ce553..cd17a4c7f02abf16fcb3b793c10d8b86
static RandomSource create(long seed) { static RandomSource create(long seed) {
- return new LegacyRandomSource(seed); - return new LegacyRandomSource(seed);
+ return new ThreadSafeLegacyRandomSource(seed); // DivineMC - Some optimizations + return new ThreadSafeLegacyRandomSource(seed); // DivineMC - Misc Optimizations
} }
static RandomSource createNewThreadLocalInstance() { static RandomSource createNewThreadLocalInstance() {
diff --git a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java diff --git a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java
index 15de39fa82c7aea18298509fe9587d027c30cc15..c199f99efe25737602a3565ca6f70177571ff886 100644 index 15de39fa82c7aea18298509fe9587d027c30cc15..eb534ed5a7478fc632db096328e3582f4ec410b8 100644
--- a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java --- a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java
+++ b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java +++ b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java
@@ -15,7 +15,7 @@ public class DebugSampleSubscriptionTracker { @@ -15,7 +15,7 @@ public class DebugSampleSubscriptionTracker {
@@ -295,12 +429,12 @@ index 15de39fa82c7aea18298509fe9587d027c30cc15..c199f99efe25737602a3565ca6f70177
private final PlayerList playerList; private final PlayerList playerList;
private final EnumMap<RemoteDebugSampleType, Map<ServerPlayer, DebugSampleSubscriptionTracker.SubscriptionStartedAt>> subscriptions; private final EnumMap<RemoteDebugSampleType, Map<ServerPlayer, DebugSampleSubscriptionTracker.SubscriptionStartedAt>> subscriptions;
- private final Queue<DebugSampleSubscriptionTracker.SubscriptionRequest> subscriptionRequestQueue = new LinkedList<>(); - private final Queue<DebugSampleSubscriptionTracker.SubscriptionRequest> subscriptionRequestQueue = new LinkedList<>();
+ private final java.util.List<SubscriptionRequest> subscriptionRequestQueue = java.util.Collections.synchronizedList(new LinkedList<>()); // DivineMC - Some optimizations + private final java.util.List<SubscriptionRequest> subscriptionRequestQueue = java.util.Collections.synchronizedList(new LinkedList<>()); // DivineMC - Misc Optimizations
public DebugSampleSubscriptionTracker(PlayerList playerList) { public DebugSampleSubscriptionTracker(PlayerList playerList) {
this.playerList = playerList; this.playerList = playerList;
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 258cb45f1f959b75c1bcdb130811af2f8fddf07d..40641a649631cfe63b0077d66115aaa525377cf0 100644 index 258cb45f1f959b75c1bcdb130811af2f8fddf07d..9c0e539f09bddac018f93d212e3cdbc446f3c672 100644
--- a/net/minecraft/world/entity/Entity.java --- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java
@@ -143,7 +143,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -143,7 +143,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
@@ -308,7 +442,7 @@ index 258cb45f1f959b75c1bcdb130811af2f8fddf07d..40641a649631cfe63b0077d66115aaa5
// Paper start - Share random for entities to make them more random // Paper start - Share random for entities to make them more random
- public static RandomSource SHARED_RANDOM = new RandomRandomSource(); - public static RandomSource SHARED_RANDOM = new RandomRandomSource();
+ public static RandomSource SHARED_RANDOM = new net.minecraft.world.level.levelgen.ThreadSafeLegacyRandomSource(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()); // DivineMC - Some optimizations + public static RandomSource SHARED_RANDOM = new net.minecraft.world.level.levelgen.ThreadSafeLegacyRandomSource(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()); // DivineMC - Misc Optimizations
// Paper start - replace random // Paper start - replace random
private static final class RandomRandomSource extends ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom { private static final class RandomRandomSource extends ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom {
public RandomRandomSource() { public RandomRandomSource() {
@@ -359,7 +493,7 @@ index 5ded2f808a9fcb26856567de6bc56e206f948a84..02d64a5ea756b2c91a71b7a0fc0f2121
// Paper start - Perf: Use array for gamerule storage // Paper start - Perf: Use array for gamerule storage
diff --git a/net/minecraft/world/level/LocalMobCapCalculator.java b/net/minecraft/world/level/LocalMobCapCalculator.java diff --git a/net/minecraft/world/level/LocalMobCapCalculator.java b/net/minecraft/world/level/LocalMobCapCalculator.java
index 9641219c190261dea0db5f95f040a705ba0a3ff9..91966607f8f48b56e2c7e9389bd7d8acda99a48d 100644 index 9641219c190261dea0db5f95f040a705ba0a3ff9..a3fccdeb2c076e12b611683da55d45e00a166417 100644
--- a/net/minecraft/world/level/LocalMobCapCalculator.java --- a/net/minecraft/world/level/LocalMobCapCalculator.java
+++ b/net/minecraft/world/level/LocalMobCapCalculator.java +++ b/net/minecraft/world/level/LocalMobCapCalculator.java
@@ -13,16 +13,24 @@ import net.minecraft.world.entity.MobCategory; @@ -13,16 +13,24 @@ import net.minecraft.world.entity.MobCategory;
@@ -367,7 +501,7 @@ index 9641219c190261dea0db5f95f040a705ba0a3ff9..91966607f8f48b56e2c7e9389bd7d8ac
public class LocalMobCapCalculator { public class LocalMobCapCalculator {
private final Long2ObjectMap<List<ServerPlayer>> playersNearChunk = new Long2ObjectOpenHashMap<>(); private final Long2ObjectMap<List<ServerPlayer>> playersNearChunk = new Long2ObjectOpenHashMap<>();
- private final Map<ServerPlayer, LocalMobCapCalculator.MobCounts> playerMobCounts = Maps.newHashMap(); - private final Map<ServerPlayer, LocalMobCapCalculator.MobCounts> playerMobCounts = Maps.newHashMap();
+ private final Map<ServerPlayer, LocalMobCapCalculator.MobCounts> playerMobCounts = Maps.newConcurrentMap(); // DivineMC - Some optimizations + private final Map<ServerPlayer, LocalMobCapCalculator.MobCounts> playerMobCounts = Maps.newConcurrentMap(); // DivineMC - Misc Optimizations
private final ChunkMap chunkMap; private final ChunkMap chunkMap;
public LocalMobCapCalculator(ChunkMap chunkMap) { public LocalMobCapCalculator(ChunkMap chunkMap) {
@@ -395,28 +529,41 @@ index 9641219c190261dea0db5f95f040a705ba0a3ff9..91966607f8f48b56e2c7e9389bd7d8ac
static class MobCounts { static class MobCounts {
- private final Object2IntMap<MobCategory> counts = new Object2IntOpenHashMap<>(MobCategory.values().length); - private final Object2IntMap<MobCategory> counts = new Object2IntOpenHashMap<>(MobCategory.values().length);
+ private final int[] spawnGroupDensities = new int[MobCategory.values().length]; // DivineMC - Some optimizations + private final int[] spawnGroupDensities = new int[MobCategory.values().length]; // DivineMC - Misc Optimizations
public void add(MobCategory category) { public void add(MobCategory category) {
- this.counts.computeInt(category, (key, value) -> value == null ? 1 : value + 1); - this.counts.computeInt(category, (key, value) -> value == null ? 1 : value + 1);
+ this.spawnGroupDensities[category.ordinal()] ++; // DivineMC - Some optimizations + this.spawnGroupDensities[category.ordinal()] ++; // DivineMC - Misc Optimizations
} }
public boolean canSpawn(MobCategory category) { public boolean canSpawn(MobCategory category) {
- return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk(); - return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk();
+ return this.spawnGroupDensities[category.ordinal()] < category.getMaxInstancesPerChunk(); // DivineMC - Some optimizations + return this.spawnGroupDensities[category.ordinal()] < category.getMaxInstancesPerChunk(); // DivineMC - Misc Optimizations
} }
} }
} }
diff --git a/net/minecraft/world/level/levelgen/blending/Blender.java b/net/minecraft/world/level/levelgen/blending/Blender.java
index 01e5b29d6e9a5c53c0e23b61ed0c1d7be1a0fe08..d80df05e40f3941ade5ed320e12f8dcf47e6b247 100644
--- a/net/minecraft/world/level/levelgen/blending/Blender.java
+++ b/net/minecraft/world/level/levelgen/blending/Blender.java
@@ -144,7 +144,7 @@ public class Blender {
private static double heightToOffset(double height) {
double d = 1.0;
double d1 = height + 0.5;
- double d2 = Mth.positiveModulo(d1, 8.0);
+ double d2 = Mth.positiveModuloForPositiveIntegerDenominator(d1, 8.0); // DivineMC - Math optimizations
return 1.0 * (32.0 * (d1 - 128.0) - 3.0 * (d1 - 120.0) * d2 + 3.0 * d2 * d2) / (128.0 * (32.0 - 3.0 * d2));
}
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index 681dec447486138088fe5f705ef4fadab531139f..c34515e0a2954730665acf429dfec6fc3069e7c4 100644 index 681dec447486138088fe5f705ef4fadab531139f..12ea268eaec629fde20d55460e618fde3a3e006d 100644
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java --- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java +++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -198,6 +198,7 @@ public class MapItemSavedData extends SavedData { @@ -198,6 +198,7 @@ public class MapItemSavedData extends SavedData {
} }
} }
+ mapItemSavedData.setDirty(false); // DivineMC - Some optimizations + mapItemSavedData.setDirty(false); // DivineMC - Misc Optimizations
return mapItemSavedData; return mapItemSavedData;
} }
@@ -433,3 +580,71 @@ index d9a3b5a2e6495b7e22c114506c2bd1e406f58f8f..a6e03345afd6d8a38e06a43c59103209
private final DataFixer fixerUpper; private final DataFixer fixerUpper;
private final HolderLookup.Provider registries; private final HolderLookup.Provider registries;
private final Path dataFolder; private final Path dataFolder;
diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java
index c9c6e4e460ad8435f12761704bb9b0284d6aa708..54807bb4b4189ceaded1f78a1a9ab85ce40ab2b1 100644
--- a/net/minecraft/world/phys/AABB.java
+++ b/net/minecraft/world/phys/AABB.java
@@ -189,13 +189,15 @@ public class AABB {
}
public AABB intersect(AABB other) {
- double max = Math.max(this.minX, other.minX);
- double max1 = Math.max(this.minY, other.minY);
- double max2 = Math.max(this.minZ, other.minZ);
- double min = Math.min(this.maxX, other.maxX);
- double min1 = Math.min(this.maxY, other.maxY);
- double min2 = Math.min(this.maxZ, other.maxZ);
- return new AABB(max, max1, max2, min, min1, min2);
+ // DivineMC start - Math Optimizations
+ return new AABB(
+ this.minX > other.minX ? this.minX : other.minX,
+ this.minY > other.minY ? this.minY : other.minY,
+ this.minZ > other.minZ ? this.minZ : other.minZ,
+ this.maxX < other.maxX ? this.maxX : other.maxX,
+ this.maxY < other.maxY ? this.maxY : other.maxY,
+ this.maxZ < other.maxZ ? this.maxZ : other.maxZ
+ );
}
public AABB minmax(AABB other) {
@@ -227,16 +229,37 @@ public class AABB {
}
public boolean intersects(AABB other) {
- return this.intersects(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ);
+ // DivineMC start - Math Optimizations
+ return this.minX < other.maxX &&
+ this.maxX > other.minX &&
+ this.minY < other.maxY &&
+ this.maxY > other.minY &&
+ this.minZ < other.maxZ &&
+ this.maxZ > other.minZ;
+ // DivineMC end - Math Optimizations
}
public boolean intersects(double x1, double y1, double z1, double x2, double y2, double z2) {
- return this.minX < x2 && this.maxX > x1 && this.minY < y2 && this.maxY > y1 && this.minZ < z2 && this.maxZ > z1;
+ // DivineMC start - Math Optimizations
+ return this.minX < x2 &&
+ this.maxX > x1 &&
+ this.minY < y2 &&
+ this.maxY > y1 &&
+ this.minZ < z2 &&
+ this.maxZ > z1;
+ // DivineMC end - Math Optimizations
}
public boolean intersects(Vec3 min, Vec3 max) {
return this.intersects(
- Math.min(min.x, max.x), Math.min(min.y, max.y), Math.min(min.z, max.z), Math.max(min.x, max.x), Math.max(min.y, max.y), Math.max(min.z, max.z)
+ // DivineMC start - Math Optimizations
+ min.x < max.x ? min.x : max.x,
+ min.y < max.y ? min.y : max.y,
+ min.z < max.z ? min.z : max.z,
+ min.x > max.x ? min.x : max.x,
+ min.y > max.y ? min.y : max.y,
+ min.z > max.z ? min.z : max.z
+ // DivineMC end - Math Optimizations
);
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,329 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Fri, 31 Jan 2025 21:50:46 +0300
Subject: [PATCH] Math Optimizations
diff --git a/com/mojang/math/OctahedralGroup.java b/com/mojang/math/OctahedralGroup.java
index 11902e7427761746ee098fea3276a34fef0096ba..3ba23fa243f7af712a41316066ca554f1c23b495 100644
--- a/com/mojang/math/OctahedralGroup.java
+++ b/com/mojang/math/OctahedralGroup.java
@@ -112,6 +112,7 @@ public enum OctahedralGroup implements StringRepresentable {
this.transformation = new Matrix3f().scaling(invertX ? -1.0F : 1.0F, invertY ? -1.0F : 1.0F, invertZ ? -1.0F : 1.0F);
this.transformation.mul(permutation.transformation());
this.initializeRotationDirections(); // Paper - Avoid Lazy Initialization for Enum Fields
+ this.rotate(Direction.UP); // DivineMC - Math Optimizations
}
private BooleanList packInversions() {
diff --git a/com/mojang/math/Transformation.java b/com/mojang/math/Transformation.java
index aa755b8b7f8bc5910322e0c5b520f603da06a85a..e781dea43279aa77cc40a7afd2281c32cc8347a9 100644
--- a/com/mojang/math/Transformation.java
+++ b/com/mojang/math/Transformation.java
@@ -51,6 +51,7 @@ public final class Transformation {
} else {
this.matrix = matrix;
}
+ ensureDecomposed(); // DivineMC - Math Optimizations
}
public Transformation(@Nullable Vector3f translation, @Nullable Quaternionf leftRotation, @Nullable Vector3f scale, @Nullable Quaternionf rightRotation) {
@@ -60,6 +61,7 @@ public final class Transformation {
this.scale = scale != null ? scale : new Vector3f(1.0F, 1.0F, 1.0F);
this.rightRotation = rightRotation != null ? rightRotation : new Quaternionf();
this.decomposed = true;
+ ensureDecomposed(); // DivineMC - Math Optimizations
}
public static Transformation identity() {
diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java
index ab3a221c115992d0f4ea921aa92cf0976b815ff4..076a931341da486162f289a5f19d3d6736df7768 100644
--- a/net/minecraft/util/Mth.java
+++ b/net/minecraft/util/Mth.java
@@ -46,11 +46,11 @@ public class Mth {
private static final double[] COS_TAB = new double[257];
public static float sin(float value) {
- return SIN[(int)(value * 10430.378F) & 65535];
+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.sin(value); // DivineMC - Math Optimizations
}
public static float cos(float value) {
- return SIN[(int)(value * 10430.378F + 16384.0F) & 65535];
+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.cos(value); // DivineMC - Math Optimizations
}
public static float sqrt(float value) {
@@ -58,18 +58,15 @@ public class Mth {
}
public static int floor(float value) {
- int i = (int)value;
- return value < i ? i - 1 : i;
+ return (int) Math.floor(value); // DivineMC - Math Optimizations
}
public static int floor(double value) {
- int i = (int)value;
- return value < i ? i - 1 : i;
+ return (int) Math.floor(value); // DivineMC - Math Optimizations
}
public static long lfloor(double value) {
- long l = (long)value;
- return value < l ? l - 1L : l;
+ return (long) Math.floor(value); // DivineMC - Math Optimizations
}
public static float abs(float value) {
@@ -81,13 +78,11 @@ public class Mth {
}
public static int ceil(float value) {
- int i = (int)value;
- return value > i ? i + 1 : i;
+ return (int) Math.ceil(value); // DivineMC - Math Optimizations
}
public static int ceil(double value) {
- int i = (int)value;
- return value > i ? i + 1 : i;
+ return (int) Math.ceil(value); // DivineMC - Math Optimizations
}
public static int clamp(int value, int min, int max) {
@@ -123,15 +118,7 @@ public class Mth {
}
public static double absMax(double x, double y) {
- if (x < 0.0) {
- x = -x;
- }
-
- if (y < 0.0) {
- y = -y;
- }
-
- return Math.max(x, y);
+ return Math.max(Math.abs(x), Math.abs(y)); // DivineMC - Math Optimizations
}
public static int floorDiv(int dividend, int divisor) {
@@ -162,14 +149,26 @@ public class Mth {
return Math.floorMod(x, y);
}
- public static float positiveModulo(float numerator, float denominator) {
+ public static float positiveModuloForAnyDenominator(float numerator, float denominator) { // DivineMC - Math Optimizations
return (numerator % denominator + denominator) % denominator;
}
- public static double positiveModulo(double numerator, double denominator) {
+ public static double positiveModuloForAnyDenominator(double numerator, double denominator) { // DivineMC - Math Optimizations
return (numerator % denominator + denominator) % denominator;
}
+ // DivineMC start - Math Optimizations
+ public static float positiveModuloForPositiveIntegerDenominator(float numerator, float denominator) {
+ var modulo = numerator % denominator;
+ return modulo < 0 ? modulo + denominator : modulo;
+ }
+
+ public static double positiveModuloForPositiveIntegerDenominator(double numerator, double denominator) {
+ var modulo = numerator % denominator;
+ return modulo < 0 ? modulo + denominator : modulo;
+ }
+ // DivineMC end - Math Optimizations
+
public static boolean isMultipleOf(int number, int multiple) {
return number % multiple == 0;
}
diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java
index 73962e79a0f3d892e3155443a1b84508b0f4042e..db400d7b25e454b4a1ac8d09a590c3c7d2504052 100644
--- a/net/minecraft/world/level/biome/BiomeManager.java
+++ b/net/minecraft/world/level/biome/BiomeManager.java
@@ -14,6 +14,7 @@ public class BiomeManager {
private static final int ZOOM_MASK = 3;
private final BiomeManager.NoiseBiomeSource noiseBiomeSource;
private final long biomeZoomSeed;
+ private static final double maxOffset = 0.4500000001D; // DivineMC - Math Optimizations
public BiomeManager(BiomeManager.NoiseBiomeSource noiseBiomeSource, long biomeZoomSeed) {
this.noiseBiomeSource = noiseBiomeSource;
@@ -29,39 +30,65 @@ public class BiomeManager {
}
public Holder<Biome> getBiome(BlockPos pos) {
- int i = pos.getX() - 2;
- int i1 = pos.getY() - 2;
- int i2 = pos.getZ() - 2;
- int i3 = i >> 2;
- int i4 = i1 >> 2;
- int i5 = i2 >> 2;
- double d = (i & 3) / 4.0;
- double d1 = (i1 & 3) / 4.0;
- double d2 = (i2 & 3) / 4.0;
- int i6 = 0;
- double d3 = Double.POSITIVE_INFINITY;
+ // DivineMC start - Math Optimizations
+ int xMinus2 = pos.getX() - 2;
+ int yMinus2 = pos.getY() - 2;
+ int zMinus2 = pos.getZ() - 2;
+ int x = xMinus2 >> 2;
+ int y = yMinus2 >> 2;
+ int z = zMinus2 >> 2;
+ double quartX = (double) (xMinus2 & 3) / 4.0;
+ double quartY = (double) (yMinus2 & 3) / 4.0;
+ double quartZ = (double) (zMinus2 & 3) / 4.0;
+ int smallestX = 0;
+ double smallestDist = Double.POSITIVE_INFINITY;
+ for (int biomeX = 0; biomeX < 8; ++biomeX) {
+ boolean everyOtherQuad = (biomeX & 4) == 0;
+ boolean everyOtherPair = (biomeX & 2) == 0;
+ boolean everyOther = (biomeX & 1) == 0;
+ double quartXX = everyOtherQuad ? quartX : quartX - 1.0;
+ double quartYY = everyOtherPair ? quartY : quartY - 1.0;
+ double quartZZ = everyOther ? quartZ : quartZ - 1.0;
- for (int i7 = 0; i7 < 8; i7++) {
- boolean flag = (i7 & 4) == 0;
- boolean flag1 = (i7 & 2) == 0;
- boolean flag2 = (i7 & 1) == 0;
- int i8 = flag ? i3 : i3 + 1;
- int i9 = flag1 ? i4 : i4 + 1;
- int i10 = flag2 ? i5 : i5 + 1;
- double d4 = flag ? d : d - 1.0;
- double d5 = flag1 ? d1 : d1 - 1.0;
- double d6 = flag2 ? d2 : d2 - 1.0;
- double fiddledDistance = getFiddledDistance(this.biomeZoomSeed, i8, i9, i10, d4, d5, d6);
- if (d3 > fiddledDistance) {
- i6 = i7;
- d3 = fiddledDistance;
+ double maxQuartYY = 0.0, maxQuartZZ = 0.0;
+ if (biomeX != 0) {
+ maxQuartYY = Mth.square(Math.max(quartYY + maxOffset, Math.abs(quartYY - maxOffset)));
+ maxQuartZZ = Mth.square(Math.max(quartZZ + maxOffset, Math.abs(quartZZ - maxOffset)));
+ double maxQuartXX = Mth.square(Math.max(quartXX + maxOffset, Math.abs(quartXX - maxOffset)));
+ if (smallestDist < maxQuartXX + maxQuartYY + maxQuartZZ) continue;
}
- }
+ int xx = everyOtherQuad ? x : x + 1;
+ int yy = everyOtherPair ? y : y + 1;
+ int zz = everyOther ? z : z + 1;
+
+ long seed = LinearCongruentialGenerator.next(this.biomeZoomSeed, xx);
+ seed = LinearCongruentialGenerator.next(seed, yy);
+ seed = LinearCongruentialGenerator.next(seed, zz);
+ seed = LinearCongruentialGenerator.next(seed, xx);
+ seed = LinearCongruentialGenerator.next(seed, yy);
+ seed = LinearCongruentialGenerator.next(seed, zz);
+ double offsetX = getFiddle(seed);
+ double sqrX = Mth.square(quartXX + offsetX);
+ if (biomeX != 0 && smallestDist < sqrX + maxQuartYY + maxQuartZZ) continue;
+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed);
+ double offsetY = getFiddle(seed);
+ double sqrY = Mth.square(quartYY + offsetY);
+ if (biomeX != 0 && smallestDist < sqrX + sqrY + maxQuartZZ) continue;
+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed);
+ double offsetZ = getFiddle(seed);
+ double biomeDist = sqrX + sqrY + Mth.square(quartZZ + offsetZ);
- int i7x = (i6 & 4) == 0 ? i3 : i3 + 1;
- int i11 = (i6 & 2) == 0 ? i4 : i4 + 1;
- int i12 = (i6 & 1) == 0 ? i5 : i5 + 1;
- return this.noiseBiomeSource.getNoiseBiome(i7x, i11, i12);
+ if (smallestDist > biomeDist) {
+ smallestX = biomeX;
+ smallestDist = biomeDist;
+ }
+ }
+ return this.noiseBiomeSource.getNoiseBiome(
+ (smallestX & 4) == 0 ? x : x + 1,
+ (smallestX & 2) == 0 ? y : y + 1,
+ (smallestX & 1) == 0 ? z : z + 1
+ );
+ // DivineMC end - Math Optimizations
}
public Holder<Biome> getNoiseBiomeAtPosition(double x, double y, double z) {
diff --git a/net/minecraft/world/level/levelgen/blending/Blender.java b/net/minecraft/world/level/levelgen/blending/Blender.java
index 01e5b29d6e9a5c53c0e23b61ed0c1d7be1a0fe08..d80df05e40f3941ade5ed320e12f8dcf47e6b247 100644
--- a/net/minecraft/world/level/levelgen/blending/Blender.java
+++ b/net/minecraft/world/level/levelgen/blending/Blender.java
@@ -144,7 +144,7 @@ public class Blender {
private static double heightToOffset(double height) {
double d = 1.0;
double d1 = height + 0.5;
- double d2 = Mth.positiveModulo(d1, 8.0);
+ double d2 = Mth.positiveModuloForPositiveIntegerDenominator(d1, 8.0); // DivineMC - Math optimizations
return 1.0 * (32.0 * (d1 - 128.0) - 3.0 * (d1 - 120.0) * d2 + 3.0 * d2 * d2) / (128.0 * (32.0 - 3.0 * d2));
}
diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java
index c9c6e4e460ad8435f12761704bb9b0284d6aa708..54807bb4b4189ceaded1f78a1a9ab85ce40ab2b1 100644
--- a/net/minecraft/world/phys/AABB.java
+++ b/net/minecraft/world/phys/AABB.java
@@ -189,13 +189,15 @@ public class AABB {
}
public AABB intersect(AABB other) {
- double max = Math.max(this.minX, other.minX);
- double max1 = Math.max(this.minY, other.minY);
- double max2 = Math.max(this.minZ, other.minZ);
- double min = Math.min(this.maxX, other.maxX);
- double min1 = Math.min(this.maxY, other.maxY);
- double min2 = Math.min(this.maxZ, other.maxZ);
- return new AABB(max, max1, max2, min, min1, min2);
+ // DivineMC start - Math Optimizations
+ return new AABB(
+ this.minX > other.minX ? this.minX : other.minX,
+ this.minY > other.minY ? this.minY : other.minY,
+ this.minZ > other.minZ ? this.minZ : other.minZ,
+ this.maxX < other.maxX ? this.maxX : other.maxX,
+ this.maxY < other.maxY ? this.maxY : other.maxY,
+ this.maxZ < other.maxZ ? this.maxZ : other.maxZ
+ );
}
public AABB minmax(AABB other) {
@@ -227,16 +229,37 @@ public class AABB {
}
public boolean intersects(AABB other) {
- return this.intersects(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ);
+ // DivineMC start - Math Optimizations
+ return this.minX < other.maxX &&
+ this.maxX > other.minX &&
+ this.minY < other.maxY &&
+ this.maxY > other.minY &&
+ this.minZ < other.maxZ &&
+ this.maxZ > other.minZ;
+ // DivineMC end - Math Optimizations
}
public boolean intersects(double x1, double y1, double z1, double x2, double y2, double z2) {
- return this.minX < x2 && this.maxX > x1 && this.minY < y2 && this.maxY > y1 && this.minZ < z2 && this.maxZ > z1;
+ // DivineMC start - Math Optimizations
+ return this.minX < x2 &&
+ this.maxX > x1 &&
+ this.minY < y2 &&
+ this.maxY > y1 &&
+ this.minZ < z2 &&
+ this.maxZ > z1;
+ // DivineMC end - Math Optimizations
}
public boolean intersects(Vec3 min, Vec3 max) {
return this.intersects(
- Math.min(min.x, max.x), Math.min(min.y, max.y), Math.min(min.z, max.z), Math.max(min.x, max.x), Math.max(min.y, max.y), Math.max(min.z, max.z)
+ // DivineMC start - Math Optimizations
+ min.x < max.x ? min.x : max.x,
+ min.y < max.y ? min.y : max.y,
+ min.z < max.z ? min.z : max.z,
+ min.x > max.x ? min.x : max.x,
+ min.y > max.y ? min.y : max.y,
+ min.z > max.z ? min.z : max.z
+ // DivineMC end - Math Optimizations
);
}

View File

@@ -1,985 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 00:33:03 +0300
Subject: [PATCH] Chunk System optimization
diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..b588449cfe766c14a0cf4ea9640b04a51bbcf433 100644
--- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
@@ -59,12 +59,15 @@ public final class NearbyPlayers {
public static final int GENERAL_REALLY_SMALL_AREA_VIEW_DISTANCE_BLOCKS = (GENERAL_REALLY_SMALL_VIEW_DISTANCE << 4);
private final ServerLevel world;
- private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
- private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
- private final Long2ReferenceOpenHashMap<ReferenceList<ServerPlayer>>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES];
+ // DivineMC start - Chunk System optimization
+ private final Object callbackLock = new Object();
+ private final it.unimi.dsi.fastutil.objects.Reference2ReferenceMap<ServerPlayer, TrackedPlayer[]> players = it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps.synchronize(new Reference2ReferenceOpenHashMap<>());
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<TrackedChunk> byChunk = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>());
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<ReferenceList<ServerPlayer>>[] directByChunk = new it.unimi.dsi.fastutil.longs.Long2ReferenceMap[TOTAL_MAP_TYPES];
+ // DivineMC end - Chunk System optimization
{
for (int i = 0; i < this.directByChunk.length; ++i) {
- this.directByChunk[i] = new Long2ReferenceOpenHashMap<>();
+ this.directByChunk[i] = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>()); // DivineMC - Chunk System optimization
}
}
@@ -188,7 +191,10 @@ public final class NearbyPlayers {
final ReferenceList<ServerPlayer> list = this.players[idx];
if (list == null) {
++this.nonEmptyLists;
- final ReferenceList<ServerPlayer> players = (this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY));
+ // DivineMC start - Chunk System optimization
+ this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY);
+ final ReferenceList<ServerPlayer> players = this.players[idx];
+ // DivineMC end - Chunk System optimization
this.nearbyPlayers.directByChunk[idx].put(this.chunkKey, players);
players.add(player);
return;
diff --git a/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java b/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
index 866f38eb0f379ffbe2888023a7d1c290f521a231..08666b4aa1c7663861dc361f60e6f1cc46694521 100644
--- a/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
+++ b/ca/spottedleaf/moonrise/patches/blockstate_propertyaccess/util/ZeroCollidingReferenceStateTable.java
@@ -21,13 +21,15 @@ import net.minecraft.world.level.block.state.properties.Property;
public final class ZeroCollidingReferenceStateTable<O, S> {
- private final Int2ObjectOpenHashMap<Indexer> propertyToIndexer;
+ private final it.unimi.dsi.fastutil.ints.Int2ObjectMap<Indexer> propertyToIndexer; // DivineMC - Chunk System optimization
private S[] lookup;
private final Collection<Property<?>> properties;
public ZeroCollidingReferenceStateTable(final Collection<Property<?>> properties) {
- this.propertyToIndexer = new Int2ObjectOpenHashMap<>(properties.size());
- this.properties = new ReferenceArrayList<>(properties);
+ // DivineMC start - Chunk System optimization
+ this.propertyToIndexer = it.unimi.dsi.fastutil.ints.Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>(properties.size()));
+ this.properties = it.unimi.dsi.fastutil.objects.ReferenceLists.synchronize(new ReferenceArrayList<>(properties));
+ // DivineMC end - Chunk System optimization
final List<Property<?>> sortedProperties = new ArrayList<>(properties);
@@ -77,11 +79,11 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
return ret;
}
- public boolean isLoaded() {
+ public synchronized boolean isLoaded() { // DivineMC - Chunk System optimization
return this.lookup != null;
}
- public void loadInTable(final Map<Map<Property<?>, Comparable<?>>, S> universe) {
+ public synchronized void loadInTable(final Map<Map<Property<?>, Comparable<?>>, S> universe) { // DivineMC - Chunk System optimization
if (this.lookup != null) {
throw new IllegalStateException();
}
@@ -117,7 +119,7 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
return ((PropertyAccess<T>)property).moonrise$getById((int)modded);
}
- public <T extends Comparable<T>> S set(final long index, final Property<T> property, final T with) {
+ public synchronized <T extends Comparable<T>> S set(final long index, final Property<T> property, final T with) { // DivineMC - Chunk System optimization
final int newValueId = ((PropertyAccess<T>)property).moonrise$getIdFor(with);
if (newValueId < 0) {
return null;
@@ -139,7 +141,7 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
return this.lookup[(int)newIndex];
}
- public <T extends Comparable<T>> S trySet(final long index, final Property<T> property, final T with, final S dfl) {
+ public synchronized <T extends Comparable<T>> S trySet(final long index, final Property<T> property, final T with, final S dfl) { // DivineMC - Chunk System optimization
final Indexer indexer = this.propertyToIndexer.get(((PropertyAccess<T>)property).moonrise$getId());
if (indexer == null) {
return dfl;
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index 8ef5a1aaac9c27873ce746eb281f77bb318a3c69..76b8d42ae530b59cdaba0583365a557da6b90ede 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -301,7 +301,7 @@ public final class RegionizedPlayerChunkLoader {
return false;
}
- public void tick() {
+ public synchronized void tick() { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread("Cannot tick player chunk loader async");
long currTime = System.nanoTime();
for (final ServerPlayer player : new java.util.ArrayList<>(this.world.players())) {
@@ -312,6 +312,7 @@ public final class RegionizedPlayerChunkLoader {
}
loader.update(); // can't invoke plugin logic
loader.updateQueues(currTime);
+ player.connection.resumeFlushing(); // DivineMC - Chunk System optimization
}
}
@@ -362,7 +363,7 @@ public final class RegionizedPlayerChunkLoader {
GENERATED_TICKET_LEVEL,
TICK_TICKET_LEVEL
};
- private final Long2ByteOpenHashMap chunkTicketStage = new Long2ByteOpenHashMap();
+ private final it.unimi.dsi.fastutil.longs.Long2ByteMap chunkTicketStage = it.unimi.dsi.fastutil.longs.Long2ByteMaps.synchronize(new Long2ByteOpenHashMap()); // DivineMC - Chunk System optimization
{
this.chunkTicketStage.defaultReturnValue(CHUNK_TICKET_STAGE_NONE);
}
@@ -384,10 +385,19 @@ public final class RegionizedPlayerChunkLoader {
final int centerX = PlayerChunkLoaderData.this.lastChunkX;
final int centerZ = PlayerChunkLoaderData.this.lastChunkZ;
- return Integer.compare(
- Math.abs(c1x - centerX) + Math.abs(c1z - centerZ),
- Math.abs(c2x - centerX) + Math.abs(c2z - centerZ)
- );
+ // DivineMC start - Chunk Loading Priority Optimization
+ if (org.bxteam.divinemc.DivineConfig.chunkTaskPriority == org.bxteam.divinemc.server.chunk.ChunkTaskPriority.EUCLIDEAN_CIRCLE_PATTERN) {
+ return Integer.compare(
+ (c1x - centerX) * (c1x - centerX) + (c1z - centerZ) * (c1z - centerZ),
+ (c2x - centerX) * (c2x - centerX) + (c2z - centerZ) * (c2z - centerZ)
+ );
+ } else {
+ return Integer.compare(
+ Math.abs(c1x - centerX) + Math.abs(c1z - centerZ),
+ Math.abs(c2x - centerX) + Math.abs(c2z - centerZ)
+ );
+ }
+ // DivineMC end - Chunk Loading Priority Optimization
};
private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
@@ -490,7 +500,7 @@ public final class RegionizedPlayerChunkLoader {
}
@Override
- protected void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) {
+ protected synchronized void removeCallback(final PlayerChunkLoaderData parameter, final int chunkX, final int chunkZ) { // DivineMC - Chunk System optimization - synchronized
final long chunk = CoordinateUtils.getChunkKey(chunkX, chunkZ);
// note: by the time this is called, the tick cleanup should have ran - so, if the chunk is at
// the tick stage it was deemed in range for loading. Thus, we need to move it to generated
@@ -624,7 +634,7 @@ public final class RegionizedPlayerChunkLoader {
return Math.max(Math.abs(dx), Math.abs(dz)) <= this.lastTickDistance;
}
- private boolean areNeighboursGenerated(final int chunkX, final int chunkZ, final int radius) {
+ private synchronized boolean areNeighboursGenerated(final int chunkX, final int chunkZ, final int radius) { // DivineMC - Chunk System optimization - synchronized
for (int dz = -radius; dz <= radius; ++dz) {
for (int dx = -radius; dx <= radius; ++dx) {
if ((dx | dz) == 0) {
@@ -643,19 +653,11 @@ public final class RegionizedPlayerChunkLoader {
return true;
}
- void updateQueues(final long time) {
+ synchronized void updateQueues(final long time) { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread(this.player, "Cannot tick player chunk loader async");
if (this.removed) {
throw new IllegalStateException("Ticking removed player chunk loader");
}
- // update rate limits
- final double loadRate = this.getMaxChunkLoadRate();
- final double genRate = this.getMaxChunkGenRate();
- final double sendRate = this.getMaxChunkSendRate();
-
- this.chunkLoadTicketLimiter.tickAllocation(time, loadRate, loadRate);
- this.chunkGenerateTicketLimiter.tickAllocation(time, genRate, genRate);
- this.chunkSendLimiter.tickAllocation(time, sendRate, sendRate);
// try to progress chunk loads
while (!this.loadingQueue.isEmpty()) {
@@ -682,8 +684,7 @@ public final class RegionizedPlayerChunkLoader {
}
// try to push more chunk loads
- final long maxLoads = Math.max(0L, Math.min(MAX_RATE, Math.min(this.loadQueue.size(), this.getMaxChunkLoads())));
- final int maxLoadsThisTick = (int)this.chunkLoadTicketLimiter.takeAllocation(time, loadRate, maxLoads);
+ final int maxLoadsThisTick = this.loadQueue.size(); // DivineMC - Chunk System optimization
if (maxLoadsThisTick > 0) {
final LongArrayList chunks = new LongArrayList(maxLoadsThisTick);
for (int i = 0; i < maxLoadsThisTick; ++i) {
@@ -758,9 +759,7 @@ public final class RegionizedPlayerChunkLoader {
}
// try to push more chunk generations
- final long maxGens = Math.max(0L, Math.min(MAX_RATE, Math.min(this.genQueue.size(), this.getMaxChunkGenerates())));
- // preview the allocations, as we may not actually utilise all of them
- final long maxGensThisTick = this.chunkGenerateTicketLimiter.previewAllocation(time, genRate, maxGens);
+ final long maxGensThisTick = this.genQueue.size(); // DivineMC - Chunk System optimization
long ratedGensThisTick = 0L;
while (!this.genQueue.isEmpty()) {
final long chunkKey = this.genQueue.firstLong();
@@ -790,8 +789,6 @@ public final class RegionizedPlayerChunkLoader {
);
this.generatingQueue.enqueue(chunkKey);
}
- // take the allocations we actually used
- this.chunkGenerateTicketLimiter.takeAllocation(time, genRate, ratedGensThisTick);
// try to pull ticking chunks
while (!this.tickingQueue.isEmpty()) {
@@ -821,10 +818,10 @@ public final class RegionizedPlayerChunkLoader {
}
// try to pull sending chunks
- final long maxSends = Math.max(0L, Math.min(MAX_RATE, Integer.MAX_VALUE)); // note: no logic to track concurrent sends
- final int maxSendsThisTick = Math.min((int)this.chunkSendLimiter.takeAllocation(time, sendRate, maxSends), this.sendQueue.size());
+ final int maxSendsThisTick = this.sendQueue.size(); // DivineMC - Chunk System optimization
// we do not return sends that we took from the allocation back because we want to limit the max send rate, not target it
for (int i = 0; i < maxSendsThisTick; ++i) {
+ if (this.sendQueue.isEmpty()) break; // DivineMC - Chunk System optimization
final long pendingSend = this.sendQueue.firstLong();
final int pendingSendX = CoordinateUtils.getChunkX(pendingSend);
final int pendingSendZ = CoordinateUtils.getChunkZ(pendingSend);
@@ -889,9 +886,6 @@ public final class RegionizedPlayerChunkLoader {
// reset limiters, they will start at a zero allocation
final long time = System.nanoTime();
- this.chunkLoadTicketLimiter.reset(time);
- this.chunkGenerateTicketLimiter.reset(time);
- this.chunkSendLimiter.reset(time);
// now we can update
this.update();
@@ -910,10 +904,10 @@ public final class RegionizedPlayerChunkLoader {
);
}
- void update() {
+ synchronized void update() { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread(this.player, "Cannot update player asynchronously");
if (this.removed) {
- throw new IllegalStateException("Updating removed player chunk loader");
+ return; // DivineMC - Chunk System optimization
}
final ViewDistances playerDistances = ((ChunkSystemServerPlayer)this.player).moonrise$getViewDistanceHolder().getViewDistances();
final ViewDistances worldDistances = ((ChunkSystemServerLevel)this.world).moonrise$getViewDistanceHolder().getViewDistances();
@@ -1062,7 +1056,7 @@ public final class RegionizedPlayerChunkLoader {
this.flushDelayedTicketOps();
}
- void remove() {
+ synchronized void remove() { // DivineMC - Chunk System optimization - synchronized
TickThread.ensureTickThread(this.player, "Cannot add player asynchronously");
if (this.removed) {
throw new IllegalStateException("Removing removed player chunk loader");
@@ -1090,7 +1084,7 @@ public final class RegionizedPlayerChunkLoader {
}
public LongOpenHashSet getSentChunksRaw() {
- return this.sentChunks;
+ return new LongOpenHashSet(this.sentChunks); // DivineMC - Chunk System optimization
}
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
index 0c99bffa769d53562a10d23c4a9b37dc59c7f478..f4fcc3b2676b17ebc276dcb177285f18a0cdfe99 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
@@ -71,36 +71,49 @@ public final class ChunkHolderManager {
private static final long PROBE_MARKER = Long.MIN_VALUE + 1;
public final ReentrantAreaLock ticketLockArea;
- private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket<?>>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
- private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
+ // DivineMC start - Chunk System optimization
+ private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket<?>>> tickets = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
+ private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
+ // DivineMC end - Chunk System optimization
final ChunkUnloadQueue unloadQueue;
- private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f);
+ private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F); // DivineMC - Chunk System optimization
private final ServerLevel world;
private final ChunkTaskScheduler taskScheduler;
private long currentTick;
- private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
- private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
- if (c1 == c2) {
- return 0;
- }
+ // DivineMC start - Chunk System optimization
+ public static class LevelHolderData {
+ private final java.util.concurrent.ConcurrentLinkedDeque<NewChunkHolder> pendingFullLoadUpdate = new java.util.concurrent.ConcurrentLinkedDeque<>();
+ private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
+ if (c1 == c2) {
+ return 0;
+ }
- final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave);
+ final int saveTickCompare = Long.compare(c1.lastAutoSave, c2.lastAutoSave);
- if (saveTickCompare != 0) {
- return saveTickCompare;
- }
+ if (saveTickCompare != 0) {
+ return saveTickCompare;
+ }
- final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ);
- final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ);
+ final long coord1 = CoordinateUtils.getChunkKey(c1.chunkX, c1.chunkZ);
+ final long coord2 = CoordinateUtils.getChunkKey(c2.chunkX, c2.chunkZ);
- if (coord1 == coord2) {
- throw new IllegalStateException("Duplicate chunkholder in auto save queue");
- }
+ if (coord1 == coord2) {
+ throw new IllegalStateException("Duplicate chunkholder in auto save queue");
+ }
- return Long.compare(coord1, coord2);
- });
+ return Long.compare(coord1, coord2);
+ });
+ }
+
+ public LevelHolderData getData() {
+ if (this.world == null) {
+ throw new RuntimeException("World was null!");
+ }
+ return world.chunkHolderData;
+ }
+ // DivineMC end - Chunk System optimization
public ChunkHolderManager(final ServerLevel world, final ChunkTaskScheduler taskScheduler) {
this.world = world;
@@ -222,26 +235,29 @@ public final class ChunkHolderManager {
this.taskScheduler.setShutdown(true);
}
- void ensureInAutosave(final NewChunkHolder holder) {
- if (!this.autoSaveQueue.contains(holder)) {
+ // DivineMC start - Chunk System optimization
+ synchronized void ensureInAutosave(final NewChunkHolder holder) {
+ final LevelHolderData data = getData();
+ if (!data.autoSaveQueue.contains(holder)) {
holder.lastAutoSave = this.currentTick;
- this.autoSaveQueue.add(holder);
+ data.autoSaveQueue.add(holder);
}
}
- public void autoSave() {
+ public synchronized void autoSave() {
+ final LevelHolderData data = getData();
final List<NewChunkHolder> reschedule = new ArrayList<>();
final long currentTick = this.currentTick;
final long maxSaveTime = currentTick - Math.max(1L, PlatformHooks.get().configAutoSaveInterval(this.world));
final int maxToSave = PlatformHooks.get().configMaxAutoSavePerTick(this.world);
- for (int autoSaved = 0; autoSaved < maxToSave && !this.autoSaveQueue.isEmpty();) {
- final NewChunkHolder holder = this.autoSaveQueue.first();
+ for (int autoSaved = 0; autoSaved < maxToSave && !data.autoSaveQueue.isEmpty();) {
+ final NewChunkHolder holder = data.autoSaveQueue.first();
if (holder.lastAutoSave > maxSaveTime) {
break;
}
- this.autoSaveQueue.remove(holder);
+ data.autoSaveQueue.remove(holder);
holder.lastAutoSave = currentTick;
if (holder.save(false) != null) {
@@ -255,10 +271,11 @@ public final class ChunkHolderManager {
for (final NewChunkHolder holder : reschedule) {
if (holder.getChunkStatus().isOrAfter(FullChunkStatus.FULL)) {
- this.autoSaveQueue.add(holder);
+ data.autoSaveQueue.add(holder);
}
}
}
+ // DivineMC end - Chunk System optimization
public void saveAllChunks(final boolean flush, final boolean shutdown, final boolean logProgress) {
final List<NewChunkHolder> holders = this.getChunkHolders();
@@ -317,13 +334,9 @@ public final class ChunkHolderManager {
}
if (logProgress) {
final long currTime = System.nanoTime();
- if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(10L)) {
+ if ((currTime - lastLog) > TimeUnit.SECONDS.toNanos(5L)) { // DivineMC - Log a bit more frequently
lastLog = currTime;
- LOGGER.info(
- "Saved " + savedChunk + " block chunks, " + savedEntity + " entity chunks, " + savedPoi
- + " poi chunks in world '" + WorldUtil.getWorldName(this.world) + "', progress: "
- + format.format((double)(i+1)/(double)len * 100.0)
- );
+ LOGGER.info("Saved {} block chunks, {} entity chunks, {} poi chunks in world '{}', progress: {}", savedChunk, savedEntity, savedPoi, ca.spottedleaf.moonrise.common.util.WorldUtil.getWorldName(this.world), format.format((double) (i + 1) / (double) len * 100.0)); // DivineMC - Beautify log
}
}
}
@@ -425,8 +438,8 @@ public final class ChunkHolderManager {
final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> ret = new Long2ObjectOpenHashMap<>();
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
- final long coord = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long coord = iterator.next(); // DivineMC - Chunk System optimization
sections.computeIfAbsent(
CoordinateUtils.getChunkKey(
CoordinateUtils.getChunkX(coord) >> sectionShift,
@@ -523,7 +536,7 @@ public final class ChunkHolderManager {
chunkZ >> sectionShift
);
- this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (final long keyInMap) -> {
+ this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (keyInMap) -> { // DivineMC - Chunk System optimization
return new Long2IntOpenHashMap();
}).addTo(chunkKey, 1);
}
@@ -567,7 +580,7 @@ public final class ChunkHolderManager {
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
try {
- final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> {
+ final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (keyInMap) -> { // DivineMC - Chunk System optimization
return SortedArraySet.create(4);
});
@@ -697,8 +710,8 @@ public final class ChunkHolderManager {
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
- for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
- final long coord = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.tickets.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long coord = iterator.next(); // DivineMC - Chunk System optimization
sections.computeIfAbsent(
CoordinateUtils.getChunkKey(
CoordinateUtils.getChunkX(coord) >> sectionShift,
@@ -746,8 +759,8 @@ public final class ChunkHolderManager {
return removeDelay <= 0L;
};
- for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) {
- final long sectionKey = iterator.nextLong();
+ for (final Iterator<Long> iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
+ final long sectionKey = iterator.next(); // DivineMC - Chunk System optimization
if (!this.sectionToChunkToExpireCount.containsKey(sectionKey)) {
// removed concurrently
@@ -1033,7 +1046,7 @@ public final class ChunkHolderManager {
}
if (!TickThread.isTickThreadFor(world)) { // DivineMC - parallel world ticking
this.taskScheduler.scheduleChunkTask(() -> {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
pendingFullLoadUpdate.add(changedFullStatus.get(i));
}
@@ -1041,16 +1054,16 @@ public final class ChunkHolderManager {
ChunkHolderManager.this.processPendingFullUpdate();
}, Priority.HIGHEST);
} else {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
pendingFullLoadUpdate.add(changedFullStatus.get(i));
}
}
}
- private void removeChunkHolder(final NewChunkHolder holder) {
+ private synchronized void removeChunkHolder(final NewChunkHolder holder) { // DivineMC - Chunk System optimization
holder.onUnload();
- this.autoSaveQueue.remove(holder);
+ this.getData().autoSaveQueue.remove(holder); // DivineMC - Chunk System optimization
PlatformHooks.get().onChunkHolderDelete(this.world, holder.vanillaChunkHolder);
this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ));
}
@@ -1208,6 +1221,27 @@ public final class ChunkHolderManager {
}
}
+ // DivineMC start - Chunk System optimization
+ public final java.util.Set<Long> blockTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true));
+ public final java.util.Set<Long> entityTickingChunkHolders = java.util.Collections.synchronizedSet(new org.agrona.collections.ObjectHashSet<>(10, 0.88f, true));
+
+ public void markBlockTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.add(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markNonBlockTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.blockTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markEntityTicking(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.add(newChunkHolder.getCachedLongPos());
+ }
+
+ public void markNonEntityTickingIfPossible(@org.jetbrains.annotations.NotNull NewChunkHolder newChunkHolder) {
+ this.entityTickingChunkHolders.remove(newChunkHolder.getCachedLongPos());
+ }
+ // DivineMC end - Chunk System optimization
+
public enum TicketOperationType {
ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE
}
@@ -1381,7 +1415,7 @@ public final class ChunkHolderManager {
// only call on tick thread
private boolean processPendingFullUpdate() {
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Chunk System optimization
boolean ret = false;
@@ -1417,8 +1451,7 @@ public final class ChunkHolderManager {
final JsonArray allTicketsJson = new JsonArray();
ret.add("tickets", allTicketsJson);
- for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>>> iterator = this.tickets.entryIterator();
- iterator.hasNext();) {
+ for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>>> iterator = this.tickets.entryIterator(); iterator.hasNext();) { // DivineMC - Chunk System optimization
final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>> coordinateTickets = iterator.next();
final long coordinate = coordinateTickets.getKey();
final SortedArraySet<Ticket<?>> tickets = coordinateTickets.getValue();
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
index e4a5fa25ed368fc4662c30934da2963ef446d782..6da0ea5cd83a00578223e0a19f952c917bcbcdae 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
@@ -644,11 +644,19 @@ public final class NewChunkHolder {
}
public final ChunkHolder vanillaChunkHolder;
+ // DivineMC start - Chunk System optimization
+ private final long cachedLongPos;
+
+ public long getCachedLongPos() {
+ return cachedLongPos;
+ }
+ // DivineMC end - Chunk System optimization
public NewChunkHolder(final ServerLevel world, final int chunkX, final int chunkZ, final ChunkTaskScheduler scheduler) {
this.world = world;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
+ this.cachedLongPos = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(this.chunkX, this.chunkZ); // DivineMC - Chunk System optimization
this.scheduler = scheduler;
this.vanillaChunkHolder = new ChunkHolder(
new ChunkPos(chunkX, chunkZ), ChunkHolderManager.MAX_TICKET_LEVEL, world,
@@ -790,9 +798,11 @@ public final class NewChunkHolder {
// note: these are completed with null to indicate that no write occurred
// they are also completed with null to indicate a null write occurred
- private UnloadTask chunkDataUnload;
- private UnloadTask entityDataUnload;
- private UnloadTask poiDataUnload;
+ // DivineMC start - Chunk System optimization
+ private volatile UnloadTask chunkDataUnload;
+ private volatile UnloadTask entityDataUnload;
+ private volatile UnloadTask poiDataUnload;
+ // DivineMC end - Chunk System optimization
public static final record UnloadTask(CallbackCompletable<CompoundTag> completable, PrioritisedExecutor.PrioritisedTask task,
LazyRunnable toRun) {}
@@ -1190,6 +1200,7 @@ public final class NewChunkHolder {
for (int dz = -NEIGHBOUR_RADIUS; dz <= NEIGHBOUR_RADIUS; ++dz) {
for (int dx = -NEIGHBOUR_RADIUS; dx <= NEIGHBOUR_RADIUS; ++dx) {
final NewChunkHolder holder = (dx | dz) == 0 ? this : this.scheduler.chunkHolderManager.getChunkHolder(dx + this.chunkX, dz + this.chunkZ);
+ if (holder == null) continue; // DivineMC - Chunk System optimization
if (loaded) {
if (holder.setNeighbourFullLoaded(-dx, -dz)) {
changedFullStatus.add(holder);
@@ -1214,6 +1225,19 @@ public final class NewChunkHolder {
private void updateCurrentState(final FullChunkStatus to) {
this.currentFullChunkStatus = to;
+ // DivineMC start - Chunk System optimization
+ if (to.isOrAfter(FullChunkStatus.BLOCK_TICKING)) {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markBlockTicking(this);
+ } else {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonBlockTickingIfPossible(this);
+ }
+
+ if (to.isOrAfter(FullChunkStatus.ENTITY_TICKING)) {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markEntityTicking(this);
+ } else {
+ this.world.moonrise$getChunkTaskScheduler().chunkHolderManager.markNonEntityTickingIfPossible(this);
+ }
+ // DivineMC end - Chunk System optimization
}
// only to be called on the main thread, no locks need to be held
@@ -1348,11 +1372,11 @@ public final class NewChunkHolder {
return this.requestedGenStatus;
}
- private final Reference2ObjectOpenHashMap<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = new Reference2ObjectOpenHashMap<>();
+ private final Map<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Chunk System optimization
void addStatusConsumer(final ChunkStatus status, final Consumer<ChunkAccess> consumer) {
this.statusWaiters.computeIfAbsent(status, (final ChunkStatus keyInMap) -> {
- return new ArrayList<>(4);
+ return new java.util.concurrent.CopyOnWriteArrayList<>(); // DivineMC - Chunk System optimization
}).add(consumer);
}
@@ -1394,11 +1418,11 @@ public final class NewChunkHolder {
}, Priority.HIGHEST);
}
- private final Reference2ObjectOpenHashMap<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = new Reference2ObjectOpenHashMap<>();
+ private final Map<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = new java.util.concurrent.ConcurrentHashMap<>();
void addFullStatusConsumer(final FullChunkStatus status, final Consumer<LevelChunk> consumer) {
this.fullStatusWaiters.computeIfAbsent(status, (final FullChunkStatus keyInMap) -> {
- return new ArrayList<>(4);
+ return new java.util.concurrent.CopyOnWriteArrayList<>(); // DivineMC - Chunk System optimization
}).add(consumer);
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
index e97e7d276faf055c89207385d3820debffb06463..4aeb75a2cdcfb4206bab3eee5ad674dd9890e720 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
@@ -2,6 +2,6 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration;
public final class ChunkTickConstants {
- public static final int PLAYER_SPAWN_TRACK_RANGE = 8;
+ public static final int PLAYER_SPAWN_TRACK_RANGE = (int) Math.round(org.bxteam.divinemc.DivineConfig.playerNearChunkDetectionRange / 16.0); // DivineMC - Chunk System optimization
}
diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
index 4ca68a903e67606fc4ef0bfa9862a73797121c8b..f94f443f862611f039454d1dc8ff2a4ba5f081d3 100644
--- a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
+++ b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
@@ -325,7 +325,7 @@ public final class SWMRNibbleArray {
}
// operation type: updating
- public boolean updateVisible() {
+ public synchronized boolean updateVisible() { // DivineMC - Chunk System optimization
if (!this.isDirty()) {
return false;
}
diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java
index 5eab6179ce3913cb4e4d424f910ba423faf21c85..4b1efd53e423bdfe90d5efd472823869fc87e73b 100644
--- a/net/minecraft/server/level/DistanceManager.java
+++ b/net/minecraft/server/level/DistanceManager.java
@@ -178,15 +178,13 @@ public abstract class DistanceManager implements ca.spottedleaf.moonrise.patches
public boolean inEntityTickingRange(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos);
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkHolderManager().entityTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean inBlockTickingRange(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(chunkPos);
- return chunkHolder != null && chunkHolder.isTickingReady();
+ return this.moonrise$getChunkHolderManager().blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index ab30af9cd58ff7310e05be87b08f42bacf69e11e..ae0e36d198ad8243920c8e8a55c0be4945542763 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -439,8 +439,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
public boolean isPositionTicking(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder newChunkHolder = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- return newChunkHolder != null && newChunkHolder.isTickingReady();
+ return ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 973198ae0a73d6747e73548bdcbc1de46b6fb107..1581bf8ff425c6e0df28d107300d7266e9f87ed5 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -181,6 +181,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
public final ServerChunkCache chunkSource;
private final MinecraftServer server;
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
+ public final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData chunkHolderData; // DivineMC - Chunk System optimization
private int lastSpawnChunkRadius;
final EntityTickList entityTickList = new EntityTickList(this); // DivineMC - parallel world ticking
// Paper - rewrite chunk system
@@ -689,6 +690,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper start - rewrite chunk system
this.moonrise$setEntityLookup(new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup((ServerLevel)(Object)this, ((ServerLevel)(Object)this).new EntityCallbacks()));
this.chunkTaskScheduler = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler((ServerLevel)(Object)this);
+ this.chunkHolderData = new ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager.LevelHolderData(); // DivineMC - Chunk System optimization
this.entityDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController(
new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityDataController.EntityRegionFileStorage(
new RegionStorageInfo(levelStorageAccess.getLevelId(), dimension, "entities"),
@@ -832,8 +834,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public boolean shouldTickBlocksAt(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder holder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- return holder != null && holder.isTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
@@ -2525,30 +2526,25 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private boolean isPositionTickingWithEntitiesLoaded(long chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkPos);
- // isTicking implies the chunk is loaded, and the chunk is loaded now implies the entities are loaded
- return chunkHolder != null && chunkHolder.isTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.blockTickingChunkHolders.contains(chunkPos); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean isPositionEntityTicking(BlockPos pos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos));
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean isNaturalSpawningAllowed(BlockPos pos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos));
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(pos)); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
public boolean isNaturalSpawningAllowed(ChunkPos chunkPos) {
// Paper start - rewrite chunk system
- final ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkPos));
- return chunkHolder != null && chunkHolder.isEntityTickingReady();
+ return this.moonrise$getChunkTaskScheduler().chunkHolderManager.entityTickingChunkHolders.contains(ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(chunkPos)); // DivineMC - Chunk System optimization
// Paper end - rewrite chunk system
}
diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java
index 26c8c1e5598daf3550aef05b12218c47bda6618b..94c824ab1457939c425e1f99929d3222ee2c18a0 100644
--- a/net/minecraft/world/level/LevelReader.java
+++ b/net/minecraft/world/level/LevelReader.java
@@ -70,10 +70,27 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste
@Override
default Holder<Biome> getNoiseBiome(int x, int y, int z) {
- ChunkAccess chunk = this.getChunk(QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false);
+ ChunkAccess chunk = this.fasterChunkAccess(this, QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false); // DivineMC - Chunk System optimization
return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z);
}
+ // DivineMC start - Chunk System optimization
+ private @Nullable ChunkAccess fasterChunkAccess(LevelReader instance, int x, int z, ChunkStatus chunkStatus, boolean create) {
+ if (!create && instance instanceof net.minecraft.server.level.ServerLevel world) {
+ final net.minecraft.server.level.ChunkHolder holder = (world.getChunkSource().chunkMap).getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
+ if (holder != null) {
+ final java.util.concurrent.CompletableFuture<net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk>> future = holder.getFullChunkFuture();
+ final net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk> either = future.getNow(null);
+ if (either != null) {
+ final net.minecraft.world.level.chunk.LevelChunk chunk = either.orElse(null);
+ if (chunk != null) return chunk;
+ }
+ }
+ }
+ return instance.getChunk(x, z, chunkStatus, create);
+ }
+ // DivineMC end - Chunk System optimization
+
Holder<Biome> getUncachedNoiseBiome(int x, int y, int z);
boolean isClientSide();
diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java
index e66239e2da91bd3ddf358d239be796719c0da327..35e9d8cfe12252d3419626f1cefb64d30e20069e 100644
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
@@ -41,7 +41,7 @@ public class ProtoChunk extends ChunkAccess {
@Nullable
private volatile LevelLightEngine lightEngine;
private volatile ChunkStatus status = ChunkStatus.EMPTY;
- private final List<CompoundTag> entities = Lists.newArrayList();
+ private final List<CompoundTag> entities = Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Chunk System optimization
@Nullable
private CarvingMask carvingMask;
@Nullable
diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java
index 2199a9e2a0141c646d108f2687a27f1d165453c5..c28c2583b257f92207b822a1fdde8f5b7e480992 100644
--- a/net/minecraft/world/level/chunk/storage/IOWorker.java
+++ b/net/minecraft/world/level/chunk/storage/IOWorker.java
@@ -212,7 +212,38 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable {
});
}
+ // DivineMC start - Chunk System optimization
+ private void checkHardLimit() {
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheLimit) {
+ LOGGER.warn("Chunk data cache size exceeded hard limit ({} >= {}), forcing writes to disk (you can increase chunkDataCacheLimit in c2me.toml)", this.pendingWrites.size(), org.bxteam.divinemc.DivineConfig.chunkDataCacheLimit);
+ while (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit * 0.75) {
+ writeResult0();
+ }
+ }
+ }
+
+ private void writeResult0() {
+ java.util.Iterator<java.util.Map.Entry<net.minecraft.world.level.ChunkPos, net.minecraft.world.level.chunk.storage.IOWorker.PendingStore>> iterator = this.pendingWrites.entrySet().iterator();
+ if (iterator.hasNext()) {
+ java.util.Map.Entry<ChunkPos, IOWorker.PendingStore> entry = iterator.next();
+ iterator.remove();
+ this.runStore(entry.getKey(), entry.getValue());
+ }
+ }
+ // DivineMC end - Chunk System optimization
+
private void storePendingChunk() {
+ // DivineMC start - Chunk System optimization
+ if (!this.pendingWrites.isEmpty()) {
+ checkHardLimit();
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit) {
+ int writeFrequency = Math.min(1, (this.pendingWrites.size() - (int) org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit) / 16);
+ for (int i = 0; i < writeFrequency; i++) {
+ writeResult0();
+ }
+ }
+ }
+ // DivineMC end - Chunk System optimization
Entry<ChunkPos, IOWorker.PendingStore> entry = this.pendingWrites.pollFirstEntry();
if (entry != null) {
this.runStore(entry.getKey(), entry.getValue());
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 6ebd1300c2561116b83cb2472ac7939ead36d576..16cd10ab8de69ca3d29c84cf93715645322fd72a 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -244,7 +244,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
protected RegionFileStorage(RegionStorageInfo info, Path folder, boolean sync) { // Paper - protected
this.folder = folder;
- this.sync = sync;
+ this.sync = Boolean.parseBoolean(System.getProperty("com.ishland.c2me.chunkio.syncDiskWrites", String.valueOf(sync))); // DivineMC - C2ME: sync disk writes
this.info = info;
this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
}
diff --git a/net/minecraft/world/level/levelgen/Column.java b/net/minecraft/world/level/levelgen/Column.java
index 4a1df0f8578c9ee5538ed8c94d3c7911f36f83b8..716c2c69843234cdef34339d859babc95ffe318c 100644
--- a/net/minecraft/world/level/levelgen/Column.java
+++ b/net/minecraft/world/level/levelgen/Column.java
@@ -156,7 +156,7 @@ public abstract class Column {
}
public int height() {
- return this.ceiling - this.floor - 1;
+ return net.minecraft.util.Mth.abs(this.ceiling - this.floor - 1); // DivineMC - Chunk System optimization
}
@Override
diff --git a/net/minecraft/world/level/levelgen/WorldgenRandom.java b/net/minecraft/world/level/levelgen/WorldgenRandom.java
index c2d7cd788071e25b8ba2503c30ae80c7a9f353ed..0a2e13c4a3db6517267e1f9e74b6152c73e8351f 100644
--- a/net/minecraft/world/level/levelgen/WorldgenRandom.java
+++ b/net/minecraft/world/level/levelgen/WorldgenRandom.java
@@ -73,7 +73,7 @@ public class WorldgenRandom extends LegacyRandomSource {
}
public static enum Algorithm {
- LEGACY(LegacyRandomSource::new),
+ LEGACY(ThreadSafeLegacyRandomSource::new), // DivineMC - Chunk System optimization
XOROSHIRO(XoroshiroRandomSource::new);
private final LongFunction<RandomSource> constructor;
diff --git a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
index f4009671880b00ecec98fe604215e2824e453cdf..c607c801223ea71343ece67b81151e31362f1c31 100644
--- a/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
+++ b/net/minecraft/world/level/levelgen/feature/stateproviders/RandomizedIntStateProvider.java
@@ -55,17 +55,21 @@ public class RandomizedIntStateProvider extends BlockStateProvider {
@Override
public BlockState getState(RandomSource random, BlockPos pos) {
- BlockState state = this.source.getState(random, pos);
- if (this.property == null || !state.hasProperty(this.property)) {
- IntegerProperty integerProperty = findProperty(state, this.propertyName);
- if (integerProperty == null) {
- return state;
+ // DivineMC start - Chunk System optimization
+ BlockState blockState = this.source.getState(random, pos);
+ IntegerProperty propertyLocal = this.property;
+ if (propertyLocal == null || !blockState.hasProperty(propertyLocal)) {
+ IntegerProperty intProperty = findProperty(blockState, this.propertyName);
+ if (intProperty == null) {
+ return blockState;
}
- this.property = integerProperty;
+ propertyLocal = intProperty;
+ this.property = intProperty;
}
- return state.setValue(this.property, Integer.valueOf(this.values.sample(random)));
+ return (BlockState)blockState.setValue(propertyLocal, this.values.sample(random));
+ // DivineMC end - Chunk System optimization
}
@Nullable
diff --git a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
index d122221deefb218db962e97ba2d958c33d903b8a..56311b439ac22700593d2d31da3a4efe3a519d53 100644
--- a/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
+++ b/net/minecraft/world/level/levelgen/structure/ScatteredFeaturePiece.java
@@ -12,7 +12,7 @@ public abstract class ScatteredFeaturePiece extends StructurePiece {
protected final int width;
protected final int height;
protected final int depth;
- protected int heightPosition = -1;
+ protected volatile int heightPosition = -1; // DivineMC - Chunk System optimization - make volatile
protected ScatteredFeaturePiece(StructurePieceType type, int x, int y, int z, int width, int height, int depth, Direction orientation) {
super(type, 0, StructurePiece.makeBoundingBox(x, y, z, orientation, width, height, depth));
diff --git a/net/minecraft/world/level/levelgen/structure/StructureStart.java b/net/minecraft/world/level/levelgen/structure/StructureStart.java
index 4dafa79dd4ec55a443ba3731a79e7cd6e8052f48..8aeab4d773473ad20b1c64295c93d6fcb4ea02a1 100644
--- a/net/minecraft/world/level/levelgen/structure/StructureStart.java
+++ b/net/minecraft/world/level/levelgen/structure/StructureStart.java
@@ -26,7 +26,7 @@ public final class StructureStart {
private final Structure structure;
private final PiecesContainer pieceContainer;
private final ChunkPos chunkPos;
- private int references;
+ private final java.util.concurrent.atomic.AtomicInteger references = new java.util.concurrent.atomic.AtomicInteger(); // DivineMC - Chunk System optimization
@Nullable
private volatile BoundingBox cachedBoundingBox;
@@ -39,7 +39,7 @@ public final class StructureStart {
public StructureStart(Structure structure, ChunkPos chunkPos, int references, PiecesContainer pieceContainer) {
this.structure = structure;
this.chunkPos = chunkPos;
- this.references = references;
+ this.references.set(references); // DivineMC - Chunk System optimization
this.pieceContainer = pieceContainer;
}
@@ -126,7 +126,7 @@ public final class StructureStart {
compoundTag.putString("id", context.registryAccess().lookupOrThrow(Registries.STRUCTURE).getKey(this.structure).toString());
compoundTag.putInt("ChunkX", chunkPos.x);
compoundTag.putInt("ChunkZ", chunkPos.z);
- compoundTag.putInt("references", this.references);
+ compoundTag.putInt("references", this.references.get()); // DivineMC - Chunk System optimization
compoundTag.put("Children", this.pieceContainer.save(context));
return compoundTag;
} else {
@@ -144,15 +144,15 @@ public final class StructureStart {
}
public boolean canBeReferenced() {
- return this.references < this.getMaxReferences();
+ return this.references.get() < this.getMaxReferences(); // DivineMC - Chunk System optimization
}
public void addReference() {
- this.references++;
+ this.references.getAndIncrement(); // DivineMC - Chunk System optimization
}
public int getReferences() {
- return this.references;
+ return this.references.get(); // DivineMC - Chunk System optimization
}
protected int getMaxReferences() {

View File

@@ -1,682 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 00:55:34 +0300
Subject: [PATCH] Optimize hoppers
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 9f7698f8ce56d5d89cf86f6ea2d5b4d51b18c9a2..351b035d1f3025af28b5147b95b912e0e2ab9212 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1746,7 +1746,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
serverLevel.updateLagCompensationTick(); // Paper - lag compensation
- net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables
if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) {
serverLevelTickingSemaphore.acquire();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 1581bf8ff425c6e0df28d107300d7266e9f87ed5..8c136d77451c17613834c4a7dab6ab6c2fe4d716 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -194,7 +194,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final LevelTicks<Fluid> fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
private final PathTypeCache pathTypesByPosCache = new PathTypeCache();
final Set<Mob> navigatingMobs = new ObjectOpenHashSet<>();
- volatile boolean isUpdatingNavigations;
+ final java.util.concurrent.atomic.AtomicBoolean isUpdatingNavigations = new java.util.concurrent.atomic.AtomicBoolean(false); // DivineMC - Optimize Hoppers
protected final Raids raids;
private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents = new ObjectLinkedOpenHashSet<>();
private final List<BlockEventData> blockEventsToReschedule = new ArrayList<>(64);
@@ -1729,7 +1729,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) {
- if (this.isUpdatingNavigations) {
+ if (this.isUpdatingNavigations.get() && false) { // DivineMC
String string = "recursive call to sendBlockUpdated";
Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated"));
}
@@ -1760,13 +1760,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - catch CME see below why
try {
- this.isUpdatingNavigations = true;
+ this.isUpdatingNavigations.set(true); // DivineMC
for (PathNavigation pathNavigation : list) {
pathNavigation.recomputePath();
}
} finally {
- this.isUpdatingNavigations = false;
+ this.isUpdatingNavigations.set(false); // DivineMC
}
}
} // Paper - option to disable pathfinding updates
@@ -2653,7 +2653,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
if (entity instanceof Mob mob) {
- if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning
+ if (false && ServerLevel.this.isUpdatingNavigations.get()) { // Paper - Remove unnecessary onTrackingStart during navigation warning // DivineMC
String string = "onTrackingStart called during navigation iteration";
Util.logAndPauseIfInIde(
"onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")
@@ -2723,7 +2723,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
if (entity instanceof Mob mob) {
- if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning
+ if (false && ServerLevel.this.isUpdatingNavigations.get()) { // Paper - Remove unnecessary onTrackingStart during navigation warning // DivineMC
String string = "onTrackingStart called during navigation iteration";
Util.logAndPauseIfInIde(
"onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 5cd1326ad5d046c88b2b3449d610a78fa880b4cd..a0ee6ad6e7a6791605191d20d742e16cc9857a60 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -139,56 +139,18 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
}
- // Paper start - Perf: Optimize Hoppers
- private static final int HOPPER_EMPTY = 0;
- private static final int HOPPER_HAS_ITEMS = 1;
- private static final int HOPPER_IS_FULL = 2;
-
- private static int getFullState(final HopperBlockEntity hopper) {
- hopper.unpackLootTable(null);
-
- final List<ItemStack> hopperItems = hopper.items;
-
- boolean empty = true;
- boolean full = true;
-
- for (int i = 0, len = hopperItems.size(); i < len; ++i) {
- final ItemStack stack = hopperItems.get(i);
- if (stack.isEmpty()) {
- full = false;
- continue;
- }
-
- if (!full) {
- // can't be full
- return HOPPER_HAS_ITEMS;
- }
-
- empty = false;
-
- if (stack.getCount() != stack.getMaxStackSize()) {
- // can't be full or empty
- return HOPPER_HAS_ITEMS;
- }
- }
-
- return empty ? HOPPER_EMPTY : (full ? HOPPER_IS_FULL : HOPPER_HAS_ITEMS);
- }
- // Paper end - Perf: Optimize Hoppers
-
private static boolean tryMoveItems(Level level, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier validator) {
if (level.isClientSide) {
return false;
} else {
if (!blockEntity.isOnCooldown() && state.getValue(HopperBlock.ENABLED)) {
boolean flag = false;
- final int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers
- if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
+ if (!blockEntity.isEmpty()) { // DivineMC - Optimize hoppers
flag = ejectItems(level, pos, blockEntity);
}
- if (fullState != HOPPER_IS_FULL || flag) { // Paper - Perf: Optimize Hoppers
- flag |= validator.getAsBoolean(); // Paper - note: this is not a validator, it's what adds/sucks in items
+ if (!blockEntity.inventoryFull()) { // DivineMC - Optimize hoppers
+ flag |= validator.getAsBoolean(); // DivineMC - Optimize hoppers
}
if (flag) {
@@ -212,206 +174,6 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
return true;
}
- // Paper start - Perf: Optimize Hoppers
- public static boolean skipHopperEvents;
- private static boolean skipPullModeEventFire;
- private static boolean skipPushModeEventFire;
-
- private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
- skipPushModeEventFire = skipHopperEvents;
- boolean foundItem = false;
- for (int i = 0; i < hopper.getContainerSize(); ++i) {
- final ItemStack item = hopper.getItem(i);
- if (!item.isEmpty()) {
- foundItem = true;
- ItemStack origItemStack = item;
- ItemStack movedItem = origItemStack;
-
- final int originalItemCount = origItemStack.getCount();
- final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
- origItemStack.setCount(movedItemCount);
-
- // We only need to fire the event once to give protection plugins a chance to cancel this event
- // Because nothing uses getItem, every event call should end up the same result.
- if (!skipPushModeEventFire) {
- movedItem = callPushMoveEvent(destination, movedItem, hopper);
- if (movedItem == null) { // cancelled
- origItemStack.setCount(originalItemCount);
- return false;
- }
- }
-
- final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
- final int remainingItemCount = remainingItem.getCount();
- if (remainingItemCount != movedItemCount) {
- origItemStack = origItemStack.copy(true);
- origItemStack.setCount(originalItemCount);
- if (!origItemStack.isEmpty()) {
- origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
- }
- hopper.setItem(i, origItemStack);
- destination.setChanged();
- return true;
- }
- origItemStack.setCount(originalItemCount);
- }
- }
- if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
- hopper.setCooldown(level.spigotConfig.hopperTransfer);
- }
- return false;
- }
-
- private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) {
- ItemStack movedItem = origItemStack;
- final int originalItemCount = origItemStack.getCount();
- final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
- container.setChanged(); // original logic always marks source inv as changed even if no move happens.
- movedItem.setCount(movedItemCount);
-
- if (!skipPullModeEventFire) {
- movedItem = callPullMoveEvent(hopper, container, movedItem);
- if (movedItem == null) { // cancelled
- origItemStack.setCount(originalItemCount);
- // Drastically improve performance by returning true.
- // No plugin could have relied on the behavior of false as the other call
- // site for IMIE did not exhibit the same behavior
- return true;
- }
- }
-
- final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
- final int remainingItemCount = remainingItem.getCount();
- if (remainingItemCount != movedItemCount) {
- origItemStack = origItemStack.copy(true);
- origItemStack.setCount(originalItemCount);
- if (!origItemStack.isEmpty()) {
- origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
- }
-
- ignoreBlockEntityUpdates = true;
- container.setItem(i, origItemStack);
- ignoreBlockEntityUpdates = false;
- container.setChanged();
- return true;
- }
- origItemStack.setCount(originalItemCount);
-
- if (level.paperConfig().hopper.cooldownWhenFull) {
- applyCooldown(hopper);
- }
-
- return false;
- }
-
- @Nullable
- private static ItemStack callPushMoveEvent(Container destination, ItemStack itemStack, HopperBlockEntity hopper) {
- final org.bukkit.inventory.Inventory destinationInventory = getInventory(destination);
- final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(
- hopper.getOwner(false).getInventory(),
- org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack),
- destinationInventory,
- true
- );
- final boolean result = event.callEvent();
- if (!event.calledGetItem && !event.calledSetItem) {
- skipPushModeEventFire = true;
- }
- if (!result) {
- applyCooldown(hopper);
- return null;
- }
-
- if (event.calledSetItem) {
- return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
- } else {
- return itemStack;
- }
- }
-
- @Nullable
- private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) {
- final org.bukkit.inventory.Inventory sourceInventory = getInventory(container);
- final org.bukkit.inventory.Inventory destination = getInventory(hopper);
-
- // Mirror is safe as no plugins ever use this item
- final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(sourceInventory, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), destination, false);
- final boolean result = event.callEvent();
- if (!event.calledGetItem && !event.calledSetItem) {
- skipPullModeEventFire = true;
- }
- if (!result) {
- applyCooldown(hopper);
- return null;
- }
-
- if (event.calledSetItem) {
- return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
- } else {
- return itemstack;
- }
- }
-
- private static org.bukkit.inventory.Inventory getInventory(final Container container) {
- final org.bukkit.inventory.Inventory sourceInventory;
- if (container instanceof net.minecraft.world.CompoundContainer compoundContainer) {
- // Have to special-case large chests as they work oddly
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- } else if (container instanceof BlockEntity blockEntity) {
- sourceInventory = blockEntity.getOwner(false).getInventory();
- } else if (container.getOwner() != null) {
- sourceInventory = container.getOwner().getInventory();
- } else {
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
- }
- return sourceInventory;
- }
-
- private static void applyCooldown(final Hopper hopper) {
- if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) {
- blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
- }
- }
-
- private static boolean allMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
- if (container instanceof WorldlyContainer) {
- for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
- if (!test.test(container.getItem(slot), slot)) {
- return false;
- }
- }
- } else {
- int size = container.getContainerSize();
- for (int slot = 0; slot < size; slot++) {
- if (!test.test(container.getItem(slot), slot)) {
- return false;
- }
- }
- }
- return true;
- }
-
- private static boolean anyMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
- if (container instanceof WorldlyContainer) {
- for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
- if (test.test(container.getItem(slot), slot)) {
- return true;
- }
- }
- } else {
- int size = container.getContainerSize();
- for (int slot = 0; slot < size; slot++) {
- if (test.test(container.getItem(slot), slot)) {
- return true;
- }
- }
- }
- return true;
- }
- private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemStack, i) -> itemStack.getCount() >= itemStack.getMaxStackSize();
- private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemStack, i) -> itemStack.isEmpty();
- // Paper end - Perf: Optimize Hoppers
-
private static boolean ejectItems(Level level, BlockPos pos, HopperBlockEntity blockEntity) {
Container attachedContainer = getAttachedContainer(level, pos, blockEntity);
if (attachedContainer == null) {
@@ -421,60 +183,59 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (isFullContainer(attachedContainer, opposite)) {
return false;
} else {
- // Paper start - Perf: Optimize Hoppers
- return hopperPush(level, attachedContainer, opposite, blockEntity);
- //for (int i = 0; i < blockEntity.getContainerSize(); i++) {
- // ItemStack item = blockEntity.getItem(i);
- // if (!item.isEmpty()) {
- // int count = item.getCount();
- // // CraftBukkit start - Call event when pushing items into other inventories
- // ItemStack original = item.copy();
- // org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
- // blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
- // ); // Spigot
-
- // org.bukkit.inventory.Inventory destinationInventory;
- // // Have to special case large chests as they work oddly
- // if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
- // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- // } else if (attachedContainer.getOwner() != null) {
- // destinationInventory = attachedContainer.getOwner().getInventory();
- // } else {
- // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
- // }
-
- // org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
- // blockEntity.getOwner().getInventory(),
- // oitemstack,
- // destinationInventory,
- // true
- // );
- // if (!event.callEvent()) {
- // blockEntity.setItem(i, original);
- // blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
- // return false;
- // }
- // int origCount = event.getItem().getAmount(); // Spigot
- // ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
- // // CraftBukkit end
-
- // if (itemStack.isEmpty()) {
- // attachedContainer.setChanged();
- // return true;
- // }
-
- // item.setCount(count);
- // // Spigot start
- // item.shrink(origCount - itemStack.getCount());
- // if (count <= level.spigotConfig.hopperAmount) {
- // // Spigot end
- // blockEntity.setItem(i, item);
- // }
- // }
- //}
-
- //return false;
- // Paper end - Perf: Optimize Hoppers
+ // DivineMC start - Optimize hoppers
+ for (int i = 0; i < blockEntity.getContainerSize(); i++) {
+ ItemStack item = blockEntity.getItem(i);
+ if (!item.isEmpty()) {
+ int count = item.getCount();
+ // CraftBukkit start - Call event when pushing items into other inventories
+ ItemStack original = item.copy();
+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
+ blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
+ ); // Spigot
+
+ org.bukkit.inventory.Inventory destinationInventory;
+ // Have to special case large chests as they work oddly
+ if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ } else if (attachedContainer.getOwner() != null) {
+ destinationInventory = attachedContainer.getOwner().getInventory();
+ } else {
+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
+ }
+
+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
+ blockEntity.getOwner().getInventory(),
+ oitemstack,
+ destinationInventory,
+ true
+ );
+ if (!event.callEvent()) {
+ blockEntity.setItem(i, original);
+ blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
+ return false;
+ }
+ int origCount = event.getItem().getAmount(); // Spigot
+ ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
+ // CraftBukkit end
+
+ if (itemStack.isEmpty()) {
+ attachedContainer.setChanged();
+ return true;
+ }
+
+ item.setCount(count);
+ // Spigot start
+ item.shrink(origCount - itemStack.getCount());
+ if (count <= level.spigotConfig.hopperAmount) {
+ // Spigot end
+ blockEntity.setItem(i, item);
+ }
+ }
+ }
+
+ return false;
+ // DivineMC end - Optimize hoppers
}
}
}
@@ -529,7 +290,6 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
Container sourceContainer = getSourceContainer(level, hopper, blockPos, blockState);
if (sourceContainer != null) {
Direction direction = Direction.DOWN;
- skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers
for (int i : getSlots(sourceContainer, direction)) {
if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction, level)) { // Spigot
@@ -555,59 +315,58 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction, Level level) { // Spigot
ItemStack item = container.getItem(slot);
if (!item.isEmpty() && canTakeItemFromContainer(hopper, container, item, slot, direction)) {
- // Paper start - Perf: Optimize Hoppers
- return hopperPull(level, hopper, container, item, slot);
- //int count = item.getCount();
- //// CraftBukkit start - Call event on collection of items from inventories into the hopper
- //ItemStack original = item.copy();
- //org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
- // container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
- //);
-
- //org.bukkit.inventory.Inventory sourceInventory;
- //// Have to special case large chests as they work oddly
- //if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
- // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- //} else if (container.getOwner() != null) {
- // sourceInventory = container.getOwner().getInventory();
- //} else {
- // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
- //}
-
- //org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
- // sourceInventory,
- // oitemstack,
- // hopper.getOwner().getInventory(),
- // false
- //);
-
- //if (!event.callEvent()) {
- // container.setItem(slot, original);
-
- // if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
- // hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
- // }
-
- // return false;
- //}
- //int origCount = event.getItem().getAmount(); // Spigot
- //ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
- //// CraftBukkit end
-
- //if (itemStack.isEmpty()) {
- // container.setChanged();
- // return true;
- //}
-
- //item.setCount(count);
- //// Spigot start
- //item.shrink(origCount - itemStack.getCount());
- //if (count <= level.spigotConfig.hopperAmount) {
- // // Spigot end
- // container.setItem(slot, item);
- //}
- // Paper end - Perf: Optimize Hoppers
+ // DivineMC start - Optimize hoppers
+ int count = item.getCount();
+ // CraftBukkit start - Call event on collection of items from inventories into the hopper
+ ItemStack original = item.copy();
+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
+ container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
+ );
+
+ org.bukkit.inventory.Inventory sourceInventory;
+ // Have to special case large chests as they work oddly
+ if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ } else if (container.getOwner() != null) {
+ sourceInventory = container.getOwner().getInventory();
+ } else {
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
+ }
+
+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
+ sourceInventory,
+ oitemstack,
+ hopper.getOwner().getInventory(),
+ false
+ );
+
+ if (!event.callEvent()) {
+ container.setItem(slot, original);
+
+ if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
+ hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
+ }
+
+ return false;
+ }
+ int origCount = event.getItem().getAmount(); // Spigot
+ ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
+ // CraftBukkit end
+
+ if (itemStack.isEmpty()) {
+ container.setChanged();
+ return true;
+ }
+
+ item.setCount(count);
+ // Spigot start
+ item.shrink(origCount - itemStack.getCount());
+ if (count <= level.spigotConfig.hopperAmount) {
+ // Spigot end
+ container.setItem(slot, item);
+ }
}
+ // DivineMC end - Optimize hoppers
return false;
}
@@ -615,15 +374,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public static boolean addItem(Container container, ItemEntity item) {
boolean flag = false;
// CraftBukkit start
- if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
org.bukkit.event.inventory.InventoryPickupItemEvent event = new org.bukkit.event.inventory.InventoryPickupItemEvent(
- getInventory(container), (org.bukkit.entity.Item) item.getBukkitEntity() // Paper - Perf: Optimize Hoppers; use getInventory() to avoid snapshot creation
+ container.getOwner().getInventory(), (org.bukkit.entity.Item) item.getBukkitEntity() // DivineMC - Optimize hoppers
);
if (!event.callEvent()) {
return false;
}
// CraftBukkit end
- } // Paper - Perf: Optimize Hoppers
ItemStack itemStack = item.getItem().copy();
ItemStack itemStack1 = addItem(null, container, itemStack, null);
if (itemStack1.isEmpty()) {
@@ -678,9 +435,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
stack = stack.split(destination.getMaxStackSize());
}
// Spigot end
- ignoreBlockEntityUpdates = true; // Paper - Perf: Optimize Hoppers
destination.setItem(slot, stack);
- ignoreBlockEntityUpdates = false; // Paper - Perf: Optimize Hoppers
stack = leftover; // Paper - Make hoppers respect inventory max stack size
flag = true;
} else if (canMergeItems(item, stack)) {
@@ -768,19 +523,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable
public static Container getContainerAt(Level level, BlockPos pos) {
- return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, true); // Paper - Optimize hoppers
+ return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); // DivineMC - Optimize hoppers
}
@Nullable
private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z) {
- // Paper start - Perf: Optimize Hoppers
- return HopperBlockEntity.getContainerAt(level, pos, state, x, y, z, false);
- }
- @Nullable
- private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z, final boolean optimizeEntities) {
- // Paper end - Perf: Optimize Hoppers
Container blockContainer = getBlockContainer(level, pos, state);
- if (blockContainer == null && (!optimizeEntities || !level.paperConfig().hopper.ignoreOccludingBlocks || !state.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers
+ if (blockContainer == null) { // DivineMC - Optimize hoppers
blockContainer = getEntityContainer(level, x, y, z);
}
@@ -806,14 +555,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable
private static Container getEntityContainer(Level level, double x, double y, double z) {
- List<Entity> entities = level.getEntitiesOfClass(
- (Class) Container.class, new AABB(x - 0.5, y - 0.5, z - 0.5, x + 0.5, y + 0.5, z + 0.5), EntitySelector.CONTAINER_ENTITY_SELECTOR // Paper - Perf: Optimize hoppers
- );
+ List<Entity> entities = level.getEntities(
+ (Entity)null, new AABB(x - 0.5, y - 0.5, z - 0.5, x + 0.5, y + 0.5, z + 0.5), EntitySelector.CONTAINER_ENTITY_SELECTOR
+ ); // DivineMC - Optimize hoppers
return !entities.isEmpty() ? (Container)entities.get(level.random.nextInt(entities.size())) : null;
}
private static boolean canMergeItems(ItemStack stack1, ItemStack stack2) {
- return stack1.getCount() < stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?!
+ return stack1.getCount() <= stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2); // DivineMC - Optimize hoppers
}
@Override
diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java
index faf45ac459f7c25309d6ef6dce371d484a0dae7b..6f0d1b28a45b93c51c5476283f1629a86e3420d1 100644
--- a/net/minecraft/world/ticks/LevelChunkTicks.java
+++ b/net/minecraft/world/ticks/LevelChunkTicks.java
@@ -17,7 +17,8 @@ import net.minecraft.core.BlockPos;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.level.ChunkPos;
-public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickContainerAccess<T>, ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks { // Paper - rewrite chunk system
+public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickContainerAccess<T>, ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks { // DivineMC
+ private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LevelChunkTicks.class); // Paper - rewrite chunk system
private final Queue<ScheduledTick<T>> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER);
@Nullable
private List<SavedTick<T>> pendingTicks;
@@ -71,10 +72,18 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
@Nullable
public ScheduledTick<T> poll() {
- ScheduledTick<T> scheduledTick = this.tickQueue.poll();
- if (scheduledTick != null) {
- this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system
+ // DivineMC start - catch exceptions when polling chunk ticks
+ ScheduledTick<T> scheduledTick = null;
+ try {
+ scheduledTick = this.tickQueue.poll();
+ if (scheduledTick != null) {
+ this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system
+ }
+ } catch (Exception e) {
+ log.error("Encountered caught exception when polling chunk ticks, blocking and returning null.", e);
+ return null;
}
+ // DivineMC end - catch exceptions when polling chunk ticks
return scheduledTick;
}

View File

@@ -6,7 +6,7 @@ Subject: [PATCH] Option to allow weird movement and disable teleporting
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 19c7802969aa9d1e15b4c67ee5c97e73daf0a460..b2881d1b0cc2bc172dd21349e07b7e6f89bd996c 100644 index f8c76bb2c9fa625e191036dc58ef3dfb1d4ee930..5b8031a45b1f4f6d0e86c2a839d173a6e3f4f697 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -574,7 +574,7 @@ public class ServerGamePacketListenerImpl @@ -574,7 +574,7 @@ public class ServerGamePacketListenerImpl

View File

@@ -5,13 +5,13 @@ Subject: [PATCH] Lag compensation
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 351b035d1f3025af28b5147b95b912e0e2ab9212..1bcccba4df407ec4d53f49c3c2c7493db87b2240 100644 index 5a726da8535aa939f043829a3c60fdd9d4ed154a..0aebdd1cb0e1b63ff9a867bdcda7cbdc3c194b56 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
protected boolean upnp = false; // Purpur - UPnP Port Forwarding protected boolean upnp = false; // Purpur - UPnP Port Forwarding
public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - parallel world ticking public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - Parallel world ticking
+ public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation + public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) { public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
@@ -25,7 +25,7 @@ index 351b035d1f3025af28b5147b95b912e0e2ab9212..1bcccba4df407ec4d53f49c3c2c7493d
this.tickCount++; this.tickCount++;
this.tickRateManager.tick(); this.tickRateManager.tick();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 8c136d77451c17613834c4a7dab6ab6c2fe4d716..f7f7a553d52f42cbbc5d839b850d65ddf97c3ed1 100644 index a70007d324e2169d1b2a1a11046500196b8b5660..53b606c34f65b80a676ddd26d64028dbdebecb43 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -218,6 +218,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -218,6 +218,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@@ -36,7 +36,7 @@ index 8c136d77451c17613834c4a7dab6ab6c2fe4d716..f7f7a553d52f42cbbc5d839b850d65dd
public LevelChunk getChunkIfLoaded(int x, int z) { public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
@@ -772,6 +773,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -774,6 +775,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
} }
} }
@@ -45,7 +45,7 @@ index 8c136d77451c17613834c4a7dab6ab6c2fe4d716..f7f7a553d52f42cbbc5d839b850d65dd
this.updateSkyBrightness(); this.updateSkyBrightness();
if (runsNormally) { if (runsNormally) {
this.tickTime(); this.tickTime();
@@ -851,11 +854,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -853,11 +856,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.setDayTime(this.preciseTime); this.setDayTime(this.preciseTime);
} else } else
// Purpur end - Configurable daylight cycle // Purpur end - Configurable daylight cycle
@@ -96,10 +96,10 @@ index 04a1c17a34b495b71eb1b0ccd597cef83480464d..edb128a3f454e7b3009ca360509decd7
protected float getBlockSpeedFactor() { protected float getBlockSpeedFactor() {
return Mth.lerp((float)this.getAttributeValue(Attributes.MOVEMENT_EFFICIENCY), super.getBlockSpeedFactor(), 1.0F); return Mth.lerp((float)this.getAttributeValue(Attributes.MOVEMENT_EFFICIENCY), super.getBlockSpeedFactor(), 1.0F);
diff --git a/net/minecraft/world/entity/PortalProcessor.java b/net/minecraft/world/entity/PortalProcessor.java diff --git a/net/minecraft/world/entity/PortalProcessor.java b/net/minecraft/world/entity/PortalProcessor.java
index 88b07fbb96b20124777889830afa480673629d43..d2661ea79536010414f77256332f214d19106dd9 100644 index be357d9e3c5327ceec12c31830551a564c8cea1b..f77da420bc88df6ec304086fc1eba0690fe278b1 100644
--- a/net/minecraft/world/entity/PortalProcessor.java --- a/net/minecraft/world/entity/PortalProcessor.java
+++ b/net/minecraft/world/entity/PortalProcessor.java +++ b/net/minecraft/world/entity/PortalProcessor.java
@@ -24,10 +24,20 @@ public class PortalProcessor { @@ -26,10 +26,20 @@ public class PortalProcessor {
return false; return false;
} else { } else {
this.insidePortalThisTick = false; this.insidePortalThisTick = false;
@@ -244,7 +244,7 @@ index b631e35e965b1914cdeeddab8bd6bdbfd2465079..bb7dab597850fba8f0dff4461fc518e0
} }
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index ba88a3aed79543f69a5bf30cfd03f30983d229cf..0337f4b9ca3c9c9a1e2a7cf19fcbad5e78b949dc 100644 index b245f594ff91e2d29c83f56b9ed5165f37387e7e..534384727e852dc8ea822f49f182af49eb3a40c1 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java --- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -907,6 +907,19 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @@ -907,6 +907,19 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] MSPT Tracking for each world
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 1bcccba4df407ec4d53f49c3c2c7493db87b2240..54c8605a4e36605208344e39726a4c3bbe972076 100644 index 11b89a625b942f5f2f882c54dbfc08c16e983425..fc9de137ed1681afd1ef51391cf8f30fd4c61c4b 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -1684,7 +1684,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -1684,7 +1684,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -25,10 +25,10 @@ index 1bcccba4df407ec4d53f49c3c2c7493db87b2240..54c8605a4e36605208344e39726a4c3b
CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world"); CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world");
serverLevel.fillReportDetails(crashReport); serverLevel.fillReportDetails(crashReport);
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index f7f7a553d52f42cbbc5d839b850d65ddf97c3ed1..fdaf752b4d39402de504cc8dfb6f0593f9b19d9a 100644 index e034d9f903728cdf7356629694c9f528ba5ebae3..561066a2cf769e13ef3cea0881f7a2010ecbf2ec 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -574,6 +574,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -575,6 +575,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
} }
// Paper end - chunk tick iteration // Paper end - chunk tick iteration

View File

@@ -6,12 +6,12 @@ Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 54c8605a4e36605208344e39726a4c3bbe972076..72ab570ca8b532a1f55408515f34a02aa0c79a6a 100644 index df07a4a62bd518f3a13995a3ccc7970c714bad7b..851f943cddad03ae12e1ed85f64072682447a367 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
protected boolean upnp = false; // Purpur - UPnP Port Forwarding protected boolean upnp = false; // Purpur - UPnP Port Forwarding
public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - parallel world ticking public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - Parallel world ticking
public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
+ public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run + public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run

View File

@@ -9,7 +9,7 @@ This is a fully vanilla optimization. Improves: [Blast]Furnace/Campfire/Smoker/S
This was mostly made for the auto crafting table, since the performance boost is much more visible while using that mod This was mostly made for the auto crafting table, since the performance boost is much more visible while using that mod
diff --git a/net/minecraft/world/item/crafting/RecipeManager.java b/net/minecraft/world/item/crafting/RecipeManager.java diff --git a/net/minecraft/world/item/crafting/RecipeManager.java b/net/minecraft/world/item/crafting/RecipeManager.java
index f679b7f4f152faf0255b8776c91dfff1be2851c8..300d9564602126a2e8a94774dc3a0f7c21d75e17 100644 index c7d91a38fc3b5cf2487e09719a1f9bc39ca5d20e..875e9711c9dacaf73636c7c7ce1cf740a23f006f 100644
--- a/net/minecraft/world/item/crafting/RecipeManager.java --- a/net/minecraft/world/item/crafting/RecipeManager.java
+++ b/net/minecraft/world/item/crafting/RecipeManager.java +++ b/net/minecraft/world/item/crafting/RecipeManager.java
@@ -166,7 +166,7 @@ public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> imp @@ -166,7 +166,7 @@ public class RecipeManager extends SimplePreparableReloadListener<RecipeMap> imp

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Block Log4Shell exploit
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index b2881d1b0cc2bc172dd21349e07b7e6f89bd996c..c96c13ff7e2f0f62166e429dcb66ff5217604c32 100644 index 5b8031a45b1f4f6d0e86c2a839d173a6e3f4f697..a3ec8c92dae7735bb0b1ececc9851c829c486a53 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2425,6 +2425,7 @@ public class ServerGamePacketListenerImpl @@ -2425,6 +2425,7 @@ public class ServerGamePacketListenerImpl

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Re-Fix MC-117075
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..440d890d32a6705aa5ebc84040c4290634bbae9b 100644 index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..92fc936c6bdbda909b9cdf157ec9d46a4872098c 100644
--- a/net/minecraft/world/level/Level.java --- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java
@@ -113,7 +113,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -113,7 +113,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -17,7 +17,14 @@ index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..440d890d32a6705aa5ebc84040c42906
protected final NeighborUpdater neighborUpdater; protected final NeighborUpdater neighborUpdater;
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList(); private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
private boolean tickingBlockEntities; private boolean tickingBlockEntities;
@@ -1528,7 +1528,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -1521,14 +1521,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
boolean runsNormally = this.tickRateManager().runsNormally();
int tickedEntities = 0; // Paper - rewrite chunk system
- var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<TickingBlockEntity>(); // Paper - Fix MC-117075; use removeAll
- toRemove.add(null); // Paper - Fix MC-117075
for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition); TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition);
// Spigot end // Spigot end
if (tickingBlockEntity.isRemoved()) { if (tickingBlockEntity.isRemoved()) {
@@ -26,11 +33,12 @@ index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..440d890d32a6705aa5ebc84040c42906
} else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { } else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) {
tickingBlockEntity.tick(); tickingBlockEntity.tick();
// DivineMC start - Parallel world ticking // DivineMC start - Parallel world ticking
@@ -1541,6 +1541,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -1539,7 +1537,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
// DivineMC end - Parallel world ticking
}
} }
this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 - this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
+ this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removals - Fix MC-117075 + this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removals - Fix MC-117075
this.tickingBlockEntities = false; this.tickingBlockEntities = false;
this.spigotConfig.currentPrimedTnt = 0; // Spigot this.spigotConfig.currentPrimedTnt = 0; // Spigot
}

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Optimize canSee checks
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index 34c37abfe6c33ca1073450c8925f553d34be87a0..5f754dedc2fcbcc67b20c7069b8c5fccd68a7361 100644 index dccf4d4b1067e1b09e38cabeae82185929494b62..55da7420dc3dfff468529a0f101f864dbefe3c7c 100644
--- a/net/minecraft/server/level/ChunkMap.java --- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java
@@ -1293,7 +1293,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -1258,7 +1258,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
// Paper end - Configurable entity tracking range by Y // Paper end - Configurable entity tracking range by Y
// CraftBukkit start - respect vanish API // CraftBukkit start - respect vanish API

View File

@@ -218,10 +218,10 @@ index 9fcdff2be139296f4e14b54c33cc795efdff0c7f..64c3bbe540599e5195f0cc89635bff2c
// Paper start - Add setting for proxy online mode status // Paper start - Add setting for proxy online mode status
return properties.enforceSecureProfile return properties.enforceSecureProfile
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
index 0c499eca39371993c46d510fa45298efdd67d20c..2eccb615dfebf64ca76d2cce1876d6ec2afe518d 100644 index 801dd76a2c7f76fc6fdb7167cbf3ab1310be36c9..4fa55fac5dab26a505cba2c1876e9459a582da12 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java --- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -308,10 +308,64 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -312,10 +312,64 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
} }
public void send(Packet<?> packet) { public void send(Packet<?> packet) {

View File

@@ -231,7 +231,7 @@ index 4a6da3648c513a6cce16cf71246937d2d0ad014d..6af4c9026e814dee1ed4c7593ad00b5f
+ // Quiil end - Optimize Structure Generation + // Quiil end - Optimize Structure Generation
} }
diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
index ab1dcbe416e2c3c94cfddf04b7ed053425a71806..985d11f0b72858d66ad011d83106730b07e25242 100644 index a37eb2e29b4577ebc711e8ef7b47fbbc3bc66897..45d6fbeeaac577bb35adb69fd344b9486953ea03 100644
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java --- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java +++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
@@ -249,6 +249,12 @@ public class StructureTemplate { @@ -249,6 +249,12 @@ public class StructureTemplate {

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Verify Minecraft EULA earlier
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
index b48fc9e0b95fe6c8f72c5501b8de374e6ac2e5d6..44e98037c986dec845613fa24f9664ef1803b96c 100644 index 1485186d4989874ef89c4e83830f26358a43759c..c4f9b67c92e4c7e8015f637fe633a9e8da276e5c 100644
--- a/net/minecraft/server/Main.java --- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java +++ b/net/minecraft/server/Main.java
@@ -131,7 +131,6 @@ public class Main { @@ -123,7 +123,6 @@ public class Main {
dedicatedServerSettings.forceSave(); dedicatedServerSettings.forceSave();
RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression); RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression);
Path path2 = Paths.get("eula.txt"); Path path2 = Paths.get("eula.txt");
@@ -16,7 +16,7 @@ index b48fc9e0b95fe6c8f72c5501b8de374e6ac2e5d6..44e98037c986dec845613fa24f9664ef
// Paper start - load config files early for access below if needed // Paper start - load config files early for access below if needed
org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("bukkit-settings")); org.bukkit.configuration.file.YamlConfiguration bukkitConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("bukkit-settings"));
org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("spigot-settings")); org.bukkit.configuration.file.YamlConfiguration spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("spigot-settings"));
@@ -154,19 +153,6 @@ public class Main { @@ -146,19 +145,6 @@ public class Main {
return; return;
} }

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Configurable MC-67
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 258cb45f1f959b75c1bcdb130811af2f8fddf07d..64ba7d3573461a97c842849ee80642b0d43ee1c8 100644 index 3943789e241f6bb6bc165099b1fb585463cf3d86..07e8bda8eb200d5a7554e0319e1a00dc85454e1a 100644
--- a/net/minecraft/world/entity/Entity.java --- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java
@@ -3997,6 +3997,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -4017,6 +4017,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
} }
public boolean canTeleport(Level fromLevel, Level toLevel) { public boolean canTeleport(Level fromLevel, Level toLevel) {

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Option to disable saving of snowball and firework
diff --git a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java diff --git a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
index 774ca9e0b56fd175ae246051de762d0c4256ca58..3a380d038ef1231624a646c38b60a4344694e321 100644 index c7ae41b2cbc1eb85a6eb9c16813bd326fb8f49f0..e6764ee35f9d9d20a7693d50ea61b703867e3c79 100644
--- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java --- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
+++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java +++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
@@ -364,4 +364,14 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier { @@ -364,4 +364,14 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {

View File

@@ -20,7 +20,7 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..aa4dd7517e8be167aef1eaf7aa907e3c
if (var4 instanceof ReportedException reportedException && reportedException.getCause() instanceof OutOfMemoryError) { if (var4 instanceof ReportedException reportedException && reportedException.getCause() instanceof OutOfMemoryError) {
throw makeReportedException(var4, packet, processor); throw makeReportedException(var4, packet, processor);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 72ab570ca8b532a1f55408515f34a02aa0c79a6a..fe2d9328a7e9365f8c7e24e862038bc94ddfe1ca 100644 index 804de864da13ae0be6a1caee88e95a19e35d08c0..5a0c8791495aa522e511918ad0a24d9bbe6b5877 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -1694,6 +1694,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -1694,6 +1694,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View File

@@ -36,10 +36,10 @@ index 212d2bcfd34f7cb14e18a8af2cd296fc01d371f6..ec76e4f29ba96b31a24a5d195b852342
new java.util.concurrent.LinkedBlockingQueue<>(), new java.util.concurrent.LinkedBlockingQueue<>(),
new com.google.common.util.concurrent.ThreadFactoryBuilder() new com.google.common.util.concurrent.ThreadFactoryBuilder()
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index fe2d9328a7e9365f8c7e24e862038bc94ddfe1ca..daf6141a6aed6baf7b8de4030324703a0fe872d3 100644 index 5a0c8791495aa522e511918ad0a24d9bbe6b5877..9d6fa3bced0ba5ab3443bdf4ce306598a8e4a31f 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -2709,8 +2709,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -2710,8 +2710,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
} }
} }
@@ -54,7 +54,7 @@ index fe2d9328a7e9365f8c7e24e862038bc94ddfe1ca..daf6141a6aed6baf7b8de4030324703a
public ChatDecorator getChatDecorator() { public ChatDecorator getChatDecorator() {
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index c96c13ff7e2f0f62166e429dcb66ff5217604c32..6bcf21bd3210c161c67d6301585ac8b1f79a325e 100644 index a3ec8c92dae7735bb0b1ececc9851c829c486a53..02b4275d170cc854a7482f0e963394aee21171dd 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -808,8 +808,11 @@ public class ServerGamePacketListenerImpl @@ -808,8 +808,11 @@ public class ServerGamePacketListenerImpl

View File

@@ -5,14 +5,14 @@ Subject: [PATCH] Async Chunk Sending
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index 76b8d42ae530b59cdaba0583365a557da6b90ede..4943f57f648d5350e174c995ccb12bf8b2eb700f 100644 index 76b8d42ae530b59cdaba0583365a557da6b90ede..235772cc9a7c878235b97c8d84cacda3016f91ca 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -55,6 +55,8 @@ public final class RegionizedPlayerChunkLoader { @@ -55,6 +55,8 @@ public final class RegionizedPlayerChunkLoader {
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY); public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL; public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;
+ public static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("RegionizedPlayerChunkLoader"); + private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("RegionizedPlayerChunkLoader"); // DivineMC - Async Chunk Sending
+ +
public static final class ViewDistanceHolder { public static final class ViewDistanceHolder {

View File

@@ -10,7 +10,7 @@ As part of: ModernFix (https://github.com/embeddedt/ModernFix)
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
index 230cb433c38f9b6ffb1adeaa8b6040490f13e826..a436ec61bafc90d3ba6da0d5534f3b56b498b29b 100644 index 712d3d1669aecd38934957c81835e1f38289539a..810e61913aece5a8158f83b6dd56a7b6cb083c19 100644
--- a/net/minecraft/world/level/chunk/PalettedContainer.java --- a/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java +++ b/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -275,6 +275,28 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer @@ -275,6 +275,28 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Linear region file format
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
index a814512fcfb85312474ae2c2c21443843bf57831..c21e04c1d43797db221e4712fcc987a44eaa983c 100644 index a814512fcfb85312474ae2c2c21443843bf57831..fdccc27c528b01b16a72e614ffd96523aa6f50d2 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java
@@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage { @@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage {
@@ -13,15 +13,15 @@ index a814512fcfb85312474ae2c2c21443843bf57831..c21e04c1d43797db221e4712fcc987a4
public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ); public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ);
- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); - public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ);
+ public org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - Linear region file format + public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - Linear region file format
- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; - public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException;
+ public org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - Linear region file format + public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - Linear region file format
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite( public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(
final int chunkX, final int chunkZ, final CompoundTag compound final int chunkX, final int chunkZ, final CompoundTag compound
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..57ae23fdd5a95e7670eb4dfaca0d290edfc1d25c 100644 index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..34682217252cb98a70511a8cb25f077ec9f872b8 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java
@@ -1260,7 +1260,7 @@ public final class MoonriseRegionFileIO { @@ -1260,7 +1260,7 @@ public final class MoonriseRegionFileIO {
@@ -29,7 +29,7 @@ index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..57ae23fdd5a95e7670eb4dfaca0d290e
// Paper start - flush regionfiles on save // Paper start - flush regionfiles on save
if (this.world.paperConfig().chunks.flushRegionsOnSave) { if (this.world.paperConfig().chunks.flushRegionsOnSave) {
- final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); - final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - Linear region file format
if (regionFile != null) { if (regionFile != null) {
regionFile.flush(); regionFile.flush();
} // else: evicted from cache, which should have called flush } // else: evicted from cache, which should have called flush
@@ -38,12 +38,12 @@ index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..57ae23fdd5a95e7670eb4dfaca0d290e
public static interface IORunnable { public static interface IORunnable {
- public void run(final RegionFile regionFile) throws IOException; - public void run(final RegionFile regionFile) throws IOException;
+ public void run(final org.stupidcraft.linearpaper.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format + public void run(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format
} }
} }
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
index 51c126735ace8fdde89ad97b5cab62f244212db0..c466ce5c669e4b5ed835b13584a5ae5afe08fa11 100644 index 51c126735ace8fdde89ad97b5cab62f244212db0..8713d00d767c9225a0823d2fdbb0b479005738d7 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java --- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
@@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer { @@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer {
@@ -51,10 +51,10 @@ index 51c126735ace8fdde89ad97b5cab62f244212db0..c466ce5c669e4b5ed835b13584a5ae5a
public void moonrise$setWriteOnClose(final boolean value); public void moonrise$setWriteOnClose(final boolean value);
- public void moonrise$write(final RegionFile regionFile) throws IOException; - public void moonrise$write(final RegionFile regionFile) throws IOException;
+ public void moonrise$write(final org.stupidcraft.linearpaper.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format + public void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format
} }
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index daf6141a6aed6baf7b8de4030324703a0fe872d3..6182c6f7cc6f5199897a5e227dabe9f9738733a5 100644 index 26a4a279122bb03a83dd4a34e780d6a4567ba3a8..51b79f614417f231951e9ba05b29ff0044e081e7 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -947,10 +947,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -947,10 +947,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -71,7 +71,7 @@ index daf6141a6aed6baf7b8de4030324703a0fe872d3..6182c6f7cc6f5199897a5e227dabe9f9
return flag; return flag;
diff --git a/net/minecraft/util/worldupdate/WorldUpgrader.java b/net/minecraft/util/worldupdate/WorldUpgrader.java diff --git a/net/minecraft/util/worldupdate/WorldUpgrader.java b/net/minecraft/util/worldupdate/WorldUpgrader.java
index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d05ce3afb3 100644 index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..e99f3c3567f9e6fb5a328bf9b59d40c72522f922 100644
--- a/net/minecraft/util/worldupdate/WorldUpgrader.java --- a/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/net/minecraft/util/worldupdate/WorldUpgrader.java +++ b/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -72,7 +72,7 @@ public class WorldUpgrader implements AutoCloseable { @@ -72,7 +72,7 @@ public class WorldUpgrader implements AutoCloseable {
@@ -97,7 +97,7 @@ index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d0
List<ChunkPos> list1 = Lists.newArrayList(); List<ChunkPos> list1 = Lists.newArrayList();
- try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) { - try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) {
+ try (org.stupidcraft.linearpaper.region.IRegionFile regionFile = org.stupidcraft.linearpaper.region.IRegionFileFactory.getAbstractRegionFile(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Linear region file format + try (org.bxteam.divinemc.region.IRegionFile regionFile = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Linear region file format
for (int i2 = 0; i2 < 32; i2++) { for (int i2 = 0; i2 < 32; i2++) {
for (int i3 = 0; i3 < 32; i3++) { for (int i3 = 0; i3 < 32; i3++) {
ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1); ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1);
@@ -106,7 +106,7 @@ index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d0
protected abstract boolean tryProcessOnePosition(T chunkStorage, ChunkPos chunkPos, ResourceKey<Level> dimension); protected abstract boolean tryProcessOnePosition(T chunkStorage, ChunkPos chunkPos, ResourceKey<Level> dimension);
- private void onFileFinished(RegionFile regionFile) { - private void onFileFinished(RegionFile regionFile) {
+ private void onFileFinished(org.stupidcraft.linearpaper.region.IRegionFile regionFile) { // DivineMC - Linear region file format + private void onFileFinished(org.bxteam.divinemc.region.IRegionFile regionFile) { // DivineMC - Linear region file format
if (WorldUpgrader.this.recreateRegionFiles) { if (WorldUpgrader.this.recreateRegionFiles) {
if (this.previousWriteFuture != null) { if (this.previousWriteFuture != null) {
this.previousWriteFuture.join(); this.previousWriteFuture.join();
@@ -115,12 +115,12 @@ index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..2ab8e8d9db5ea390a1334c28b97ef6d0
} }
- record FileToUpgrade(RegionFile file, List<ChunkPos> chunksToUpgrade) { - record FileToUpgrade(RegionFile file, List<ChunkPos> chunksToUpgrade) {
+ record FileToUpgrade(org.stupidcraft.linearpaper.region.IRegionFile file, List<ChunkPos> chunksToUpgrade) { // DivineMC - Linear region file format + record FileToUpgrade(org.bxteam.divinemc.region.IRegionFile file, List<ChunkPos> chunksToUpgrade) { // DivineMC - Linear region file format
} }
class PoiUpgrader extends WorldUpgrader.SimpleRegionStorageUpgrader { class PoiUpgrader extends WorldUpgrader.SimpleRegionStorageUpgrader {
diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java
index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..5d29e3046485dcdda9356f6bfe6f6463e9b9bef4 100644 index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..2988084cf2d72557dd304dcb904d09441e79863d 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFile.java --- a/net/minecraft/world/level/chunk/storage/RegionFile.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java +++ b/net/minecraft/world/level/chunk/storage/RegionFile.java
@@ -22,7 +22,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler; @@ -22,7 +22,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler;
@@ -128,7 +128,7 @@ index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..5d29e3046485dcdda9356f6bfe6f6463
import org.slf4j.Logger; import org.slf4j.Logger;
-public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system -public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system
+public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile, org.stupidcraft.linearpaper.region.IRegionFile { // Paper - rewrite chunk system // DivineMC - Linear region file format +public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile, org.bxteam.divinemc.region.IRegionFile { // Paper - rewrite chunk system // DivineMC - Linear region file format
private static final Logger LOGGER = LogUtils.getLogger(); private static final Logger LOGGER = LogUtils.getLogger();
public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails
private static final int SECTOR_BYTES = 4096; private static final int SECTOR_BYTES = 4096;
@@ -137,12 +137,12 @@ index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..5d29e3046485dcdda9356f6bfe6f6463
@Override @Override
- public final void moonrise$write(final RegionFile regionFile) throws IOException { - public final void moonrise$write(final RegionFile regionFile) throws IOException {
+ public final void moonrise$write(final org.stupidcraft.linearpaper.region.IRegionFile regionFile) throws IOException { // DivineMC - Linear region file format + public final void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException { // DivineMC - Linear region file format
regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count)); regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count));
} }
// Paper end - rewrite chunk system // Paper end - rewrite chunk system
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b4196cf25588 100644 index 16cd10ab8de69ca3d29c84cf93715645322fd72a..9fd987078625bee796b381108ae7dbfb1f14d256 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -18,7 +18,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise @@ -18,7 +18,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
@@ -150,7 +150,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
public static final String ANVIL_EXTENSION = ".mca"; public static final String ANVIL_EXTENSION = ".mca";
private static final int MAX_CACHE_SIZE = 256; private static final int MAX_CACHE_SIZE = 256;
- public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); - public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
+ public final Long2ObjectLinkedOpenHashMap<org.stupidcraft.linearpaper.region.IRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - Linear region file format + public final Long2ObjectLinkedOpenHashMap<org.bxteam.divinemc.region.IRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - Linear region file format
private final RegionStorageInfo info; private final RegionStorageInfo info;
private final Path folder; private final Path folder;
private final boolean sync; private final boolean sync;
@@ -168,7 +168,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(); private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet();
private static String getRegionFileName(final int chunkX, final int chunkZ) { private static String getRegionFileName(final int chunkX, final int chunkZ) {
+ // DivineMC start - Linear region file format + // DivineMC start - Linear region file format
+ if (org.bxteam.divinemc.DivineConfig.regionFormatTypeName == org.stupidcraft.linearpaper.region.EnumRegionFileExtension.LINEAR) { + if (org.bxteam.divinemc.DivineConfig.regionFormatTypeName == org.bxteam.divinemc.region.RegionFileFormat.LINEAR) {
+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".linear"; + return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".linear";
+ } + }
+ // DivineMC end - Linear region file format + // DivineMC end - Linear region file format
@@ -181,17 +181,17 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
@Override @Override
- public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { - public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) {
+ public synchronized final org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - Linear region file format + public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - Linear region file format
return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT)); return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT));
} }
@Override @Override
- public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { - public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException {
+ public synchronized final org.stupidcraft.linearpaper.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - Linear region file format + public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - Linear region file format
final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT);
- RegionFile ret = this.regionCache.getAndMoveToFirst(key); - RegionFile ret = this.regionCache.getAndMoveToFirst(key);
+ org.stupidcraft.linearpaper.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format
if (ret != null) { if (ret != null) {
return ret; return ret;
} }
@@ -200,7 +200,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
FileUtil.createDirectoriesSafe(this.folder); FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync); - ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = org.stupidcraft.linearpaper.region.IRegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format + ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format
this.regionCache.putAndMoveToFirst(key, ret); this.regionCache.putAndMoveToFirst(key, ret);
@@ -209,7 +209,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final ChunkPos pos = new ChunkPos(chunkX, chunkZ); final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
- final RegionFile regionFile = this.getRegionFile(pos); - final RegionFile regionFile = this.getRegionFile(pos);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Linear region file format
// note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input // note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input
// (and, the regionfile parameter is unused for writing until the write call) // (and, the regionfile parameter is unused for writing until the write call)
@@ -223,7 +223,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final ChunkPos pos = new ChunkPos(chunkX, chunkZ); final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) { if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) {
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); - final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format
if (regionFile != null) { if (regionFile != null) {
regionFile.clear(pos); regionFile.clear(pos);
} // else: didn't exist } // else: didn't exist
@@ -232,7 +232,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final int chunkX, final int chunkZ final int chunkX, final int chunkZ
) throws IOException { ) throws IOException {
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); - final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
+ final org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format + final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Linear region file format
final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ)); final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ));
@@ -241,7 +241,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
// Paper end - rewrite chunk system // Paper end - rewrite chunk system
// Paper start - rewrite chunk system // Paper start - rewrite chunk system
- public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { - public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException {
+ public org.stupidcraft.linearpaper.region.IRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - Linear region file format + public org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - Linear region file format
return this.getRegionFile(chunkcoordintpair, false); return this.getRegionFile(chunkcoordintpair, false);
} }
// Paper end - rewrite chunk system // Paper end - rewrite chunk system
@@ -250,7 +250,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
} }
- @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit - @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit
+ @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private org.stupidcraft.linearpaper.region.IRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - Linear region file format + @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - Linear region file format
// Paper start - rewrite chunk system // Paper start - rewrite chunk system
if (existingOnly) { if (existingOnly) {
return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z); return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z);
@@ -259,7 +259,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT); final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT);
- RegionFile ret = this.regionCache.getAndMoveToFirst(key); - RegionFile ret = this.regionCache.getAndMoveToFirst(key);
+ org.stupidcraft.linearpaper.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Linear region file format
if (ret != null) { if (ret != null) {
return ret; return ret;
} }
@@ -268,7 +268,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
FileUtil.createDirectoriesSafe(this.folder); FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync); - ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = org.stupidcraft.linearpaper.region.IRegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format + ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format
this.regionCache.putAndMoveToFirst(key, ret); this.regionCache.putAndMoveToFirst(key, ret);
@@ -277,7 +277,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
} }
- private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { - private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {
+ private static CompoundTag readOversizedChunk(org.stupidcraft.linearpaper.region.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // DivineMC - Linear region file format + private static CompoundTag readOversizedChunk(org.bxteam.divinemc.region.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // DivineMC - Linear region file format
synchronized (regionfile) { synchronized (regionfile) {
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
@@ -286,7 +286,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
public CompoundTag read(ChunkPos chunkPos) throws IOException { public CompoundTag read(ChunkPos chunkPos) throws IOException {
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
- RegionFile regionFile = this.getRegionFile(chunkPos, true); - RegionFile regionFile = this.getRegionFile(chunkPos, true);
+ org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format
if (regionFile == null) { if (regionFile == null) {
return null; return null;
} }
@@ -295,7 +295,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException { public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException {
// CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing
- RegionFile regionFile = this.getRegionFile(chunkPos, true); - RegionFile regionFile = this.getRegionFile(chunkPos, true);
+ org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Linear region file format
if (regionFile == null) { if (regionFile == null) {
return; return;
} }
@@ -304,7 +304,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
public void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { // Paper - rewrite chunk system - public public void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { // Paper - rewrite chunk system - public
- RegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system - RegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system
+ org.stupidcraft.linearpaper.region.IRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - Linear region file format + org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - Linear region file format
// Paper start - rewrite chunk system // Paper start - rewrite chunk system
if (regionFile == null) { if (regionFile == null) {
// if the RegionFile doesn't exist, no point in deleting from it // if the RegionFile doesn't exist, no point in deleting from it
@@ -313,7 +313,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
synchronized (this) { synchronized (this) {
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>(); final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
- for (final RegionFile regionFile : this.regionCache.values()) { - for (final RegionFile regionFile : this.regionCache.values()) {
+ for (final org.stupidcraft.linearpaper.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format + for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format
try { try {
regionFile.close(); regionFile.close();
} catch (final IOException ex) { } catch (final IOException ex) {
@@ -322,7 +322,7 @@ index 16cd10ab8de69ca3d29c84cf93715645322fd72a..1061d1480af0d4947d0f7f1b0028b419
synchronized (this) { synchronized (this) {
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>(); final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
- for (final RegionFile regionFile : this.regionCache.values()) { - for (final RegionFile regionFile : this.regionCache.values()) {
+ for (final org.stupidcraft.linearpaper.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format + for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Linear region file format
try { try {
regionFile.flush(); regionFile.flush();
} catch (final IOException ex) { } catch (final IOException ex) {

View File

@@ -5,11 +5,11 @@ Subject: [PATCH] Async mob spawning
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 6182c6f7cc6f5199897a5e227dabe9f9738733a5..272a87eaa7a6406d0b059c18d7a7aa8c945dffa0 100644 index 51b79f614417f231951e9ba05b29ff0044e081e7..dee93ae262a2a06e68dfe8ae1b7193172c436990 100644
--- a/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -291,6 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -291,6 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - parallel world ticking public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - Parallel world ticking
public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
+ public org.bxteam.divinemc.util.AsyncProcessor mobSpawnExecutor = new org.bxteam.divinemc.util.AsyncProcessor("mob_spawning"); // DivineMC - Async mob spawning + public org.bxteam.divinemc.util.AsyncProcessor mobSpawnExecutor = new org.bxteam.divinemc.util.AsyncProcessor("mob_spawning"); // DivineMC - Async mob spawning
@@ -173,7 +173,7 @@ index d3f5242fc66529bf3137da4d505a6cf55e749e43..650dfce05bfc68d4c664471b430bd5c0
} }
} }
diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java
index 3c6ec711bf9a75657c13da647e4ae7947257b627..564a00938ef45837b1f8fa90504c54a6dc9bb383 100644 index 018a04674897cfcec0e8de5cb2ab06243a994ae3..8c1de4654a3a29e75716a03efd476b8a3b7fe9e9 100644
--- a/net/minecraft/world/level/entity/EntityTickList.java --- a/net/minecraft/world/level/entity/EntityTickList.java
+++ b/net/minecraft/world/level/entity/EntityTickList.java +++ b/net/minecraft/world/level/entity/EntityTickList.java
@@ -9,7 +9,7 @@ import javax.annotation.Nullable; @@ -9,7 +9,7 @@ import javax.annotation.Nullable;
@@ -182,10 +182,10 @@ index 3c6ec711bf9a75657c13da647e4ae7947257b627..564a00938ef45837b1f8fa90504c54a6
public class EntityTickList { public class EntityTickList {
- public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system - public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
+ public final java.util.concurrent.ConcurrentLinkedQueue<Entity> entities = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - rewrite chunk system // DivineMC - Async mob spawning + public final java.util.concurrent.ConcurrentLinkedQueue<Entity> entities = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - rewrite chunk system // DivineMC - Async mob spawning
// DivineMC start - parallel world ticking // DivineMC start - Parallel world ticking
// Used to track async entity additions/removals/loops
private final net.minecraft.server.level.ServerLevel serverLevel; private final net.minecraft.server.level.ServerLevel serverLevel;
@@ -44,13 +44,13 @@ public class EntityTickList {
@@ -43,13 +43,13 @@ public class EntityTickList {
// Paper start - rewrite chunk system // Paper start - rewrite chunk system
// To ensure nothing weird happens with dimension travelling, do not iterate over new entries... // To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
// (by dfl iterator() is configured to not iterate over new entries) // (by dfl iterator() is configured to not iterate over new entries)

View File

@@ -31,10 +31,10 @@ index ae0a3c3d9d6300293a6d0dff5cae49ebe7c11dab..3b08dad7a9fac7ac9acec0bfb85d4826
} }
} }
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index fdaf752b4d39402de504cc8dfb6f0593f9b19d9a..74d6cf9b0fa0e47d5c94a16ce54f32810afb2da5 100644 index 561066a2cf769e13ef3cea0881f7a2010ecbf2ec..5fe908ce51f95e1eab024dcd41ed108373f17fea 100644
--- a/net/minecraft/server/level/ServerLevel.java --- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java
@@ -816,6 +816,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe @@ -818,6 +818,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.entityTickList this.entityTickList
.forEach( .forEach(
entity -> { entity -> {
@@ -43,7 +43,7 @@ index fdaf752b4d39402de504cc8dfb6f0593f9b19d9a..74d6cf9b0fa0e47d5c94a16ce54f3281
if (!tickRateManager.isEntityFrozen(entity)) { if (!tickRateManager.isEntityFrozen(entity)) {
entity.checkDespawn(); entity.checkDespawn();
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 96775eadaac9afb600b5c1b553db40970d9d7a3d..b6becf5e14abddcb60b1f4c4babecfe81cf5c09c 100644 index 04ae7636d14a40a427b5d9b746632b0c489efa21..f1cd66d7d96771bc4967e214f70c756fec30efe5 100644
--- a/net/minecraft/world/entity/Entity.java --- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java
@@ -336,6 +336,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess @@ -336,6 +336,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess

View File

@@ -0,0 +1,331 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Thu, 27 Mar 2025 00:04:19 +0300
Subject: [PATCH] Paper PR: Throttle failed spawn attempts
Original license: GPLv3
Original project: https://github.com/PaperMC/Paper
Paper pull request: https://github.com/PaperMC/Paper/pull/11099
Example config in paper-world-defaults.yml:
```
spawning-throttle:
failed-attempts-threshold: 1200
throttled-ticks-per-spawn:
ambient: 10 # default value in bukkit.yml tickers-per * 10
axolotls: 10
creature: 4000
monster: 10
underground_water_creature: 10
water_ambient: 10
water_creature: 10
```
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index 650dfce05bfc68d4c664471b430bd5c0f9629283..3e9ab446632ffe56de45f7622db44070e1cbaf1f 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -175,29 +175,52 @@ public final class NaturalSpawner {
// Copied from getFilteredSpawningCategories
int limit = mobCategory.getMaxInstancesPerChunk();
SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(mobCategory);
+ // Paper start - throttle failed spawn attempts
+ boolean spawnThisTick = true;
+ long ticksPerSpawn = level.ticksPerSpawnCategory.getLong(spawnCategory);
+ long ticksPerSpawnTmp = ticksPerSpawn;
+ io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.SpawningThrottle spawningThrottle = level.paperConfig().entities.spawning.spawningThrottle;
+ if (spawningThrottle.failedAttemptsThreshold.test(threshold -> chunk.failedSpawnAttempts[mobCategory.ordinal()] > threshold)) {
+ ticksPerSpawn = Math.max(ticksPerSpawn, spawningThrottle.throttledTicksPerSpawn.getOrDefault(mobCategory, -1));
+ }
+ // Paper end - throttle failed spawn attempts
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
+ spawnThisTick = ticksPerSpawnTmp != 0 && level.getGameTime() % ticksPerSpawn == 0; // Paper - throttle failed spawn attempts
limit = level.getWorld().getSpawnLimit(spawnCategory);
}
- // Apply per-player limit
- int minDiff = Integer.MAX_VALUE;
- final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
- level.moonrise$getNearbyPlayers().getPlayers(chunk.getPos(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
- if (inRange != null) {
- final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
- for (int k = 0, len = inRange.size(); k < len; k++) {
- minDiff = Math.min(limit - level.getChunkSource().chunkMap.getMobCountNear(backingSet[k], mobCategory), minDiff);
+ // Paper start - throttle failed spawn attempts
+ if (!spawningThrottle.failedAttemptsThreshold.enabled() || spawnThisTick) {
+ // Apply per-player limit
+ int minDiff = Integer.MAX_VALUE;
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
+ level.moonrise$getNearbyPlayers().getPlayers(chunk.getPos(), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange != null) {
+ final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
+ for (int k = 0, len = inRange.size(); k < len; k++) {
+ minDiff = Math.min(limit - level.getChunkSource().chunkMap.getMobCountNear(backingSet[k], mobCategory), minDiff);
+ }
}
- }
- maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
- canSpawn = maxSpawns > 0;
+ maxSpawns = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
+ canSpawn = maxSpawns > 0;
+ } else {
+ canSpawn = false;
+ }
+ // Paper end - throttle failed spawn attempts
} else {
canSpawn = spawnState.canSpawnForCategoryLocal(mobCategory, chunk.getPos());
}
if (canSpawn) {
- spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn,
- maxSpawns, level.paperConfig().entities.spawning.perPlayerMobSpawns ? level.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
+ // Paper start - throttle failed spawn attempts
+ int spawnCount = spawnCategoryForChunk(mobCategory, level, chunk, spawnState::canSpawn, spawnState::afterSpawn,
+ maxSpawns, level.paperConfig().entities.spawning.perPlayerMobSpawns ? level.getChunkSource().chunkMap::updatePlayerMobTypeMap : null, false);
+ if (spawnCount == 0) {
+ chunk.failedSpawnAttempts[mobCategory.ordinal()]++;
+ } else {
+ chunk.failedSpawnAttempts[mobCategory.ordinal()] = 0;
+ }
+ // Paper end - throttle failed spawn attempts
// Paper end - Optional per player mob spawns
}
}
@@ -221,12 +244,21 @@ public final class NaturalSpawner {
}
public static void spawnCategoryForChunk(
MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final Consumer<Entity> trackEntity
+ // Paper start - throttle failed spawn attempts
+ ) {
+ spawnCategoryForChunk(category, level, chunk, filter, callback, maxSpawns, trackEntity, false);
+ }
+ public static int spawnCategoryForChunk(
+ MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final Consumer<Entity> trackEntity, final boolean nothing
+ // Paper end - throttle failed spawn attempts
) {
// Paper end - Optional per player mob spawns
BlockPos randomPosWithin = getRandomPosWithin(level, chunk);
if (randomPosWithin.getY() >= level.getMinY() + 1) {
- spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
+ return spawnCategoryForPosition(category, level, chunk, randomPosWithin, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts
}
+
+ return 0; // Paper - throttle failed spawn attempts
}
@VisibleForDebug
@@ -246,16 +278,22 @@ public final class NaturalSpawner {
}
public static void spawnCategoryForPosition(
MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer<Entity> trackEntity
+ // Paper start - throttle failed spawn attempts
+ ) {
+ spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false);
+ }
+ public static int spawnCategoryForPosition(
+ MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer<Entity> trackEntity, final boolean nothing
+ // Paper end - throttle failed spawn attempts
) {
// Paper end - Optional per player mob spawns
StructureManager structureManager = level.structureManager();
ChunkGenerator generator = level.getChunkSource().getGenerator();
int y = pos.getY();
+ int i = 0; // Paper - throttle failed spawn attempts
BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
- int i = 0;
-
for (int i1 = 0; i1 < 3; i1++) {
int x = pos.getX();
int z = pos.getZ();
@@ -295,13 +333,13 @@ public final class NaturalSpawner {
}
// Paper end - per player mob count backoff
if (doSpawning == PreSpawnStatus.ABORT) {
- return;
+ return i; // Paper - throttle failed spawn attempts
}
if (doSpawning == PreSpawnStatus.SUCCESS && filter.test(spawnerData.type, mutableBlockPos, chunk)) {
// Paper end - PreCreatureSpawnEvent
Mob mobForSpawn = getMobForSpawn(level, spawnerData.type);
if (mobForSpawn == null) {
- return;
+ return i; // Paper - throttle failed spawn attempts
}
mobForSpawn.moveTo(d, y, d1, level.random.nextFloat() * 360.0F, 0.0F);
@@ -324,7 +362,7 @@ public final class NaturalSpawner {
}
// CraftBukkit end
if (i >= mobForSpawn.getMaxSpawnClusterSize() || i >= maxSpawns) { // Paper - Optional per player mob spawns
- return;
+ return i; // Paper - throttle failed spawn attempts
}
if (mobForSpawn.isMaxGroupSizeReached(i3)) {
@@ -337,6 +375,8 @@ public final class NaturalSpawner {
}
}
}
+
+ return i; // Paper - throttle failed spawn attempts
}
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) {
diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java
index 80a0f5524e91e55d716e93c29e199d9816b0072a..3ba674ca0656d42b7d9e445cf25166253bf11f2e 100644
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -91,6 +91,7 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY);
// CraftBukkit end
public final Registry<Biome> biomeRegistry; // CraftBukkit
+ public final long[] failedSpawnAttempts = new long[net.minecraft.world.entity.MobCategory.values().length]; // Paper - throttle failed spawn attempts
// Paper start - rewrite chunk system
private volatile ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray[] blockNibbles;
diff --git a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
index 6b6aaeca14178b5b709e20ae13552d42217f15c0..56ed001b8ce9273bdc7afd8228f69e69e71f45ff 100644
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
@@ -92,6 +92,7 @@ public record SerializableChunkData(
List<CompoundTag> blockEntities,
CompoundTag structureData
, @Nullable net.minecraft.nbt.Tag persistentDataContainer // CraftBukkit - persistentDataContainer
+ , @Nullable long[] failedSpawnAttempts // Paper - throttle failed spawn attempts
) {
public static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(
Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState(), null // Paper - Anti-Xray
@@ -216,6 +217,19 @@ public record SerializableChunkData(
lists[i] = list4;
}
+ // Paper start - throttle failed spawn attempts
+ long[] failedSpawnAttemptsData = null;
+ if (tag.contains("Paper.FailedSpawnAttempts", net.minecraft.nbt.Tag.TAG_COMPOUND)) {
+ failedSpawnAttemptsData = new long[net.minecraft.world.entity.MobCategory.values().length];
+ CompoundTag failedSpawnAttemptsTag = tag.getCompound("Paper.FailedSpawnAttempts");
+ for (net.minecraft.world.entity.MobCategory mobCategory : net.minecraft.world.level.NaturalSpawner.SPAWNING_CATEGORIES) {
+ if (failedSpawnAttemptsTag.contains(mobCategory.getSerializedName(), net.minecraft.nbt.Tag.TAG_LONG)) {
+ failedSpawnAttemptsData[mobCategory.ordinal()] = failedSpawnAttemptsTag.getLong(mobCategory.getSerializedName());
+ }
+ }
+ }
+ // Paper end - throttle failed spawn attempts
+
List<CompoundTag> list5 = Lists.transform(tag.getList("entities", 10), tag1 -> (CompoundTag)tag1);
List<CompoundTag> list6 = Lists.transform(tag.getList("block_entities", 10), tag1 -> (CompoundTag)tag1);
CompoundTag compound1 = tag.getCompound("structures");
@@ -294,6 +308,7 @@ public record SerializableChunkData(
list6,
compound1
, tag.get("ChunkBukkitValues") // CraftBukkit - ChunkBukkitValues
+ , failedSpawnAttemptsData // Paper - throttle failed spawn attempts
);
}
}
@@ -450,6 +465,15 @@ public record SerializableChunkData(
chunkAccess.addPackedPostProcess(this.postProcessingSections[i], i);
}
+ // Paper start - throttle failed spawn attempts
+ long[] failedSpawnAttemptsData = this.failedSpawnAttempts;
+ if (failedSpawnAttemptsData != null) {
+ for (net.minecraft.world.entity.MobCategory mobCategory : net.minecraft.world.entity.MobCategory.values()) {
+ System.arraycopy(failedSpawnAttemptsData, 0, chunkAccess.failedSpawnAttempts, 0, failedSpawnAttemptsData.length);
+ }
+ }
+ // Paper end - throttle failed spawn attempts
+
if (chunkType == ChunkType.LEVELCHUNK) {
return this.loadStarlightLightData(level, new ImposterProtoChunk((LevelChunk)chunkAccess, false)); // Paper - starlight
} else {
@@ -587,6 +611,7 @@ public record SerializableChunkData(
persistentDataContainer = chunk.persistentDataContainer.toTagCompound();
}
// CraftBukkit end
+ final long[] failedSpawnAttemptsData = chunk.failedSpawnAttempts; // Paper - throttle failed spawn attempts
return new SerializableChunkData(
level.registryAccess().lookupOrThrow(Registries.BIOME),
pos,
@@ -607,6 +632,7 @@ public record SerializableChunkData(
list1,
compoundTag
, persistentDataContainer // CraftBukkit - persistentDataContainer
+ , failedSpawnAttemptsData // Paper - throttle failed spawn attempts
);
}
}
@@ -703,6 +729,21 @@ public record SerializableChunkData(
compoundTag.put("ChunkBukkitValues", this.persistentDataContainer);
}
// CraftBukkit end
+ // Paper start - throttle failed spawn attempts
+ CompoundTag failedSpawnAttemptsTag = new CompoundTag();
+ long[] failedSpawnAttemptsData = this.failedSpawnAttempts;
+ if (failedSpawnAttemptsData != null) {
+ for (net.minecraft.world.entity.MobCategory mobCategory : net.minecraft.world.entity.MobCategory.values()) {
+ long failedAttempts = failedSpawnAttemptsData[mobCategory.ordinal()];
+ if (failedAttempts > 0) {
+ failedSpawnAttemptsTag.putLong(mobCategory.getSerializedName(), failedAttempts);
+ }
+ }
+ }
+ if (!failedSpawnAttemptsTag.isEmpty()) {
+ compoundTag.put("Paper.FailedSpawnAttempts", failedSpawnAttemptsTag);
+ }
+ // Paper end - throttle failed spawn attempts
// Paper start - starlight
if (this.lightCorrect && !this.chunkStatus.isBefore(net.minecraft.world.level.chunk.status.ChunkStatus.LIGHT)) {
// clobber vanilla value to force vanilla to relight
@@ -931,4 +972,49 @@ public record SerializableChunkData(
}
// Paper end - starlight - convert from record
}
+
+ // Paper start - throttle failed spawn attempts - for plugin compatibility
+ public SerializableChunkData(
+ Registry<Biome> biomeRegistry,
+ ChunkPos chunkPos,
+ int minSectionY,
+ long lastUpdateTime,
+ long inhabitedTime,
+ ChunkStatus chunkStatus,
+ @Nullable BlendingData.Packed blendingData,
+ @Nullable BelowZeroRetrogen belowZeroRetrogen,
+ UpgradeData upgradeData,
+ @Nullable long[] carvingMask,
+ Map<Heightmap.Types, long[]> heightmaps,
+ ChunkAccess.PackedTicks packedTicks,
+ ShortList[] postProcessingSections,
+ boolean lightCorrect,
+ List<net.minecraft.world.level.chunk.storage.SerializableChunkData.SectionData> sectionData,
+ List<CompoundTag> entities,
+ List<CompoundTag> blockEntities,
+ CompoundTag structureData,
+ @Nullable net.minecraft.nbt.Tag persistentDataContainer // CraftBukkit - persistentDataContainer
+ ) {
+ this(biomeRegistry,
+ chunkPos,
+ minSectionY,
+ lastUpdateTime,
+ inhabitedTime,
+ chunkStatus,
+ blendingData,
+ belowZeroRetrogen,
+ upgradeData,
+ carvingMask,
+ heightmaps,
+ packedTicks,
+ postProcessingSections,
+ lightCorrect,
+ sectionData,
+ entities,
+ blockEntities,
+ structureData,
+ persistentDataContainer,
+ null);
+ }
+ // Paper end - throttle failed spawn attempts
}

View File

@@ -0,0 +1,137 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 6 Apr 2025 20:53:48 +0300
Subject: [PATCH] Optimize Raids
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 92e35158b68dcb8d1f34fb1b748c12d1d39468c7..c87d1f81bd1b4b9756bd2f4c1dbc58a2dc85c63b 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -219,6 +219,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current)
public boolean hasRidableMoveEvent = false; // Purpur - Ridables
public org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag Compensation
+ public net.minecraft.world.item.ItemStack ominousBanner; // DivineMC - Optimize Raids
public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
@@ -714,6 +715,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.tickExecutor = java.util.concurrent.Executors.newSingleThreadExecutor(new org.bxteam.divinemc.server.ServerLevelTickExecutorThreadFactory(getWorld().getName())); // DivineMC - Parallel world ticking
this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
this.chunkSystemPriorities = new org.bxteam.divinemc.server.chunk.PriorityHandler(this); // DivineMC - Chunk System optimizations
+ this.ominousBanner = Objects.requireNonNullElse(this.registryAccess(), net.minecraft.core.RegistryAccess.EMPTY).lookup(Registries.BANNER_PATTERN).map(Raid::getOminousBannerInstance).orElse(null); // DivineMC - Optimize Raids
}
// Paper start
diff --git a/net/minecraft/world/entity/raid/Raid.java b/net/minecraft/world/entity/raid/Raid.java
index 41b0db439b425b052bd1469daa6620a435ca852b..4e53cb7ad7c787fd7581763ae3e77c988277887c 100644
--- a/net/minecraft/world/entity/raid/Raid.java
+++ b/net/minecraft/world/entity/raid/Raid.java
@@ -109,6 +109,7 @@ public class Raid {
private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry PDC_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(PDC_TYPE_REGISTRY);
// Paper end
+ private boolean isBarDirty; // DivineMC - Optimize Raids
public Raid(int id, ServerLevel level, BlockPos center) {
this.id = id;
@@ -263,6 +264,12 @@ public class Raid {
}
public void tick() {
+ // DivineMC start - Optimize Raids
+ if (this.isBarDirty) {
+ this.raidEvent.setProgress(Mth.clamp(this.getHealthOfLivingRaiders() / this.totalHealth, 0.0F, 1.0F));
+ this.isBarDirty = false;
+ }
+ // DivineMC end - Optimize Raids
if (!this.isStopped()) {
if (this.status == Raid.RaidStatus.ONGOING) {
boolean flag = this.active;
@@ -581,7 +588,7 @@ public class Raid {
}
public void updateBossbar() {
- this.raidEvent.setProgress(Mth.clamp(this.getHealthOfLivingRaiders() / this.totalHealth, 0.0F, 1.0F));
+ this.isBarDirty = true; // DivineMC - Optimize Raids
}
public float getHealthOfLivingRaiders() {
diff --git a/net/minecraft/world/entity/raid/Raider.java b/net/minecraft/world/entity/raid/Raider.java
index c06b589e669b055a26f662df60070d5908256220..7f954bab6e8a1b25abcb3aa6c2d26315dacec930 100644
--- a/net/minecraft/world/entity/raid/Raider.java
+++ b/net/minecraft/world/entity/raid/Raider.java
@@ -42,9 +42,25 @@ import net.minecraft.world.phys.Vec3;
public abstract class Raider extends PatrollingMonster {
protected static final EntityDataAccessor<Boolean> IS_CELEBRATING = SynchedEntityData.defineId(Raider.class, EntityDataSerializers.BOOLEAN);
- static final Predicate<ItemEntity> ALLOWED_ITEMS = item -> !item.hasPickUpDelay()
- && item.isAlive()
- && ItemStack.matches(item.getItem(), Raid.getOminousBannerInstance(item.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)));
+ // DivineMC start - Optimize Raids
+ static final Predicate<ItemEntity> ALLOWED_ITEMS = (itemEntity) -> {
+ ItemStack ominousBanner = ((ServerLevel) itemEntity.level()).ominousBanner;
+ if (ominousBanner == null) {
+ ominousBanner = Raid.getOminousBannerInstance(itemEntity.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN));
+ }
+
+ return !itemEntity.hasPickUpDelay() && itemEntity.isAlive() &&
+ ItemStack.matches(itemEntity.getItem(), ominousBanner);
+ };
+
+ private ItemStack getOminousBanner(net.minecraft.core.HolderGetter<net.minecraft.world.level.block.entity.BannerPattern> bannerPatternLookup) {
+ ItemStack ominousBanner = ((ServerLevel) this.level()).ominousBanner;
+ if (ominousBanner == null) {
+ ominousBanner = Raid.getOminousBannerInstance(bannerPatternLookup);
+ }
+ return ominousBanner;
+ }
+ // DivineMC end - Optimize Raids
@Nullable
protected Raid raid;
private int wave;
@@ -147,7 +163,7 @@ public abstract class Raider extends PatrollingMonster {
public boolean isCaptain() {
ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD);
boolean flag = !itemBySlot.isEmpty()
- && ItemStack.matches(itemBySlot, Raid.getOminousBannerInstance(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)));
+ && ItemStack.matches(itemBySlot, getOminousBanner(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN))); // DivineMC - Optimize Raids
boolean isPatrolLeader = this.isPatrolLeader();
return flag && isPatrolLeader;
}
@@ -211,7 +227,7 @@ public abstract class Raider extends PatrollingMonster {
boolean flag = this.hasActiveRaid() && this.getCurrentRaid().getLeader(this.getWave()) != null;
if (this.hasActiveRaid()
&& !flag
- && ItemStack.matches(item, Raid.getOminousBannerInstance(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) {
+ && ItemStack.matches(item, getOminousBanner(this.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)))) { // DivineMC - Optimize Raids
// Paper start - EntityPickupItemEvent fixes
if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0, false).isCancelled()) {
return;
@@ -398,6 +414,16 @@ public abstract class Raider extends PatrollingMonster {
&& !this.cannotPickUpBanner();
}
+ // DivineMC start - Optimize Raids
+ private ItemStack getOminousBanner(net.minecraft.core.HolderGetter<net.minecraft.world.level.block.entity.BannerPattern> bannerPatternLookup) {
+ ItemStack ominousBanner = ((ServerLevel) this.mob.level()).ominousBanner;
+ if (ominousBanner == null) {
+ ominousBanner = Raid.getOminousBannerInstance(bannerPatternLookup);
+ }
+ return ominousBanner;
+ }
+ // DivineMC end - Optimize Raids
+
private boolean cannotPickUpBanner() {
if (!this.mob.level().purpurConfig.pillagerBypassMobGriefing == !getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING) || !this.mob.canPickUpLoot()) return false; // Paper - respect game and entity rules for picking up items // Purpur - Add mobGriefing bypass to everything affected
if (!this.mob.hasActiveRaid()) {
@@ -407,7 +433,7 @@ public abstract class Raider extends PatrollingMonster {
} else if (!this.mob.canBeLeader()) {
return true;
} else if (ItemStack.matches(
- this.mob.getItemBySlot(EquipmentSlot.HEAD), Raid.getOminousBannerInstance(this.mob.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN))
+ this.mob.getItemBySlot(EquipmentSlot.HEAD), getOminousBanner(this.mob.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN)) // DivineMC - Optimize Raids
)) {
return true;
} else {

View File

@@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 12 Apr 2025 17:40:53 +0300
Subject: [PATCH] SparklyPaper: Allow throttling hopper checks if the target
container is full
Original project: https://github.com/SparklyPower/SparklyPaper
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 5cd1326ad5d046c88b2b3449d610a78fa880b4cd..6ad3388ac45a4d2ef85fc0fafece7de6e387f738 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -419,6 +419,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
} else {
Direction opposite = blockEntity.facing.getOpposite();
if (isFullContainer(attachedContainer, opposite)) {
+ // DivineMC start - SparklyPaper: Allow throttling hopper checks if the target container is full
+ if (org.bxteam.divinemc.DivineConfig.hopperThrottleWhenFull && org.bxteam.divinemc.DivineConfig.hopperThrottleSkipTicks > 0) {
+ blockEntity.setCooldown(org.bxteam.divinemc.DivineConfig.hopperThrottleSkipTicks);
+ }
+ // DivineMC end - SparklyPaper: Allow throttling hopper checks if the target container is full
return false;
} else {
// Paper start - Perf: Optimize Hoppers

View File

@@ -315,6 +315,13 @@ index 776bc01784b53e3f1d9a35046109c3b9ee4f0882..3731ca80ed58cd385cd66ffbe67f2eea
} }
logger.log(Level.SEVERE, "------------------------------"); logger.log(Level.SEVERE, "------------------------------");
diff --git a/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks
index e57c3ca79677b1dfe7cf3db36f0406de7ea5bd0a..fc80cbc5dbb49e7a8e251a47c9c05e0c2b20e8d0 100644
--- a/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks
+++ b/src/main/resources/META-INF/services/ca.spottedleaf.moonrise.common.PlatformHooks
@@ -1 +1 @@
-ca.spottedleaf.moonrise.paper.PaperHooks
+org.bxteam.divinemc.DivineHooks
diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
index 518591dd83289e041a16e2c2e7d7e7640d4b2e1b..f54753531b3bf2e8b5377f342465e727c7da98f2 100644 index 518591dd83289e041a16e2c2e7d7e7640d4b2e1b..f54753531b3bf2e8b5377f342465e727c7da98f2 100644
GIT binary patch GIT binary patch

View File

@@ -221,89 +221,126 @@ index 69cdd304d255d52c9b7dc9b6a33ffdb630b79abe..c153e79ebe1f2338f0d0ca6b45b39279
} }
+ // DivineMC end - Parallel world ticking + // DivineMC end - Parallel world ticking
} }
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
index d7398b1ecf2660c29fb7d106b48fe02d3736603e..124715b53090085fc0a9f50bb2df196d31d89bed 100644
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
@@ -28,6 +28,7 @@ import java.util.logging.Level;
class PaperEventManager {
private final Server server;
+ private final org.purpurmc.purpur.util.MinecraftInternalPlugin minecraftInternalPlugin = new org.purpurmc.purpur.util.MinecraftInternalPlugin(); // DivineMC - Parallel world ticking
public PaperEventManager(Server server) {
this.server = server;
@@ -40,6 +41,12 @@ class PaperEventManager {
if (listeners.length == 0) return;
// DivineMC end - Skip event if no listeners
if (event.isAsynchronous() && this.server.isPrimaryThread()) {
+ // DivineMC start - Parallel world ticking
+ if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && org.bxteam.divinemc.DivineConfig.pwtCompatabilityMode) {
+ org.bukkit.Bukkit.getAsyncScheduler().runNow(minecraftInternalPlugin, task -> event.callEvent());
+ return;
+ }
+ // DivineMC end - Parallel world ticking
throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously.");
} else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) {
throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously.");
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index bc2522968205d0c701a2fa23f29565a500881492..fc4fd93632cbeea929ee866673d721cf4ef1f418 100644 index bc2522968205d0c701a2fa23f29565a500881492..312018206729b623a7c854af1c11a2d0bc888372 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -446,7 +446,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -446,7 +446,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override @Override
public boolean unloadChunkRequest(int x, int z) { public boolean unloadChunkRequest(int x, int z) {
- org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot - org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot unload chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + // DivineMC start - Parallel world ticking
+ if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot unload chunk asynchronously");
+ } else {
+ org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
+ }
+ // DivineMC end - Parallel world ticking
if (this.isChunkLoaded(x, z)) { if (this.isChunkLoaded(x, z)) {
this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE); this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE);
} }
@@ -471,6 +471,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -471,6 +477,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override @Override
public boolean refreshChunk(int x, int z) { public boolean refreshChunk(int x, int z) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot refresh chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot refresh chunk asynchronously"); // DivineMC - Parallel world ticking
ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z)); ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
if (playerChunk == null) return false; if (playerChunk == null) return false;
@@ -521,7 +522,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -521,7 +528,13 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override @Override
public boolean loadChunk(int x, int z, boolean generate) { public boolean loadChunk(int x, int z, boolean generate) {
- org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot - org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "May not sync load chunks asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + // DivineMC start - Parallel world ticking
+ if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "May not sync load chunks asynchronously");
+ } else {
+ org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
+ }
+ // DivineMC end - Parallel world ticking
warnUnsafeChunk("loading a faraway chunk", x, z); // Paper warnUnsafeChunk("loading a faraway chunk", x, z); // Paper
ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper
@@ -749,6 +750,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -749,6 +762,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override @Override
public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) { public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // DivineMC - Parallel world ticking
this.world.captureTreeGeneration = true; this.world.captureTreeGeneration = true;
this.world.captureBlockStates = true; this.world.captureBlockStates = true;
boolean grownTree = this.generateTree(loc, type); boolean grownTree = this.generateTree(loc, type);
@@ -864,6 +866,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -864,6 +878,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
} }
public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source, Consumer<net.minecraft.world.level.ServerExplosion> configurator) { public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source, Consumer<net.minecraft.world.level.ServerExplosion> configurator) {
// Paper end - expand explosion API // Paper end - expand explosion API
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // DivineMC - Parallel world ticking
net.minecraft.world.level.Level.ExplosionInteraction explosionType; net.minecraft.world.level.Level.ExplosionInteraction explosionType;
if (!breakBlocks) { if (!breakBlocks) {
explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks
@@ -955,6 +958,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -955,6 +970,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override @Override
public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) { public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x >> 4, z >> 4, "Cannot retrieve chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x >> 4, z >> 4, "Cannot retrieve chunk asynchronously"); // DivineMC - Parallel world ticking
warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper
// Transient load for this tick // Transient load for this tick
return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z); return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z);
@@ -985,6 +989,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -985,6 +1001,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override @Override
public void setBiome(int x, int y, int z, Holder<net.minecraft.world.level.biome.Biome> bb) { public void setBiome(int x, int y, int z, Holder<net.minecraft.world.level.biome.Biome> bb) {
BlockPos pos = new BlockPos(x, 0, z); BlockPos pos = new BlockPos(x, 0, z);
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // DivineMC - Parallel world ticking
if (this.world.hasChunkAt(pos)) { if (this.world.hasChunkAt(pos)) {
net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos); net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos);
@@ -2288,6 +2293,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @@ -2288,6 +2305,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override @Override
public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) { public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs) + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); // DivineMC - Parallel world ticking
getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position)); getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position));
} }
// Paper end // Paper end
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b330450fbc 100644 index 5cb69d0b822e11a99a96aef4f59986d083b079f4..0e47184336f63123211e24a966908a16aa27d6c6 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -75,6 +75,11 @@ public class CraftBlock implements Block { @@ -75,6 +75,11 @@ public class CraftBlock implements Block {
} }
public net.minecraft.world.level.block.state.BlockState getNMS() { public net.minecraft.world.level.block.state.BlockState getNMS() {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
return this.world.getBlockState(this.position); return this.world.getBlockState(this.position);
} }
@@ -311,11 +348,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
} }
private void setData(final byte data, int flag) { private void setData(final byte data, int flag) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag); this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag);
} }
@@ -323,11 +360,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
} }
public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) { public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
// SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup // SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup
if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes
// SPIGOT-4612: faster - just clear tile // SPIGOT-4612: faster - just clear tile
@@ -335,33 +372,33 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public Biome getBiome() { public Biome getBiome() {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ()); return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ());
} }
// Paper start // Paper start
@Override @Override
public Biome getComputedBiome() { public Biome getComputedBiome() {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ()); return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ());
} }
// Paper end // Paper end
@Override @Override
public void setBiome(Biome bio) { public void setBiome(Biome bio) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio); this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio);
} }
@@ -369,11 +406,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public boolean isBlockFaceIndirectlyPowered(BlockFace face) { public boolean isBlockFaceIndirectlyPowered(BlockFace face) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face)); int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face));
Block relative = this.getRelative(face); Block relative = this.getRelative(face);
@@ -381,11 +418,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public int getBlockPower(BlockFace face) { public int getBlockPower(BlockFace face) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
int power = 0; int power = 0;
net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
int x = this.getX(); int x = this.getX();
@@ -393,11 +430,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public boolean breakNaturally() { public boolean breakNaturally() {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
return this.breakNaturally(null); return this.breakNaturally(null);
} }
@@ -405,11 +442,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public boolean applyBoneMeal(BlockFace face) { public boolean applyBoneMeal(BlockFace face) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
Direction direction = CraftBlock.blockFaceToNotch(face); Direction direction = CraftBlock.blockFaceToNotch(face);
BlockFertilizeEvent event = null; BlockFertilizeEvent event = null;
ServerLevel world = this.getCraftWorld().getHandle(); ServerLevel world = this.getCraftWorld().getHandle();
@@ -419,10 +456,10 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
if (world.capturedBlockStates.size() > 0) { if (world.capturedBlockStates.size() > 0) {
- TreeType treeType = SaplingBlock.treeType; - TreeType treeType = SaplingBlock.treeType;
- SaplingBlock.treeType = null; - SaplingBlock.treeType = null;
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ TreeType treeType = SaplingBlock.treeTypeRT.get(); + TreeType treeType = SaplingBlock.getTreeTypeTL();
+ SaplingBlock.treeTypeRT.set(null); + SaplingBlock.setTreeTypeTL(null);
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
List<BlockState> blocks = new ArrayList<>(world.capturedBlockStates.values()); List<BlockState> blocks = new ArrayList<>(world.capturedBlockStates.values());
world.capturedBlockStates.clear(); world.capturedBlockStates.clear();
StructureGrowEvent structureEvent = null; StructureGrowEvent structureEvent = null;
@@ -430,11 +467,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) { public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
Preconditions.checkArgument(start != null, "Location start cannot be null"); Preconditions.checkArgument(start != null, "Location start cannot be null");
Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world"); Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world");
start.checkFinite(); start.checkFinite();
@@ -442,11 +479,11 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public boolean canPlace(BlockData data) { public boolean canPlace(BlockData data) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
Preconditions.checkArgument(data != null, "BlockData cannot be null"); Preconditions.checkArgument(data != null, "BlockData cannot be null");
net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState(); net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState();
net.minecraft.world.level.Level world = this.world.getMinecraftWorld(); net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
@@ -454,53 +491,70 @@ index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b3
@Override @Override
public void tick() { public void tick() {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (world instanceof ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
final ServerLevel level = this.world.getMinecraftWorld(); final ServerLevel level = this.world.getMinecraftWorld();
this.getNMS().tick(level, this.position, level.random); this.getNMS().tick(level, this.position, level.random);
} }
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
index 768d3f93da2522d467183654260a8bd8653588b1..762bb2827dc1c0c0649a4cb3d8b0c8c0c9ea95d1 100644 index 768d3f93da2522d467183654260a8bd8653588b1..dd3c9e214a59d20c2b5e8556951687e2aba2d116 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
@@ -25,7 +25,7 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft @@ -26,6 +26,25 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
private final T tileEntity;
private final T snapshot; private final T snapshot;
public boolean snapshotDisabled; // Paper public boolean snapshotDisabled; // Paper
- public static boolean DISABLE_SNAPSHOT = false; // Paper public static boolean DISABLE_SNAPSHOT = false; // Paper
+ public static ThreadLocal<Boolean> DISABLE_SNAPSHOT = ThreadLocal.withInitial(() -> Boolean.FALSE); // DivineMC - parallel world ticking + // DivineMC start - Parallel world ticking
+ public static ThreadLocal<Boolean> DISABLE_SNAPSHOT_TL = ThreadLocal.withInitial(() -> Boolean.FALSE);
+
+ public static boolean getDisableSnapshotTL() {
+ if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && DISABLE_SNAPSHOT_TL.get()) return true;
+
+ synchronized (CraftBlockEntityState.class) {
+ return DISABLE_SNAPSHOT;
+ }
+ }
+
+ public static void setDisableSnapshotTL(boolean value) {
+ if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) DISABLE_SNAPSHOT_TL.set(value);
+
+ synchronized (CraftBlockEntityState.class) {
+ DISABLE_SNAPSHOT = value;
+ }
+ }
+ // DivineMC end - Parallel world ticking
public CraftBlockEntityState(World world, T tileEntity) { public CraftBlockEntityState(World world, T tileEntity) {
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState()); super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
@@ -34,8 +34,10 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft @@ -34,8 +53,10 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
try { // Paper - Show blockstate location if we failed to read it try { // Paper - Show blockstate location if we failed to read it
// Paper start // Paper start
- this.snapshotDisabled = DISABLE_SNAPSHOT; - this.snapshotDisabled = DISABLE_SNAPSHOT;
- if (DISABLE_SNAPSHOT) { - if (DISABLE_SNAPSHOT) {
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ this.snapshotDisabled = DISABLE_SNAPSHOT.get(); + this.snapshotDisabled = getDisableSnapshotTL();
+ if (DISABLE_SNAPSHOT.get()) { + if (snapshotDisabled) {
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
this.snapshot = this.tileEntity; this.snapshot = this.tileEntity;
} else { } else {
this.snapshot = this.createSnapshot(tileEntity); this.snapshot = this.createSnapshot(tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..951e47811e861dffd59cc39e2dcd6fd68900fc72 100644 index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..cddb460892f1756faa4b58ae53406058acd9803d 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
@@ -215,6 +215,12 @@ public class CraftBlockState implements BlockState { @@ -215,6 +215,12 @@ public class CraftBlockState implements BlockState {
LevelAccessor access = this.getWorldHandle(); LevelAccessor access = this.getWorldHandle();
CraftBlock block = this.getBlock(); CraftBlock block = this.getBlock();
+ // DivineMC start - parallel world ticking + // DivineMC start - Parallel world ticking
+ if (access instanceof net.minecraft.server.level.ServerLevel serverWorld) { + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && access instanceof net.minecraft.server.level.ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously"); + ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ } + }
+ // DivineMC end - parallel world ticking + // DivineMC end - Parallel world ticking
+ +
if (block.getType() != this.getType()) { if (block.getType() != this.getType()) {
if (!force) { if (!force) {
@@ -509,12 +563,12 @@ index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..951e47811e861dffd59cc39e2dcd6fd6
@Override @Override
public java.util.Collection<org.bukkit.inventory.ItemStack> getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) { public java.util.Collection<org.bukkit.inventory.ItemStack> getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); // DivineMC - parallel world ticking + if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); // DivineMC - Parallel world ticking
this.requirePlaced(); this.requirePlaced();
net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item); net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..a8e740b255336c2d611e44129418b5fb29792592 100644 index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..c3cc5012cf460f57495d8867f198007676bae5bf 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java --- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java +++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
@@ -249,8 +249,10 @@ public final class CraftBlockStates { @@ -249,8 +249,10 @@ public final class CraftBlockStates {
@@ -524,8 +578,8 @@ index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..a8e740b255336c2d611e44129418b5fb
- boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT; - boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT;
- CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot; - CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot;
+ // DivineMC start - Parallel world ticking + // DivineMC start - Parallel world ticking
+ boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT.get(); + boolean prev = CraftBlockEntityState.getDisableSnapshotTL();
+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(!useSnapshot); + CraftBlockEntityState.setDisableSnapshotTL(!useSnapshot);
+ // DivineMC end - Parallel world ticking + // DivineMC end - Parallel world ticking
try { try {
// Paper end // Paper end
@@ -535,38 +589,59 @@ index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..a8e740b255336c2d611e44129418b5fb
// Paper start // Paper start
} finally { } finally {
- CraftBlockEntityState.DISABLE_SNAPSHOT = prev; - CraftBlockEntityState.DISABLE_SNAPSHOT = prev;
+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(prev); // DivineMC - parallel world ticking + CraftBlockEntityState.setDisableSnapshotTL(prev); // DivineMC - Parallel world ticking
} }
// Paper end // Paper end
} }
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 4df143dfa4c01dc70e496ec8dc44fdde00ab40c6..1a398376298fbc5a247d6645e733f7c543106fb1 100644 index 4df143dfa4c01dc70e496ec8dc44fdde00ab40c6..59ee059f8d2d96b5e5ae507f209d267da24c9fa1 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -960,7 +960,7 @@ public class CraftEventFactory { @@ -961,6 +961,26 @@ public class CraftEventFactory {
return CraftEventFactory.handleBlockSpreadEvent(world, source, target, block, 2);
} }
- public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
+ public static final ThreadLocal<BlockPos> sourceBlockOverrideRT = new ThreadLocal<>(); // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. // DivineMC - parallel world ticking (this is from Folia, fixes concurrency bugs with sculk catalysts) + // DivineMC start - Parallel world ticking
+ public static final ThreadLocal<BlockPos> sourceBlockOverrideTL = new ThreadLocal<>();
+
+ public static BlockPos getSourceBlockOverrideTL() {
+ BlockPos sourceBlockOverrideRTCopy;
+ if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking && (sourceBlockOverrideRTCopy = sourceBlockOverrideTL.get()) != null) return sourceBlockOverrideRTCopy;
+
+ synchronized (CraftEventFactory.class) {
+ return sourceBlockOverride;
+ }
+ }
+
+ public static void setSourceBlockOverrideTL(BlockPos value) {
+ if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) sourceBlockOverrideTL.set(value);
+
+ synchronized (CraftEventFactory.class) {
+ sourceBlockOverride = value;
+ }
+ }
+ // DivineMC end - Parallel world ticking
public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) { public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) {
// Suppress during worldgen // Suppress during worldgen
@@ -972,7 +972,7 @@ public class CraftEventFactory { @@ -972,7 +992,10 @@ public class CraftEventFactory {
CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag); CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag);
state.setData(block); state.setData(block);
- BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), state); - BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), state);
+ BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverrideRT.get() != null ? CraftEventFactory.sourceBlockOverrideRT.get() : source), state); // DivineMC - parallel world ticking + // DivineMC start - Parallel world ticking
+ final BlockPos sourceBlockOverrideRTSnap = getSourceBlockOverrideTL();
+ BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, sourceBlockOverrideRTSnap != null ? sourceBlockOverrideRTSnap : source), state);
+ // DivineMC end - Parallel world ticking
Bukkit.getPluginManager().callEvent(event); Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) { if (!event.isCancelled()) {
@@ -2245,7 +2245,7 @@ public class CraftEventFactory { @@ -2245,7 +2268,7 @@ public class CraftEventFactory {
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1)); CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1));
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to)); org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to));
- if (!net.minecraft.world.level.block.DispenserBlock.eventFired) { - if (!net.minecraft.world.level.block.DispenserBlock.eventFired) {
+ if (!net.minecraft.world.level.block.DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking + if (!net.minecraft.world.level.block.DispenserBlock.getEventFiredTL()) { // DivineMC - Parallel world ticking
if (!event.callEvent()) { if (!event.callEvent()) {
return itemStack; return itemStack;
} }

View File

@@ -0,0 +1,686 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 6 Apr 2025 18:03:38 +0300
Subject: [PATCH] Chunk System Optimizations
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java
index 7fed43a1e7bcf35c4d7fd3224837a47fedd59860..353f1412b6edf481162ded50fa9a23d3442b9ed5 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/EntityList.java
@@ -1,5 +1,7 @@
package ca.spottedleaf.moonrise.common.list;
+import it.unimi.dsi.fastutil.ints.Int2IntMap;
+import it.unimi.dsi.fastutil.ints.Int2IntMaps;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import net.minecraft.world.entity.Entity;
import java.util.Arrays;
@@ -13,7 +15,7 @@ import java.util.NoSuchElementException;
*/
public final class EntityList implements Iterable<Entity> {
- private final Int2IntOpenHashMap entityToIndex = new Int2IntOpenHashMap(2, 0.8f);
+ private final Int2IntMap entityToIndex = Int2IntMaps.synchronize(new Int2IntOpenHashMap(2, 0.8f)); // DivineMC - Chunk System Optimizations
{
this.entityToIndex.defaultReturnValue(Integer.MIN_VALUE);
}
@@ -27,11 +29,11 @@ public final class EntityList implements Iterable<Entity> {
return this.count;
}
- public boolean contains(final Entity entity) {
+ public synchronized boolean contains(final Entity entity) { // DivineMC - Chunk System Optimizations
return this.entityToIndex.containsKey(entity.getId());
}
- public boolean remove(final Entity entity) {
+ public synchronized boolean remove(final Entity entity) { // DivineMC - Chunk System Optimizations
final int index = this.entityToIndex.remove(entity.getId());
if (index == Integer.MIN_VALUE) {
return false;
@@ -50,7 +52,7 @@ public final class EntityList implements Iterable<Entity> {
return true;
}
- public boolean add(final Entity entity) {
+ public synchronized boolean add(final Entity entity) { // DivineMC - Chunk System Optimizations
final int count = this.count;
final int currIndex = this.entityToIndex.putIfAbsent(entity.getId(), count);
@@ -82,18 +84,18 @@ public final class EntityList implements Iterable<Entity> {
return this.entities[index];
}
- public Entity[] getRawData() {
+ public synchronized Entity[] getRawData() { // DivineMC - Chunk System Optimizations
return this.entities;
}
- public void clear() {
+ public synchronized void clear() { // DivineMC - Chunk System Optimizations
this.entityToIndex.clear();
Arrays.fill(this.entities, 0, this.count, null);
this.count = 0;
}
@Override
- public Iterator<Entity> iterator() {
+ public synchronized Iterator<Entity> iterator() { // DivineMC - Chunk System Optimizations
return new Iterator<>() {
private Entity lastRet;
private int current;
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java
index 2e876b918672e8ef3b5197b7e6b1597247fdeaa1..aab585e226e0928d778dc83a33bdcaf5f5a6f213 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ReferenceList.java
@@ -1,142 +1,26 @@
package ca.spottedleaf.moonrise.common.list;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.NoSuchElementException;
+// DivineMC start - Chunk System Optimizations - rewrite
+import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
+import it.unimi.dsi.fastutil.objects.ReferenceLists;
-public final class ReferenceList<E> implements Iterable<E> {
-
- private static final Object[] EMPTY_LIST = new Object[0];
-
- private final Reference2IntOpenHashMap<E> referenceToIndex;
- private E[] references;
- private int count;
-
- public ReferenceList() {
- this((E[])EMPTY_LIST);
- }
-
- public ReferenceList(final E[] referenceArray) {
- this.references = referenceArray;
- this.referenceToIndex = new Reference2IntOpenHashMap<>(2, 0.8f);
- this.referenceToIndex.defaultReturnValue(Integer.MIN_VALUE);
- }
-
- private ReferenceList(final E[] references, final int count, final Reference2IntOpenHashMap<E> referenceToIndex) {
- this.references = references;
- this.count = count;
- this.referenceToIndex = referenceToIndex;
- }
-
- public ReferenceList<E> copy() {
- return new ReferenceList<>(this.references.clone(), this.count, this.referenceToIndex.clone());
- }
-
- public int size() {
- return this.count;
- }
-
- public boolean contains(final E obj) {
- return this.referenceToIndex.containsKey(obj);
+public class ReferenceList<E> extends ReferenceLists.SynchronizedList<E> {
+ public ReferenceList(E[] elements) {
+ super(new RefListInner<>(elements));
}
- public boolean remove(final E obj) {
- final int index = this.referenceToIndex.removeInt(obj);
- if (index == Integer.MIN_VALUE) {
- return false;
- }
-
- // move the object at the end to this index
- final int endIndex = --this.count;
- final E end = (E)this.references[endIndex];
- if (index != endIndex) {
- // not empty after this call
- this.referenceToIndex.put(end, index); // update index
- }
- this.references[index] = end;
- this.references[endIndex] = null;
-
- return true;
+ public synchronized E[] getRawDataUnchecked() {
+ return ((RefListInner<E>) this.list).getRawDataUnchecked();
}
- public boolean add(final E obj) {
- final int count = this.count;
- final int currIndex = this.referenceToIndex.putIfAbsent(obj, count);
-
- if (currIndex != Integer.MIN_VALUE) {
- return false; // already in this list
+ public static class RefListInner<A> extends ReferenceArrayList<A> {
+ public RefListInner(A[] elements) {
+ super(elements, true);
}
- E[] list = this.references;
-
- if (list.length == count) {
- // resize required
- list = this.references = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative
+ public A[] getRawDataUnchecked() {
+ return this.a;
}
-
- list[count] = obj;
- this.count = count + 1;
-
- return true;
- }
-
- public E getChecked(final int index) {
- if (index < 0 || index >= this.count) {
- throw new IndexOutOfBoundsException("Index: " + index + " is out of bounds, size: " + this.count);
- }
- return this.references[index];
- }
-
- public E getUnchecked(final int index) {
- return this.references[index];
- }
-
- public Object[] getRawData() {
- return this.references;
- }
-
- public E[] getRawDataUnchecked() {
- return this.references;
- }
-
- public void clear() {
- this.referenceToIndex.clear();
- Arrays.fill(this.references, 0, this.count, null);
- this.count = 0;
- }
-
- @Override
- public Iterator<E> iterator() {
- return new Iterator<>() {
- private E lastRet;
- private int current;
-
- @Override
- public boolean hasNext() {
- return this.current < ReferenceList.this.count;
- }
-
- @Override
- public E next() {
- if (this.current >= ReferenceList.this.count) {
- throw new NoSuchElementException();
- }
- return this.lastRet = ReferenceList.this.references[this.current++];
- }
-
- @Override
- public void remove() {
- final E lastRet = this.lastRet;
-
- if (lastRet == null) {
- throw new IllegalStateException();
- }
- this.lastRet = null;
-
- ReferenceList.this.remove(lastRet);
- --this.current;
- }
- };
}
}
+// DivineMC end - Chunk System Optimizations - rewrite
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java
index 2bae9949ef325d0001aa638150fbbdf968367e75..11bf4ddb298bb39f7f39a9c33c90b48a3171266b 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/ShortList.java
@@ -1,11 +1,13 @@
package ca.spottedleaf.moonrise.common.list;
+import it.unimi.dsi.fastutil.shorts.Short2ShortMap;
+import it.unimi.dsi.fastutil.shorts.Short2ShortMaps;
import it.unimi.dsi.fastutil.shorts.Short2ShortOpenHashMap;
import java.util.Arrays;
public final class ShortList {
- private final Short2ShortOpenHashMap map = new Short2ShortOpenHashMap();
+ private final Short2ShortMap map = Short2ShortMaps.synchronize(new Short2ShortOpenHashMap()); // DivineMC - Chunk System Optimizations
{
this.map.defaultReturnValue(Short.MIN_VALUE);
}
@@ -13,13 +15,13 @@ public final class ShortList {
private static final short[] EMPTY_LIST = new short[0];
private short[] byIndex = EMPTY_LIST;
- private short count;
+ private volatile short count; // DivineMC - Chunk System Optimizations
public int size() {
- return (int)this.count;
+ return this.count; // DivineMC - Chunk System Optimizations
}
- public short getRaw(final int index) {
+ public synchronized short getRaw(final int index) { // DivineMC - Chunk System Optimizations
return this.byIndex[index];
}
@@ -30,8 +32,8 @@ public final class ShortList {
}
}
- public boolean add(final short value) {
- final int count = (int)this.count;
+ public synchronized boolean add(final short value) { // DivineMC - Chunk System Optimizations
+ final int count = this.count; // DivineMC - Chunk System Optimizations
final short currIndex = this.map.putIfAbsent(value, (short)count);
if (currIndex != Short.MIN_VALUE) {
@@ -51,7 +53,7 @@ public final class ShortList {
return true;
}
- public boolean remove(final short value) {
+ public synchronized boolean remove(final short value) { // DivineMC - Chunk System Optimizations
final short index = this.map.remove(value);
if (index == Short.MIN_VALUE) {
return false;
@@ -70,7 +72,7 @@ public final class ShortList {
return true;
}
- public void clear() {
+ public synchronized void clear() { // DivineMC - Chunk System Optimizations
this.count = (short)0;
this.map.clear();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java
index 460e27ab0506c83a28934800ee74ee886d4b025e..49e53bf85352f4d1b9997fa3c30e37e40c0ff01c 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java
@@ -15,7 +15,7 @@ public final class Delayed26WayDistancePropagator3D {
// Generally updates to positions are made close to other updates, so we link to decrease cache misses when
// propagating updates
- protected final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet();
+ protected final it.unimi.dsi.fastutil.longs.LongSet updatedSources = it.unimi.dsi.fastutil.longs.LongSets.synchronize(new LongLinkedOpenHashSet()); // DivineMC - Chunk System Optimizations
@FunctionalInterface
public static interface LevelChangeCallback {
@@ -94,29 +94,29 @@ public final class Delayed26WayDistancePropagator3D {
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << level);
}
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << index);
}
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelRemoveWorkQueueBitset |= (1L << level);
}
- public boolean propagateUpdates() {
+ public synchronized boolean propagateUpdates() { // DivineMC - Chunk System Optimizations
if (this.updatedSources.isEmpty()) {
return false;
}
@@ -157,15 +157,15 @@ public final class Delayed26WayDistancePropagator3D {
return ret;
}
- protected void propagateIncreases() {
+ protected synchronized void propagateIncreases() { // DivineMC - Chunk System Optimizations
for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset);
this.levelIncreaseWorkQueueBitset != 0L;
this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final boolean neighbourCheck = level < 0;
@@ -226,15 +226,15 @@ public final class Delayed26WayDistancePropagator3D {
}
}
- protected void propagateDecreases() {
+ protected synchronized void propagateDecreases() { // DivineMC - Chunk System Optimizations
for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset);
this.levelRemoveWorkQueueBitset != 0L;
this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- final byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ final byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
if (currentLevel == 0) {
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java
index ab2fa1563d5e32a5313dfcc1da411cab45fb5ca0..1bababc2515d8c805e4ee0c943065f451a38b7b8 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java
@@ -356,24 +356,24 @@ public final class Delayed8WayDistancePropagator2D {
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
final WorkQueue queue = this.levelIncreaseWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << level);
}
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
final WorkQueue queue = this.levelIncreaseWorkQueues[index];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << index);
}
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
final WorkQueue queue = this.levelRemoveWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelRemoveWorkQueueBitset |= (1L << level);
}
@@ -426,8 +426,8 @@ public final class Delayed8WayDistancePropagator2D {
final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final boolean neighbourCheck = level < 0;
@@ -492,8 +492,8 @@ public final class Delayed8WayDistancePropagator2D {
final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- final byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ final byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
if (currentLevel == 0) {
@@ -561,7 +561,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private int find(final long k) {
+ private synchronized int find(final long k) { // DivineMC - Chunk System Optimizations
if (k == 0L) {
return this.containsNullKey ? this.n : -(this.n + 1);
} else {
@@ -585,7 +585,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private void insert(final int pos, final long k, final byte v) {
+ private synchronized void insert(final int pos, final long k, final byte v) { // DivineMC - Chunk System Optimizations
if (pos == this.n) {
this.containsNullKey = true;
}
@@ -598,7 +598,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- public byte putIfGreater(final long key, final byte value) {
+ public synchronized byte putIfGreater(final long key, final byte value) { // DivineMC - Chunk System Optimizations
final int pos = this.find(key);
if (pos < 0) {
if (this.defRetValue < value) {
@@ -616,7 +616,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private void removeEntry(final int pos) {
+ private synchronized void removeEntry(final int pos) { // DivineMC - Chunk System Optimizations
--this.size;
this.shiftKeys(pos);
if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) {
@@ -625,7 +625,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private void removeNullEntry() {
+ private synchronized void removeNullEntry() { // DivineMC - Chunk System Optimizations
this.containsNullKey = false;
--this.size;
if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) {
@@ -634,7 +634,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- public byte removeIfGreaterOrEqual(final long key, final byte value) {
+ public synchronized byte removeIfGreaterOrEqual(final long key, final byte value) { // DivineMC - Chunk System Optimizations
if (key == 0L) {
if (!this.containsNullKey) {
return this.defRetValue;
@@ -679,8 +679,8 @@ public final class Delayed8WayDistancePropagator2D {
protected static final class WorkQueue {
- public final NoResizeLongArrayFIFODeque queuedCoordinates = new NoResizeLongArrayFIFODeque();
- public final NoResizeByteArrayFIFODeque queuedLevels = new NoResizeByteArrayFIFODeque();
+ public final java.util.concurrent.ConcurrentLinkedDeque<Long> queuedCoordinates = new java.util.concurrent.ConcurrentLinkedDeque<>();
+ public final java.util.concurrent.ConcurrentLinkedDeque<Byte> queuedLevels = new java.util.concurrent.ConcurrentLinkedDeque<>();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
index 632920e04686d8a0fd0a60e87348be1fe7862a3c..f10c6c156b8dd9acecc8b1ee81bd28260fb6e4d8 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
@@ -3,6 +3,12 @@ package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.concurrentutil.executor.thread.PrioritisedThreadPool;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import com.mojang.logging.LogUtils;
+import org.bxteam.divinemc.DivineConfig;
+import org.bxteam.divinemc.server.chunk.ChunkSystemAlgorithms;
+import org.bxteam.divinemc.server.chunk.TheChunkSystem;
+import org.bxteam.divinemc.spark.ThreadDumperRegistry;
+import org.bxteam.divinemc.util.ThreadBuilder;
+import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -12,83 +18,63 @@ public final class MoonriseCommon {
private static final Logger LOGGER = LogUtils.getClassLogger();
- public static final PrioritisedThreadPool WORKER_POOL = new PrioritisedThreadPool(
- new Consumer<>() {
- private final AtomicInteger idGenerator = new AtomicInteger();
+ public static TheChunkSystem WORKER_POOL;
+ public static TheChunkSystem.ExecutorGroup PARALLEL_GEN_GROUP;
+ public static TheChunkSystem.ExecutorGroup RADIUS_AWARE_GROUP;
+ public static TheChunkSystem.ExecutorGroup LOAD_GROUP;
- @Override
- public void accept(Thread thread) {
- thread.setDaemon(true);
- thread.setName(PlatformHooks.get().getBrand() + " Common Worker #" + this.idGenerator.getAndIncrement());
- thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(final Thread thread, final Throwable throwable) {
- LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable);
- }
- });
- }
- }
- );
- public static final long WORKER_QUEUE_HOLD_TIME = (long)(20.0e6); // 20ms
- public static final int CLIENT_DIVISION = 0;
- public static final PrioritisedThreadPool.ExecutorGroup RENDER_EXECUTOR_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(CLIENT_DIVISION, 0);
- public static final int SERVER_DIVISION = 1;
- public static final PrioritisedThreadPool.ExecutorGroup PARALLEL_GEN_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0);
- public static final PrioritisedThreadPool.ExecutorGroup RADIUS_AWARE_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0);
- public static final PrioritisedThreadPool.ExecutorGroup LOAD_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0);
-
- public static void adjustWorkerThreads(final int configWorkerThreads, final int configIoThreads) {
- int defaultWorkerThreads = Runtime.getRuntime().availableProcessors() / 2;
- if (defaultWorkerThreads <= 4) {
- defaultWorkerThreads = defaultWorkerThreads <= 3 ? 1 : 2;
- } else {
- defaultWorkerThreads = defaultWorkerThreads / 2;
- }
- defaultWorkerThreads = Integer.getInteger(PlatformHooks.get().getBrand() + ".WorkerThreadCount", Integer.valueOf(defaultWorkerThreads));
-
- int workerThreads = configWorkerThreads;
+ public static void init(final int configWorkerThreads, final int configIoThreads) {
+ ChunkSystemAlgorithms algorithm = DivineConfig.chunkWorkerAlgorithm;
+ int workerThreads = algorithm.evalWorkers(configWorkerThreads, configIoThreads);
+ int ioThreads = algorithm.evalIO(configWorkerThreads, configIoThreads);
- if (workerThreads <= 0) {
- workerThreads = defaultWorkerThreads;
- }
+ WORKER_POOL = buildChunkSystem(workerThreads);
- final int ioThreads = Math.max(1, configIoThreads);
+ PARALLEL_GEN_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup();
+ RADIUS_AWARE_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup();
+ LOAD_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup();
- WORKER_POOL.adjustThreadCount(workerThreads);
IO_POOL.adjustThreadCount(ioThreads);
+ LOGGER.info("Running ChunkSystem with {} worker threads and {} I/O threads", workerThreads, ioThreads);
+ }
- LOGGER.info(PlatformHooks.get().getBrand() + " is using " + workerThreads + " worker threads, " + ioThreads + " I/O threads");
+ private static @NotNull TheChunkSystem buildChunkSystem(int workerThreads) {
+ return new TheChunkSystem(workerThreads, new ThreadBuilder() {
+ @Override
+ public void accept(final Thread thread) {
+ thread.setPriority(DivineConfig.threadPoolPriority);
+ thread.setDaemon(true);
+ thread.setUncaughtExceptionHandler((thread1, throwable) -> LOGGER.error("Uncaught exception in thread {}", thread1.getName(), throwable));
+ thread.setName("World Gen Worker #" + getAndIncrementId());
+ ThreadDumperRegistry.REGISTRY.add(thread.getName());
+ }
+ });
}
public static final PrioritisedThreadPool IO_POOL = new PrioritisedThreadPool(
- new Consumer<>() {
- private final AtomicInteger idGenerator = new AtomicInteger();
-
- @Override
- public void accept(final Thread thread) {
- thread.setDaemon(true);
- thread.setName(PlatformHooks.get().getBrand() + " I/O Worker #" + this.idGenerator.getAndIncrement());
- thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
- @Override
- public void uncaughtException(final Thread thread, final Throwable throwable) {
- LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable);
- }
- });
- }
+ new Consumer<>() {
+ private final AtomicInteger idGenerator = new AtomicInteger();
+
+ @Override
+ public void accept(final Thread thread) {
+ thread.setDaemon(true);
+ thread.setName(PlatformHooks.get().getBrand() + " I/O Worker #" + this.idGenerator.getAndIncrement());
+ ThreadDumperRegistry.REGISTRY.add(thread.getName());
+ thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
+ @Override
+ public void uncaughtException(final Thread thread, final Throwable throwable) {
+ LOGGER.error("Uncaught exception in thread {}", thread.getName(), throwable);
+ }
+ });
}
+ }
);
public static final long IO_QUEUE_HOLD_TIME = (long)(100.0e6); // 100ms
- public static final PrioritisedThreadPool.ExecutorGroup CLIENT_PROFILER_IO_GROUP = IO_POOL.createExecutorGroup(CLIENT_DIVISION, 0);
- public static final PrioritisedThreadPool.ExecutorGroup SERVER_REGION_IO_GROUP = IO_POOL.createExecutorGroup(SERVER_DIVISION, 0);
+ public static final PrioritisedThreadPool.ExecutorGroup SERVER_REGION_IO_GROUP = IO_POOL.createExecutorGroup(1, 0);
public static void haltExecutors() {
- MoonriseCommon.WORKER_POOL.shutdown(false);
- LOGGER.info("Awaiting termination of worker pool for up to 60s...");
- if (!MoonriseCommon.WORKER_POOL.join(TimeUnit.SECONDS.toMillis(60L))) {
- LOGGER.error("Worker pool did not shut down in time!");
- MoonriseCommon.WORKER_POOL.halt(false);
- }
-
+ LOGGER.info("Shutting down ChunkSystem...");
+ MoonriseCommon.WORKER_POOL.shutdown();
MoonriseCommon.IO_POOL.shutdown(false);
LOGGER.info("Awaiting termination of I/O pool for up to 60s...");
if (!MoonriseCommon.IO_POOL.join(TimeUnit.SECONDS.toMillis(60L))) {
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java
index 559c959aff3c9deef867b9e425fba3e2e669cac6..a5b0585b56d71d21c9da3b129d213def142bb1f6 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java
@@ -4,7 +4,7 @@ import ca.spottedleaf.moonrise.common.PlatformHooks;
public final class MoonriseConstants {
- public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", 32);
+ public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", org.bxteam.divinemc.DivineConfig.maxViewDistance); // DivineMC - Configurable view distance
private MoonriseConstants() {}
diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
index 8b70a8e9b0aacbe7964b0441b5bbbaab228962d8..f0c420f4a1b282fb976825c33cb7a118e45de36d 100644
--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
@@ -229,7 +229,7 @@ public class GlobalConfiguration extends ConfigurationPart {
@PostProcess
private void postProcess() {
- ca.spottedleaf.moonrise.common.util.MoonriseCommon.adjustWorkerThreads(this.workerThreads, this.ioThreads);
+ ca.spottedleaf.moonrise.common.util.MoonriseCommon.init(this.workerThreads, this.ioThreads);
String newChunkSystemGenParallelism = this.genParallelism;
if (newChunkSystemGenParallelism.equalsIgnoreCase("default")) {
newChunkSystemGenParallelism = "true";
@@ -245,7 +245,6 @@ public class GlobalConfiguration extends ConfigurationPart {
} else {
throw new IllegalStateException("Invalid option for gen-parallelism: must be one of [on, off, enabled, disabled, true, false, default]");
}
- FeatureHooks.initChunkTaskScheduler(useParallelGen);
}
}

View File

@@ -1,61 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 22 Feb 2025 02:33:28 +0300
Subject: [PATCH] Add chunk worker algorithm
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
index 632920e04686d8a0fd0a60e87348be1fe7862a3c..27447481c6e6b526cda032aff54a5c87256c217d 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
@@ -3,6 +3,8 @@ package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.concurrentutil.executor.thread.PrioritisedThreadPool;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import com.mojang.logging.LogUtils;
+import org.bxteam.divinemc.DivineConfig;
+import org.bxteam.divinemc.server.chunk.ChunkSystemAlgorithms;
import org.slf4j.Logger;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@@ -29,7 +31,7 @@ public final class MoonriseCommon {
}
}
);
- public static final long WORKER_QUEUE_HOLD_TIME = (long)(20.0e6); // 20ms
+ public static final long WORKER_QUEUE_HOLD_TIME = (long)(2.0e6); // 2ms // DivineMC - Reduce from 20ms to 2ms
public static final int CLIENT_DIVISION = 0;
public static final PrioritisedThreadPool.ExecutorGroup RENDER_EXECUTOR_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(CLIENT_DIVISION, 0);
public static final int SERVER_DIVISION = 1;
@@ -38,26 +40,16 @@ public final class MoonriseCommon {
public static final PrioritisedThreadPool.ExecutorGroup LOAD_GROUP = MoonriseCommon.WORKER_POOL.createExecutorGroup(SERVER_DIVISION, 0);
public static void adjustWorkerThreads(final int configWorkerThreads, final int configIoThreads) {
- int defaultWorkerThreads = Runtime.getRuntime().availableProcessors() / 2;
- if (defaultWorkerThreads <= 4) {
- defaultWorkerThreads = defaultWorkerThreads <= 3 ? 1 : 2;
- } else {
- defaultWorkerThreads = defaultWorkerThreads / 2;
- }
- defaultWorkerThreads = Integer.getInteger(PlatformHooks.get().getBrand() + ".WorkerThreadCount", Integer.valueOf(defaultWorkerThreads));
-
- int workerThreads = configWorkerThreads;
-
- if (workerThreads <= 0) {
- workerThreads = defaultWorkerThreads;
- }
-
- final int ioThreads = Math.max(1, configIoThreads);
+ // DivineMC start - Add chunk worker algorithm
+ ChunkSystemAlgorithms algorithm = DivineConfig.chunkWorkerAlgorithm;
+ int workerThreads = algorithm.evalWorkers(configWorkerThreads, configIoThreads);
+ int ioThreads = algorithm.evalIO(configWorkerThreads, configIoThreads);
WORKER_POOL.adjustThreadCount(workerThreads);
IO_POOL.adjustThreadCount(ioThreads);
- LOGGER.info(PlatformHooks.get().getBrand() + " is using " + workerThreads + " worker threads, " + ioThreads + " I/O threads");
+ LOGGER.info("ChunkSystem using '{}' algorithm, {} worker threads, {} I/O threads", algorithm.asDebugString(), workerThreads, ioThreads);
+ // DivineMC end - Add chunk worker algorithm
}
public static final PrioritisedThreadPool IO_POOL = new PrioritisedThreadPool(

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Optimize canSee checks
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index db2cd4603c26bca59654f0a5225b18c446a7f612..fcc124e1005f4ddda10b9d08226e6d64693f9009 100644 index d2010fc46215c37c3ef1d8a75cc39bce655d2c3f..3cb2cd294874ece5fbefd0618b4db27701ef118a 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -215,7 +215,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @@ -210,7 +210,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
private boolean hasPlayedBefore = false; private boolean hasPlayedBefore = false;
private final ConversationTracker conversationTracker = new ConversationTracker(); private final ConversationTracker conversationTracker = new ConversationTracker();
private final Set<String> channels = new HashSet<String>(); private final Set<String> channels = new HashSet<String>();
@@ -17,7 +17,7 @@ index db2cd4603c26bca59654f0a5225b18c446a7f612..fcc124e1005f4ddda10b9d08226e6d64
private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>(); private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
private int hash = 0; private int hash = 0;
@@ -2272,9 +2272,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player { @@ -2267,9 +2267,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override @Override
public boolean canSee(org.bukkit.entity.Entity entity) { public boolean canSee(org.bukkit.entity.Entity entity) {

View File

@@ -5,14 +5,14 @@ Subject: [PATCH] Configurable thread pool priority
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
index 27447481c6e6b526cda032aff54a5c87256c217d..87d22532c680b7c6d3244a13e91fccbcc1a7e004 100644 index f10c6c156b8dd9acecc8b1ee81bd28260fb6e4d8..c720304d8f2427cd4433d76e28ede13552181648 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java --- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java +++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
@@ -28,6 +28,7 @@ public final class MoonriseCommon { @@ -66,6 +66,7 @@ public final class MoonriseCommon {
LOGGER.error("Uncaught exception in thread " + thread.getName(), throwable); LOGGER.error("Uncaught exception in thread {}", thread.getName(), throwable);
} }
}); });
+ thread.setPriority(DivineConfig.threadPoolPriority); // DivineMC - Configurable thread pool priority + thread.setPriority(DivineConfig.threadPoolPriority); // DivineMC - Configurable thread pool priority
}
} }
}
); );

View File

@@ -5,11 +5,11 @@ Subject: [PATCH] Multithreaded Tracker
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
index d7398b1ecf2660c29fb7d106b48fe02d3736603e..a9ec83b5bcb329bf3d2f3fb0e502685a37f9dcbc 100644 index 124715b53090085fc0a9f50bb2df196d31d89bed..adf526bcb5b4df3b798a8b80ad11b7b2c30775d7 100644
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java --- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
@@ -42,6 +42,12 @@ class PaperEventManager { @@ -49,6 +49,12 @@ class PaperEventManager {
if (event.isAsynchronous() && this.server.isPrimaryThread()) { // DivineMC end - Parallel world ticking
throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously."); throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously.");
} else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) { } else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) {
+ // DivineMC start - Multithreaded Tracker + // DivineMC start - Multithreaded Tracker
@@ -22,10 +22,10 @@ index d7398b1ecf2660c29fb7d106b48fe02d3736603e..a9ec83b5bcb329bf3d2f3fb0e502685a
} }
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 1a398376298fbc5a247d6645e733f7c543106fb1..b761e416d3844063efd66d7ec8519f548995aacd 100644 index 59ee059f8d2d96b5e5ae507f209d267da24c9fa1..68c529473e9ce24cb6c6108cb65100757d1d8759 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1973,6 +1973,26 @@ public class CraftEventFactory { @@ -1996,6 +1996,26 @@ public class CraftEventFactory {
} }
public static boolean handleBlockFormEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState block, int flag, @Nullable Entity entity) { public static boolean handleBlockFormEvent(Level world, BlockPos pos, net.minecraft.world.level.block.state.BlockState block, int flag, @Nullable Entity entity) {

View File

@@ -5,10 +5,10 @@ Subject: [PATCH] Paper PR: Add FillBottleEvents for player and dispenser
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index b761e416d3844063efd66d7ec8519f548995aacd..036913b57313ac437115698282c6d76eb749cf52 100644 index 68c529473e9ce24cb6c6108cb65100757d1d8759..ba5adea7a791a9539ae485ef1c1641a56ca19236 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -2307,4 +2307,18 @@ public class CraftEventFactory { @@ -2330,4 +2330,18 @@ public class CraftEventFactory {
return event; return event;
} }
// Paper end - add EntityFertilizeEggEvent // Paper end - add EntityFertilizeEggEvent

View File

@@ -0,0 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Thu, 27 Mar 2025 00:04:19 +0300
Subject: [PATCH] Paper PR: Throttle failed spawn attempts
Original license: GPLv3
Original project: https://github.com/PaperMC/Paper
Paper pull request: https://github.com/PaperMC/Paper/pull/11099
Example config in paper-world-defaults.yml:
```
spawning-throttle:
failed-attempts-threshold: 1200
throttled-ticks-per-spawn:
ambient: 10 # default value in bukkit.yml tickers-per * 10
axolotls: 10
creature: 4000
monster: 10
underground_water_creature: 10
water_ambient: 10
water_creature: 10
```
diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
index 7bfa7aa30c1181587c7632f920f48348d2493ea4..d838c90f98c6593404c77d0aab8655c0d15905c4 100644
--- a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
+++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
@@ -181,6 +181,17 @@ public class WorldConfiguration extends ConfigurationPart {
@MergeMap
public Reference2IntMap<MobCategory> ticksPerSpawn = Util.make(new Reference2IntOpenHashMap<>(NaturalSpawner.SPAWNING_CATEGORIES.length), map -> Arrays.stream(NaturalSpawner.SPAWNING_CATEGORIES).forEach(mobCategory -> map.put(mobCategory, -1)));
+ // Paper start - throttle failed spawn attempts
+ public SpawningThrottle spawningThrottle;
+
+ public class SpawningThrottle extends ConfigurationPart {
+ public IntOr.Disabled failedAttemptsThreshold = IntOr.Disabled.DISABLED;
+
+ @MergeMap
+ public Reference2IntMap<MobCategory> throttledTicksPerSpawn = Util.make(new Reference2IntOpenHashMap<>(NaturalSpawner.SPAWNING_CATEGORIES.length), map -> Arrays.stream(NaturalSpawner.SPAWNING_CATEGORIES).forEach(mobCategory -> map.put(mobCategory, -1)));
+ }
+ // Paper end - throttle failed spawn attempts
+
@ConfigSerializable
public record DespawnRangePair(@Required DespawnRange hard, @Required DespawnRange soft) {
public static DespawnRangePair createDefault() {

View File

@@ -1,11 +0,0 @@
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseConstants.java
@@ -4,7 +_,7 @@
public final class MoonriseConstants {
- public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", 32);
+ public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", org.bxteam.divinemc.DivineConfig.maxViewDistance); // DivineMC - Configurable view distance
private MoonriseConstants() {}

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Add missing purpur config options
diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java diff --git a/src/main/java/org/purpurmc/purpur/PurpurConfig.java b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
index 168361632d4af27c2144864ade539ce7ea217217..48248e1a7eb9f63220dd619c1868dcca3150c345 100644 index 554ae05a1a7f7dbe91455cb14b1d9a02f3b7d288..2c32f98e4f3ac2705ae6e95a8e8965b4b9d9a0d5 100644
--- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java --- a/src/main/java/org/purpurmc/purpur/PurpurConfig.java
+++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java +++ b/src/main/java/org/purpurmc/purpur/PurpurConfig.java
@@ -327,6 +327,7 @@ public class PurpurConfig { @@ -327,6 +327,7 @@ public class PurpurConfig {
@@ -16,7 +16,7 @@ index 168361632d4af27c2144864ade539ce7ea217217..48248e1a7eb9f63220dd619c1868dcca
public static boolean enderChestSixRows = false; public static boolean enderChestSixRows = false;
public static boolean enderChestPermissionRows = false; public static boolean enderChestPermissionRows = false;
public static boolean cryingObsidianValidForPortalFrame = false; public static boolean cryingObsidianValidForPortalFrame = false;
@@ -369,6 +370,7 @@ public class PurpurConfig { @@ -370,6 +371,7 @@ public class PurpurConfig {
case 1 -> 9; case 1 -> 9;
default -> 27; default -> 27;
}); });

View File

@@ -0,0 +1,191 @@
package com.ishland.flowsched.executor;
import com.ishland.flowsched.structs.DynamicPriorityQueue;
import com.ishland.flowsched.util.Assertions;
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
public class ExecutorManager {
public final DynamicPriorityQueue<Task> globalWorkQueue;
protected final ConcurrentMap<LockToken, FreeableTaskList> lockListeners = new ConcurrentHashMap<>();
protected final WorkerThread[] workerThreads;
final Object workerMonitor = new Object();
/**
* Creates a new executor manager.
*
* @param workerThreadCount the number of worker threads.
*/
public ExecutorManager(int workerThreadCount) {
this(workerThreadCount, thread -> { });
}
/**
* Creates a new executor manager.
*
* @param workerThreadCount the number of worker threads.
* @param threadInitializer the thread initializer.
*/
public ExecutorManager(int workerThreadCount, Consumer<Thread> threadInitializer) {
globalWorkQueue = new DynamicPriorityQueue<>();
workerThreads = new WorkerThread[workerThreadCount];
for (int i = 0; i < workerThreadCount; i++) {
final WorkerThread thread = new WorkerThread(this);
threadInitializer.accept(thread);
thread.start();
workerThreads[i] = thread;
}
}
/**
* Attempt to lock the given tokens.
* The caller should discard the task if this method returns false, as it reschedules the task.
*
* @return {@code true} if the lock is acquired, {@code false} otherwise.
*/
boolean tryLock(Task task) {
retry:
while (true) {
final FreeableTaskList listenerSet = new FreeableTaskList();
LockToken[] lockTokens = task.lockTokens();
for (int i = 0; i < lockTokens.length; i++) {
LockToken token = lockTokens[i];
final FreeableTaskList present = this.lockListeners.putIfAbsent(token, listenerSet);
if (present != null) {
for (int j = 0; j < i; j++) {
this.lockListeners.remove(lockTokens[j], listenerSet);
}
callListeners(listenerSet);
synchronized (present) {
if (present.freed) {
continue retry;
} else {
present.add(task);
}
}
return false;
}
}
return true;
}
}
/**
* Release the locks held by the given task.
*
* @param task the task.
*/
void releaseLocks(Task task) {
FreeableTaskList expectedListeners = null;
for (LockToken token : task.lockTokens()) {
final FreeableTaskList listeners = this.lockListeners.remove(token);
if (listeners != null) {
if (expectedListeners == null) {
expectedListeners = listeners;
} else {
Assertions.assertTrue(expectedListeners == listeners, "Inconsistent lock listeners");
}
} else {
throw new IllegalStateException("Lock token " + token + " is not locked");
}
}
if (expectedListeners != null) {
callListeners(expectedListeners); // synchronizes
}
}
private void callListeners(FreeableTaskList listeners) {
synchronized (listeners) {
listeners.freed = true;
if (listeners.isEmpty()) return;
for (Task listener : listeners) {
this.schedule0(listener);
}
}
this.wakeup();
}
/**
* Polls an executable task from the global work queue.
*
* @return the task, or {@code null} if no task is executable.
*/
Task pollExecutableTask() {
Task task;
while ((task = this.globalWorkQueue.dequeue()) != null) {
if (this.tryLock(task)) {
return task;
}
}
return null;
}
/**
* Shuts down the executor manager.
*/
public void shutdown() {
for (WorkerThread workerThread : workerThreads) {
workerThread.shutdown();
}
}
/**
* Schedules a task.
*
* @param task the task.
*/
public void schedule(Task task) {
schedule0(task);
wakeup();
}
private void schedule0(Task task) {
this.globalWorkQueue.enqueue(task, task.priority());
}
public void wakeup() { // Canvas - private -> public
synchronized (this.workerMonitor) {
this.workerMonitor.notify();
}
}
public boolean hasPendingTasks() {
return this.globalWorkQueue.size() != 0;
}
/**
* Schedules a runnable for execution with the given priority.
*
* @param runnable the runnable.
* @param priority the priority.
*/
public void schedule(Runnable runnable, int priority) {
this.schedule(new SimpleTask(runnable, priority));
}
/**
* Creates an executor that schedules runnables with the given priority.
*
* @param priority the priority.
* @return the executor.
*/
public Executor executor(int priority) {
return runnable -> this.schedule(runnable, priority);
}
/**
* Notifies the executor manager that the priority of the given task has changed.
*
* @param task the task.
*/
public void notifyPriorityChange(Task task) {
this.globalWorkQueue.changePriority(task, task.priority());
}
protected static class FreeableTaskList extends ReferenceArrayList<Task> { // Canvas - private -> protected
private boolean freed = false;
}
}

View File

@@ -0,0 +1,3 @@
package com.ishland.flowsched.executor;
public interface LockToken { }

View File

@@ -0,0 +1,37 @@
package com.ishland.flowsched.executor;
import java.util.Objects;
public class SimpleTask implements Task {
private final Runnable wrapped;
private final int priority;
public SimpleTask(Runnable wrapped, int priority) {
this.wrapped = Objects.requireNonNull(wrapped);
this.priority = priority;
}
@Override
public void run(Runnable releaseLocks) {
try {
wrapped.run();
} finally {
releaseLocks.run();
}
}
@Override
public void propagateException(Throwable t) {
t.printStackTrace();
}
@Override
public LockToken[] lockTokens() {
return new LockToken[0];
}
@Override
public int priority() {
return this.priority;
}
}

View File

@@ -0,0 +1,11 @@
package com.ishland.flowsched.executor;
public interface Task {
void run(Runnable releaseLocks);
void propagateException(Throwable t);
LockToken[] lockTokens();
int priority();
}

View File

@@ -0,0 +1,84 @@
package com.ishland.flowsched.executor;
import ca.spottedleaf.moonrise.common.util.TickThread;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.LockSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class WorkerThread extends TickThread {
private static final Logger LOGGER = LoggerFactory.getLogger("FlowSched Executor Worker Thread");
private final ExecutorManager executorManager;
private final AtomicBoolean shutdown = new AtomicBoolean(false);
public volatile boolean active = false;
public WorkerThread(ExecutorManager executorManager) {
super("null_worker");
this.executorManager = executorManager;
}
@Override
public void run() {
main_loop:
while (true) {
if (this.shutdown.get()) {
return;
}
active = true;
if (pollTasks()) {
continue;
}
synchronized (this.executorManager.workerMonitor) {
if (this.executorManager.hasPendingTasks()) continue main_loop;
try {
active = false;
this.executorManager.workerMonitor.wait();
} catch (InterruptedException ignored) {
}
}
}
}
private boolean pollTasks() {
final Task task = executorManager.pollExecutableTask();
try {
if (task != null) {
AtomicBoolean released = new AtomicBoolean(false);
try {
task.run(() -> {
if (released.compareAndSet(false, true)) {
executorManager.releaseLocks(task);
}
});
} catch (Throwable t) {
try {
if (released.compareAndSet(false, true)) {
executorManager.releaseLocks(task);
}
} catch (Throwable t1) {
t.addSuppressed(t1);
LOGGER.error("Exception thrown while releasing locks", t);
}
try {
task.propagateException(t);
} catch (Throwable t1) {
t.addSuppressed(t1);
LOGGER.error("Exception thrown while propagating exception", t);
}
}
return true;
}
return false;
} catch (Throwable t) {
LOGGER.error("Exception thrown while executing task", t);
return true;
}
}
public void shutdown() {
shutdown.set(true);
LockSupport.unpark(this);
}
}

View File

@@ -0,0 +1,85 @@
package com.ishland.flowsched.structs;
import org.bxteam.divinemc.server.chunk.PriorityHandler;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicIntegerArray;
@SuppressWarnings("unchecked")
public class DynamicPriorityQueue<E> {
private final AtomicIntegerArray taskCount;
public final ConcurrentLinkedQueue<E>[] priorities;
private final ConcurrentHashMap<E, Integer> priorityMap = new ConcurrentHashMap<>();
public DynamicPriorityQueue() {
this.taskCount = new AtomicIntegerArray(PriorityHandler.MAX_PRIORITY + 1);
this.priorities = new ConcurrentLinkedQueue[PriorityHandler.MAX_PRIORITY + 1];
for (int i = 0; i < (PriorityHandler.MAX_PRIORITY + 1); i++) {
this.priorities[i] = new ConcurrentLinkedQueue<>();
}
}
public void enqueue(E element, int priority) {
if (this.priorityMap.putIfAbsent(element, priority) != null)
throw new IllegalArgumentException("Element already in queue");
this.priorities[priority].add(element);
this.taskCount.incrementAndGet(priority);
}
public boolean changePriority(E element, int newPriority) {
Integer currentPriority = this.priorityMap.get(element);
if (currentPriority == null || currentPriority == newPriority) {
return false;
}
int currentIndex = currentPriority;
boolean removedFromQueue = this.priorities[currentIndex].remove(element);
if (!removedFromQueue) {
return false;
}
this.taskCount.decrementAndGet(currentIndex);
final boolean changeSuccess = this.priorityMap.replace(element, currentPriority, newPriority);
if (!changeSuccess) {
return false;
}
this.priorities[newPriority].add(element);
this.taskCount.incrementAndGet(newPriority);
return true;
}
public E dequeue() {
for (int i = 0; i < this.priorities.length; i++) {
if (this.taskCount.get(i) == 0) continue;
E element = priorities[i].poll();
if (element != null) {
this.taskCount.decrementAndGet(i);
this.priorityMap.remove(element);
return element;
}
}
return null;
}
public boolean contains(E element) {
return priorityMap.containsKey(element);
}
public void remove(E element) {
Integer priority = this.priorityMap.remove(element);
if (priority == null) return;
boolean removed = this.priorities[priority].remove(element);
if (removed) this.taskCount.decrementAndGet(priority);
}
public int size() {
return priorityMap.size();
}
public boolean isEmpty() {
return size() == 0;
}
}

View File

@@ -1,4 +1,4 @@
package org.bxteam.divinemc.util; package com.ishland.flowsched.util;
public final class Assertions { public final class Assertions {
public static void assertTrue(boolean value, String message) { public static void assertTrue(boolean value, String message) {

View File

@@ -20,7 +20,7 @@ import org.bxteam.divinemc.DivineConfig;
import java.util.Map; import java.util.Map;
public class PufferfishSentryAppender extends AbstractAppender { public class PufferfishSentryAppender extends AbstractAppender {
private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger(PufferfishSentryAppender.class.getSimpleName()); private static final org.apache.logging.log4j.Logger LOGGER = LogManager.getLogger("PufferfishSentryAppender");
private static final Gson GSON = new Gson(); private static final Gson GSON = new Gson();
private final Level logLevel; private final Level logLevel;

View File

@@ -7,7 +7,7 @@ import org.apache.logging.log4j.Logger;
import org.bxteam.divinemc.DivineConfig; import org.bxteam.divinemc.DivineConfig;
public class SentryManager { public class SentryManager {
private static final Logger LOGGER = LogManager.getLogger(SentryManager.class); private static final Logger LOGGER = LogManager.getLogger("SentryManager");
private static boolean initialized = false; private static boolean initialized = false;
private SentryManager() { private SentryManager() {

View File

@@ -18,6 +18,12 @@ public class DivineBootstrap {
public static void boot(final OptionSet options) { public static void boot(final OptionSet options) {
SharedConstants.tryDetectVersion(); SharedConstants.tryDetectVersion();
io.papermc.paper.ServerBuildInfo info = io.papermc.paper.ServerBuildInfo.buildInfo();
if (io.papermc.paper.ServerBuildInfoImpl.IS_EXPERIMENTAL) {
LOGGER.warn("Running an experimental version of {}, please proceed with caution.", info.brandName());
}
Path path2 = Paths.get("eula.txt"); Path path2 = Paths.get("eula.txt");
Eula eula = new Eula(path2); Eula eula = new Eula(path2);
boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree"); boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree");

View File

@@ -10,13 +10,14 @@ import org.apache.logging.log4j.Logger;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.MemoryConfiguration; import org.bukkit.configuration.MemoryConfiguration;
import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy; import org.bxteam.divinemc.entity.pathfinding.PathfindTaskRejectPolicy;
import org.bxteam.divinemc.region.LinearImplementation;
import org.bxteam.divinemc.server.chunk.ChunkSystemAlgorithms; import org.bxteam.divinemc.server.chunk.ChunkSystemAlgorithms;
import org.bxteam.divinemc.server.chunk.ChunkTaskPriority; import org.bxteam.divinemc.server.chunk.ChunkTaskPriority;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.simpleyaml.configuration.comments.CommentType; import org.simpleyaml.configuration.comments.CommentType;
import org.simpleyaml.configuration.file.YamlFile; import org.simpleyaml.configuration.file.YamlFile;
import org.simpleyaml.exceptions.InvalidConfigurationException; import org.simpleyaml.exceptions.InvalidConfigurationException;
import org.stupidcraft.linearpaper.region.EnumRegionFileExtension; import org.bxteam.divinemc.region.RegionFileFormat;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@@ -185,7 +186,6 @@ public class DivineConfig {
public static ChunkSystemAlgorithms chunkWorkerAlgorithm = ChunkSystemAlgorithms.C2ME; public static ChunkSystemAlgorithms chunkWorkerAlgorithm = ChunkSystemAlgorithms.C2ME;
public static ChunkTaskPriority chunkTaskPriority = ChunkTaskPriority.EUCLIDEAN_CIRCLE_PATTERN; public static ChunkTaskPriority chunkTaskPriority = ChunkTaskPriority.EUCLIDEAN_CIRCLE_PATTERN;
public static int threadPoolPriority = Thread.NORM_PRIORITY + 1; public static int threadPoolPriority = Thread.NORM_PRIORITY + 1;
public static boolean enableAsyncNoiseFill = false;
public static boolean asyncChunkSendingEnabled = true; public static boolean asyncChunkSendingEnabled = true;
public static boolean enableSecureSeed = false; public static boolean enableSecureSeed = false;
public static boolean smoothBedrockLayer = false; public static boolean smoothBedrockLayer = false;
@@ -223,8 +223,6 @@ public class DivineConfig {
" - DEFAULT_DIAMOND_PATTERN: Default one, chunk priorities will be ordered in a diamond pattern")); " - DEFAULT_DIAMOND_PATTERN: Default one, chunk priorities will be ordered in a diamond pattern"));
threadPoolPriority = getInt("settings.chunks.thread-pool-priority", threadPoolPriority, threadPoolPriority = getInt("settings.chunks.thread-pool-priority", threadPoolPriority,
"Sets the priority of the thread pool used for chunk generation"); "Sets the priority of the thread pool used for chunk generation");
enableAsyncNoiseFill = getBoolean("settings.chunks.enable-async-noise-fill", enableAsyncNoiseFill,
"Runs noise filling and biome populating in a virtual thread executor. If disabled, it will run sync.");
enableSecureSeed = getBoolean("settings.chunks.enable-secure-seed", enableSecureSeed, enableSecureSeed = getBoolean("settings.chunks.enable-secure-seed", enableSecureSeed,
"This feature is based on Secure Seed mod by Earthcomputer.", "This feature is based on Secure Seed mod by Earthcomputer.",
@@ -282,6 +280,8 @@ public class DivineConfig {
public static boolean disableLeafDecay = false; public static boolean disableLeafDecay = false;
public static boolean commandBlockParseResultsCaching = true; public static boolean commandBlockParseResultsCaching = true;
public static boolean enableAsyncSpawning = true; public static boolean enableAsyncSpawning = true;
public static boolean hopperThrottleWhenFull = false;
public static int hopperThrottleSkipTicks = 0;
private static void miscSettings() { private static void miscSettings() {
skipUselessSecondaryPoiSensor = getBoolean("settings.misc.skip-useless-secondary-poi-sensor", skipUselessSecondaryPoiSensor); skipUselessSecondaryPoiSensor = getBoolean("settings.misc.skip-useless-secondary-poi-sensor", skipUselessSecondaryPoiSensor);
clumpOrbs = getBoolean("settings.misc.clump-orbs", clumpOrbs, clumpOrbs = getBoolean("settings.misc.clump-orbs", clumpOrbs,
@@ -303,6 +303,11 @@ public class DivineConfig {
"Caches the parse results of command blocks, can significantly reduce performance impact."); "Caches the parse results of command blocks, can significantly reduce performance impact.");
enableAsyncSpawning = getBoolean("settings.misc.enable-async-spawning", enableAsyncSpawning, enableAsyncSpawning = getBoolean("settings.misc.enable-async-spawning", enableAsyncSpawning,
"Enables optimization that will offload much of the computational effort involved with spawning new mobs to a different thread."); "Enables optimization that will offload much of the computational effort involved with spawning new mobs to a different thread.");
hopperThrottleWhenFull = getBoolean("settings.misc.hopper-throttle-when-full.enabled", hopperThrottleWhenFull,
"When enabled, hoppers will throttle if target container is full.");
hopperThrottleSkipTicks = getInt("settings.misc.hopper-throttle-when-full.skip-ticks", hopperThrottleSkipTicks,
"The amount of ticks to skip when the hopper is throttled.");
} }
public static String sentryDsn = ""; public static String sentryDsn = "";
@@ -522,32 +527,50 @@ public class DivineConfig {
if (asyncEntityTrackerQueueSize <= 0) asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384; if (asyncEntityTrackerQueueSize <= 0) asyncEntityTrackerQueueSize = asyncEntityTrackerMaxThreads * 384;
} }
public static EnumRegionFileExtension regionFormatTypeName = EnumRegionFileExtension.MCA; public static RegionFileFormat regionFormatTypeName = RegionFileFormat.ANVIL;
public static LinearImplementation linearImplementation = LinearImplementation.V2;
public static int linearFlushMaxThreads = 4;
public static int linearFlushDelay = 100;
public static boolean linearUseVirtualThread = false;
public static int linearCompressionLevel = 1; public static int linearCompressionLevel = 1;
public static int linearFlushFrequency = 5;
private static void linearRegionFormat() { private static void linearRegionFormat() {
regionFormatTypeName = EnumRegionFileExtension.fromName(getString("settings.linear-region-format.type", regionFormatTypeName.name(), regionFormatTypeName = RegionFileFormat.fromName(getString("settings.linear-region-format.type", regionFormatTypeName.name(),
"The type of region file format to use for storing chunk data.", "The type of region file format to use for storing chunk data.",
"Valid values:", "Valid values:",
" - LINEAR: Linear region file format", " - LINEAR: Linear region file format",
" - MCA: Anvil region file format (default)")); " - ANVIL: Anvil region file format (default)"));
linearImplementation = LinearImplementation.valueOf(getString("settings.linear-region-format.implementation", linearImplementation.name(),
"The implementation of the linear region file format to use.",
"Valid values:",
" - V1: Basic and default linear implementation",
" - V2: Introduces a grid-based compression scheme for better data management and flexibility (default)"));
linearFlushMaxThreads = getInt("settings.linear-region-format.flush-max-threads", linearFlushMaxThreads,
"The maximum number of threads to use for flushing linear region files.",
"If this value is less than or equal to 0, it will be set to the number of available processors + this value.");
linearFlushDelay = getInt("settings.linear-region-format.flush-delay", linearFlushDelay,
"The delay in milliseconds to wait before flushing next files.");
linearUseVirtualThread = getBoolean("settings.linear-region-format.use-virtual-thread", linearUseVirtualThread,
"Whether to use virtual threads for flushing.");
linearCompressionLevel = getInt("settings.linear-region-format.compression-level", linearCompressionLevel, linearCompressionLevel = getInt("settings.linear-region-format.compression-level", linearCompressionLevel,
"The compression level to use for the linear region file format."); "The compression level to use for the linear region file format.");
linearFlushFrequency = getInt("settings.linear-region-format.flush-frequency", linearFlushFrequency,
"The frequency in seconds to flush the linear region file format.");
setComment("settings.linear-region-format", setComment("settings.linear-region-format",
"The linear region file format is a custom region file format that is designed to be more efficient than the MCA format.", "The linear region file format is a custom region file format that is designed to be more efficient than the ANVIL format.",
"It uses uses ZSTD compression instead of ZLIB. This format saves about 50% of disk space.", "It uses uses ZSTD compression instead of ZLIB. This format saves about 50% of disk space.",
"Read more information about linear region format at https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools", "Read more information about linear region format at https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools",
"WARNING: If you are want to use this format, make sure to create backup of your world before switching to it, there is potential risk to lose chunk data."); "WARNING: If you are want to use this format, make sure to create backup of your world before switching to it, there is potential risk to lose chunk data.");
if (regionFormatTypeName == EnumRegionFileExtension.UNKNOWN) { if (regionFormatTypeName == RegionFileFormat.UNKNOWN) {
LOGGER.error("Unknown region file type: {}, falling back to MCA format.", regionFormatTypeName); LOGGER.error("Unknown region file type: {}, falling back to ANVIL format.", regionFormatTypeName);
regionFormatTypeName = EnumRegionFileExtension.MCA; regionFormatTypeName = RegionFileFormat.ANVIL;
} }
if (linearCompressionLevel > 23 || linearCompressionLevel < 1) { if (linearFlushMaxThreads <= 0) {
linearFlushMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + linearFlushMaxThreads, 1);
}
if (linearCompressionLevel > 22 || linearCompressionLevel < 1) {
LOGGER.warn("Invalid linear compression level: {}, resetting to default (1)", playerNearChunkDetectionRange); LOGGER.warn("Invalid linear compression level: {}, resetting to default (1)", playerNearChunkDetectionRange);
linearCompressionLevel = 1; linearCompressionLevel = 1;
} }

View File

@@ -0,0 +1,10 @@
package org.bxteam.divinemc;
import ca.spottedleaf.moonrise.paper.PaperHooks;
public final class DivineHooks extends PaperHooks {
@Override
public String getBrand() {
return "DivineMC";
}
}

View File

@@ -1,4 +1,4 @@
package org.stupidcraft.linearpaper.region; package org.bxteam.divinemc.region;
import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile; import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile;
import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.CompoundTag;

View File

@@ -0,0 +1,6 @@
package org.bxteam.divinemc.region;
public enum LinearImplementation {
V1,
V2
}

View File

@@ -0,0 +1,659 @@
package org.bxteam.divinemc.region;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import com.github.luben.zstd.ZstdInputStream;
import com.github.luben.zstd.ZstdOutputStream;
import com.mojang.logging.LogUtils;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ChunkPos;
import net.openhft.hashing.LongHashFunction;
import org.bxteam.divinemc.DivineConfig;
import org.bxteam.divinemc.spark.ThreadDumperRegistry;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;
public class LinearRegionFile implements IRegionFile {
public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024;
private static final Object SAVE_LOCK = new Object();
private static final long SUPERBLOCK = 0xc3ff13183cca9d9aL;
private static final Logger LOGGER = LogUtils.getLogger();
private static final byte V1_VERSION = 2;
private static final byte V2_VERSION = 3;
private byte[][] bucketBuffers;
private final byte[][] chunkCompressedBuffers = new byte[1024][];
private final int[] chunkUncompressedSizes = new int[1024];
private final long[] chunkTimestamps = new long[1024];
private final Object markedToSaveLock = new Object();
private boolean markedToSave = false;
private final LZ4Compressor compressor;
private final LZ4FastDecompressor decompressor;
private volatile boolean regionFileOpen = false;
private volatile boolean close = false;
private final Path regionFilePath;
private final int gridSizeDefault = 8;
private int gridSize = gridSizeDefault;
private int bucketSize = 4;
private final int compressionLevel;
private final LinearImplementation linearImpl;
private final Thread schedulingThread;
private static int activeSaveThreads = 0;
public LinearRegionFile(Path path, LinearImplementation linearImplementation, int compressionLevel) {
this.regionFilePath = path;
this.linearImpl = linearImplementation;
this.compressionLevel = compressionLevel;
this.compressor = LZ4Factory.fastestInstance().fastCompressor();
this.decompressor = LZ4Factory.fastestInstance().fastDecompressor();
Runnable flushCheck = () -> {
while (!close) {
synchronized (SAVE_LOCK) {
if (markedToSave && activeSaveThreads < DivineConfig.linearFlushMaxThreads) {
activeSaveThreads++;
Runnable flushOperation = () -> {
try {
flush();
} catch (IOException ex) {
LOGGER.error("Region file {} flush failed", regionFilePath.toAbsolutePath(), ex);
} finally {
synchronized (SAVE_LOCK) {
activeSaveThreads--;
}
}
};
Thread saveThread = DivineConfig.linearUseVirtualThread
? Thread.ofVirtual().name("Linear IO - " + this.hashCode()).unstarted(flushOperation)
: Thread.ofPlatform().name("Linear IO - " + this.hashCode()).unstarted(flushOperation);
saveThread.setPriority(Thread.NORM_PRIORITY - 3);
saveThread.start();
ThreadDumperRegistry.REGISTRY.add(saveThread.getName());
}
}
LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(DivineConfig.linearFlushDelay));
}
};
this.schedulingThread = DivineConfig.linearUseVirtualThread
? Thread.ofVirtual().unstarted(flushCheck)
: Thread.ofPlatform().unstarted(flushCheck);
this.schedulingThread.setName("Linear IO Schedule - " + this.hashCode());
ThreadDumperRegistry.REGISTRY.add(this.schedulingThread.getName());
}
private synchronized void openRegionFile() {
if (regionFileOpen) return;
regionFileOpen = true;
File file = regionFilePath.toFile();
if (!file.canRead()) {
schedulingThread.start();
return;
}
try {
byte[] fileContent = Files.readAllBytes(regionFilePath);
ByteBuffer byteBuffer = ByteBuffer.wrap(fileContent);
long superBlock = byteBuffer.getLong();
if (superBlock != SUPERBLOCK) {
throw new RuntimeException("Invalid superblock: " + superBlock + " file " + regionFilePath);
}
byte version = byteBuffer.get();
if (version == V1_VERSION) {
parseLinearV1(byteBuffer);
} else if (version == V2_VERSION) {
parseLinearV2(byteBuffer);
} else {
throw new RuntimeException("Invalid version: " + version + " file " + regionFilePath);
}
schedulingThread.start();
} catch (IOException e) {
throw new RuntimeException("Failed to open region file " + regionFilePath, e);
}
}
private void parseLinearV1(ByteBuffer buffer) throws IOException {
final int HEADER_SIZE = 32;
final int FOOTER_SIZE = 8;
buffer.position(buffer.position() + 11);
int dataCount = buffer.getInt();
long fileLength = regionFilePath.toFile().length();
if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) {
throw new IOException("Invalid file length: " + regionFilePath + " " + fileLength + " expected " + (HEADER_SIZE + dataCount + FOOTER_SIZE));
}
buffer.position(buffer.position() + 8);
byte[] rawCompressed = new byte[dataCount];
buffer.get(rawCompressed);
try (ByteArrayInputStream bais = new ByteArrayInputStream(rawCompressed);
ZstdInputStream zstdIn = new ZstdInputStream(bais)) {
ByteBuffer decompressedBuffer = ByteBuffer.wrap(zstdIn.readAllBytes());
int[] starts = new int[1024];
for (int i = 0; i < 1024; i++) {
starts[i] = decompressedBuffer.getInt();
decompressedBuffer.getInt();
}
for (int i = 0; i < 1024; i++) {
if (starts[i] > 0) {
int size = starts[i];
byte[] chunkData = new byte[size];
decompressedBuffer.get(chunkData);
int maxCompressedLength = compressor.maxCompressedLength(size);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = compressor.compress(chunkData, 0, size, compressed, 0, maxCompressedLength);
byte[] finalCompressed = new byte[compressedLength];
System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength);
chunkCompressedBuffers[i] = finalCompressed;
chunkUncompressedSizes[i] = size;
chunkTimestamps[i] = currentTimestamp();
}
}
}
}
private void parseLinearV2(ByteBuffer buffer) throws IOException {
buffer.getLong();
gridSize = buffer.get();
if (!(gridSize == 1 || gridSize == 2 || gridSize == 4 || gridSize == 8 || gridSize == 16 || gridSize == 32)) {
throw new RuntimeException("Invalid grid size: " + gridSize + " file " + regionFilePath);
}
bucketSize = 32 / gridSize;
buffer.getInt();
buffer.getInt();
boolean[] chunkExistenceBitmap = deserializeExistenceBitmap(buffer);
while (true) {
byte featureNameLength = buffer.get();
if (featureNameLength == 0) break;
byte[] featureNameBytes = new byte[featureNameLength];
buffer.get(featureNameBytes);
String featureName = new String(featureNameBytes);
int featureValue = buffer.getInt();
}
int bucketCount = gridSize * gridSize;
int[] bucketSizes = new int[bucketCount];
byte[] bucketCompressionLevels = new byte[bucketCount];
long[] bucketHashes = new long[bucketCount];
for (int i = 0; i < bucketCount; i++) {
bucketSizes[i] = buffer.getInt();
bucketCompressionLevels[i] = buffer.get();
bucketHashes[i] = buffer.getLong();
}
bucketBuffers = new byte[bucketCount][];
for (int i = 0; i < bucketCount; i++) {
if (bucketSizes[i] > 0) {
bucketBuffers[i] = new byte[bucketSizes[i]];
buffer.get(bucketBuffers[i]);
long rawHash = LongHashFunction.xx().hashBytes(bucketBuffers[i]);
if (rawHash != bucketHashes[i]) {
throw new IOException("Region file hash incorrect " + regionFilePath);
}
}
}
long footerSuperBlock = buffer.getLong();
if (footerSuperBlock != SUPERBLOCK) {
throw new IOException("Footer superblock invalid " + regionFilePath);
}
}
private synchronized void markToSave() {
synchronized (markedToSaveLock) {
markedToSave = true;
}
}
private synchronized boolean isMarkedToSave() {
synchronized (markedToSaveLock) {
if (markedToSave) {
markedToSave = false;
return true;
}
return false;
}
}
@Override
public synchronized boolean doesChunkExist(ChunkPos pos) {
openRegionFile();
return hasChunk(pos);
}
@Override
public synchronized boolean hasChunk(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
int index = getChunkIndex(pos.x, pos.z);
return chunkUncompressedSizes[index] > 0;
}
@Override
public synchronized void flush() throws IOException {
if (!isMarkedToSave()) return;
openRegionFile();
if (linearImpl == LinearImplementation.V1) {
flushLinearV1();
} else if (linearImpl == LinearImplementation.V2) {
flushLinearV2();
}
}
private void flushLinearV1() throws IOException {
long timestamp = currentTimestamp();
short chunkCount = 0;
File tempFile = new File(regionFilePath.toString() + ".tmp");
try (FileOutputStream fos = new FileOutputStream(tempFile);
ByteArrayOutputStream zstdBAOS = new ByteArrayOutputStream();
ZstdOutputStream zstdOut = new ZstdOutputStream(zstdBAOS, compressionLevel);
DataOutputStream zstdDataOut = new DataOutputStream(zstdOut);
DataOutputStream fileDataOut = new DataOutputStream(fos)) {
fileDataOut.writeLong(SUPERBLOCK);
fileDataOut.writeByte(V1_VERSION);
fileDataOut.writeLong(timestamp);
fileDataOut.writeByte(compressionLevel);
ArrayList<byte[]> decompressedChunks = new ArrayList<>(1024);
for (int i = 0; i < 1024; i++) {
if (chunkUncompressedSizes[i] != 0) {
chunkCount++;
byte[] decompressed = new byte[chunkUncompressedSizes[i]];
decompressor.decompress(chunkCompressedBuffers[i], 0, decompressed, 0, chunkUncompressedSizes[i]);
decompressedChunks.add(decompressed);
} else {
decompressedChunks.add(null);
}
}
for (int i = 0; i < 1024; i++) {
zstdDataOut.writeInt(chunkUncompressedSizes[i]);
zstdDataOut.writeInt((int) chunkTimestamps[i]);
}
for (int i = 0; i < 1024; i++) {
if (decompressedChunks.get(i) != null) {
zstdDataOut.write(decompressedChunks.get(i));
}
}
zstdDataOut.close();
fileDataOut.writeShort(chunkCount);
byte[] compressedZstdData = zstdBAOS.toByteArray();
fileDataOut.writeInt(compressedZstdData.length);
fileDataOut.writeLong(0);
fileDataOut.write(compressedZstdData);
fileDataOut.writeLong(SUPERBLOCK);
fileDataOut.flush();
fos.getFD().sync();
fos.getChannel().force(true);
}
Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING);
}
private void flushLinearV2() throws IOException {
long timestamp = currentTimestamp();
File tempFile = new File(regionFilePath.toString() + ".tmp");
try (FileOutputStream fos = new FileOutputStream(tempFile);
DataOutputStream dataOut = new DataOutputStream(fos)) {
dataOut.writeLong(SUPERBLOCK);
dataOut.writeByte(V2_VERSION);
dataOut.writeLong(timestamp);
dataOut.writeByte(gridSize);
int[] regionCoords = parseRegionCoordinates(regionFilePath.getFileName().toString());
dataOut.writeInt(regionCoords[0]);
dataOut.writeInt(regionCoords[1]);
boolean[] chunkExistence = new boolean[1024];
for (int i = 0; i < 1024; i++) {
chunkExistence[i] = (chunkUncompressedSizes[i] > 0);
}
writeExistenceBitmap(dataOut, chunkExistence);
writeNBTFeatures(dataOut);
byte[][] buckets = buildBuckets();
int bucketCount = gridSize * gridSize;
for (int i = 0; i < bucketCount; i++) {
dataOut.writeInt(buckets[i] != null ? buckets[i].length : 0);
dataOut.writeByte(compressionLevel);
long bucketHash = buckets[i] != null ? LongHashFunction.xx().hashBytes(buckets[i]) : 0;
dataOut.writeLong(bucketHash);
}
for (int i = 0; i < bucketCount; i++) {
if (buckets[i] != null) {
dataOut.write(buckets[i]);
}
}
dataOut.writeLong(SUPERBLOCK);
dataOut.flush();
fos.getFD().sync();
fos.getChannel().force(true);
}
Files.move(tempFile.toPath(), regionFilePath, StandardCopyOption.REPLACE_EXISTING);
}
private void writeNBTFeatures(DataOutputStream dataOut) throws IOException {
dataOut.writeByte(0);
}
private byte[][] buildBuckets() throws IOException {
int bucketCount = gridSize * gridSize;
byte[][] buckets = new byte[bucketCount][];
for (int bx = 0; bx < gridSize; bx++) {
for (int bz = 0; bz < gridSize; bz++) {
int bucketIdx = bx * gridSize + bz;
if (bucketBuffers != null && bucketBuffers[bucketIdx] != null) {
buckets[bucketIdx] = bucketBuffers[bucketIdx];
continue;
}
try (ByteArrayOutputStream bucketBAOS = new ByteArrayOutputStream();
ZstdOutputStream bucketZstdOut = new ZstdOutputStream(bucketBAOS, compressionLevel);
DataOutputStream bucketDataOut = new DataOutputStream(bucketZstdOut)) {
boolean hasData = false;
int cellCount = 32 / gridSize;
for (int cx = 0; cx < cellCount; cx++) {
for (int cz = 0; cz < cellCount; cz++) {
int chunkIndex = (bx * cellCount + cx) + (bz * cellCount + cz) * 32;
if (chunkUncompressedSizes[chunkIndex] > 0) {
hasData = true;
byte[] chunkData = new byte[chunkUncompressedSizes[chunkIndex]];
decompressor.decompress(chunkCompressedBuffers[chunkIndex], 0, chunkData, 0, chunkUncompressedSizes[chunkIndex]);
bucketDataOut.writeInt(chunkData.length + 8);
bucketDataOut.writeLong(chunkTimestamps[chunkIndex]);
bucketDataOut.write(chunkData);
} else {
bucketDataOut.writeInt(0);
bucketDataOut.writeLong(chunkTimestamps[chunkIndex]);
}
}
}
bucketDataOut.close();
if (hasData) {
buckets[bucketIdx] = bucketBAOS.toByteArray();
}
}
}
}
return buckets;
}
private void openBucketForChunk(int chunkX, int chunkZ) {
int modX = Math.floorMod(chunkX, 32);
int modZ = Math.floorMod(chunkZ, 32);
int bucketIdx = chunkToBucketIndex(modX, modZ);
if (bucketBuffers == null || bucketBuffers[bucketIdx] == null) {
return;
}
try (ByteArrayInputStream bucketBAIS = new ByteArrayInputStream(bucketBuffers[bucketIdx]);
ZstdInputStream bucketZstdIn = new ZstdInputStream(bucketBAIS)) {
ByteBuffer bucketBuffer = ByteBuffer.wrap(bucketZstdIn.readAllBytes());
int cellsPerBucket = 32 / gridSize;
int bx = modX / bucketSize, bz = modZ / bucketSize;
for (int cx = 0; cx < cellsPerBucket; cx++) {
for (int cz = 0; cz < cellsPerBucket; cz++) {
int chunkIndex = (bx * cellsPerBucket + cx) + (bz * cellsPerBucket + cz) * 32;
int chunkSize = bucketBuffer.getInt();
long timestamp = bucketBuffer.getLong();
chunkTimestamps[chunkIndex] = timestamp;
if (chunkSize > 0) {
byte[] chunkData = new byte[chunkSize - 8];
bucketBuffer.get(chunkData);
int maxCompressedLength = compressor.maxCompressedLength(chunkData.length);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = compressor.compress(chunkData, 0, chunkData.length, compressed, 0, maxCompressedLength);
byte[] finalCompressed = new byte[compressedLength];
System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength);
chunkCompressedBuffers[chunkIndex] = finalCompressed;
chunkUncompressedSizes[chunkIndex] = chunkData.length;
}
}
}
} catch (IOException ex) {
throw new RuntimeException("Region file corrupted: " + regionFilePath + " bucket: " + bucketIdx, ex);
}
bucketBuffers[bucketIdx] = null;
}
@Override
public synchronized void write(ChunkPos pos, ByteBuffer buffer) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
try {
byte[] rawData = toByteArray(new ByteArrayInputStream(buffer.array()));
int uncompressedSize = rawData.length;
if (uncompressedSize > MAX_CHUNK_SIZE) {
LOGGER.error("Chunk dupe attempt {}", regionFilePath);
clear(pos);
} else {
int maxCompressedLength = compressor.maxCompressedLength(uncompressedSize);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = compressor.compress(rawData, 0, uncompressedSize, compressed, 0, maxCompressedLength);
byte[] finalCompressed = new byte[compressedLength];
System.arraycopy(compressed, 0, finalCompressed, 0, compressedLength);
int index = getChunkIndex(pos.x, pos.z);
chunkCompressedBuffers[index] = finalCompressed;
chunkTimestamps[index] = currentTimestamp();
chunkUncompressedSizes[index] = uncompressedSize;
}
} catch (IOException e) {
LOGGER.error("Chunk write IOException {} {}", e, regionFilePath);
}
markToSave();
}
@Override
public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos)));
}
@Override
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) {
DataOutputStream out = getChunkDataOutputStream(pos);
return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData(
data,
ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE,
out,
regionFile -> {
try {
out.close();
} catch (IOException e) {
LOGGER.error("Failed to close region file stream", e);
}
}
);
}
private class ChunkBuffer extends ByteArrayOutputStream {
private final ChunkPos pos;
public ChunkBuffer(ChunkPos pos) {
super();
this.pos = pos;
}
@Override
public void close() {
ByteBuffer byteBuffer = ByteBuffer.wrap(this.buf, 0, this.count);
LinearRegionFile.this.write(this.pos, byteBuffer);
}
}
private byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] tempBuffer = new byte[4096];
int length;
while ((length = in.read(tempBuffer)) >= 0) {
out.write(tempBuffer, 0, length);
}
return out.toByteArray();
}
@Nullable
@Override
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
int index = getChunkIndex(pos.x, pos.z);
if (chunkUncompressedSizes[index] != 0) {
byte[] decompressed = new byte[chunkUncompressedSizes[index]];
decompressor.decompress(chunkCompressedBuffers[index], 0, decompressed, 0, chunkUncompressedSizes[index]);
return new DataInputStream(new ByteArrayInputStream(decompressed));
}
return null;
}
@Override
public synchronized void clear(ChunkPos pos) {
openRegionFile();
openBucketForChunk(pos.x, pos.z);
int index = getChunkIndex(pos.x, pos.z);
chunkCompressedBuffers[index] = null;
chunkUncompressedSizes[index] = 0;
chunkTimestamps[index] = 0;
markToSave();
}
@Override
public synchronized void close() throws IOException {
openRegionFile();
close = true;
try {
flush();
} catch (IOException e) {
throw new IOException("Region flush IOException " + e + " " + regionFilePath, e);
}
}
private static int getChunkIndex(int x, int z) {
return (x & 31) + ((z & 31) << 5);
}
private static int currentTimestamp() {
return (int) (System.currentTimeMillis() / 1000L);
}
@Override
public boolean recalculateHeader() {
return false;
}
@Override
public void setOversized(int x, int z, boolean something) {
// stub
}
@Override
public CompoundTag getOversizedData(int x, int z) throws IOException {
throw new IOException("getOversizedData is a stub " + regionFilePath);
}
@Override
public boolean isOversized(int x, int z) {
return false;
}
@Override
public Path getPath() {
return regionFilePath;
}
private boolean[] deserializeExistenceBitmap(ByteBuffer buffer) {
boolean[] result = new boolean[1024];
for (int i = 0; i < 128; i++) {
byte b = buffer.get();
for (int j = 0; j < 8; j++) {
result[i * 8 + j] = ((b >> (7 - j)) & 1) == 1;
}
}
return result;
}
private void writeExistenceBitmap(DataOutputStream out, boolean[] bitmap) throws IOException {
for (int i = 0; i < 128; i++) {
byte b = 0;
for (int j = 0; j < 8; j++) {
if (bitmap[i * 8 + j]) {
b |= (1 << (7 - j));
}
}
out.writeByte(b);
}
}
private int chunkToBucketIndex(int chunkX, int chunkZ) {
int bx = chunkX / bucketSize, bz = chunkZ / bucketSize;
return bx * gridSize + bz;
}
private int[] parseRegionCoordinates(String fileName) {
int regionX = 0;
int regionZ = 0;
String[] parts = fileName.split("\\.");
if (parts.length >= 4) {
try {
regionX = Integer.parseInt(parts[1]);
regionZ = Integer.parseInt(parts[2]);
} catch (NumberFormatException e) {
LOGGER.error("Failed to parse region coordinates from file name: {}", fileName, e);
}
} else {
LOGGER.warn("Unexpected file name format: {}", fileName);
}
return new int[]{regionX, regionZ};
}
}

View File

@@ -1,4 +1,4 @@
package org.stupidcraft.linearpaper.region; package org.bxteam.divinemc.region;
import net.minecraft.world.level.chunk.storage.RegionFile; import net.minecraft.world.level.chunk.storage.RegionFile;
import net.minecraft.world.level.chunk.storage.RegionFileVersion; import net.minecraft.world.level.chunk.storage.RegionFileVersion;
@@ -10,34 +10,20 @@ import org.jetbrains.annotations.NotNull;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Path; import java.nio.file.Path;
public class IRegionFileFactory { public class RegionFileFactory {
@Contract("_, _, _, _ -> new") @Contract("_, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException {
return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync);
} }
@Contract("_, _, _, _, _ -> new") @Contract("_, _, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync, boolean canRecalcHeader) throws IOException { public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException {
return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync, canRecalcHeader);
}
@Contract("_, _, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException {
return getAbstractRegionFile(storageKey, path, directory, compressionFormat, dsync, true);
}
@Contract("_, _, _, _, _, _ -> new")
public static @NotNull IRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, boolean canRecalcHeader) throws IOException {
final String fullFileName = path.getFileName().toString(); final String fullFileName = path.getFileName().toString();
final String[] fullNameSplit = fullFileName.split("\\."); final String[] fullNameSplit = fullFileName.split("\\.");
final String extensionName = fullNameSplit[fullNameSplit.length - 1]; final String extensionName = fullNameSplit[fullNameSplit.length - 1];
switch (EnumRegionFileExtension.fromExtension(extensionName)) { switch (RegionFileFormat.fromExtension(extensionName)) {
case UNKNOWN -> {
return new RegionFile(storageKey, path, directory, compressionFormat, dsync);
}
case LINEAR -> { case LINEAR -> {
return new LinearRegionFile(path, DivineConfig.linearCompressionLevel); return new LinearRegionFile(path, DivineConfig.linearImplementation, DivineConfig.linearCompressionLevel);
} }
default -> { default -> {

View File

@@ -1,46 +1,46 @@
package org.stupidcraft.linearpaper.region; package org.bxteam.divinemc.region;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import java.util.Locale; import java.util.Locale;
public enum EnumRegionFileExtension { public enum RegionFileFormat {
LINEAR(".linear"), LINEAR(".linear"),
MCA(".mca"), ANVIL(".mca"),
UNKNOWN(null); UNKNOWN(null);
private final String extensionName; private final String extension;
EnumRegionFileExtension(String extensionName) { RegionFileFormat(String extension) {
this.extensionName = extensionName; this.extension = extension;
} }
public String getExtensionName() { public String getExtensionName() {
return this.extensionName; return this.extension;
} }
@Contract(pure = true) @Contract(pure = true)
public static EnumRegionFileExtension fromName(@NotNull String name) { public static RegionFileFormat fromName(@NotNull String name) {
switch (name.toUpperCase(Locale.ROOT)) { switch (name.toUpperCase(Locale.ROOT)) {
case "MCA" -> { case "MCA", "ANVIL" -> {
return MCA; return ANVIL;
} }
case "LINEAR" -> { case "LINEAR" -> {
return LINEAR; return LINEAR;
} }
default -> { default -> {
return UNKNOWN; throw new IllegalArgumentException("Unknown region file format: " + name);
} }
} }
} }
@Contract(pure = true) @Contract(pure = true)
public static EnumRegionFileExtension fromExtension(@NotNull String name) { public static RegionFileFormat fromExtension(@NotNull String name) {
switch (name.toLowerCase()) { switch (name.toLowerCase()) {
case "mca" -> { case "mca", "anvil" -> {
return MCA; return ANVIL;
} }
case "linear" -> { case "linear" -> {

View File

@@ -0,0 +1,32 @@
package org.bxteam.divinemc.server.chunk;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
import net.minecraft.server.level.ServerLevel;
import java.lang.invoke.VarHandle;
public class ChunkRunnable implements Runnable {
public final int chunkX;
public final int chunkZ;
public final ServerLevel world;
private volatile Runnable toRun;
private static final VarHandle TO_RUN_HANDLE = ConcurrentUtil.getVarHandle(ChunkRunnable.class, "toRun", Runnable.class);
public ChunkRunnable(int chunkX, int chunkZ, ServerLevel world, Runnable run) {
this.chunkX = chunkX;
this.chunkZ = chunkZ;
this.world = world;
this.toRun = run;
}
public void setRunnable(final Runnable run) {
final Runnable prev = (Runnable)TO_RUN_HANDLE.compareAndExchange(this, (Runnable)null, run);
if (prev != null) {
throw new IllegalStateException("Runnable already set");
}
}
@Override
public void run() {
((Runnable)TO_RUN_HANDLE.getVolatile(this)).run();
}
}

View File

@@ -0,0 +1,428 @@
package org.bxteam.divinemc.server.chunk;
import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.executor.RadiusAwarePrioritisedExecutor;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkUpgradeGenericStatusTask;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask;
import java.lang.invoke.VarHandle;
import java.util.Comparator;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
public final class ChunkSystemTaskQueue implements PrioritisedExecutor {
private final AtomicLong taskIdGenerator = new AtomicLong();
private final AtomicLong scheduledTasks = new AtomicLong();
private final AtomicLong executedTasks = new AtomicLong();
private final AtomicLong subOrderGenerator = new AtomicLong();
private final AtomicBoolean shutdown = new AtomicBoolean();
private final ConcurrentSkipListMap<ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder, Boolean> tasks = new ConcurrentSkipListMap<>(ChunkSystemTaskQueue.PrioritisedQueuedTask.COMPARATOR);
private final TheChunkSystem chunkSystem;
public ChunkSystemTaskQueue(TheChunkSystem chunkSystem) {
this.chunkSystem = chunkSystem;
}
@Override
public long getTotalTasksScheduled() {
return this.scheduledTasks.get();
}
@Override
public long getTotalTasksExecuted() {
return this.executedTasks.get();
}
@Override
public long generateNextSubOrder() {
return this.subOrderGenerator.getAndIncrement();
}
@Override
public boolean shutdown() {
return !this.shutdown.getAndSet(true);
}
@Override
public boolean isShutdown() {
return this.shutdown.get();
}
@Override
public boolean executeTask() {
for (; ; ) {
final Map.Entry<ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder, Boolean> firstEntry = this.tasks.pollFirstEntry();
if (firstEntry != null) {
final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder task = firstEntry.getKey();
task.markRemoved();
if (!task.task.execute()) {
continue;
}
return true;
}
return false;
}
}
@Override
public PrioritisedTask createTask(final Runnable task) {
return this.createTask(task, Priority.NORMAL, this.generateNextSubOrder());
}
@Override
public PrioritisedTask createTask(final Runnable task, final Priority priority) {
return this.createTask(task, priority, this.generateNextSubOrder());
}
@Override
public PrioritisedTask createTask(final Runnable task, final Priority priority, final long subOrder) {
return new ChunkSystemTaskQueue.PrioritisedQueuedTask(task, priority, subOrder);
}
@Override
public PrioritisedTask queueTask(final Runnable task) {
return this.queueTask(task, Priority.NORMAL, this.generateNextSubOrder());
}
@Override
public PrioritisedTask queueTask(final Runnable task, final Priority priority) {
return this.queueTask(task, priority, this.generateNextSubOrder());
}
@Override
public PrioritisedTask queueTask(final Runnable task, final Priority priority, final long subOrder) {
final ChunkSystemTaskQueue.PrioritisedQueuedTask ret = new ChunkSystemTaskQueue.PrioritisedQueuedTask(task, priority, subOrder);
ret.queue();
return ret;
}
private final class PrioritisedQueuedTask implements PrioritisedExecutor.PrioritisedTask {
public static final Comparator<ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder> COMPARATOR = (final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder t1, final ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder t2) -> {
final int priorityCompare = t1.priority - t2.priority;
if (priorityCompare != 0) {
return priorityCompare;
}
final int subOrderCompare = Long.compare(t1.subOrder, t2.subOrder);
if (subOrderCompare != 0) {
return subOrderCompare;
}
return Long.compare(t1.id, t2.id);
};
private final long id;
private final Runnable execute;
private Priority priority;
private long subOrder;
private ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder holder;
public PrioritisedQueuedTask(final Runnable execute, final Priority priority, final long subOrder) {
if (!Priority.isValidPriority(priority)) {
throw new IllegalArgumentException("Invalid priority " + priority);
}
this.execute = execute;
this.priority = priority;
this.subOrder = subOrder;
this.id = ChunkSystemTaskQueue.this.taskIdGenerator.getAndIncrement();
}
@Override
public PrioritisedExecutor getExecutor() {
return ChunkSystemTaskQueue.this;
}
@Override
public boolean queue() {
synchronized (this) {
if (this.holder != null || this.priority == Priority.COMPLETING) {
return false;
}
if (ChunkSystemTaskQueue.this.isShutdown()) {
throw new IllegalStateException("Queue is shutdown");
}
this.holder = new Holder(this, this.priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.scheduledTasks.getAndIncrement();
int priority = this.holder.task.priority.priority;
if (this.holder.task.priority.isHigherOrEqualPriority(Priority.BLOCKING)) {
priority = PriorityHandler.BLOCKING;
} else if (this.holder.task.execute instanceof ChunkUpgradeGenericStatusTask upgradeTask) {
int x = upgradeTask.chunkX;
int z = upgradeTask.chunkZ;
priority = upgradeTask.world.chunkSystemPriorities.priority(x, z);
} else if (this.holder.task.execute instanceof RadiusAwarePrioritisedExecutor.Task task) {
int x = task.chunkX;
int z = task.chunkZ;
if (!(x == 0 && z == 0)) {
priority = task.world.chunkSystemPriorities.priority(x, z);
} // else | infinite radius task, ignore.
} else if (this.holder.task.execute instanceof GenericDataLoadTask<?, ?>.ProcessOffMainTask offMainTask) {
int x = offMainTask.loadTask().chunkX;
int z = offMainTask.loadTask().chunkZ;
priority = offMainTask.loadTask().world.chunkSystemPriorities.priority(x, z);
} else if (this.holder.task.execute instanceof ChunkRunnable chunkRunnable) {
int x = chunkRunnable.chunkX;
int z = chunkRunnable.chunkZ;
priority = chunkRunnable.world.chunkSystemPriorities.priority(x, z);
}
ChunkSystemTaskQueue.this.chunkSystem.schedule(this.holder.task.execute, priority);
}
if (ChunkSystemTaskQueue.this.isShutdown()) {
this.cancel();
throw new IllegalStateException("Queue is shutdown");
}
return true;
}
@Override
public boolean isQueued() {
synchronized (this) {
return this.holder != null && this.priority != Priority.COMPLETING;
}
}
@Override
public boolean cancel() {
synchronized (this) {
if (this.priority == Priority.COMPLETING) {
return false;
}
this.priority = Priority.COMPLETING;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
ChunkSystemTaskQueue.this.executedTasks.getAndIncrement();
}
return true;
}
}
@Override
public boolean execute() {
final boolean increaseExecuted;
synchronized (this) {
if (this.priority == Priority.COMPLETING) {
return false;
}
this.priority = Priority.COMPLETING;
if (increaseExecuted = (this.holder != null)) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
}
}
try {
this.execute.run();
return true;
} finally {
if (increaseExecuted) {
ChunkSystemTaskQueue.this.executedTasks.getAndIncrement();
}
}
}
@Override
public Priority getPriority() {
synchronized (this) {
return this.priority;
}
}
@Override
public boolean setPriority(final Priority priority) {
synchronized (this) {
if (this.priority == Priority.COMPLETING || this.priority == priority) {
return false;
}
this.priority = priority;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE);
}
return true;
}
}
@Override
public boolean raisePriority(final Priority priority) {
synchronized (this) {
if (this.priority == Priority.COMPLETING || this.priority.isHigherOrEqualPriority(priority)) {
return false;
}
this.priority = priority;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE);
}
return true;
}
}
@Override
public boolean lowerPriority(Priority priority) {
synchronized (this) {
if (this.priority == Priority.COMPLETING || this.priority.isLowerOrEqualPriority(priority)) {
return false;
}
this.priority = priority;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE);
}
return true;
}
}
@Override
public long getSubOrder() {
synchronized (this) {
return this.subOrder;
}
}
@Override
public boolean setSubOrder(final long subOrder) {
synchronized (this) {
if (this.priority == Priority.COMPLETING || this.subOrder == subOrder) {
return false;
}
this.subOrder = subOrder;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE);
}
return true;
}
}
@Override
public boolean raiseSubOrder(long subOrder) {
synchronized (this) {
if (this.priority == Priority.COMPLETING || this.subOrder >= subOrder) {
return false;
}
this.subOrder = subOrder;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE);
}
return true;
}
}
@Override
public boolean lowerSubOrder(final long subOrder) {
synchronized (this) {
if (this.priority == Priority.COMPLETING || this.subOrder <= subOrder) {
return false;
}
this.subOrder = subOrder;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE);
}
return true;
}
}
@Override
public boolean setPriorityAndSubOrder(final Priority priority, final long subOrder) {
synchronized (this) {
if (this.priority == Priority.COMPLETING || (this.priority == priority && this.subOrder == subOrder)) {
return false;
}
this.priority = priority;
this.subOrder = subOrder;
if (this.holder != null) {
if (this.holder.markRemoved()) {
ChunkSystemTaskQueue.this.tasks.remove(this.holder);
}
this.holder = new ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder(this, priority.priority, this.subOrder, this.id);
ChunkSystemTaskQueue.this.tasks.put(this.holder, Boolean.TRUE);
}
return true;
}
}
private static final class Holder {
private static final VarHandle REMOVED_HANDLE = ConcurrentUtil.getVarHandle(ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder.class, "removed", boolean.class);
private final ChunkSystemTaskQueue.PrioritisedQueuedTask task;
private final int priority;
private final long subOrder;
private final long id;
private volatile boolean removed;
private Holder(
final ChunkSystemTaskQueue.PrioritisedQueuedTask task, final int priority, final long subOrder,
final long id
) {
this.task = task;
this.priority = priority;
this.subOrder = subOrder;
this.id = id;
}
public boolean markRemoved() {
return !(boolean) REMOVED_HANDLE.getAndSet((ChunkSystemTaskQueue.PrioritisedQueuedTask.Holder) this, (boolean) true);
}
}
}
}

View File

@@ -0,0 +1,32 @@
package org.bxteam.divinemc.server.chunk;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.level.ChunkPos;
import static ca.spottedleaf.moonrise.common.util.MoonriseConstants.MAX_VIEW_DISTANCE;
public class PriorityHandler {
public static final int MAX_PRIORITY = MAX_VIEW_DISTANCE + 2;
public static final int BLOCKING = 0;
public final ServerLevel level;
public PriorityHandler(ServerLevel world) {
this.level = world;
}
public int priority(int chunkX, int chunkZ) {
int priority = MAX_PRIORITY;
for (final ServerPlayer player : this.level.players()) {
ChunkPos playerChunk = player.chunkPosition();
int playerChunkX = playerChunk.x;
int playerChunkZ = playerChunk.z;
int dist = Math.max(Mth.abs(playerChunkX - chunkX), Mth.abs(playerChunkZ - chunkZ));
int distPriority = Math.max(0, MAX_VIEW_DISTANCE - dist);
priority = Math.min(priority, distPriority);
}
return priority;
}
}

View File

@@ -0,0 +1,355 @@
package org.bxteam.divinemc.server.chunk;
import ca.spottedleaf.concurrentutil.executor.PrioritisedExecutor;
import ca.spottedleaf.concurrentutil.util.Priority;
import com.ishland.flowsched.executor.ExecutorManager;
import org.bxteam.divinemc.util.ThreadBuilder;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicLong;
public class TheChunkSystem extends ExecutorManager {
protected final Logger LOGGER = LoggerFactory.getLogger("TheChunkSystem");
private final TheChunkSystem.COWArrayList<TheChunkSystem.ExecutorGroup> executors = new TheChunkSystem.COWArrayList<>(TheChunkSystem.ExecutorGroup.class);
private boolean shutdown;
public TheChunkSystem(final int workerThreadCount, final ThreadBuilder threadInitializer) {
super(workerThreadCount, threadInitializer);
LOGGER.info("Initialized new ChunkSystem with {} allocated threads", workerThreadCount);
}
@Override
public void shutdown() {
synchronized (this) {
this.shutdown = true;
}
super.shutdown();
this.wakeup();
for (final TheChunkSystem.ExecutorGroup group : this.executors.getArray()) {
for (final TheChunkSystem.ExecutorGroup.ThreadPoolExecutor executor : group.executors.getArray()) {
executor.shutdown();
}
}
LOGGER.info("ChunkSystem shutdown complete");
}
private void notifyAllThreads() {
this.wakeup();
}
public TheChunkSystem.ExecutorGroup createExecutorGroup() {
synchronized (this) {
if (this.shutdown) {
throw new IllegalStateException("Queue is shutdown: " + this);
}
final TheChunkSystem.ExecutorGroup ret = new TheChunkSystem.ExecutorGroup();
this.executors.add(ret);
return ret;
}
}
private static final class COWArrayList<E> {
private volatile E[] array;
public COWArrayList(final Class<E> clazz) {
this.array = (E[]) Array.newInstance(clazz, 0);
}
public E[] getArray() {
return this.array;
}
public void add(final E element) {
synchronized (this) {
final E[] array = this.array;
final E[] copy = Arrays.copyOf(array, array.length + 1);
copy[array.length] = element;
this.array = copy;
}
}
public boolean remove(final E element) {
synchronized (this) {
final E[] array = this.array;
int index = -1;
for (int i = 0, len = array.length; i < len; ++i) {
if (array[i] == element) {
index = i;
break;
}
}
if (index == -1) {
return false;
}
final E[] copy = (E[]) Array.newInstance(array.getClass().getComponentType(), array.length - 1);
System.arraycopy(array, 0, copy, 0, index);
System.arraycopy(array, index + 1, copy, index, (array.length - 1) - index);
this.array = copy;
}
return true;
}
}
public final class ExecutorGroup {
private final AtomicLong subOrderGenerator = new AtomicLong();
private final TheChunkSystem.COWArrayList<TheChunkSystem.ExecutorGroup.ThreadPoolExecutor> executors = new TheChunkSystem.COWArrayList<>(TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.class);
private ExecutorGroup() { }
public TheChunkSystem.ExecutorGroup.ThreadPoolExecutor[] getAllExecutors() {
return this.executors.getArray().clone();
}
private TheChunkSystem getThreadPool() {
return TheChunkSystem.this;
}
public TheChunkSystem.ExecutorGroup.@NotNull ThreadPoolExecutor createExecutor() {
synchronized (TheChunkSystem.this) {
if (TheChunkSystem.this.shutdown) {
throw new IllegalStateException("Queue is shutdown: " + TheChunkSystem.this);
}
final TheChunkSystem.ExecutorGroup.ThreadPoolExecutor ret = new TheChunkSystem.ExecutorGroup.ThreadPoolExecutor();
this.executors.add(ret);
return ret;
}
}
public final class ThreadPoolExecutor implements PrioritisedExecutor {
private final ChunkSystemTaskQueue taskBuilder = new ChunkSystemTaskQueue(TheChunkSystem.this);
private volatile boolean halt;
private ThreadPoolExecutor() { }
private TheChunkSystem.ExecutorGroup getGroup() {
return TheChunkSystem.ExecutorGroup.this;
}
private void notifyPriorityShift() {
TheChunkSystem.this.notifyAllThreads();
}
private void notifyScheduled() {
TheChunkSystem.this.notifyAllThreads();
}
/**
* Removes this queue from the thread pool without shutting the queue down or waiting for queued tasks to be executed
*/
public void halt() {
this.halt = true;
TheChunkSystem.ExecutorGroup.this.executors.remove(this);
}
public boolean isActive() {
if (this.halt) {
return false;
} else {
if (!this.isShutdown()) {
return true;
}
return !TheChunkSystem.this.globalWorkQueue.isEmpty();
}
}
@Override
public boolean shutdown() {
if (TheChunkSystem.this.globalWorkQueue.isEmpty()) {
TheChunkSystem.ExecutorGroup.this.executors.remove(this);
}
return true;
}
@Override
public boolean isShutdown() {
return TheChunkSystem.this.shutdown;
}
@Override
public long getTotalTasksScheduled() {
return 0; // TODO: implement
}
@Override
public long getTotalTasksExecuted() {
return 0; // TODO: implement
}
@Override
public long generateNextSubOrder() {
return TheChunkSystem.ExecutorGroup.this.subOrderGenerator.getAndIncrement();
}
@Override
public boolean executeTask() {
throw new UnsupportedOperationException("Unable to execute task from ThreadPoolExecutor as interface into FlowSched");
}
@Override
public PrioritisedTask queueTask(final Runnable task) {
final PrioritisedTask ret = this.createTask(task);
ret.queue();
return ret;
}
@Override
public PrioritisedTask queueTask(final Runnable task, final Priority priority) {
final PrioritisedTask ret = this.createTask(task, priority);
ret.queue();
return ret;
}
@Override
public PrioritisedTask queueTask(final Runnable task, final Priority priority, final long subOrder) {
final PrioritisedTask ret = this.createTask(task, priority, subOrder);
ret.queue();
return ret;
}
@Override
public PrioritisedTask createTask(final Runnable task) {
return this.createTask(task, Priority.NORMAL);
}
@Override
public PrioritisedTask createTask(final Runnable task, final Priority priority) {
return this.createTask(task, priority, this.generateNextSubOrder());
}
@Override
public PrioritisedTask createTask(final Runnable task, final Priority priority, final long subOrder) {
return new TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.WrappedTask(this.taskBuilder.createTask(task, priority, subOrder));
}
private final class WrappedTask implements PrioritisedTask {
private final PrioritisedTask wrapped;
private WrappedTask(final PrioritisedTask wrapped) {
this.wrapped = wrapped;
}
@Override
public PrioritisedExecutor getExecutor() {
return TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this;
}
@Override
public boolean queue() {
if (this.wrapped.queue()) {
final Priority priority = this.getPriority();
if (priority != Priority.COMPLETING) {
TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyScheduled();
}
return true;
}
return false;
}
@Override
public boolean isQueued() {
return this.wrapped.isQueued();
}
@Override
public boolean cancel() {
return this.wrapped.cancel();
}
@Override
public boolean execute() {
return this.wrapped.execute();
}
@Override
public Priority getPriority() {
return this.wrapped.getPriority();
}
@Override
public boolean setPriority(final Priority priority) {
if (this.wrapped.setPriority(priority)) {
TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift();
return true;
}
return false;
}
@Override
public boolean raisePriority(final Priority priority) {
if (this.wrapped.raisePriority(priority)) {
TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift();
return true;
}
return false;
}
@Override
public boolean lowerPriority(final Priority priority) {
return this.wrapped.lowerPriority(priority);
}
@Override
public long getSubOrder() {
return this.wrapped.getSubOrder();
}
@Override
public boolean setSubOrder(final long subOrder) {
return this.wrapped.setSubOrder(subOrder);
}
@Override
public boolean raiseSubOrder(final long subOrder) {
return this.wrapped.raiseSubOrder(subOrder);
}
@Override
public boolean lowerSubOrder(final long subOrder) {
return this.wrapped.lowerSubOrder(subOrder);
}
@Override
public boolean setPriorityAndSubOrder(final Priority priority, final long subOrder) {
if (this.wrapped.setPriorityAndSubOrder(priority, subOrder)) {
TheChunkSystem.ExecutorGroup.ThreadPoolExecutor.this.notifyPriorityShift();
return true;
}
return false;
}
}
}
}
}

View File

@@ -0,0 +1,744 @@
package org.bxteam.divinemc.util;
import it.unimi.dsi.fastutil.bytes.ByteIterator;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntCollection;
import it.unimi.dsi.fastutil.ints.IntIterator;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongListIterator;
import it.unimi.dsi.fastutil.objects.ObjectCollection;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import it.unimi.dsi.fastutil.objects.ReferenceSet;
import it.unimi.dsi.fastutil.shorts.ShortIterator;
import org.apache.commons.lang3.ArrayUtils;
import org.jetbrains.annotations.NotNull;
import java.util.Collection;
import java.util.Iterator;
import java.util.ListIterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
public final class CollectionWrapperUtil {
private CollectionWrapperUtil() {
throw new IllegalStateException("This class cannot be instantiated");
}
private static <T> Int2ObjectMap.@NotNull Entry<T> intEntryForwards(Map.Entry<Integer, T> entry) {
return new Int2ObjectMap.Entry<>() {
@Override
public T getValue() {
return entry.getValue();
}
@Override
public T setValue(T value) {
return entry.setValue(value);
}
@Override
public int getIntKey() {
return entry.getKey();
}
@Override
public boolean equals(Object obj) {
if (obj == entry) {
return true;
}
return super.equals(obj);
}
@Override
public int hashCode() {
return entry.hashCode();
}
};
}
private static <T> Map.Entry<Integer, T> intEntryBackwards(Int2ObjectMap.Entry<T> entry) {
return entry;
}
public static <T> ObjectSet<Int2ObjectMap.Entry<T>> entrySetIntWrap(Map<Integer, T> map) {
return new ConvertingObjectSet<>(
map.entrySet(),
CollectionWrapperUtil::intEntryForwards,
CollectionWrapperUtil::intEntryBackwards
);
}
public static IntSet wrapIntSet(Set<Integer> intset) {
return new WrappingIntSet(intset);
}
public static ByteIterator itrByteWrap(Iterator<Byte> backing) {
return new WrappingByteIterator(backing);
}
public static ByteIterator itrByteWrap(Iterable<Byte> backing) {
return itrByteWrap(backing.iterator());
}
public static IntIterator itrIntWrap(Iterator<Integer> backing) {
return new WrappingIntIterator(backing);
}
public static IntIterator itrIntWrap(Iterable<Integer> backing) {
return itrIntWrap(backing.iterator());
}
public static LongIterator itrLongWrap(Iterator<Long> backing) {
return new WrappingLongIterator(backing);
}
public static LongIterator itrLongWrap(Iterable<Long> backing) {
return itrLongWrap(backing.iterator());
}
public static ShortIterator itrShortWrap(Iterator<Short> backing) {
return new WrappingShortIterator(backing);
}
public static ShortIterator itrShortWrap(Iterable<Short> backing) {
return itrShortWrap(backing.iterator());
}
public static LongListIterator wrap(ListIterator<Long> c) {
return new WrappingLongListIterator(c);
}
public static LongListIterator wrap(Iterator<Long> c) {
return new SlimWrappingLongListIterator(c);
}
public static <K> ObjectCollection<K> wrap(Collection<K> c) {
return new WrappingObjectCollection<>(c);
}
public static <K> ReferenceSet<K> wrap(Set<K> s) {
return new WrappingRefSet<>(s);
}
public static <T> ObjectIterator<T> itrWrap(Iterable<T> in) {
return new WrapperObjectIterator<>(in.iterator());
}
public static class ConvertingObjectSet<E, T> implements ObjectSet<T> {
private final Set<E> backing;
private final Function<E, T> forward;
private final Function<T, E> back;
public ConvertingObjectSet(Set<E> backing, Function<E, T> forward, Function<T, E> back) {
this.backing = Objects.requireNonNull(backing, "Backing set cannot be null");
this.forward = Objects.requireNonNull(forward, "Forward function cannot be null");
this.back = Objects.requireNonNull(back, "Backward function cannot be null");
}
@Override
public int size() {
return backing.size();
}
@Override
public boolean isEmpty() {
return backing.isEmpty();
}
@SuppressWarnings("unchecked")
@Override
public boolean contains(Object o) {
try {
return backing.contains(back.apply((T) o));
} catch (ClassCastException cce) {
return false;
}
}
@Override
public Object[] toArray() {
return backing.stream().map(forward).toArray();
}
@Override
public <R> R[] toArray(R[] a) {
return backing.stream().map(forward).collect(Collectors.toSet()).toArray(a);
}
@Override
public boolean add(T e) {
return backing.add(back.apply(e));
}
@SuppressWarnings("unchecked")
@Override
public boolean remove(Object o) {
try {
return backing.remove(back.apply((T) o));
} catch (ClassCastException cce) {
return false;
}
}
@SuppressWarnings("unchecked")
@Override
public boolean containsAll(Collection<?> c) {
try {
return backing.containsAll(c.stream()
.map(i -> back.apply((T) i))
.collect(Collectors.toSet()));
} catch (ClassCastException cce) {
return false;
}
}
@Override
public boolean addAll(Collection<? extends T> c) {
return backing.addAll(c.stream().map(back).collect(Collectors.toSet()));
}
@SuppressWarnings("unchecked")
@Override
public boolean removeAll(Collection<?> c) {
try {
return backing.removeAll(c.stream()
.map(i -> back.apply((T) i))
.collect(Collectors.toSet()));
} catch (ClassCastException cce) {
return false;
}
}
@SuppressWarnings("unchecked")
@Override
public boolean retainAll(Collection<?> c) {
try {
return backing.retainAll(c.stream()
.map(i -> back.apply((T) i))
.collect(Collectors.toSet()));
} catch (ClassCastException cce) {
return false;
}
}
@Override
public void clear() {
backing.clear();
}
@Override
public ObjectIterator<T> iterator() {
return new ObjectIterator<>() {
private final Iterator<E> backg = backing.iterator();
@Override
public boolean hasNext() {
return backg.hasNext();
}
@Override
public T next() {
return forward.apply(backg.next());
}
@Override
public void remove() {
backg.remove();
}
};
}
}
static class WrappingIntIterator implements IntIterator {
private final Iterator<Integer> backing;
WrappingIntIterator(Iterator<Integer> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public boolean hasNext() {
return backing.hasNext();
}
@Override
public int nextInt() {
return backing.next();
}
@Override
public Integer next() {
return backing.next();
}
@Override
public void remove() {
backing.remove();
}
}
static class WrappingLongIterator implements LongIterator {
private final Iterator<Long> backing;
WrappingLongIterator(Iterator<Long> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public boolean hasNext() {
return backing.hasNext();
}
@Override
public long nextLong() {
return backing.next();
}
@Override
public Long next() {
return backing.next();
}
@Override
public void remove() {
backing.remove();
}
}
static class WrappingShortIterator implements ShortIterator {
private final Iterator<Short> backing;
WrappingShortIterator(Iterator<Short> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public boolean hasNext() {
return backing.hasNext();
}
@Override
public short nextShort() {
return backing.next();
}
@Override
public Short next() {
return backing.next();
}
@Override
public void remove() {
backing.remove();
}
}
static class WrappingByteIterator implements ByteIterator {
private final Iterator<Byte> backing;
WrappingByteIterator(Iterator<Byte> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public boolean hasNext() {
return backing.hasNext();
}
@Override
public byte nextByte() {
return next();
}
@Override
public Byte next() {
return backing.next();
}
@Override
public void remove() {
backing.remove();
}
}
public static class WrappingIntSet implements IntSet {
private final Set<Integer> backing;
public WrappingIntSet(Set<Integer> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public boolean add(int key) {
return backing.add(key);
}
@Override
public boolean contains(int key) {
return backing.contains(key);
}
@Override
public int[] toIntArray() {
return backing.stream().mapToInt(Integer::intValue).toArray();
}
@Override
public int[] toArray(int[] a) {
return ArrayUtils.toPrimitive(backing.toArray(new Integer[0]));
}
@Override
public boolean addAll(IntCollection c) {
return backing.addAll(c);
}
@Override
public boolean containsAll(IntCollection c) {
return backing.containsAll(c);
}
@Override
public boolean removeAll(IntCollection c) {
return backing.removeAll(c);
}
@Override
public boolean retainAll(IntCollection c) {
return backing.retainAll(c);
}
@Override
public int size() {
return backing.size();
}
@Override
public boolean isEmpty() {
return backing.isEmpty();
}
@Override
public Object[] toArray() {
return backing.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return backing.toArray(a);
}
@Override
public boolean containsAll(Collection<?> c) {
return backing.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends Integer> c) {
return backing.addAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return backing.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return backing.retainAll(c);
}
@Override
public void clear() {
backing.clear();
}
@Override
public IntIterator iterator() {
return new WrappingIntIterator(backing.iterator());
}
@Override
public boolean remove(int k) {
return backing.remove(k);
}
}
public static class WrappingRefSet<V> implements ReferenceSet<V> {
private final Set<V> backing;
public WrappingRefSet(Set<V> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public boolean add(V key) {
return backing.add(key);
}
@Override
public boolean remove(final Object o) {
return backing.remove(o);
}
@Override
public boolean containsAll(@NotNull final Collection<?> c) {
return backing.containsAll(c);
}
@Override
public boolean addAll(@NotNull final Collection<? extends V> c) {
return backing.addAll(c);
}
@Override
public boolean removeAll(@NotNull final Collection<?> c) {
return backing.removeAll(c);
}
@Override
public boolean retainAll(@NotNull final Collection<?> c) {
return backing.retainAll(c);
}
@Override
public void clear() {
this.backing.clear();
}
@Override
public int size() {
return backing.size();
}
@Override
public boolean isEmpty() {
return backing.isEmpty();
}
@Override
public boolean contains(final Object o) {
return backing.contains(o);
}
@Override
public ObjectIterator<V> iterator() {
return null;
}
@Override
public @NotNull Object[] toArray() {
return this.backing.toArray();
}
@Override
public @NotNull <T> T[] toArray(@NotNull final T[] a) {
return this.backing.toArray(a);
}
}
public static class WrappingLongListIterator implements LongListIterator {
private final ListIterator<Long> backing;
WrappingLongListIterator(ListIterator<Long> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public long previousLong() {
return backing.previous();
}
@Override
public long nextLong() {
return backing.next();
}
@Override
public boolean hasNext() {
return backing.hasNext();
}
@Override
public boolean hasPrevious() {
return backing.hasPrevious();
}
@Override
public int nextIndex() {
return backing.nextIndex();
}
@Override
public int previousIndex() {
return backing.previousIndex();
}
@Override
public void add(long k) {
backing.add(k);
}
@Override
public void remove() {
backing.remove();
}
@Override
public void set(long k) {
backing.set(k);
}
}
public static class SlimWrappingLongListIterator implements LongListIterator {
private final Iterator<Long> backing;
SlimWrappingLongListIterator(Iterator<Long> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public long previousLong() {
throw new UnsupportedOperationException();
}
@Override
public long nextLong() {
return backing.next();
}
@Override
public boolean hasNext() {
return backing.hasNext();
}
@Override
public boolean hasPrevious() {
throw new UnsupportedOperationException();
}
@Override
public int nextIndex() {
throw new UnsupportedOperationException();
}
@Override
public int previousIndex() {
throw new UnsupportedOperationException();
}
@Override
public void add(long k) {
throw new UnsupportedOperationException();
}
@Override
public void remove() {
backing.remove();
}
@Override
public void set(long k) {
throw new UnsupportedOperationException();
}
}
public static class WrappingObjectCollection<V> implements ObjectCollection<V> {
private final Collection<V> backing;
public WrappingObjectCollection(Collection<V> backing) {
this.backing = Objects.requireNonNull(backing);
}
@Override
public int size() {
return backing.size();
}
@Override
public boolean isEmpty() {
return backing.isEmpty();
}
@Override
public boolean contains(Object o) {
return backing.contains(o);
}
@Override
public Object[] toArray() {
return backing.toArray();
}
@Override
public <T> T[] toArray(T[] a) {
return backing.toArray(a);
}
@Override
public boolean add(V e) {
return backing.add(e);
}
@Override
public boolean remove(Object o) {
return backing.remove(o);
}
@Override
public boolean containsAll(Collection<?> c) {
return backing.containsAll(c);
}
@Override
public boolean addAll(Collection<? extends V> c) {
return backing.addAll(c);
}
@Override
public boolean removeAll(Collection<?> c) {
return backing.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c) {
return backing.retainAll(c);
}
@Override
public void clear() {
backing.clear();
}
@Override
public ObjectIterator<V> iterator() {
return itrWrap(backing);
}
}
private record WrapperObjectIterator<T>(Iterator<T> parent) implements ObjectIterator<T> {
private WrapperObjectIterator(Iterator<T> parent) {
this.parent = Objects.requireNonNull(parent);
}
@Override
public boolean hasNext() {
return parent.hasNext();
}
@Override
public T next() {
return parent.next();
}
@Override
public void remove() {
parent.remove();
}
}
}

View File

@@ -0,0 +1,64 @@
package org.bxteam.divinemc.util;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import net.minecraft.world.level.levelgen.structure.structures.WoodlandMansionPieces;
public class ConcurrentFlagMatrix extends WoodlandMansionPieces.SimpleGrid {
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
public ConcurrentFlagMatrix(int rows, int columns, int fallbackValue) {
super(rows, columns, fallbackValue);
}
public void set(int row, int column, int value) {
this.readWriteLock.writeLock().lock();
try {
super.set(row, column, value);
} finally {
this.readWriteLock.writeLock().unlock();
}
}
public void set(int startRow, int startColumn, int endRow, int endColumn, int value) {
this.readWriteLock.writeLock().lock();
try {
super.set(startRow, startColumn, endRow, endColumn, value);
} finally {
this.readWriteLock.writeLock().unlock();
}
}
public int get(int row, int column) {
this.readWriteLock.readLock().lock();
int result;
try {
result = super.get(row, column);
} finally {
this.readWriteLock.readLock().unlock();
}
return result;
}
public void setIf(int row, int column, int expectedValue, int newValue) {
if (this.get(row, column) == expectedValue) {
this.set(row, column, newValue);
}
}
public boolean edgesTo(int row, int column, int value) {
this.readWriteLock.readLock().lock();
boolean result;
try {
result = super.edgesTo(row, column, value);
} finally {
this.readWriteLock.readLock().unlock();
}
return result;
}
}

View File

@@ -1,35 +0,0 @@
package org.bxteam.divinemc.util;
import java.io.File;
import java.io.IOException;
public final class Files {
public static void deleteRecursively(File dir) throws IOException {
if (dir == null || !dir.isDirectory()) {
return;
}
try {
File[] files = dir.listFiles();
if (files == null) {
throw new IOException("Error enumerating directory during recursive delete operation: " + dir.getAbsolutePath());
}
for (File child : files) {
if (child.isDirectory()) {
Files.deleteRecursively(child);
} else if (child.isFile()) {
if (!child.delete()) {
throw new IOException("Error deleting file during recursive delete operation: " + child.getAbsolutePath());
}
}
}
if (!dir.delete()) {
throw new IOException("Error deleting directory during recursive delete operation: " + dir.getAbsolutePath());
}
} catch (SecurityException ex) {
throw new IOException("Security error during recursive delete operation", ex);
}
}
}

View File

@@ -1,12 +0,0 @@
package org.bxteam.divinemc.util;
public final class MemoryUtil {
public static int[] byte2int(byte[] data) {
if (data == null) return null;
int[] ints = new int[data.length];
for (int i = 0; i < data.length; i++) {
ints[i] = data[i] & 0xff;
}
return ints;
}
}

View File

@@ -0,0 +1,7 @@
package org.bxteam.divinemc.util;
public enum PWTTeleportState {
INACTIVE,
PENDING,
CANCELLED
}

View File

@@ -0,0 +1,40 @@
package org.bxteam.divinemc.util;
import com.mojang.datafixers.util.Pair;
import com.mojang.serialization.Codec;
import com.mojang.serialization.DataResult;
import com.mojang.serialization.DynamicOps;
import java.util.concurrent.locks.ReentrantLock;
public class SynchronizedCodec<A> implements Codec<A> {
private final ReentrantLock lock = new ReentrantLock(false);
private final Codec<A> delegate;
public SynchronizedCodec(Codec<A> delegate) {
this.delegate = delegate;
}
@Override
public <T> DataResult<Pair<A, T>> decode(DynamicOps<T> ops, T input) {
try {
lock.lockInterruptibly();
return this.delegate.decode(ops, input);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
if (lock.isHeldByCurrentThread()) lock.unlock();
}
}
@Override
public <T> DataResult<T> encode(A input, DynamicOps<T> ops, T prefix) {
try {
lock.lockInterruptibly();
return this.delegate.encode(input, ops, prefix);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
if (lock.isHeldByCurrentThread()) lock.unlock();
}
}
}

View File

@@ -0,0 +1,12 @@
package org.bxteam.divinemc.util;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Consumer;
public interface ThreadBuilder extends Consumer<Thread> {
AtomicInteger id = new AtomicInteger();
default int getAndIncrementId() {
return id.getAndIncrement();
}
}

View File

@@ -0,0 +1,160 @@
package org.bxteam.divinemc.util.map;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.IntSet;
import it.unimi.dsi.fastutil.objects.ObjectCollection;
import it.unimi.dsi.fastutil.objects.ObjectSet;
import org.bxteam.divinemc.util.CollectionWrapperUtil;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
public final class Int2ObjectConcurrentHashMap<V> implements Int2ObjectMap<V> {
private final ConcurrentHashMap<Integer, V> backing;
private V defaultReturnValue;
public Int2ObjectConcurrentHashMap() {
this(16);
}
public Int2ObjectConcurrentHashMap(int initialCapacity) {
if (initialCapacity < 0) {
throw new IllegalArgumentException("Initial capacity cannot be negative: " + initialCapacity);
}
this.backing = new ConcurrentHashMap<>(initialCapacity);
}
public Int2ObjectConcurrentHashMap(Map<Integer, V> map) {
this(Math.max(16, map.size()));
putAll(Objects.requireNonNull(map, "Source map cannot be null"));
}
@Override
public V get(int key) {
V value = backing.get(key);
return value != null ? value : defaultReturnValue;
}
@Override
public V get(Object key) {
V value = backing.get(key);
return value != null ? value : defaultReturnValue;
}
@Override
public boolean isEmpty() {
return backing.isEmpty();
}
@Override
public boolean containsValue(Object value) {
return backing.containsValue(value);
}
@Override
public void putAll(Map<? extends Integer, ? extends V> m) {
Objects.requireNonNull(m, "Source map cannot be null");
backing.putAll(m);
}
@Override
public int size() {
return backing.size();
}
@Override
public void defaultReturnValue(V rv) {
this.defaultReturnValue = rv;
}
@Override
public V defaultReturnValue() {
return defaultReturnValue;
}
@Override
public ObjectSet<Entry<V>> int2ObjectEntrySet() {
return CollectionWrapperUtil.entrySetIntWrap(backing);
}
@Override
public IntSet keySet() {
return CollectionWrapperUtil.wrapIntSet(backing.keySet());
}
@Override
public ObjectCollection<V> values() {
return CollectionWrapperUtil.wrap(backing.values());
}
@Override
public boolean containsKey(int key) {
return backing.containsKey(key);
}
@Override
public V put(int key, V value) {
return backing.put(key, value);
}
@Override
public V remove(int key) {
return backing.remove(key);
}
@Override
public void clear() {
backing.clear();
}
public V compute(int key, java.util.function.BiFunction<? super Integer, ? super V, ? extends V> remappingFunction) {
Objects.requireNonNull(remappingFunction);
return backing.compute(key, remappingFunction);
}
public ConcurrentHashMap<Integer, V> concurrentView() {
return backing;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Int2ObjectMap<?> that)) return false;
if (size() != that.size()) return false;
return int2ObjectEntrySet().containsAll(that.int2ObjectEntrySet());
}
@Override
public int hashCode() {
return backing.hashCode();
}
@Override
public String toString() {
return backing.toString();
}
public V getOrDefault(int key, V defaultValue) {
V value = get(key);
return value != null ? value : defaultValue;
}
public V putIfAbsent(int key, V value) {
return backing.putIfAbsent(key, value);
}
public boolean remove(int key, Object value) {
return backing.remove(key, value);
}
public boolean replace(int key, V oldValue, V newValue) {
return backing.replace(key, oldValue, newValue);
}
public V replace(int key, V value) {
return backing.replace(key, value);
}
}

View File

@@ -1,308 +0,0 @@
package org.stupidcraft.linearpaper.region;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import com.github.luben.zstd.ZstdInputStream;
import com.github.luben.zstd.ZstdOutputStream;
import com.mojang.logging.LogUtils;
import net.jpountz.lz4.LZ4Compressor;
import net.jpountz.lz4.LZ4Factory;
import net.jpountz.lz4.LZ4FastDecompressor;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.ChunkPos;
import org.bxteam.divinemc.DivineConfig;
import org.slf4j.Logger;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;
public class LinearRegionFile implements IRegionFile {
private static final long SUPERBLOCK = -4323716122432332390L;
private static final byte VERSION = 2;
private static final int HEADER_SIZE = 32;
private static final int FOOTER_SIZE = 8;
private static final Logger LOGGER = LogUtils.getLogger();
private static final List<Byte> SUPPORTED_VERSIONS = Arrays.asList((byte) 1, (byte) 2);
private final byte[][] buffer = new byte[1024][];
private final int[] bufferUncompressedSize = new int[1024];
private final int[] chunkTimestamps = new int[1024];
private final LZ4Compressor compressor;
private final LZ4FastDecompressor decompressor;
private final int compressionLevel;
public boolean closed = false;
public Path path;
private volatile long lastFlushed = System.nanoTime();
public LinearRegionFile(Path file, int compression) throws IOException {
this.path = file;
this.compressionLevel = compression;
this.compressor = LZ4Factory.fastestInstance().fastCompressor();
this.decompressor = LZ4Factory.fastestInstance().fastDecompressor();
File regionFile = new File(this.path.toString());
Arrays.fill(this.bufferUncompressedSize, 0);
if (!regionFile.canRead()) return;
try (FileInputStream fileStream = new FileInputStream(regionFile);
DataInputStream rawDataStream = new DataInputStream(fileStream)) {
long superBlock = rawDataStream.readLong();
if (superBlock != SUPERBLOCK)
throw new RuntimeException("Invalid superblock: " + superBlock + " in " + file);
byte version = rawDataStream.readByte();
if (!SUPPORTED_VERSIONS.contains(version))
throw new RuntimeException("Invalid version: " + version + " in " + file);
rawDataStream.skipBytes(11);
int dataCount = rawDataStream.readInt();
long fileLength = file.toFile().length();
if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE)
throw new IOException("Invalid file length: " + this.path + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE));
rawDataStream.skipBytes(8);
byte[] rawCompressed = new byte[dataCount];
rawDataStream.readFully(rawCompressed, 0, dataCount);
superBlock = rawDataStream.readLong();
if (superBlock != SUPERBLOCK)
throw new IOException("Footer superblock invalid " + this.path);
try (DataInputStream dataStream = new DataInputStream(new ZstdInputStream(new ByteArrayInputStream(rawCompressed)))) {
int[] starts = new int[1024];
for (int i = 0; i < 1024; i++) {
starts[i] = dataStream.readInt();
dataStream.skipBytes(4);
}
for (int i = 0; i < 1024; i++) {
if (starts[i] > 0) {
int size = starts[i];
byte[] b = new byte[size];
dataStream.readFully(b, 0, size);
int maxCompressedLength = this.compressor.maxCompressedLength(size);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = this.compressor.compress(b, 0, size, compressed, 0, maxCompressedLength);
b = new byte[compressedLength];
System.arraycopy(compressed, 0, b, 0, compressedLength);
this.buffer[i] = b;
this.bufferUncompressedSize[i] = size;
}
}
}
}
}
private static int getChunkIndex(int x, int z) {
return (x & 31) + ((z & 31) << 5);
}
private static int getTimestamp() {
return (int) (System.currentTimeMillis() / 1000L);
}
public void flush() throws IOException {
flushWrapper();
}
public void flushWrapper() {
try {
save();
} catch (IOException e) {
LOGGER.error("Failed to flush region file {}", path.toAbsolutePath(), e);
}
}
public boolean doesChunkExist(ChunkPos pos) throws Exception {
throw new Exception("doesChunkExist is a stub");
}
private synchronized void save() throws IOException {
long timestamp = getTimestamp();
short chunkCount = 0;
File tempFile = new File(path.toString() + ".tmp");
try (FileOutputStream fileStream = new FileOutputStream(tempFile);
ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream();
ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, this.compressionLevel);
DataOutputStream zstdDataStream = new DataOutputStream(zstdStream);
DataOutputStream dataStream = new DataOutputStream(fileStream)) {
dataStream.writeLong(SUPERBLOCK);
dataStream.writeByte(VERSION);
dataStream.writeLong(timestamp);
dataStream.writeByte(this.compressionLevel);
ArrayList<byte[]> byteBuffers = new ArrayList<>();
for (int i = 0; i < 1024; i++) {
if (this.bufferUncompressedSize[i] != 0) {
chunkCount += 1;
byte[] content = new byte[bufferUncompressedSize[i]];
this.decompressor.decompress(buffer[i], 0, content, 0, bufferUncompressedSize[i]);
byteBuffers.add(content);
} else byteBuffers.add(null);
}
for (int i = 0; i < 1024; i++) {
zstdDataStream.writeInt(this.bufferUncompressedSize[i]);
zstdDataStream.writeInt(this.chunkTimestamps[i]);
}
for (int i = 0; i < 1024; i++) {
if (byteBuffers.get(i) != null)
zstdDataStream.write(byteBuffers.get(i), 0, byteBuffers.get(i).length);
}
zstdDataStream.close();
dataStream.writeShort(chunkCount);
byte[] compressed = zstdByteArray.toByteArray();
dataStream.writeInt(compressed.length);
dataStream.writeLong(0);
dataStream.write(compressed, 0, compressed.length);
dataStream.writeLong(SUPERBLOCK);
dataStream.flush();
fileStream.getFD().sync();
fileStream.getChannel().force(true);
}
Files.move(tempFile.toPath(), this.path, StandardCopyOption.REPLACE_EXISTING);
this.lastFlushed = System.nanoTime();
}
public synchronized void write(ChunkPos pos, ByteBuffer buffer) {
try {
byte[] b = toByteArray(new ByteArrayInputStream(buffer.array()));
int uncompressedSize = b.length;
int maxCompressedLength = this.compressor.maxCompressedLength(b.length);
byte[] compressed = new byte[maxCompressedLength];
int compressedLength = this.compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength);
b = new byte[compressedLength];
System.arraycopy(compressed, 0, b, 0, compressedLength);
int index = getChunkIndex(pos.x, pos.z);
this.buffer[index] = b;
this.chunkTimestamps[index] = getTimestamp();
this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize;
} catch (IOException e) {
LOGGER.error("Chunk write IOException {} {}", e, this.path);
}
if ((System.nanoTime() - this.lastFlushed) >= TimeUnit.NANOSECONDS.toSeconds(DivineConfig.linearFlushFrequency)) {
this.flushWrapper();
}
}
public DataOutputStream getChunkDataOutputStream(ChunkPos pos) {
return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos)));
}
@Override
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) {
final DataOutputStream out = this.getChunkDataOutputStream(pos);
return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData(
data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE,
out, regionFile -> out.close()
);
}
private byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] tempBuffer = new byte[4096];
int length;
while ((length = in.read(tempBuffer)) >= 0) {
out.write(tempBuffer, 0, length);
}
return out.toByteArray();
}
@Nullable
public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) {
if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) {
byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]];
this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]);
return new DataInputStream(new ByteArrayInputStream(content));
}
return null;
}
public void clear(ChunkPos pos) {
int i = getChunkIndex(pos.x, pos.z);
this.buffer[i] = null;
this.bufferUncompressedSize[i] = 0;
this.chunkTimestamps[i] = getTimestamp();
this.flushWrapper();
}
public Path getPath() {
return this.path;
}
public boolean hasChunk(ChunkPos pos) {
return this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] > 0;
}
public void close() throws IOException {
if (closed) return;
closed = true;
flush();
}
public boolean recalculateHeader() {
return false;
}
public void setOversized(int x, int z, boolean something) {
}
public CompoundTag getOversizedData(int x, int z) throws IOException {
throw new IOException("getOversizedData is a stub " + this.path);
}
public boolean isOversized(int x, int z) {
return false;
}
private class ChunkBuffer extends ByteArrayOutputStream {
private final ChunkPos pos;
public ChunkBuffer(ChunkPos chunkcoordintpair) {
super();
this.pos = chunkcoordintpair;
}
public void close() {
ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count);
LinearRegionFile.this.write(this.pos, bytebuffer);
}
}
}

View File

@@ -2,7 +2,7 @@ group = org.bxteam.divinemc
version=1.21.5-R0.1-SNAPSHOT version=1.21.5-R0.1-SNAPSHOT
mcVersion=1.21.5 mcVersion=1.21.5
purpurRef=f1e732aa3a02167f8eef3ba5c440000453e175d1 purpurRef=bdeba761ac3db3184ab23a0b7badfa963ea1ce2e
experimental=true experimental=true
org.gradle.configuration-cache=true org.gradle.configuration-cache=true