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:
47
.github/workflows/upstream.yml
vendored
47
.github/workflows/upstream.yml
vendored
@@ -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
|
|
||||||
@@ -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
|
||||||
[](https://bstats.org/plugin/server-implementation/DivineMC)
|
[](https://bstats.org/plugin/server-implementation/DivineMC)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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())) {
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -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() {
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
}
|
|
||||||
@@ -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
|
||||||
@@ -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) {
|
||||||
@@ -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 {
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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) {
|
||||||
@@ -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 {
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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 {
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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) {
|
||||||
@@ -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)
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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 {
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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(
|
|
||||||
@@ -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) {
|
||||||
@@ -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
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
@@ -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() {}
|
|
||||||
|
|
||||||
@@ -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;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package com.ishland.flowsched.executor;
|
||||||
|
|
||||||
|
public interface LockToken { }
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package com.ishland.flowsched.executor;
|
||||||
|
|
||||||
|
public interface Task {
|
||||||
|
void run(Runnable releaseLocks);
|
||||||
|
|
||||||
|
void propagateException(Throwable t);
|
||||||
|
|
||||||
|
LockToken[] lockTokens();
|
||||||
|
|
||||||
|
int priority();
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
package org.bxteam.divinemc.region;
|
||||||
|
|
||||||
|
public enum LinearImplementation {
|
||||||
|
V1,
|
||||||
|
V2
|
||||||
|
}
|
||||||
@@ -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};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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 -> {
|
||||||
@@ -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" -> {
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package org.bxteam.divinemc.util;
|
||||||
|
|
||||||
|
public enum PWTTeleportState {
|
||||||
|
INACTIVE,
|
||||||
|
PENDING,
|
||||||
|
CANCELLED
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user