mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
apply first basic patches
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
+val bxTeamMavenPublicUrl = "https://repo.bxteam.org/snapshots/"
|
||||
|
||||
dependencies {
|
||||
mache("io.papermc:mache:1.21.8+build.2")
|
||||
mache("io.papermc:mache:1.21.10+build.1")
|
||||
@@ -29,6 +_,7 @@
|
||||
|
||||
// Purpur start - Rebrand
|
||||
@@ -44,7 +44,7 @@
|
||||
+
|
||||
spigot {
|
||||
enabled = true
|
||||
buildDataRef = "436eac9815c211be1a2a6ca0702615f995e81c44"
|
||||
buildDataRef = "42d18d4c4653ffc549778dbe223f6994a031d69e"
|
||||
@@ -62,6 +_,7 @@
|
||||
libraryRepositories.addAll(
|
||||
"https://repo.maven.apache.org/maven2/",
|
||||
@@ -72,7 +72,7 @@
|
||||
}
|
||||
}
|
||||
val log4jPlugins = sourceSets.create("log4jPlugins") {
|
||||
@@ -156,10 +_,22 @@
|
||||
@@ -157,10 +_,22 @@
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@@ -90,14 +90,14 @@
|
||||
+ implementation("org.agrona:agrona:2.2.4")
|
||||
+ // DivineMC end - Dependencies
|
||||
+
|
||||
implementation("ca.spottedleaf:concurrentutil:0.0.3")
|
||||
implementation("ca.spottedleaf:concurrentutil:0.0.5")
|
||||
- implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
|
||||
- implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
|
||||
+ implementation("org.jline:jline-terminal-ffm:3.29.0") // use ffm on java 22+ // DivineMC - Bump dependencies
|
||||
+ implementation("org.jline:jline-terminal-jni:3.29.0") // fall back to jni on java 21 // DivineMC - Bump dependencies
|
||||
implementation("net.minecrell:terminalconsoleappender:1.3.0")
|
||||
implementation("net.kyori:adventure-text-serializer-ansi")
|
||||
runtimeConfiguration(sourceSets.main.map { it.runtimeClasspath })
|
||||
|
||||
@@ -170,16 +_,16 @@
|
||||
all its classes to check if they are plugins.
|
||||
Scanning takes about 1-2 seconds so adding this speeds up the server start.
|
||||
|
||||
@@ -31,10 +31,10 @@ index 97844ec1ccc986eb3d3a185d78a03ceeca49fc1a..5e40ec3fbe6e6d5f98ad98df7d4c27d6
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
|
||||
index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..0e07db9311d480c97251be6277f9d5d103ee9f22 100644
|
||||
index 2c85607bcc62b227485972707c3541247a626524..9e25b6412fadbbecda0430f8554eaa48dbe8c151 100644
|
||||
--- a/net/minecraft/server/Main.java
|
||||
+++ b/net/minecraft/server/Main.java
|
||||
@@ -69,36 +69,29 @@ public class Main {
|
||||
@@ -67,36 +67,29 @@ public class Main {
|
||||
)
|
||||
@DontObfuscate
|
||||
public static void main(final OptionSet optionSet) { // CraftBukkit - replaces main(String[] args)
|
||||
@@ -90,7 +90,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..0e07db9311d480c97251be6277f9d5d1
|
||||
Path path = (Path) optionSet.valueOf("pidFile"); // CraftBukkit
|
||||
if (path != null) {
|
||||
writePidFile(path);
|
||||
@@ -124,8 +117,6 @@ public class Main {
|
||||
@@ -122,8 +115,6 @@ public class Main {
|
||||
DedicatedServerSettings dedicatedServerSettings = new DedicatedServerSettings(optionSet); // CraftBukkit - CLI argument support
|
||||
dedicatedServerSettings.forceSave();
|
||||
RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression);
|
||||
@@ -99,7 +99,7 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..0e07db9311d480c97251be6277f9d5d1
|
||||
// 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 spigotConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("spigot-settings"));
|
||||
@@ -148,19 +139,6 @@ public class Main {
|
||||
@@ -146,19 +137,6 @@ public class Main {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -120,10 +120,10 @@ index b06c2c4aa77edafb374f7cf0406cf4d29c6e7f9f..0e07db9311d480c97251be6277f9d5d1
|
||||
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
|
||||
if (awtException != null) {
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index b68749354f2a55e41f2b39f96ac9d1190092d672..e04be8b21514db5b7ecb2419b4b37caf29960c5a 100644
|
||||
index c3366c13f2227c25126ae1458621e4579be51435..42a8e32dbba4a369406b3cfe4bd64696c875693d 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1184,6 +1184,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
@@ -1250,6 +1250,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
|
||||
protected void runServer() {
|
||||
try {
|
||||
@@ -163,10 +163,10 @@ index 614c7d9f673c926562acc8fa3b3788623900db41..937469a134e721c47e235a34acc565f1
|
||||
minecraftServerGui.runFinalizers();
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
index 77db68349aa73d33b86a867099c9395c96d5a02d..8d1174f25e0e90d0533970f4ddd8448442024936 100644
|
||||
index 0e6222214f4b5407705dcbdf4dcf574111bcf366..8215edb0dbb5a9de66d5107786c338d2fd02d5ea 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
|
||||
@@ -308,7 +308,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@@ -309,7 +309,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
// Paper start
|
||||
private static void printOversizedLog(String msg, Path file, int x, int z) {
|
||||
|
||||
@@ -5,10 +5,10 @@ Subject: [PATCH] Configuration
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 536a3da1d87e1d4087977196c5766f6550a95e47..bbe93d1861541991215d32186eec82fa8602fea2 100644
|
||||
index b138e704925193d151b69ef54f281a34d085c40b..231935f74443241a710ed2099bb32090ef34731d 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -162,6 +162,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
@@ -255,6 +255,8 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
this.setLocalIp(properties.serverIp);
|
||||
}
|
||||
|
||||
@@ -17,19 +17,19 @@ index 536a3da1d87e1d4087977196c5766f6550a95e47..bbe93d1861541991215d32186eec82fa
|
||||
// Spigot start
|
||||
this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
|
||||
org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings"));
|
||||
@@ -193,6 +195,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
@@ -286,6 +288,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
}
|
||||
org.purpurmc.purpur.PurpurConfig.registerCommands();
|
||||
// Purpur end - Purpur config files
|
||||
+ org.bxteam.divinemc.command.DivineCommands.registerCommands(this); // DivineMC - Configuration
|
||||
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||
|
||||
|
||||
// DivineMC start - Pufferfish: SIMD Support
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 848f936a26429d844ad439ca336dbcb8d81f09e8..2c60b1c8ecb54c4c9526a2b2f6e6698b77359065 100644
|
||||
index f7a4a6a69f76f0eadf00b61462d407d89eaee774..0dc444a63224ef3409f4e7ac800213d5a794a810 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -161,6 +161,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
@@ -166,6 +166,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
// Paper end - add paper world config
|
||||
|
||||
public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files
|
||||
@@ -37,7 +37,7 @@ index 848f936a26429d844ad439ca336dbcb8d81f09e8..2c60b1c8ecb54c4c9526a2b2f6e6698b
|
||||
public static @Nullable BlockPos lastPhysicsProblem; // Spigot
|
||||
private int tileTickPosition;
|
||||
public final Map<ServerExplosion.CacheKey, Float> explosionDensityCache = new java.util.HashMap<>(); // Paper - Optimize explosions
|
||||
@@ -885,6 +886,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
@@ -890,6 +891,14 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
|
||||
this.spigotConfig = new org.spigotmc.SpigotWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName()); // Spigot
|
||||
this.paperConfig = paperWorldConfigCreator.apply(this.spigotConfig); // Paper - create paper world config
|
||||
this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), environment); // Purpur - Purpur config files
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,146 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 23 Mar 2025 16:47:24 +0300
|
||||
Subject: [PATCH] Paper PR: Add FillBottleEvents for player and dispenser
|
||||
|
||||
|
||||
diff --git a/net/minecraft/core/cauldron/CauldronInteraction.java b/net/minecraft/core/cauldron/CauldronInteraction.java
|
||||
index a1ce1548bb008f1854baa4c5d6cd963c3a3f7a36..12f3875ed5638ca25787d5307de0b22cf0b63b64 100644
|
||||
--- a/net/minecraft/core/cauldron/CauldronInteraction.java
|
||||
+++ b/net/minecraft/core/cauldron/CauldronInteraction.java
|
||||
@@ -63,7 +63,12 @@ public interface CauldronInteraction {
|
||||
}
|
||||
// CraftBukkit end
|
||||
Item item = stack.getItem();
|
||||
- player.setItemInHand(hand, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.GLASS_BOTTLE)));
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ final io.papermc.paper.event.player.PlayerFillBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerFillBottleEvent(player, hand, stack, ItemUtils.createFilledResult(stack, player, new ItemStack(Items.GLASS_BOTTLE)));
|
||||
+ if (event.isCancelled()) {
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
player.awardStat(Stats.USE_CAULDRON);
|
||||
player.awardStat(Stats.ITEM_USED.get(item));
|
||||
// level.setBlockAndUpdate(pos, Blocks.WATER_CAULDRON.defaultBlockState()); // CraftBukkit
|
||||
diff --git a/net/minecraft/core/dispenser/DispenseItemBehavior.java b/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
index 582e012222123e5001c34153f2ee1ab1d08935fd..ac27ff24f018d8798921c5152e679ceed1e88d8d 100644
|
||||
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
|
||||
@@ -569,13 +569,25 @@ public interface DispenseItemBehavior {
|
||||
blockStateBase -> blockStateBase.hasProperty(BeehiveBlock.HONEY_LEVEL) && blockStateBase.getBlock() instanceof BeehiveBlock
|
||||
)
|
||||
&& blockState.getValue(BeehiveBlock.HONEY_LEVEL) >= 5) {
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ final io.papermc.paper.event.block.BlockFillBottleEvent bottleEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFillBottleEvent(serverLevel, blockSource.pos(), item, new ItemStack(Items.HONEY_BOTTLE));
|
||||
+ if (bottleEvent.isCancelled()) {
|
||||
+ return item;
|
||||
+ }
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
((BeehiveBlock)blockState.getBlock())
|
||||
.releaseBeesAndResetHoneyLevel(serverLevel, blockState, blockPos, null, BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED);
|
||||
this.setSuccess(true);
|
||||
- return this.takeLiquid(blockSource, item, new ItemStack(Items.HONEY_BOTTLE));
|
||||
+ return this.takeLiquid(blockSource, item, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(bottleEvent.getResultItem())); // DivineMC - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
} else if (serverLevel.getFluidState(blockPos).is(FluidTags.WATER)) {
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ final io.papermc.paper.event.block.BlockFillBottleEvent bottleEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockFillBottleEvent(serverLevel, blockSource.pos(), item, PotionContents.createItemStack(Items.POTION, Potions.WATER));
|
||||
+ if (bottleEvent.isCancelled()) {
|
||||
+ return item;
|
||||
+ }
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
this.setSuccess(true);
|
||||
- return this.takeLiquid(blockSource, item, PotionContents.createItemStack(Items.POTION, Potions.WATER));
|
||||
+ return this.takeLiquid(blockSource, item, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(bottleEvent.getResultItem())); // DivineMC - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
} else {
|
||||
return super.execute(blockSource, item);
|
||||
}
|
||||
diff --git a/net/minecraft/world/item/BottleItem.java b/net/minecraft/world/item/BottleItem.java
|
||||
index 105f9166297de2bfa6bdcfa9f6a0ffb00c0242ac..111f43fc5c74577f8f3067a4f84be7a6f96fdfb2 100644
|
||||
--- a/net/minecraft/world/item/BottleItem.java
|
||||
+++ b/net/minecraft/world/item/BottleItem.java
|
||||
@@ -35,6 +35,18 @@ public class BottleItem extends Item {
|
||||
);
|
||||
ItemStack itemInHand = player.getItemInHand(hand);
|
||||
if (!entitiesOfClass.isEmpty()) {
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ final io.papermc.paper.event.player.PlayerFillBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerFillBottleEvent(player, hand, itemInHand, new ItemStack(Items.DRAGON_BREATH));
|
||||
+ //noinspection DuplicatedCode
|
||||
+ if (event.isCancelled()) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ final ItemStack resultItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getResultItem());
|
||||
+ if (resultItem.is(itemInHand.getItem())) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ }
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
AreaEffectCloud areaEffectCloud = entitiesOfClass.get(0);
|
||||
areaEffectCloud.setRadius(areaEffectCloud.getRadius() - 0.5F);
|
||||
level.playSound(null, player.getX(), player.getY(), player.getZ(), SoundEvents.BOTTLE_FILL_DRAGONBREATH, SoundSource.NEUTRAL, 1.0F, 1.0F);
|
||||
@@ -43,7 +55,7 @@ public class BottleItem extends Item {
|
||||
CriteriaTriggers.PLAYER_INTERACTED_WITH_ENTITY.trigger(serverPlayer, itemInHand, areaEffectCloud);
|
||||
}
|
||||
|
||||
- return InteractionResult.SUCCESS.heldItemTransformedTo(this.turnBottleIntoItem(itemInHand, player, new ItemStack(Items.DRAGON_BREATH)));
|
||||
+ return InteractionResult.SUCCESS.heldItemTransformedTo(this.turnBottleIntoItem(itemInHand, player, resultItem)); // DivineMC - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
} else {
|
||||
BlockHitResult playerPovHitResult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.SOURCE_ONLY);
|
||||
if (playerPovHitResult.getType() == HitResult.Type.MISS) {
|
||||
@@ -56,10 +68,22 @@ public class BottleItem extends Item {
|
||||
}
|
||||
|
||||
if (level.getFluidState(blockPos).is(FluidTags.WATER)) {
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ final io.papermc.paper.event.player.PlayerFillBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerFillBottleEvent(player, hand, itemInHand, PotionContents.createItemStack(Items.POTION, Potions.WATER));
|
||||
+ //noinspection DuplicatedCode
|
||||
+ if (event.isCancelled()) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ final ItemStack resultItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getResultItem());
|
||||
+ if (resultItem.is(itemInHand.getItem())) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ }
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
level.playSound(player, player.getX(), player.getY(), player.getZ(), SoundEvents.BOTTLE_FILL, SoundSource.NEUTRAL, 1.0F, 1.0F);
|
||||
level.gameEvent(player, GameEvent.FLUID_PICKUP, blockPos);
|
||||
return InteractionResult.SUCCESS
|
||||
- .heldItemTransformedTo(this.turnBottleIntoItem(itemInHand, player, PotionContents.createItemStack(Items.POTION, Potions.WATER)));
|
||||
+ .heldItemTransformedTo(this.turnBottleIntoItem(itemInHand, player, resultItem)); // DivineMC - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/BeehiveBlock.java b/net/minecraft/world/level/block/BeehiveBlock.java
|
||||
index 3cec4c5a40c569d848bbf503501d8c8d38ecf3ce..1e92dbb04445596e3adee0ef5f1db47b7cec908e 100644
|
||||
--- a/net/minecraft/world/level/block/BeehiveBlock.java
|
||||
+++ b/net/minecraft/world/level/block/BeehiveBlock.java
|
||||
@@ -155,12 +155,26 @@ public class BeehiveBlock extends BaseEntityBlock {
|
||||
flag = true;
|
||||
level.gameEvent(player, GameEvent.SHEAR, pos);
|
||||
} else if (stack.is(Items.GLASS_BOTTLE)) {
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ final io.papermc.paper.event.player.PlayerFillBottleEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerFillBottleEvent(player, hand, stack, new ItemStack(Items.HONEY_BOTTLE));
|
||||
+ //noinspection DuplicatedCode
|
||||
+ if (event.isCancelled()) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ return InteractionResult.PASS;
|
||||
+ }
|
||||
+ final ItemStack resultItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getResultItem());
|
||||
+ if (resultItem.is(stack.getItem())) {
|
||||
+ player.containerMenu.sendAllDataToRemote();
|
||||
+ }
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
stack.shrink(1);
|
||||
level.playSound(player, player.getX(), player.getY(), player.getZ(), SoundEvents.BOTTLE_FILL, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
if (stack.isEmpty()) {
|
||||
- player.setItemInHand(hand, new ItemStack(Items.HONEY_BOTTLE));
|
||||
- } else if (!player.getInventory().add(new ItemStack(Items.HONEY_BOTTLE))) {
|
||||
- player.drop(new ItemStack(Items.HONEY_BOTTLE), false);
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ player.setItemInHand(hand, resultItem);
|
||||
+ } else if (!player.getInventory().add(resultItem)) {
|
||||
+ player.drop(resultItem, false);
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
}
|
||||
|
||||
flag = true;
|
||||
@@ -1,332 +0,0 @@
|
||||
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 345d4b80bd4383e0fb66d744d87bc8ef4100fd32..68a074a1eb11b158af773a2c44aa49d5d8462080 100644
|
||||
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||
@@ -158,29 +158,52 @@ public final class NaturalSpawner {
|
||||
// Copied from getFilteredSpawningCategories
|
||||
int limit = mobCategory.getMaxInstancesPerChunk();
|
||||
org.bukkit.entity.SpawnCategory spawnCategory = org.bukkit.craftbukkit.util.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 (org.bukkit.craftbukkit.util.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
|
||||
}
|
||||
}
|
||||
@@ -204,12 +227,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
|
||||
@@ -229,16 +261,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();
|
||||
@@ -278,14 +316,14 @@ 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
|
||||
// Paper end - PreCreatureSpawnEvent
|
||||
&& filter.test(spawnerData.type(), mutableBlockPos, chunk)) {
|
||||
Mob mobForSpawn = getMobForSpawn(level, spawnerData.type());
|
||||
if (mobForSpawn == null) {
|
||||
- return;
|
||||
+ return i; // Paper - throttle failed spawn attempts
|
||||
}
|
||||
|
||||
mobForSpawn.snapTo(d, y, d1, level.random.nextFloat() * 360.0F, 0.0F);
|
||||
@@ -308,7 +346,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)) {
|
||||
@@ -321,6 +359,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 182c14b660f8860bed627eed4e01fd4002153e9a..81511de113c292549fe5fe720a15bf3e0497ca84 100644
|
||||
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
@@ -88,6 +88,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 e04d3479383cd480cf35ed7ac3c82e7f6fb69e28..87abba1241552fe967229f1b442cd0a767cbf739 100644
|
||||
--- a/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
+++ b/net/minecraft/world/level/chunk/storage/SerializableChunkData.java
|
||||
@@ -94,6 +94,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
|
||||
@@ -190,6 +191,19 @@ public record SerializableChunkData(
|
||||
lists[i] = list2;
|
||||
}
|
||||
|
||||
+ // Paper start - throttle failed spawn attempts
|
||||
+ long[] failedSpawnAttemptsData = null;
|
||||
+ if (tag.contains("Paper.FailedSpawnAttempts")) {
|
||||
+ failedSpawnAttemptsData = new long[net.minecraft.world.entity.MobCategory.values().length];
|
||||
+ CompoundTag failedSpawnAttemptsTag = tag.getCompoundOrEmpty("Paper.FailedSpawnAttempts");
|
||||
+ for (net.minecraft.world.entity.MobCategory mobCategory : net.minecraft.world.level.NaturalSpawner.SPAWNING_CATEGORIES) {
|
||||
+ if (failedSpawnAttemptsTag.contains(mobCategory.getSerializedName())) {
|
||||
+ failedSpawnAttemptsData[mobCategory.ordinal()] = failedSpawnAttemptsTag.getLongOr(mobCategory.getSerializedName(), 0);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - throttle failed spawn attempts
|
||||
+
|
||||
List<CompoundTag> list3 = tag.getList("entities").stream().flatMap(ListTag::compoundStream).toList();
|
||||
List<CompoundTag> list4 = tag.getList("block_entities").stream().flatMap(ListTag::compoundStream).toList();
|
||||
CompoundTag compoundOrEmpty = tag.getCompoundOrEmpty("structures");
|
||||
@@ -270,6 +284,7 @@ public record SerializableChunkData(
|
||||
list4,
|
||||
compoundOrEmpty
|
||||
, tag.get("ChunkBukkitValues") // CraftBukkit - ChunkBukkitValues
|
||||
+ , failedSpawnAttemptsData // Paper - throttle failed spawn attempts
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -426,6 +441,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 {
|
||||
@@ -556,6 +580,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,
|
||||
@@ -576,6 +601,7 @@ public record SerializableChunkData(
|
||||
list1,
|
||||
compoundTag
|
||||
, persistentDataContainer // CraftBukkit - persistentDataContainer
|
||||
+ , failedSpawnAttemptsData // Paper - throttle failed spawn attempts
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -660,6 +686,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
|
||||
@@ -875,4 +916,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
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 27 Apr 2025 14:24:19 +0300
|
||||
Subject: [PATCH] Raytrace AntiXray SDK integration
|
||||
|
||||
Integration with Imanity Software's Raytrace AntiXray for better use of this plugin
|
||||
|
||||
Original project: https://github.com/Imanity-Software/raytrace-antixray-spigot-sdk
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index c4a4f08272b34f72dea4feaaeb66d153b2aab8c8..be5da5a81246b4f4abe19f7c0cf68990d6bdf5bd 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -296,6 +296,12 @@ public class ServerPlayerGameMode {
|
||||
org.bukkit.craftbukkit.event.CraftEventFactory.callBlockDamageAbortEvent(this.player, pos, this.player.getInventory().getSelectedItem()); // CraftBukkit
|
||||
}
|
||||
}
|
||||
+ // Imanity start - AntiXraySDK integration
|
||||
+ dev.imanity.antixray.sdk.AntiXrayAdapter adapter = dev.imanity.antixray.sdk.AntiXraySDK.getAdapter();
|
||||
+ if (adapter != null) {
|
||||
+ adapter.callPlayerLeftClickBlock(this.level.getWorld(), this.player.getBukkitEntity(), pos.getX(), pos.getY(), pos.getZ());
|
||||
+ }
|
||||
+ // Imanity end - AntiXraySDK integration
|
||||
this.level.chunkPacketBlockController.onPlayerLeftClickBlock(this, pos, action, face, maxBuildHeight, sequence); // Paper - Anti-Xray
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 4c1ce7e85f9c3315635472047ffaf15a711aeffd..9625213b7c1295b813071dbedea5366510c7072f 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -1171,6 +1171,12 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
snapshot.setFlags(flags); // Paper - always set the flag of the most recent call to mitigate issues with multiple update at the same pos with different flags
|
||||
}
|
||||
BlockState blockState = chunkAt.setBlockState(pos, state, flags);
|
||||
+ // Imanity start - AntiXraySDK integration
|
||||
+ dev.imanity.antixray.sdk.AntiXrayAdapter adapter = dev.imanity.antixray.sdk.AntiXraySDK.getAdapter();
|
||||
+ if (adapter != null) {
|
||||
+ adapter.callBlockChange(world, pos.getX(), pos.getY(), pos.getZ(), state.getBukkitMaterial());
|
||||
+ }
|
||||
+ // Imanity end - AntiXraySDK integration
|
||||
this.chunkPacketBlockController.onBlockChange(this, pos, state, blockState, flags, recursionLeft); // Paper - Anti-Xray
|
||||
// CraftBukkit end
|
||||
if (blockState == null) {
|
||||
@@ -1,46 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jason Penilla <11360596+jpenilla@users.noreply.github.com>
|
||||
Date: Fri, 13 Sep 2024 14:32:32 -0700
|
||||
Subject: [PATCH] Paper PR: Add ticket on player join to avoid chunk
|
||||
load-unload-load cycle
|
||||
|
||||
Original license: GPLv3
|
||||
Original project: https://github.com/PaperMC/Paper
|
||||
Paper pull request: https://github.com/PaperMC/Paper/pull/11398
|
||||
|
||||
Adding the entity will add and then immediately remove an entity load ticket, which would result in the chunk loading and then unloading before being loaded again once the player chunk loader reacts (delay can vary based on rate limit configs)
|
||||
By adding a ticket with a short removal delay we attempt to keep the chunk loaded until the player chunk loader reacts, but this is not a guarantee due to the aforementioned rate limit configs. Plugins should still handle load/unload events as normal, however this will reduce redundant calls.
|
||||
The delay is currently set to 2 seconds, however, we may want to adjust this before merging (for example the player chunk unload delay is 5 seconds)
|
||||
|
||||
This patch fixes PaperMC/Paper#9581
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index bdc1200ef5317fdaf58973bf580b0a672aee800f..1ed2ae41e47b2446bf1835efc8bad369408d52da 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -48,6 +48,7 @@ public final class RegionizedPlayerChunkLoader {
|
||||
|
||||
public static final TicketType PLAYER_TICKET = ChunkSystemTicketType.create("chunk_system:player_ticket", Long::compareTo);
|
||||
public static final TicketType PLAYER_TICKET_DELAYED = ChunkSystemTicketType.create("chunk_system:player_ticket_delayed", Long::compareTo, 1L);
|
||||
+ public static final TicketType PLAYER_JOIN = ChunkSystemTicketType.create("chunk_system:player_join", (a, b) -> 0, 5 * 20); // Paper - Add ticket on player join to avoid chunk load-unload-load cycle
|
||||
|
||||
public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL;
|
||||
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 8a67672f1175769ac213099331453fbae59442fa..c70b5ce2dc8cbcdea8715339a63e038f94849bfb 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -315,6 +315,13 @@ public abstract class PlayerList {
|
||||
// this.broadcastAll(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player))); // CraftBukkit - replaced with loop below
|
||||
// Paper start - Fire PlayerJoinEvent when Player is actually ready; correctly register player BEFORE PlayerJoinEvent, so the entity is valid and doesn't require tick delay hacks
|
||||
player.supressTrackerForLogin = true;
|
||||
+ // Paper start - Add ticket on player join to avoid chunk load-unload-load cycle
|
||||
+ serverLevel.moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(
|
||||
+ ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PLAYER_JOIN,
|
||||
+ player.chunkPosition(),
|
||||
+ ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.TICK_TICKET_LEVEL,
|
||||
+ net.minecraft.util.Unit.INSTANCE);
|
||||
+ // Paper end - Add ticket on player join to avoid chunk load-unload-load cycle
|
||||
serverLevel.addNewPlayer(player);
|
||||
this.server.getCustomBossEvents().onPlayerConnect(player); // see commented out section below serverLevel.addPlayerJoin(player);
|
||||
// Paper end - Fire PlayerJoinEvent when Player is actually ready
|
||||
@@ -1,49 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 29 Jun 2025 15:12:40 +0300
|
||||
Subject: [PATCH] Smooth teleport API
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
||||
index f7b73c4c472e53ea5593d855e7194b4eb5e4d2f5..53a0024ef133183e16b7dc06529917a4173e9b17 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -430,6 +430,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
||||
private boolean tpsBar = false; // Purpur - Implement TPSBar
|
||||
private boolean compassBar = false; // Purpur - Add compass command
|
||||
private boolean ramBar = false; // Purpur - Implement rambar commands
|
||||
+ public boolean smoothWorldTeleport; // DivineMC - Smooth teleport API
|
||||
|
||||
// Paper start - rewrite chunk system
|
||||
private ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader;
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 1fd3e78c7d3e35f0d9fc8abab2fb7efa8bcfd05c..1e4ebfa25e63c148fe7bf6cf5789e602d8e5ca83 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -747,11 +747,11 @@ public abstract class PlayerList {
|
||||
byte b = (byte)(keepInventory ? 1 : 0);
|
||||
ServerLevel serverLevel = serverPlayer.level();
|
||||
LevelData levelData = serverLevel.getLevelData();
|
||||
- serverPlayer.connection.send(new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(serverLevel), b));
|
||||
+ if (!serverPlayer.smoothWorldTeleport || !isSameLogicalHeight((ServerLevel) fromWorld, level)) serverPlayer.connection.send(new ClientboundRespawnPacket(serverPlayer.createCommonSpawnInfo(serverLevel), b)); // DivineMC - Smooth teleport API
|
||||
// serverPlayer.connection.teleport(serverPlayer.getX(), serverPlayer.getY(), serverPlayer.getZ(), serverPlayer.getYRot(), serverPlayer.getXRot());
|
||||
serverPlayer.connection.send(new ClientboundSetChunkCacheRadiusPacket(serverLevel.spigotConfig.viewDistance)); // Spigot
|
||||
serverPlayer.connection.send(new ClientboundSetSimulationDistancePacket(serverLevel.spigotConfig.simulationDistance)); // Spigot
|
||||
- serverPlayer.connection.teleport(org.bukkit.craftbukkit.util.CraftLocation.toBukkit(serverPlayer.position(), serverLevel.getWorld(), serverPlayer.getYRot(), serverPlayer.getXRot())); // CraftBukkit
|
||||
+ if (!serverPlayer.smoothWorldTeleport || !isSameLogicalHeight((ServerLevel) fromWorld, level)) serverPlayer.connection.teleport(org.bukkit.craftbukkit.util.CraftLocation.toBukkit(serverPlayer.position(), serverLevel.getWorld(), serverPlayer.getYRot(), serverPlayer.getXRot())); // DivineMC - Smooth teleport API
|
||||
serverPlayer.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle()));
|
||||
serverPlayer.connection.send(new ClientboundChangeDifficultyPacket(levelData.getDifficulty(), levelData.isDifficultyLocked()));
|
||||
serverPlayer.connection
|
||||
@@ -838,6 +838,12 @@ public abstract class PlayerList {
|
||||
return serverPlayer;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Smooth teleport API
|
||||
+ public static boolean isSameLogicalHeight(ServerLevel fromLevel, ServerLevel toLevel) {
|
||||
+ return fromLevel.getLogicalHeight() == toLevel.getLogicalHeight();
|
||||
+ }
|
||||
+ // DivineMC end - Smooth teleport API
|
||||
+
|
||||
public void sendActivePlayerEffects(ServerPlayer player) {
|
||||
this.sendActiveEffects(player, player.connection);
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 24 Feb 2025 19:10:17 +0300
|
||||
Subject: [PATCH] lithium: fast_util
|
||||
|
||||
This patch is based on the following mixins:
|
||||
* "net/caffeinemc/mods/lithium/mixin/math/fast_util/DirectionMixin.java"
|
||||
* "net/caffeinemc/mods/lithium/mixin/math/fast_util/AABBMixin.java"
|
||||
By: 2No2Name <2No2Name@web.de>
|
||||
As part of: Lithium (https://github.com/CaffeineMC/lithium)
|
||||
Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/core/Direction.java b/net/minecraft/core/Direction.java
|
||||
index 63fd7b45750430b565d599337d3112cbaa7e7550..4275a2e1e29c15cdda75c29c468255635f5c7bc1 100644
|
||||
--- a/net/minecraft/core/Direction.java
|
||||
+++ b/net/minecraft/core/Direction.java
|
||||
@@ -222,7 +222,7 @@ public enum Direction implements StringRepresentable, ca.spottedleaf.moonrise.pa
|
||||
}
|
||||
|
||||
public Direction getOpposite() {
|
||||
- return this.opposite; // Paper - optimise collisions
|
||||
+ return VALUES[this.oppositeIndex]; // DivineMC - lithium: fast_util
|
||||
}
|
||||
|
||||
public Direction getClockWise(Direction.Axis axis) {
|
||||
@@ -355,7 +355,7 @@ public enum Direction implements StringRepresentable, ca.spottedleaf.moonrise.pa
|
||||
}
|
||||
|
||||
public static Direction getRandom(RandomSource random) {
|
||||
- return Util.getRandom(VALUES, random);
|
||||
+ return VALUES[random.nextInt(VALUES.length)]; // DivineMC - lithium: fast_util
|
||||
}
|
||||
|
||||
public static Direction getApproximateNearest(double x, double y, double z) {
|
||||
diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java
|
||||
index e53398996bbb278c6e06024d8ca945b364a44c10..13678a9c0f9056b4925e4de927ec3cbc01cb114e 100644
|
||||
--- a/net/minecraft/world/phys/AABB.java
|
||||
+++ b/net/minecraft/world/phys/AABB.java
|
||||
@@ -19,6 +19,15 @@ public class AABB {
|
||||
public final double maxY;
|
||||
public final double maxZ;
|
||||
|
||||
+ // DivineMC start - lithium: fast_util
|
||||
+ static {
|
||||
+ assert Direction.Axis.X.ordinal() == 0;
|
||||
+ assert Direction.Axis.Y.ordinal() == 1;
|
||||
+ assert Direction.Axis.Z.ordinal() == 2;
|
||||
+ assert Direction.Axis.values().length == 3;
|
||||
+ }
|
||||
+ // DivineMC end - lithium: fast_util
|
||||
+
|
||||
public AABB(double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
this.minX = Math.min(x1, x2);
|
||||
this.minY = Math.min(y1, y2);
|
||||
@@ -80,11 +89,33 @@ public class AABB {
|
||||
}
|
||||
|
||||
public double min(Direction.Axis axis) {
|
||||
- return axis.choose(this.minX, this.minY, this.minZ);
|
||||
+ // DivineMC start - lithium: fast_util
|
||||
+ switch (axis.ordinal()) {
|
||||
+ case 0: // X
|
||||
+ return this.minX;
|
||||
+ case 1: // Y
|
||||
+ return this.minY;
|
||||
+ case 2: // Z
|
||||
+ return this.minZ;
|
||||
+ }
|
||||
+
|
||||
+ throw new IllegalArgumentException();
|
||||
+ // DivineMC end - lithium: fast_util
|
||||
}
|
||||
|
||||
public double max(Direction.Axis axis) {
|
||||
- return axis.choose(this.maxX, this.maxY, this.maxZ);
|
||||
+ // DivineMC start - lithium: fast_util
|
||||
+ switch (axis.ordinal()) {
|
||||
+ case 0: // X
|
||||
+ return this.maxX;
|
||||
+ case 1: // Y
|
||||
+ return this.maxY;
|
||||
+ case 2: // Z
|
||||
+ return this.maxZ;
|
||||
+ }
|
||||
+
|
||||
+ throw new IllegalArgumentException();
|
||||
+ // DivineMC end - lithium: fast_util
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,68 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 6 Jul 2025 01:55:37 +0300
|
||||
Subject: [PATCH] C2ME: Optimize world gen math
|
||||
|
||||
This patch is based on following mixins:
|
||||
* "com/ishland/c2me/opts/math/mixin/MixinChunkPos.java"
|
||||
* "com/ishland/c2me/opts/worldgen/vanilla/mixin/structure_weight_sampler/MixinStructureWeightSampler.java"
|
||||
By: ishland <ishlandmc@yeah.net>
|
||||
As part of: C2ME-fabric (https://github.com/RelativityMC/C2ME-fabric)
|
||||
Licensed under: MIT
|
||||
|
||||
diff --git a/net/minecraft/world/level/ChunkPos.java b/net/minecraft/world/level/ChunkPos.java
|
||||
index 55ce935a2fab7e32904d9ff599867269035d703f..7770e2aacaa7772a1710172f143452f076c6eef2 100644
|
||||
--- a/net/minecraft/world/level/ChunkPos.java
|
||||
+++ b/net/minecraft/world/level/ChunkPos.java
|
||||
@@ -110,7 +110,12 @@ public class ChunkPos {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
- return this == other || other instanceof ChunkPos chunkPos && this.x == chunkPos.x && this.z == chunkPos.z;
|
||||
+ // DivineMC start - C2ME: Optimize world gen math
|
||||
+ if (other == this) return true;
|
||||
+ if (other == null || other.getClass() != this.getClass()) return false;
|
||||
+ ChunkPos thatPos = (ChunkPos) other;
|
||||
+ return this.x == thatPos.x && this.z == thatPos.z;
|
||||
+ // DivineMC end - C2ME: Optimize world gen math
|
||||
}
|
||||
|
||||
public int getMiddleBlockX() {
|
||||
diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
index 74d8202b5c9bb2a3ee832be70f95c0b5cbecb460..86c15d2d90e63d21cb83622a7b29e11151a4f64a 100644
|
||||
--- a/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
+++ b/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
@@ -131,8 +131,14 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
}
|
||||
|
||||
private static double getBuryContribution(double x, double y, double z) {
|
||||
- double len = Mth.length(x, y, z);
|
||||
- return Mth.clampedMap(len, 0.0, 6.0, 1.0, 0.0);
|
||||
+ // DivineMC start - C2ME: Optimize world gen math
|
||||
+ double len = Math.sqrt(x * x + y * y + z * z);
|
||||
+ if (len > 6.0) {
|
||||
+ return 0.0;
|
||||
+ } else {
|
||||
+ return 1.0 - len / 6.0;
|
||||
+ }
|
||||
+ // DivineMC end - C2ME: Optimize world gen math
|
||||
}
|
||||
|
||||
private static double getBeardContribution(int x, int y, int z, int height) {
|
||||
diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
index 65728ef17e63d71833677fdcbd5bb90794b4822b..5716e80ba386f113d02f5d6a4848914d4bf9600f 100644
|
||||
--- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
+++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
|
||||
@@ -68,8 +68,10 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
|
||||
Aquifer.FluidStatus fluidStatus = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState());
|
||||
int seaLevel = settings.seaLevel();
|
||||
Aquifer.FluidStatus fluidStatus1 = new Aquifer.FluidStatus(seaLevel, settings.defaultFluid());
|
||||
- Aquifer.FluidStatus fluidStatus2 = new Aquifer.FluidStatus(DimensionType.MIN_Y * 2, Blocks.AIR.defaultBlockState());
|
||||
- return (x, y, z) -> y < Math.min(-54, seaLevel) ? fluidStatus : fluidStatus1;
|
||||
+ // DivineMC start - C2ME: Optimize world gen math
|
||||
+ final int min = Math.min(-54, seaLevel);
|
||||
+ return (x, y, z) -> y < min ? fluidStatus : fluidStatus1;
|
||||
+ // DivineMC end - C2ME: Optimize world gen math
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,129 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 29 Jan 2025 00:54:19 +0300
|
||||
Subject: [PATCH] Async locate command
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/commands/LocateCommand.java b/net/minecraft/server/commands/LocateCommand.java
|
||||
index a734b2597c3491db35d9660e169f8e8b6320900b..1692724f5406a22702f185f66073dd5e836ce7f8 100644
|
||||
--- a/net/minecraft/server/commands/LocateCommand.java
|
||||
+++ b/net/minecraft/server/commands/LocateCommand.java
|
||||
@@ -100,44 +100,77 @@ public class LocateCommand {
|
||||
}
|
||||
|
||||
private static int locateStructure(CommandSourceStack source, ResourceOrTagKeyArgument.Result<Structure> structure) throws CommandSyntaxException {
|
||||
- Registry<Structure> registry = source.getLevel().registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
- HolderSet<Structure> holderSet = (HolderSet<Structure>)getHolders(structure, registry)
|
||||
- .orElseThrow(() -> ERROR_STRUCTURE_INVALID.create(structure.asPrintable()));
|
||||
- BlockPos blockPos = BlockPos.containing(source.getPosition());
|
||||
- ServerLevel level = source.getLevel();
|
||||
- Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER);
|
||||
- Pair<BlockPos, Holder<Structure>> pair = level.getChunkSource().getGenerator().findNearestMapStructure(level, holderSet, blockPos, 100, false);
|
||||
- stopwatch.stop();
|
||||
- if (pair == null) {
|
||||
- throw ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable());
|
||||
- } else {
|
||||
- return showLocateResult(source, structure, blockPos, pair, "commands.locate.structure.success", false, stopwatch.elapsed());
|
||||
- }
|
||||
+ // DivineMC start - Async structure locate
|
||||
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(() -> {
|
||||
+ Registry<Structure> registry = source.getLevel().registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
+ HolderSet<Structure> holderSet;
|
||||
+ try {
|
||||
+ holderSet = getHolders(structure, registry)
|
||||
+ .orElseThrow(() -> ERROR_STRUCTURE_INVALID.create(structure.asPrintable()));
|
||||
+ } catch (CommandSyntaxException e) {
|
||||
+ source.sendFailure(Component.literal(e.getMessage()));
|
||||
+ return;
|
||||
+ }
|
||||
+ BlockPos blockPos = BlockPos.containing(source.getPosition());
|
||||
+ ServerLevel level = source.getLevel();
|
||||
+ Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER);
|
||||
+ Pair<BlockPos, Holder<Structure>> pair = level.getChunkSource().getGenerator().findNearestMapStructure(level, holderSet, blockPos, 100, false);
|
||||
+ stopwatch.stop();
|
||||
+ if (pair == null) {
|
||||
+ try {
|
||||
+ throw ERROR_STRUCTURE_NOT_FOUND.create(structure.asPrintable());
|
||||
+ } catch (CommandSyntaxException e) {
|
||||
+ source.sendFailure(Component.literal(e.getMessage()));
|
||||
+ }
|
||||
+ } else {
|
||||
+ showLocateResult(source, structure, blockPos, pair, "commands.locate.structure.success", false, stopwatch.elapsed());
|
||||
+ }
|
||||
+ });
|
||||
+ return 0;
|
||||
+ // DivineMC end - Async structure locate
|
||||
}
|
||||
|
||||
private static int locateBiome(CommandSourceStack source, ResourceOrTagArgument.Result<Biome> biome) throws CommandSyntaxException {
|
||||
- BlockPos blockPos = BlockPos.containing(source.getPosition());
|
||||
- Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER);
|
||||
- Pair<BlockPos, Holder<Biome>> pair = source.getLevel().findClosestBiome3d(biome, blockPos, 6400, 32, 64);
|
||||
- stopwatch.stop();
|
||||
- if (pair == null) {
|
||||
- throw ERROR_BIOME_NOT_FOUND.create(biome.asPrintable());
|
||||
- } else {
|
||||
- return showLocateResult(source, biome, blockPos, pair, "commands.locate.biome.success", true, stopwatch.elapsed());
|
||||
- }
|
||||
+ // DivineMC start - Async biome locate
|
||||
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(() -> {
|
||||
+ BlockPos blockPos = BlockPos.containing(source.getPosition());
|
||||
+ Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER);
|
||||
+ Pair<BlockPos, Holder<Biome>> pair = source.getLevel().findClosestBiome3d(biome, blockPos, 6400, 32, 64);
|
||||
+ stopwatch.stop();
|
||||
+ if (pair == null) {
|
||||
+ try {
|
||||
+ throw ERROR_BIOME_NOT_FOUND.create(biome.asPrintable());
|
||||
+ } catch (CommandSyntaxException e) {
|
||||
+ source.sendFailure(Component.literal(e.getMessage()));
|
||||
+ }
|
||||
+ } else {
|
||||
+ showLocateResult(source, biome, blockPos, pair, "commands.locate.biome.success", true, stopwatch.elapsed());
|
||||
+ }
|
||||
+ });
|
||||
+ return 0;
|
||||
+ // DivineMC end - Async biome locate
|
||||
}
|
||||
|
||||
private static int locatePoi(CommandSourceStack source, ResourceOrTagArgument.Result<PoiType> poiType) throws CommandSyntaxException {
|
||||
- BlockPos blockPos = BlockPos.containing(source.getPosition());
|
||||
- ServerLevel level = source.getLevel();
|
||||
- Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER);
|
||||
- Optional<Pair<Holder<PoiType>, BlockPos>> optional = level.getPoiManager().findClosestWithType(poiType, blockPos, 256, PoiManager.Occupancy.ANY);
|
||||
- stopwatch.stop();
|
||||
- if (optional.isEmpty()) {
|
||||
- throw ERROR_POI_NOT_FOUND.create(poiType.asPrintable());
|
||||
- } else {
|
||||
- return showLocateResult(source, poiType, blockPos, optional.get().swap(), "commands.locate.poi.success", false, stopwatch.elapsed());
|
||||
- }
|
||||
+ // DivineMC start - Async poi locate
|
||||
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(() -> {
|
||||
+ BlockPos blockPos = BlockPos.containing(source.getPosition());
|
||||
+ ServerLevel level = source.getLevel();
|
||||
+ Stopwatch stopwatch = Stopwatch.createStarted(Util.TICKER);
|
||||
+ Optional<Pair<Holder<PoiType>, BlockPos>> optional = level.getPoiManager().findClosestWithType(poiType, blockPos, 256, PoiManager.Occupancy.ANY);
|
||||
+ stopwatch.stop();
|
||||
+ if (optional.isEmpty()) {
|
||||
+ try {
|
||||
+ throw ERROR_POI_NOT_FOUND.create(poiType.asPrintable());
|
||||
+ } catch (CommandSyntaxException e) {
|
||||
+ source.sendFailure(Component.literal(e.getMessage()));
|
||||
+ }
|
||||
+ } else {
|
||||
+ showLocateResult(source, poiType, blockPos, optional.get().swap(), "commands.locate.poi.success", false, stopwatch.elapsed());
|
||||
+ }
|
||||
+ });
|
||||
+ return 0;
|
||||
+ // DivineMC end - Async poi locate
|
||||
}
|
||||
|
||||
public static int showLocateResult(
|
||||
@@ -192,7 +225,7 @@ public class LocateCommand {
|
||||
.withHoverEvent(new HoverEvent.ShowText(Component.translatable("chat.coordinates.tooltip")))
|
||||
);
|
||||
source.sendSuccess(() -> Component.translatable(translationKey, elementName, component, i), false);
|
||||
- LOGGER.info("Locating element " + elementName + " took " + duration.toMillis() + " ms");
|
||||
+ LOGGER.info("Locating element {} on Thread:{} took {} ms", elementName, Thread.currentThread().getName(), duration.toMillis()); // DivineMC - Log thread name
|
||||
return i;
|
||||
}
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 19:17:31 +0300
|
||||
Subject: [PATCH] Carpet-Fixes: RecipeManager Optimize
|
||||
|
||||
Original project: https://github.com/fxmorin/carpet-fixes
|
||||
Optimized the RecipeManager getFirstMatch call to be up to 3x faster
|
||||
This is a fully vanilla optimization. Improves: [Blast]Furnace/Campfire/Smoker/Stonecutter/Crafting/Sheep Color Choosing
|
||||
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
|
||||
index f2c82217811712625df594667330a73f8f44e261..d39ff67faf89f34dcb41769b268c3dafc1b6305b 100644
|
||||
--- a/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
|
||||
|
||||
public <I extends RecipeInput, T extends Recipe<I>> Optional<RecipeHolder<T>> getRecipeFor(RecipeType<T> recipeType, I input, Level level) {
|
||||
// CraftBukkit start
|
||||
- List<RecipeHolder<T>> list = this.recipes.getRecipesFor(recipeType, input, level).toList();
|
||||
+ List<RecipeHolder<T>> list = this.recipes.getRecipesForList(recipeType, input, level); // DivineMC - Carpet-Fixes - Remove streams to be faster
|
||||
return (list.isEmpty()) ? Optional.empty() : Optional.of(list.getLast()); // CraftBukkit - SPIGOT-4638: last recipe gets priority
|
||||
// CraftBukkit end
|
||||
}
|
||||
diff --git a/net/minecraft/world/item/crafting/RecipeMap.java b/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
index 098753ddd215b6ef5915fac71d8c4f0b19cf4142..1778e58dca9430756d59d07bf017ebe4cc1f4ed4 100644
|
||||
--- a/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
+++ b/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
@@ -75,4 +75,24 @@ public class RecipeMap {
|
||||
public <I extends RecipeInput, T extends Recipe<I>> Stream<RecipeHolder<T>> getRecipesFor(RecipeType<T> type, I input, Level level) {
|
||||
return input.isEmpty() ? Stream.empty() : this.byType(type).stream().filter(recipeHolder -> recipeHolder.value().matches(input, level));
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Carpet-Fixes - Remove streams to be faster
|
||||
+ public <I extends RecipeInput, T extends Recipe<I>> java.util.List<RecipeHolder<T>> getRecipesForList(RecipeType<T> type, I input, Level world) {
|
||||
+ java.util.List<RecipeHolder<T>> list;
|
||||
+
|
||||
+ if (input.isEmpty()) {
|
||||
+ return java.util.List.of();
|
||||
+ } else {
|
||||
+ list = new java.util.ArrayList<>();
|
||||
+ }
|
||||
+
|
||||
+ for (RecipeHolder<T> recipeholder : this.byType(type)) {
|
||||
+ if (recipeholder.value().matches(input, world)) {
|
||||
+ list.add(recipeholder);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return list;
|
||||
+ }
|
||||
+ // DivineMC end - Carpet-Fixes - Remove streams to be faster
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 6 Jul 2025 02:23:03 +0300
|
||||
Subject: [PATCH] lithium: faster chunk serialization
|
||||
|
||||
This patch is based on the following mixins and classes:
|
||||
* "net/caffeinemc/mods/lithium/common/world/chunk/CompactingPackedIntegerArray.java"
|
||||
* "net/caffeinemc/mods/lithium/common/world/chunk/LithiumHashPalette.java"
|
||||
* "net/caffeinemc/mods/lithium/mixin/chunk/serialization/SimpleBitStorageMixin.java"
|
||||
* "net/caffeinemc/mods/lithium/mixin/chunk/serialization/PalettedContainerMixin.java"
|
||||
By: Angeline <jellysquid3@users.noreply.github.com>
|
||||
As part of: Lithium (https://github.com/CaffeineMC/lithium)
|
||||
Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/util/BitStorage.java b/net/minecraft/util/BitStorage.java
|
||||
index 02502d50f0255f5bbcc0ecb965abb48cc1a112da..a0a0ec8747cf6477df8943d2268dece8e064cb33 100644
|
||||
--- a/net/minecraft/util/BitStorage.java
|
||||
+++ b/net/minecraft/util/BitStorage.java
|
||||
@@ -38,4 +38,6 @@ public interface BitStorage extends ca.spottedleaf.moonrise.patches.block_counti
|
||||
return ret;
|
||||
}
|
||||
// Paper end - block counting
|
||||
+
|
||||
+ <T> void compact(net.minecraft.world.level.chunk.Palette<T> srcPalette, net.minecraft.world.level.chunk.Palette<T> dstPalette, short[] out); // DivineMC - lithium: faster chunk serialization
|
||||
}
|
||||
diff --git a/net/minecraft/util/SimpleBitStorage.java b/net/minecraft/util/SimpleBitStorage.java
|
||||
index e6306a68c8652d4c5d22d5ecb1416f5f931f76ee..1d8125e23e34a929da6fb4e361eae3ccbaeabce9 100644
|
||||
--- a/net/minecraft/util/SimpleBitStorage.java
|
||||
+++ b/net/minecraft/util/SimpleBitStorage.java
|
||||
@@ -465,4 +465,44 @@ public class SimpleBitStorage implements BitStorage {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - lithium: faster chunk serialization
|
||||
+ @Override
|
||||
+ public <T> void compact(net.minecraft.world.level.chunk.Palette<T> srcPalette, net.minecraft.world.level.chunk.Palette<T> dstPalette, short[] out) {
|
||||
+ if (this.size >= Short.MAX_VALUE) {
|
||||
+ throw new IllegalStateException("Array too large");
|
||||
+ }
|
||||
+
|
||||
+ if (this.size != out.length) {
|
||||
+ throw new IllegalStateException("Array size mismatch");
|
||||
+ }
|
||||
+
|
||||
+ short[] mappings = new short[(int) (this.mask + 1)];
|
||||
+
|
||||
+ int idx = 0;
|
||||
+
|
||||
+ for (long word : this.data) {
|
||||
+ long bits = word;
|
||||
+
|
||||
+ for (int elementIdx = 0; elementIdx < this.valuesPerLong; ++elementIdx) {
|
||||
+ int value = (int) (bits & this.mask);
|
||||
+ int remappedId = mappings[value];
|
||||
+
|
||||
+ if (remappedId == 0) {
|
||||
+ remappedId = dstPalette.idFor(srcPalette.valueFor(value)) + 1;
|
||||
+ mappings[value] = (short) remappedId;
|
||||
+ }
|
||||
+
|
||||
+ out[idx] = (short) (remappedId - 1);
|
||||
+ bits >>= this.bits;
|
||||
+
|
||||
+ ++idx;
|
||||
+
|
||||
+ if (idx >= this.size) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - lithium: faster chunk serialization
|
||||
}
|
||||
diff --git a/net/minecraft/util/ZeroBitStorage.java b/net/minecraft/util/ZeroBitStorage.java
|
||||
index 09fd99c9cbd23b5f3c899bfb00c9b89651948ed8..6e264b311894f510112beb996190f5ff6943e5e8 100644
|
||||
--- a/net/minecraft/util/ZeroBitStorage.java
|
||||
+++ b/net/minecraft/util/ZeroBitStorage.java
|
||||
@@ -80,4 +80,6 @@ public class ZeroBitStorage implements BitStorage {
|
||||
return ret;
|
||||
}
|
||||
// Paper end - block counting
|
||||
+
|
||||
+ @Override public <T> void compact(net.minecraft.world.level.chunk.Palette<T> srcPalette, net.minecraft.world.level.chunk.Palette<T> dstPalette, short[] out) { } // DivineMC - lithium: faster chunk serialization
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
index a251ba67644cd02a0b00d7c8b0e2c64aa5e26291..9d892c1c3890e0aaf13fd5cd7b7d138afeaad260 100644
|
||||
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
@@ -32,6 +32,23 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
private final PalettedContainer.Strategy strategy;
|
||||
//private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
|
||||
|
||||
+ // DivineMC start - lithium: faster chunk serialization
|
||||
+ private static final ThreadLocal<short[]> CACHED_ARRAY_4096 = ThreadLocal.withInitial(() -> new short[4096]);
|
||||
+ private static final ThreadLocal<short[]> CACHED_ARRAY_64 = ThreadLocal.withInitial(() -> new short[64]);
|
||||
+
|
||||
+ private Optional<LongStream> asOptional(long[] data) {
|
||||
+ return Optional.of(Arrays.stream(data));
|
||||
+ }
|
||||
+
|
||||
+ private short[] getOrCreate(int size) {
|
||||
+ return switch (size) {
|
||||
+ case 64 -> CACHED_ARRAY_64.get();
|
||||
+ case 4096 -> CACHED_ARRAY_4096.get();
|
||||
+ default -> new short[size];
|
||||
+ };
|
||||
+ }
|
||||
+ // DivineMC end - lithium: faster chunk serialization
|
||||
+
|
||||
public void acquire() {
|
||||
// this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization
|
||||
}
|
||||
@@ -343,28 +360,49 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
public synchronized PalettedContainerRO.PackedData<T> pack(IdMap<T> registry, PalettedContainer.Strategy strategy) { // Paper - synchronize
|
||||
this.acquire();
|
||||
|
||||
- PalettedContainerRO.PackedData var12;
|
||||
+ // DivineMC start - lithium: faster chunk serialization
|
||||
+ Optional<LongStream> data = Optional.empty();
|
||||
+ List<T> elements = null;
|
||||
try {
|
||||
- HashMapPalette<T> hashMapPalette = new HashMapPalette<>(registry, this.data.storage.getBits(), this.dummyPaletteResize);
|
||||
- int size = strategy.size();
|
||||
- int[] ints = new int[size];
|
||||
- this.data.storage.unpack(ints);
|
||||
- swapPalette(ints, id -> hashMapPalette.idFor(this.data.palette.valueFor(id)));
|
||||
- int i = strategy.calculateBitsForSerialization(registry, hashMapPalette.getSize());
|
||||
- Optional<LongStream> optional;
|
||||
- if (i != 0) {
|
||||
- SimpleBitStorage simpleBitStorage = new SimpleBitStorage(i, size, ints);
|
||||
- optional = Optional.of(Arrays.stream(simpleBitStorage.getRaw()));
|
||||
- } else {
|
||||
- optional = Optional.empty();
|
||||
+ net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<T> hashPalette = null;
|
||||
+
|
||||
+ final Palette<T> palette = this.data.palette();
|
||||
+ final BitStorage storage = this.data.storage();
|
||||
+ if (storage instanceof ZeroBitStorage || palette.getSize() == 1) {
|
||||
+ elements = List.of(palette.valueFor(0));
|
||||
+ } else if (palette instanceof net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<T> lithiumHashPalette) {
|
||||
+ hashPalette = lithiumHashPalette;
|
||||
}
|
||||
|
||||
- var12 = new PalettedContainerRO.PackedData<>(hashMapPalette.getEntries(), optional);
|
||||
+ if (elements == null) {
|
||||
+ net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<T> compactedPalette = new net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<>(registry, storage.getBits(), this.dummyPaletteResize);
|
||||
+ short[] array = this.getOrCreate(strategy.size());
|
||||
+
|
||||
+ storage.compact(this.data.palette(), compactedPalette, array);
|
||||
+
|
||||
+ if (hashPalette != null && hashPalette.getSize() == compactedPalette.getSize() && storage.getBits() == strategy.calculateBitsForSerialization(registry, hashPalette.getSize())) { // paletteSize can de-sync from palette - see https://github.com/CaffeineMC/lithium-fabric/issues/279
|
||||
+ data = this.asOptional(storage.getRaw().clone());
|
||||
+ elements = hashPalette.getElements();
|
||||
+ } else {
|
||||
+ int bits = strategy.calculateBitsForSerialization(registry, compactedPalette.getSize());
|
||||
+ if (bits != 0) {
|
||||
+ SimpleBitStorage copy = new SimpleBitStorage(bits, array.length);
|
||||
+ for (int i = 0; i < array.length; ++i) {
|
||||
+ copy.set(i, array[i]);
|
||||
+ }
|
||||
+
|
||||
+ data = this.asOptional(copy.getRaw());
|
||||
+ }
|
||||
+
|
||||
+ elements = compactedPalette.getElements();
|
||||
+ }
|
||||
+ }
|
||||
} finally {
|
||||
this.release();
|
||||
}
|
||||
|
||||
- return var12;
|
||||
+ return new PalettedContainerRO.PackedData<>(elements, data);
|
||||
+ // DivineMC end - lithium: faster chunk serialization
|
||||
}
|
||||
|
||||
private static <T> void swapPalette(int[] bits, IntUnaryOperator operator) {
|
||||
@@ -404,13 +442,31 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
|
||||
@Override
|
||||
public void count(PalettedContainer.CountConsumer<T> countConsumer) {
|
||||
- if (this.data.palette.getSize() == 1) {
|
||||
- countConsumer.accept(this.data.palette.valueFor(0), this.data.storage.getSize());
|
||||
- } else {
|
||||
- Int2IntOpenHashMap map = new Int2IntOpenHashMap();
|
||||
- this.data.storage.getAll(id -> map.addTo(id, 1));
|
||||
- map.int2IntEntrySet().forEach(idEntry -> countConsumer.accept(this.data.palette.valueFor(idEntry.getIntKey()), idEntry.getIntValue()));
|
||||
+ // DivineMC start - lithium: faster chunk serialization
|
||||
+ int len = this.data.palette().getSize();
|
||||
+
|
||||
+ if (len > 4096) {
|
||||
+ if (this.data.palette.getSize() == 1) {
|
||||
+ countConsumer.accept(this.data.palette.valueFor(0), this.data.storage.getSize());
|
||||
+ } else {
|
||||
+ Int2IntOpenHashMap map = new Int2IntOpenHashMap();
|
||||
+ this.data.storage.getAll(id -> map.addTo(id, 1));
|
||||
+ map.int2IntEntrySet().forEach(idEntry -> countConsumer.accept(this.data.palette.valueFor(idEntry.getIntKey()), idEntry.getIntValue()));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ short[] counts = new short[len];
|
||||
+
|
||||
+ this.data.storage().getAll(i -> counts[i]++);
|
||||
+
|
||||
+ for (int i = 0; i < counts.length; i++) {
|
||||
+ T obj = this.data.palette().valueFor(i);
|
||||
+
|
||||
+ if (obj != null) {
|
||||
+ countConsumer.accept(obj, counts[i]);
|
||||
+ }
|
||||
}
|
||||
+ // DivineMC end - lithium: faster chunk serialization
|
||||
}
|
||||
|
||||
record Configuration<T>(Palette.Factory factory, int bits) {
|
||||
@@ -1,241 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 6 Jul 2025 02:38:39 +0300
|
||||
Subject: [PATCH] C2ME: optimize noise generation
|
||||
|
||||
This patch is based on the following mixins:
|
||||
* "com/ishland/c2me/opts/math/mixin/MixinOctavePerlinNoiseSampler.java"
|
||||
* "com/ishland/c2me/opts/math/mixin/MixinPerlinNoiseSampler.java"
|
||||
By: ishland <ishlandmc@yeah.net>
|
||||
As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric)
|
||||
Licensed under: MIT (https://opensource.org/licenses/MIT)
|
||||
|
||||
diff --git a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java
|
||||
index fb11a2eea540d55e50eab59f9857ca5d99f556f8..c40f65c30b6422a27154295a2b3a63483496dcca 100644
|
||||
--- a/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java
|
||||
+++ b/net/minecraft/world/level/levelgen/synth/ImprovedNoise.java
|
||||
@@ -11,6 +11,27 @@ public final class ImprovedNoise {
|
||||
public final double yo;
|
||||
public final double zo;
|
||||
|
||||
+ // DivineMC start - C2ME: optimize noise generation
|
||||
+ private static final double[] FLAT_SIMPLEX_GRAD = new double[]{
|
||||
+ 1, 1, 0, 0,
|
||||
+ -1, 1, 0, 0,
|
||||
+ 1, -1, 0, 0,
|
||||
+ -1, -1, 0, 0,
|
||||
+ 1, 0, 1, 0,
|
||||
+ -1, 0, 1, 0,
|
||||
+ 1, 0, -1, 0,
|
||||
+ -1, 0, -1, 0,
|
||||
+ 0, 1, 1, 0,
|
||||
+ 0, -1, 1, 0,
|
||||
+ 0, 1, -1, 0,
|
||||
+ 0, -1, -1, 0,
|
||||
+ 1, 1, 0, 0,
|
||||
+ 0, -1, 1, 0,
|
||||
+ -1, 1, 0, 0,
|
||||
+ 0, -1, -1, 0,
|
||||
+ };
|
||||
+ // DivineMC end - C2ME: optimize noise generation
|
||||
+
|
||||
public ImprovedNoise(RandomSource random) {
|
||||
this.xo = random.nextDouble() * 256.0;
|
||||
this.yo = random.nextDouble() * 256.0;
|
||||
@@ -38,9 +59,11 @@ public final class ImprovedNoise {
|
||||
double d = x + this.xo;
|
||||
double d1 = y + this.yo;
|
||||
double d2 = z + this.zo;
|
||||
- int floor = Mth.floor(d);
|
||||
- int floor1 = Mth.floor(d1);
|
||||
- int floor2 = Mth.floor(d2);
|
||||
+ // DivineMC start - C2ME: optimize noise generation
|
||||
+ double floor = Math.floor(d);
|
||||
+ double floor1 = Math.floor(d1);
|
||||
+ double floor2 = Math.floor(d2);
|
||||
+ // DivineMC end - C2ME: optimize noise generation
|
||||
double d3 = d - floor;
|
||||
double d4 = d1 - floor1;
|
||||
double d5 = d2 - floor2;
|
||||
@@ -53,25 +76,27 @@ public final class ImprovedNoise {
|
||||
d6 = d4;
|
||||
}
|
||||
|
||||
- d7 = Mth.floor(d6 / yScale + 1.0E-7F) * yScale;
|
||||
+ d7 = Math.floor(d6 / yScale + 1.0E-7F) * yScale; // DivineMC - C2ME: optimize noise generation
|
||||
} else {
|
||||
d7 = 0.0;
|
||||
}
|
||||
|
||||
- return this.sampleAndLerp(floor, floor1, floor2, d3, d4 - d7, d5, d4);
|
||||
+ return this.sampleAndLerp((int) floor, (int) floor1, (int) floor2, d3, d4 - d7, d5, d4); // DivineMC - C2ME: optimize noise generation
|
||||
}
|
||||
|
||||
public double noiseWithDerivative(double x, double y, double z, double[] values) {
|
||||
double d = x + this.xo;
|
||||
double d1 = y + this.yo;
|
||||
double d2 = z + this.zo;
|
||||
- int floor = Mth.floor(d);
|
||||
- int floor1 = Mth.floor(d1);
|
||||
- int floor2 = Mth.floor(d2);
|
||||
+ // DivineMC start - C2ME: optimize noise generation
|
||||
+ double floor = Math.floor(d);
|
||||
+ double floor1 = Math.floor(d1);
|
||||
+ double floor2 = Math.floor(d2);
|
||||
+ // DivineMC end - C2ME: optimize noise generation
|
||||
double d3 = d - floor;
|
||||
double d4 = d1 - floor1;
|
||||
double d5 = d2 - floor2;
|
||||
- return this.sampleWithDerivative(floor, floor1, floor2, d3, d4, d5, values);
|
||||
+ return this.sampleWithDerivative((int) floor, (int) floor1, (int) floor2, d3, d4, d5, values); // DivineMC - C2ME: optimize noise generation
|
||||
}
|
||||
|
||||
private static double gradDot(int gradIndex, double xFactor, double yFactor, double zFactor) {
|
||||
@@ -83,24 +108,69 @@ public final class ImprovedNoise {
|
||||
}
|
||||
|
||||
private double sampleAndLerp(int gridX, int gridY, int gridZ, double deltaX, double weirdDeltaY, double deltaZ, double deltaY) {
|
||||
- int i = this.p(gridX);
|
||||
- int i1 = this.p(gridX + 1);
|
||||
- int i2 = this.p(i + gridY);
|
||||
- int i3 = this.p(i + gridY + 1);
|
||||
- int i4 = this.p(i1 + gridY);
|
||||
- int i5 = this.p(i1 + gridY + 1);
|
||||
- double d = gradDot(this.p(i2 + gridZ), deltaX, weirdDeltaY, deltaZ);
|
||||
- double d1 = gradDot(this.p(i4 + gridZ), deltaX - 1.0, weirdDeltaY, deltaZ);
|
||||
- double d2 = gradDot(this.p(i3 + gridZ), deltaX, weirdDeltaY - 1.0, deltaZ);
|
||||
- double d3 = gradDot(this.p(i5 + gridZ), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ);
|
||||
- double d4 = gradDot(this.p(i2 + gridZ + 1), deltaX, weirdDeltaY, deltaZ - 1.0);
|
||||
- double d5 = gradDot(this.p(i4 + gridZ + 1), deltaX - 1.0, weirdDeltaY, deltaZ - 1.0);
|
||||
- double d6 = gradDot(this.p(i3 + gridZ + 1), deltaX, weirdDeltaY - 1.0, deltaZ - 1.0);
|
||||
- double d7 = gradDot(this.p(i5 + gridZ + 1), deltaX - 1.0, weirdDeltaY - 1.0, deltaZ - 1.0);
|
||||
- double d8 = Mth.smoothstep(deltaX);
|
||||
- double d9 = Mth.smoothstep(deltaY);
|
||||
- double d10 = Mth.smoothstep(deltaZ);
|
||||
- return Mth.lerp3(d8, d9, d10, d, d1, d2, d3, d4, d5, d6, d7);
|
||||
+ // DivineMC start - C2ME: optimize noise generation
|
||||
+ final int var0 = gridX & 0xFF;
|
||||
+ final int var1 = (gridX + 1) & 0xFF;
|
||||
+ final int var2 = this.p[var0] & 0xFF;
|
||||
+ final int var3 = this.p[var1] & 0xFF;
|
||||
+ final int var4 = (var2 + gridY) & 0xFF;
|
||||
+ final int var5 = (var3 + gridY) & 0xFF;
|
||||
+ final int var6 = (var2 + gridY + 1) & 0xFF;
|
||||
+ final int var7 = (var3 + gridY + 1) & 0xFF;
|
||||
+ final int var8 = this.p[var4] & 0xFF;
|
||||
+ final int var9 = this.p[var5] & 0xFF;
|
||||
+ final int var10 = this.p[var6] & 0xFF;
|
||||
+ final int var11 = this.p[var7] & 0xFF;
|
||||
+
|
||||
+ final int var12 = (var8 + gridZ) & 0xFF;
|
||||
+ final int var13 = (var9 + gridZ) & 0xFF;
|
||||
+ final int var14 = (var10 + gridZ) & 0xFF;
|
||||
+ final int var15 = (var11 + gridZ) & 0xFF;
|
||||
+ final int var16 = (var8 + gridZ + 1) & 0xFF;
|
||||
+ final int var17 = (var9 + gridZ + 1) & 0xFF;
|
||||
+ final int var18 = (var10 + gridZ + 1) & 0xFF;
|
||||
+ final int var19 = (var11 + gridZ + 1) & 0xFF;
|
||||
+ final int var20 = (this.p[var12] & 15) << 2;
|
||||
+ final int var21 = (this.p[var13] & 15) << 2;
|
||||
+ final int var22 = (this.p[var14] & 15) << 2;
|
||||
+ final int var23 = (this.p[var15] & 15) << 2;
|
||||
+ final int var24 = (this.p[var16] & 15) << 2;
|
||||
+ final int var25 = (this.p[var17] & 15) << 2;
|
||||
+ final int var26 = (this.p[var18] & 15) << 2;
|
||||
+ final int var27 = (this.p[var19] & 15) << 2;
|
||||
+ final double var60 = deltaX - 1.0;
|
||||
+ final double var61 = weirdDeltaY - 1.0;
|
||||
+ final double var62 = deltaZ - 1.0;
|
||||
+ final double var87 = FLAT_SIMPLEX_GRAD[(var20) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var20) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var20) | 2] * deltaZ;
|
||||
+ final double var88 = FLAT_SIMPLEX_GRAD[(var21) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var21) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var21) | 2] * deltaZ;
|
||||
+ final double var89 = FLAT_SIMPLEX_GRAD[(var22) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var22) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var22) | 2] * deltaZ;
|
||||
+ final double var90 = FLAT_SIMPLEX_GRAD[(var23) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var23) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var23) | 2] * deltaZ;
|
||||
+ final double var91 = FLAT_SIMPLEX_GRAD[(var24) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var24) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var24) | 2] * var62;
|
||||
+ final double var92 = FLAT_SIMPLEX_GRAD[(var25) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var25) | 1] * weirdDeltaY + FLAT_SIMPLEX_GRAD[(var25) | 2] * var62;
|
||||
+ final double var93 = FLAT_SIMPLEX_GRAD[(var26) | 0] * deltaX + FLAT_SIMPLEX_GRAD[(var26) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var26) | 2] * var62;
|
||||
+ final double var94 = FLAT_SIMPLEX_GRAD[(var27) | 0] * var60 + FLAT_SIMPLEX_GRAD[(var27) | 1] * var61 + FLAT_SIMPLEX_GRAD[(var27) | 2] * var62;
|
||||
+
|
||||
+ final double var95 = deltaX * 6.0 - 15.0;
|
||||
+ final double var96 = deltaY * 6.0 - 15.0;
|
||||
+ final double var97 = deltaZ * 6.0 - 15.0;
|
||||
+ final double var98 = deltaX * var95 + 10.0;
|
||||
+ final double var99 = deltaY * var96 + 10.0;
|
||||
+ final double var100 = deltaZ * var97 + 10.0;
|
||||
+ final double var101 = deltaX * deltaX * deltaX * var98;
|
||||
+ final double var102 = deltaY * deltaY * deltaY * var99;
|
||||
+ final double var103 = deltaZ * deltaZ * deltaZ * var100;
|
||||
+
|
||||
+ final double var113 = var87 + var101 * (var88 - var87);
|
||||
+ final double var114 = var93 + var101 * (var94 - var93);
|
||||
+ final double var115 = var91 + var101 * (var92 - var91);
|
||||
+ final double var116 = var89 + var101 * (var90 - var89);
|
||||
+ final double var117 = var114 - var115;
|
||||
+ final double var118 = var102 * (var116 - var113);
|
||||
+ final double var119 = var102 * var117;
|
||||
+ final double var120 = var113 + var118;
|
||||
+ final double var121 = var115 + var119;
|
||||
+ return var120 + (var103 * (var121 - var120));
|
||||
+ // DivineMC end - C2ME: optimize noise generation
|
||||
}
|
||||
|
||||
private double sampleWithDerivative(int gridX, int gridY, int gridZ, double deltaX, double deltaY, double deltaZ, double[] noiseValues) {
|
||||
diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
|
||||
index da3c26fbad32d75d71f7e59c8c3341316a754756..f05902bb4b0d9e746d0033e73ec9f3b5626a53b5 100644
|
||||
--- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
|
||||
+++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
|
||||
@@ -26,6 +26,7 @@ public class PerlinNoise {
|
||||
private final double lowestFreqValueFactor;
|
||||
private final double lowestFreqInputFactor;
|
||||
private final double maxValue;
|
||||
+ private final double [] amplitudesArray; // DivineMC - C2ME: optimize noise generation
|
||||
|
||||
@Deprecated
|
||||
public static PerlinNoise createLegacyForBlendedNoise(RandomSource random, IntStream octaves) {
|
||||
@@ -127,6 +128,7 @@ public class PerlinNoise {
|
||||
this.lowestFreqInputFactor = Math.pow(2.0, -i);
|
||||
this.lowestFreqValueFactor = Math.pow(2.0, size - 1) / (Math.pow(2.0, size) - 1.0);
|
||||
this.maxValue = this.edgeValue(2.0);
|
||||
+ this.amplitudesArray = this.amplitudes.toDoubleArray(); // DivineMC - C2ME: optimize noise generation
|
||||
}
|
||||
|
||||
protected double maxValue() {
|
||||
@@ -138,7 +140,29 @@ public class PerlinNoise {
|
||||
}
|
||||
|
||||
public double getValue(double x, double y, double z) {
|
||||
- return this.getValue(x, y, z, 0.0, 0.0, false);
|
||||
+ // DivineMC start - C2ME: optimize noise generation
|
||||
+ double d = 0.0;
|
||||
+ double e = this.lowestFreqInputFactor;
|
||||
+ double f = this.lowestFreqValueFactor;
|
||||
+
|
||||
+ final int length = this.noiseLevels.length;
|
||||
+
|
||||
+ for (int i = 0; i < length; i++) {
|
||||
+ ImprovedNoise perlinNoiseSampler = this.noiseLevels[i];
|
||||
+ if (perlinNoiseSampler != null) {
|
||||
+ @SuppressWarnings("deprecation")
|
||||
+ double g = perlinNoiseSampler.noise(
|
||||
+ wrap(x * e), wrap(y * e), wrap(z * e), 0.0, 0.0
|
||||
+ );
|
||||
+ d += this.amplitudesArray[i] * g * f;
|
||||
+ }
|
||||
+
|
||||
+ e *= 2.0;
|
||||
+ f /= 2.0;
|
||||
+ }
|
||||
+
|
||||
+ return d;
|
||||
+ // DivineMC end - C2ME: optimize noise generation
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@@ -187,7 +211,7 @@ public class PerlinNoise {
|
||||
}
|
||||
|
||||
public static double wrap(double value) {
|
||||
- return value - Mth.lfloor(value / 3.3554432E7 + 0.5) * 3.3554432E7;
|
||||
+ return value - Math.floor(value / 3.3554432E7 + 0.5) * 3.3554432E7; // DivineMC - C2ME: optimize noise generation
|
||||
}
|
||||
|
||||
protected int firstOctave() {
|
||||
@@ -1,65 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 6 Jul 2025 02:59:37 +0300
|
||||
Subject: [PATCH] Use Java's Math functions
|
||||
|
||||
|
||||
diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java
|
||||
index e2602c6d817794616eb05a471077447804b835a1..c4d55514a44939c3e6006d9e23b6097b6360853e 100644
|
||||
--- a/net/minecraft/util/Mth.java
|
||||
+++ b/net/minecraft/util/Mth.java
|
||||
@@ -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 - Use Java's Math functions
|
||||
}
|
||||
|
||||
public static int floor(double value) {
|
||||
- int i = (int)value;
|
||||
- return value < i ? i - 1 : i;
|
||||
+ return (int) Math.floor(value); // DivineMC - Use Java's Math functions
|
||||
}
|
||||
|
||||
public static long lfloor(double value) {
|
||||
- long l = (long)value;
|
||||
- return value < l ? l - 1L : l;
|
||||
+ return (long) Math.floor(value); // DivineMC - Use Java's Math functions
|
||||
}
|
||||
|
||||
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 - Use Java's Math functions
|
||||
}
|
||||
|
||||
public static int ceil(double value) {
|
||||
- int i = (int)value;
|
||||
- return value > i ? i + 1 : i;
|
||||
+ return (int) Math.ceil(value); // DivineMC - Use Java's Math functions
|
||||
}
|
||||
|
||||
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 - Use Java's Math functions
|
||||
}
|
||||
|
||||
public static int floorDiv(int dividend, int divisor) {
|
||||
@@ -1,42 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 6 Jul 2025 03:03:04 +0300
|
||||
Subject: [PATCH] Disable leaf decay
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/LeavesBlock.java b/net/minecraft/world/level/block/LeavesBlock.java
|
||||
index 010e9814490ffaa153df5b7865da17e2a84c7e82..f43dbc0fc05f549521490595fe594c424b2e8a87 100644
|
||||
--- a/net/minecraft/world/level/block/LeavesBlock.java
|
||||
+++ b/net/minecraft/world/level/block/LeavesBlock.java
|
||||
@@ -70,12 +70,29 @@ public abstract class LeavesBlock extends Block implements SimpleWaterloggedBloc
|
||||
}
|
||||
|
||||
protected boolean decaying(BlockState state) {
|
||||
- return !state.getValue(PERSISTENT) && state.getValue(DISTANCE) == 7;
|
||||
+ return !org.bxteam.divinemc.config.DivineConfig.FixesCategory.disableLeafDecay && !state.getValue(PERSISTENT) && state.getValue(DISTANCE) == 7; // DivineMC - Disable leaf decay
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
- level.setBlock(pos, updateDistance(state, level, pos), 3);
|
||||
+ // DivineMC start - Disable leaf decay
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.disableLeafDecay) return; // DivineMC - Disable leaf decay
|
||||
+ int newValue = 7;
|
||||
+ int oldValue = state.getValue(DISTANCE);
|
||||
+ BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
|
||||
+
|
||||
+ for (Direction direction : Direction.values()) {
|
||||
+ mutable.setWithOffset(pos, direction);
|
||||
+ newValue = Math.min(newValue, getDistanceAt(level.getBlockState(mutable)) + 1);
|
||||
+ if (newValue == 1) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (newValue != oldValue) {
|
||||
+ level.setBlock(pos, state.setValue(DISTANCE, newValue), 3);
|
||||
+ }
|
||||
+ // DivineMC end - Disable leaf decay
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,659 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 16:05:57 +0300
|
||||
Subject: [PATCH] Optimize entities
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/AgeableMob.java b/net/minecraft/world/entity/AgeableMob.java
|
||||
index 04875840085541ebfc7014868beec49bb7ab9976..caea723a4614d3c406dbce71a392716b7442987c 100644
|
||||
--- a/net/minecraft/world/entity/AgeableMob.java
|
||||
+++ b/net/minecraft/world/entity/AgeableMob.java
|
||||
@@ -125,6 +125,16 @@ public abstract class AgeableMob extends PathfinderMob {
|
||||
public void onSyncedDataUpdated(EntityDataAccessor<?> key) {
|
||||
if (DATA_BABY_ID.equals(key)) {
|
||||
this.refreshDimensions();
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ if (isBaby()) {
|
||||
+ org.bxteam.divinemc.util.entity.SensorHelper.enableSensor(this, net.minecraft.world.entity.ai.sensing.SensorType.NEAREST_ADULT, true);
|
||||
+ } else {
|
||||
+ org.bxteam.divinemc.util.entity.SensorHelper.disableSensor(this, net.minecraft.world.entity.ai.sensing.SensorType.NEAREST_ADULT);
|
||||
+ if (this.getBrain().hasMemoryValue(net.minecraft.world.entity.ai.memory.MemoryModuleType.NEAREST_VISIBLE_ADULT)) {
|
||||
+ this.getBrain().setMemory(net.minecraft.world.entity.ai.memory.MemoryModuleType.NEAREST_VISIBLE_ADULT, java.util.Optional.empty());
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Optimize entities
|
||||
}
|
||||
|
||||
super.onSyncedDataUpdated(key);
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 989043d73af2c719e6c36ac5d4c35e7d31d3410c..6c7f0c04e94eb3fa2f22d2637a1c2abceb1563f4 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1687,6 +1687,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
|
||||
private void checkInsideBlocks(Vec3 vec3, Vec3 vec31, InsideBlockEffectApplier.StepBasedCollector stepBasedCollector, LongSet set) {
|
||||
AABB aabb = this.makeBoundingBox(vec31).deflate(1.0E-5F);
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ final net.minecraft.world.level.chunk.ChunkAccess[] cachedChunk = new net.minecraft.world.level.chunk.ChunkAccess[] { null };
|
||||
+ final long[] lastChunkPos = { Long.MIN_VALUE };
|
||||
+ // DivineMC end - Optimize entities
|
||||
BlockGetter.forEachBlockIntersectedBetween(
|
||||
vec3,
|
||||
vec31,
|
||||
@@ -1695,7 +1699,21 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
if (!this.isAlive()) {
|
||||
return false;
|
||||
} else {
|
||||
- BlockState blockState = this.level().getBlockState(pos);
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ final int chunkX = pos.getX() >> 4;
|
||||
+ final int chunkZ = pos.getZ() >> 4;
|
||||
+ final long chunkLongPos = ((long) chunkZ << 32) | (chunkX & 0xFFFFFFFFL);
|
||||
+ if (lastChunkPos[0] != chunkLongPos) {
|
||||
+ // update cache, this is a different chunk than previous
|
||||
+ lastChunkPos[0] = chunkLongPos;
|
||||
+ cachedChunk[0] = this.level.getChunkIfLoaded(chunkX, chunkZ);
|
||||
+ }
|
||||
+ net.minecraft.world.level.chunk.ChunkAccess chunk = cachedChunk[0];
|
||||
+ if (chunk == null) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ BlockState blockState = chunk.getBlockState(pos);
|
||||
+ // DivineMC end - Optimize entities
|
||||
if (blockState.isAir()) {
|
||||
this.debugBlockIntersection(pos, false, false);
|
||||
return true;
|
||||
@@ -1738,6 +1756,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public boolean collidedWithFluid(FluidState fluid, BlockPos pos, Vec3 from, Vec3 to) {
|
||||
+ if (fluid.isEmpty()) return false; // DivineMC - Optimize entities
|
||||
AABB aabb = fluid.getAABB(this.level(), pos);
|
||||
return aabb != null && this.collidedWithShapeMovingFrom(from, to, List.of(aabb));
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/InsideBlockEffectApplier.java b/net/minecraft/world/entity/InsideBlockEffectApplier.java
|
||||
index a7bc5ead2062504ceac95f603bc1ca8d4290bbfd..533c790ce305043f53c76f03a12676c567118a44 100644
|
||||
--- a/net/minecraft/world/entity/InsideBlockEffectApplier.java
|
||||
+++ b/net/minecraft/world/entity/InsideBlockEffectApplier.java
|
||||
@@ -31,68 +31,115 @@ public interface InsideBlockEffectApplier {
|
||||
|
||||
public static class StepBasedCollector implements InsideBlockEffectApplier {
|
||||
private static final InsideBlockEffectType[] APPLY_ORDER = InsideBlockEffectType.values();
|
||||
- private static final int NO_STEP = -1;
|
||||
- private final Map<InsideBlockEffectType, Consumer<Entity>> effectsInStep = new java.util.EnumMap<>(InsideBlockEffectType.class); // Paper - track position inside effect was triggered on
|
||||
- private final Map<InsideBlockEffectType, List<Consumer<Entity>>> beforeEffectsInStep = Util.makeEnumMap(
|
||||
- InsideBlockEffectType.class, insideBlockEffectType -> new ArrayList<>()
|
||||
- );
|
||||
- private final Map<InsideBlockEffectType, List<Consumer<Entity>>> afterEffectsInStep = Util.makeEnumMap(
|
||||
- InsideBlockEffectType.class, insideBlockEffectType -> new ArrayList<>()
|
||||
- );
|
||||
- private final List<Consumer<Entity>> finalEffects = new ArrayList<>();
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ private final Consumer<Entity>[] effectsInStep = new Consumer[APPLY_ORDER.length];
|
||||
+ private final it.unimi.dsi.fastutil.objects.ObjectArrayList<Consumer<Entity>>[] beforeEffectsInStep = new it.unimi.dsi.fastutil.objects.ObjectArrayList[APPLY_ORDER.length];
|
||||
+ private final it.unimi.dsi.fastutil.objects.ObjectArrayList<Consumer<Entity>>[] afterEffectsInStep = new it.unimi.dsi.fastutil.objects.ObjectArrayList[APPLY_ORDER.length];
|
||||
+ private final it.unimi.dsi.fastutil.objects.ObjectArrayList<Consumer<Entity>> finalEffects = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ // DivineMC end - Optimize entities
|
||||
private int lastStep = -1;
|
||||
|
||||
- public void advanceStep(int step, net.minecraft.core.BlockPos pos) { // Paper - track position inside effect was triggered on
|
||||
- this.currentBlockPos = pos; // Paper - track position inside effect was triggered on
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ public StepBasedCollector() {
|
||||
+ for (int i = 0; i < APPLY_ORDER.length; i++) {
|
||||
+ beforeEffectsInStep[i] = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(2);
|
||||
+ afterEffectsInStep[i] = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(2);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void advanceStep(int step, net.minecraft.core.BlockPos pos) {
|
||||
+ this.currentBlockPos = pos;
|
||||
if (this.lastStep != step) {
|
||||
this.lastStep = step;
|
||||
this.flushStep();
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Optimize entities
|
||||
|
||||
public void applyAndClear(Entity entity) {
|
||||
this.flushStep();
|
||||
|
||||
- for (Consumer<Entity> consumer : this.finalEffects) {
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ List<Consumer<Entity>> effects = this.finalEffects;
|
||||
+ int size = effects.size();
|
||||
+
|
||||
+ if (size == 0) {
|
||||
+ this.lastStep = -1;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!entity.isAlive()) {
|
||||
+ effects.clear();
|
||||
+ this.lastStep = -1;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ int i = 0;
|
||||
+ while (i < size - 3) {
|
||||
+ effects.get(i++).accept(entity);
|
||||
+ effects.get(i++).accept(entity);
|
||||
+ effects.get(i++).accept(entity);
|
||||
+ effects.get(i++).accept(entity);
|
||||
if (!entity.isAlive()) {
|
||||
break;
|
||||
}
|
||||
+ }
|
||||
|
||||
- consumer.accept(entity);
|
||||
+ if (entity.isAlive()) {
|
||||
+ for (; i < size; i++) {
|
||||
+ effects.get(i).accept(entity);
|
||||
+ if (!entity.isAlive()) {
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
- this.finalEffects.clear();
|
||||
+ effects.clear();
|
||||
+ // DivineMC end - Optimize entities
|
||||
this.lastStep = -1;
|
||||
}
|
||||
|
||||
private void flushStep() {
|
||||
- for (InsideBlockEffectType insideBlockEffectType : APPLY_ORDER) {
|
||||
- List<Consumer<Entity>> list = this.beforeEffectsInStep.get(insideBlockEffectType);
|
||||
- this.finalEffects.addAll(list);
|
||||
- list.clear();
|
||||
- if (this.effectsInStep.remove(insideBlockEffectType) instanceof final Consumer<Entity> recordedEffect) { // Paper - track position inside effect was triggered on - better than null check to avoid diff.
|
||||
- this.finalEffects.add(recordedEffect); // Paper - track position inside effect was triggered on
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ final int len = APPLY_ORDER.length;
|
||||
+ final Consumer<Entity>[] effectArr = this.effectsInStep;
|
||||
+ final List<Consumer<Entity>> finalList = this.finalEffects;
|
||||
+
|
||||
+ for (int i = 0; i < len; i++) {
|
||||
+ List<Consumer<Entity>> beforeList = this.beforeEffectsInStep[i];
|
||||
+ if (!beforeList.isEmpty()) {
|
||||
+ finalList.addAll(beforeList);
|
||||
+ beforeList.clear();
|
||||
}
|
||||
|
||||
- List<Consumer<Entity>> list1 = this.afterEffectsInStep.get(insideBlockEffectType);
|
||||
- this.finalEffects.addAll(list1);
|
||||
- list1.clear();
|
||||
+ Consumer<Entity> effect = effectArr[i];
|
||||
+ if (effect != null) {
|
||||
+ finalList.add(effect);
|
||||
+ effectArr[i] = null;
|
||||
+ }
|
||||
+
|
||||
+ List<Consumer<Entity>> afterList = this.afterEffectsInStep[i];
|
||||
+ if (!afterList.isEmpty()) {
|
||||
+ finalList.addAll(afterList);
|
||||
+ afterList.clear();
|
||||
+ }
|
||||
}
|
||||
+ // DivineMC end - Optimize entities
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(InsideBlockEffectType type) {
|
||||
- this.effectsInStep.put(type, recorded(type)); // Paper - track position inside effect was triggered on
|
||||
+ effectsInStep[type.ordinal()] = recorded(type); // DivineMC - Optimize entities
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runBefore(InsideBlockEffectType type, Consumer<Entity> effect) {
|
||||
- this.beforeEffectsInStep.get(type).add(effect);
|
||||
+ beforeEffectsInStep[type.ordinal()].add(effect); // DivineMC - Optimize entities
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runAfter(InsideBlockEffectType type, Consumer<Entity> effect) {
|
||||
- this.afterEffectsInStep.get(type).add(effect);
|
||||
+ afterEffectsInStep[type.ordinal()].add(effect); // DivineMC - Optimize entities
|
||||
}
|
||||
|
||||
// Paper start - track position inside effect was triggered on
|
||||
diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java
|
||||
index 99ced3cb7d3d4c7a80d890689d7585fa9acd17f6..f839b1429c8ef2a630ae3d6e6a02678161aa5858 100644
|
||||
--- a/net/minecraft/world/entity/ai/Brain.java
|
||||
+++ b/net/minecraft/world/entity/ai/Brain.java
|
||||
@@ -45,16 +45,75 @@ public class Brain<E extends LivingEntity> {
|
||||
static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final Supplier<Codec<Brain<E>>> codec;
|
||||
private static final int SCHEDULE_UPDATE_DELAY = 20;
|
||||
- private final Map<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> memories = Maps.newHashMap();
|
||||
- public final Map<SensorType<? extends Sensor<? super E>>, Sensor<? super E>> sensors = Maps.newLinkedHashMap();
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ private Map<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> memories = Maps.newConcurrentMap();
|
||||
+ public Map<SensorType<? extends Sensor<? super E>>, Sensor<? super E>> sensors = Maps.newLinkedHashMap();
|
||||
private final Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> availableBehaviorsByPriority = Maps.newTreeMap();
|
||||
private Schedule schedule = Schedule.EMPTY;
|
||||
- private final Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> activityRequirements = Maps.newHashMap();
|
||||
+ private Map<Activity, Set<Pair<MemoryModuleType<?>, MemoryStatus>>> activityRequirements = Maps.newHashMap();
|
||||
+ // DivineMC end - Optimize entities
|
||||
private final Map<Activity, Set<MemoryModuleType<?>>> activityMemoriesToEraseWhenStopped = Maps.newHashMap();
|
||||
private Set<Activity> coreActivities = Sets.newHashSet();
|
||||
private final Set<Activity> activeActivities = Sets.newHashSet();
|
||||
private Activity defaultActivity = Activity.IDLE;
|
||||
private long lastScheduleUpdate = -9999L;
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ private java.util.ArrayList<net.minecraft.world.entity.ai.behavior.BehaviorControl<? super E>> possibleTasks;
|
||||
+ private org.bxteam.divinemc.util.collections.MaskedList<net.minecraft.world.entity.ai.behavior.BehaviorControl<? super E>> runningTasks;
|
||||
+
|
||||
+ private void onTasksChanged() {
|
||||
+ this.runningTasks = null;
|
||||
+ this.onPossibleActivitiesChanged();
|
||||
+ }
|
||||
+
|
||||
+ private void onPossibleActivitiesChanged() {
|
||||
+ this.possibleTasks = null;
|
||||
+ }
|
||||
+
|
||||
+ private void initPossibleTasks() {
|
||||
+ this.possibleTasks = new java.util.ArrayList<>();
|
||||
+ for (Map<Activity, Set<BehaviorControl<? super E>>> map : this.availableBehaviorsByPriority.values()) {
|
||||
+ for (Map.Entry<Activity, Set<BehaviorControl<? super E>>> entry : map.entrySet()) {
|
||||
+ Activity activity = entry.getKey();
|
||||
+ if (!this.activeActivities.contains(activity)) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ Set<BehaviorControl<? super E>> set = entry.getValue();
|
||||
+ for (BehaviorControl<? super E> task : set) {
|
||||
+ //noinspection UseBulkOperation
|
||||
+ this.possibleTasks.add(task);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private java.util.ArrayList<net.minecraft.world.entity.ai.behavior.BehaviorControl<? super E>> getPossibleTasks() {
|
||||
+ if (this.possibleTasks == null) {
|
||||
+ this.initPossibleTasks();
|
||||
+ }
|
||||
+ return this.possibleTasks;
|
||||
+ }
|
||||
+
|
||||
+ private org.bxteam.divinemc.util.collections.MaskedList<net.minecraft.world.entity.ai.behavior.BehaviorControl<? super E>> getCurrentlyRunningTasks() {
|
||||
+ if (this.runningTasks == null) {
|
||||
+ this.initCurrentlyRunningTasks();
|
||||
+ }
|
||||
+ return this.runningTasks;
|
||||
+ }
|
||||
+
|
||||
+ private void initCurrentlyRunningTasks() {
|
||||
+ org.bxteam.divinemc.util.collections.MaskedList<net.minecraft.world.entity.ai.behavior.BehaviorControl<? super E>> list = new org.bxteam.divinemc.util.collections.MaskedList<>(new ObjectArrayList<>(), false);
|
||||
+
|
||||
+ for (Map<Activity, Set<BehaviorControl<? super E>>> map : this.availableBehaviorsByPriority.values()) {
|
||||
+ for (Set<BehaviorControl<? super E>> set : map.values()) {
|
||||
+ for (BehaviorControl<? super E> task : set) {
|
||||
+ list.addOrSet(task, task.getStatus() == Behavior.Status.RUNNING);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ this.runningTasks = list;
|
||||
+ }
|
||||
+ // DivineMC end - Optimize entities
|
||||
|
||||
public static <E extends LivingEntity> Brain.Provider<E> provider(
|
||||
Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes
|
||||
@@ -146,6 +205,12 @@ public class Brain<E extends LivingEntity> {
|
||||
for (Brain.MemoryValue<?> memoryValue : memoryValues) {
|
||||
memoryValue.setMemoryInternal(this);
|
||||
}
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ this.onTasksChanged();
|
||||
+ this.memories = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(this.memories);
|
||||
+ this.sensors = new it.unimi.dsi.fastutil.objects.Reference2ReferenceLinkedOpenHashMap<>(this.sensors);
|
||||
+ this.activityRequirements = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(this.activityRequirements);
|
||||
+ // DivineMC end - Optimize entities
|
||||
}
|
||||
|
||||
public <T> DataResult<T> serializeStart(DynamicOps<T> ops) {
|
||||
@@ -165,6 +230,7 @@ public class Brain<E extends LivingEntity> {
|
||||
}
|
||||
|
||||
public <U> void eraseMemory(MemoryModuleType<U> type) {
|
||||
+ if (!this.memories.containsKey(type)) return; // DivineMC - Optimize entities
|
||||
this.setMemory(type, Optional.empty());
|
||||
}
|
||||
|
||||
@@ -180,16 +246,33 @@ public class Brain<E extends LivingEntity> {
|
||||
this.setMemoryInternal(memoryType, memory.map(ExpirableValue::of));
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize entities
|
||||
<U> void setMemoryInternal(MemoryModuleType<U> memoryType, Optional<? extends ExpirableValue<?>> memory) {
|
||||
+ if (memory.isPresent() && this.isEmptyCollection(memory.get().getValue())) {
|
||||
+ this.eraseMemory(memoryType);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (this.memories.containsKey(memoryType)) {
|
||||
- if (memory.isPresent() && this.isEmptyCollection(memory.get().getValue())) {
|
||||
- this.eraseMemory(memoryType);
|
||||
- } else {
|
||||
- this.memories.put(memoryType, memory);
|
||||
- }
|
||||
+ this.increaseMemoryModificationCount(this.memories, memoryType, memory);
|
||||
}
|
||||
}
|
||||
|
||||
+ private long memoryModCount = 1;
|
||||
+
|
||||
+ public long getMemoryModCount() {
|
||||
+ return memoryModCount;
|
||||
+ }
|
||||
+
|
||||
+ private <T, A> Object increaseMemoryModificationCount(Map<T, A> map, T key, A newValue) {
|
||||
+ Object oldValue = map.put(key, newValue);
|
||||
+ if (oldValue == null || ((Optional<?>) oldValue).isPresent() != ((Optional<?>) newValue).isPresent()) {
|
||||
+ this.memoryModCount++;
|
||||
+ }
|
||||
+ return oldValue;
|
||||
+ }
|
||||
+ // DivineMC end - Optimize entities
|
||||
+
|
||||
public <U> Optional<U> getMemory(MemoryModuleType<U> type) {
|
||||
Optional<? extends ExpirableValue<?>> optional = this.memories.get(type);
|
||||
if (optional == null) {
|
||||
@@ -251,19 +334,7 @@ public class Brain<E extends LivingEntity> {
|
||||
@Deprecated
|
||||
@VisibleForDebug
|
||||
public List<BehaviorControl<? super E>> getRunningBehaviors() {
|
||||
- List<BehaviorControl<? super E>> list = new ObjectArrayList<>();
|
||||
-
|
||||
- for (Map<Activity, Set<BehaviorControl<? super E>>> map : this.availableBehaviorsByPriority.values()) {
|
||||
- for (Set<BehaviorControl<? super E>> set : map.values()) {
|
||||
- for (BehaviorControl<? super E> behaviorControl : set) {
|
||||
- if (behaviorControl.getStatus() == Behavior.Status.RUNNING) {
|
||||
- list.add(behaviorControl);
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- return list;
|
||||
+ return this.getCurrentlyRunningTasks(); // DivineMC - Optimize entities
|
||||
}
|
||||
|
||||
public void useDefaultActivity() {
|
||||
@@ -294,6 +365,7 @@ public class Brain<E extends LivingEntity> {
|
||||
this.activeActivities.clear();
|
||||
this.activeActivities.addAll(this.coreActivities);
|
||||
this.activeActivities.add(activity);
|
||||
+ this.onPossibleActivitiesChanged(); // DivineMC - Optimize entities
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,11 +455,13 @@ public class Brain<E extends LivingEntity> {
|
||||
.computeIfAbsent(activity, activity1 -> Sets.newLinkedHashSet())
|
||||
.add((BehaviorControl<? super E>)pair.getSecond());
|
||||
}
|
||||
+ this.onTasksChanged(); // DivineMC - Optimize entities
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void removeAllBehaviors() {
|
||||
this.availableBehaviorsByPriority.clear();
|
||||
+ this.onTasksChanged(); // DivineMC - Optimize entities
|
||||
}
|
||||
|
||||
public boolean isActive(Activity activity) {
|
||||
@@ -404,6 +478,7 @@ public class Brain<E extends LivingEntity> {
|
||||
}
|
||||
}
|
||||
|
||||
+ brain.memoryModCount = this.memoryModCount + 1; // DivineMC - Optimize entities
|
||||
return brain;
|
||||
}
|
||||
|
||||
@@ -438,31 +513,38 @@ public class Brain<E extends LivingEntity> {
|
||||
|
||||
for (BehaviorControl<? super E> behaviorControl : this.getRunningBehaviors()) {
|
||||
behaviorControl.doStop(level, owner, gameTime);
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ if (this.runningTasks != null) {
|
||||
+ this.runningTasks.setVisible(behaviorControl, false);
|
||||
+ }
|
||||
+ // DivineMC end - Optimize entities
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize entities
|
||||
private void startEachNonRunningBehavior(ServerLevel level, E entity) {
|
||||
- long gameTime = level.getGameTime();
|
||||
-
|
||||
- for (Map<Activity, Set<BehaviorControl<? super E>>> map : this.availableBehaviorsByPriority.values()) {
|
||||
- for (Entry<Activity, Set<BehaviorControl<? super E>>> entry : map.entrySet()) {
|
||||
- Activity activity = entry.getKey();
|
||||
- if (this.activeActivities.contains(activity)) {
|
||||
- for (BehaviorControl<? super E> behaviorControl : entry.getValue()) {
|
||||
- if (behaviorControl.getStatus() == Behavior.Status.STOPPED) {
|
||||
- behaviorControl.tryStart(level, entity, gameTime);
|
||||
- }
|
||||
- }
|
||||
+ long startTime = level.getGameTime();
|
||||
+ for (BehaviorControl<? super E> task : this.getPossibleTasks()) {
|
||||
+ if (task.getStatus() == Behavior.Status.STOPPED) {
|
||||
+ task.tryStart(level, entity, startTime);
|
||||
+ if (this.runningTasks != null && task.getStatus() == Behavior.Status.RUNNING) {
|
||||
+ this.runningTasks.setVisible(task, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Optimize entities
|
||||
|
||||
private void tickEachRunningBehavior(ServerLevel level, E entity) {
|
||||
long gameTime = level.getGameTime();
|
||||
|
||||
for (BehaviorControl<? super E> behaviorControl : this.getRunningBehaviors()) {
|
||||
behaviorControl.tickOrStop(level, entity, gameTime);
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ if (this.runningTasks != null && behaviorControl.getStatus() != Behavior.Status.RUNNING) {
|
||||
+ this.runningTasks.setVisible(behaviorControl, false);
|
||||
+ }
|
||||
+ // DivineMC end - Optimize entities
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/Behavior.java b/net/minecraft/world/entity/ai/behavior/Behavior.java
|
||||
index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..02508662c722a515cfd78f872c8ba8bbffd8b6fb 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/Behavior.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/Behavior.java
|
||||
@@ -14,6 +14,10 @@ public abstract class Behavior<E extends LivingEntity> implements BehaviorContro
|
||||
private long endTimestamp;
|
||||
private final int minDuration;
|
||||
private final int maxDuration;
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ private long cachedMemoryModCount = -1;
|
||||
+ private boolean cachedHasRequiredMemoryState;
|
||||
+ // DivineMC end - Optimize entities
|
||||
private final String configKey; // Paper - configurable behavior tick rate and timings
|
||||
|
||||
public Behavior(Map<MemoryModuleType<?>, MemoryStatus> entryCondition) {
|
||||
@@ -27,7 +31,7 @@ public abstract class Behavior<E extends LivingEntity> implements BehaviorContro
|
||||
public Behavior(Map<MemoryModuleType<?>, MemoryStatus> entryCondition, int minDuration, int maxDuration) {
|
||||
this.minDuration = minDuration;
|
||||
this.maxDuration = maxDuration;
|
||||
- this.entryCondition = entryCondition;
|
||||
+ this.entryCondition = new it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap<>(entryCondition); // DivineMC - Optimize entities - Use fastutil
|
||||
// Paper start - configurable behavior tick rate and timings
|
||||
String key = io.papermc.paper.util.MappingEnvironment.reobf() ? io.papermc.paper.util.ObfHelper.INSTANCE.deobfClassName(this.getClass().getName()) : this.getClass().getName();
|
||||
int lastSeparator = key.lastIndexOf('.');
|
||||
@@ -103,17 +107,26 @@ public abstract class Behavior<E extends LivingEntity> implements BehaviorContro
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
- protected boolean hasRequiredMemories(E owner) {
|
||||
- for (Entry<MemoryModuleType<?>, MemoryStatus> entry : this.entryCondition.entrySet()) {
|
||||
- MemoryModuleType<?> memoryModuleType = entry.getKey();
|
||||
- MemoryStatus memoryStatus = entry.getValue();
|
||||
- if (!owner.getBrain().checkMemory(memoryModuleType, memoryStatus)) {
|
||||
- return false;
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ public boolean hasRequiredMemories(E entity) {
|
||||
+ net.minecraft.world.entity.ai.Brain<?> brain = entity.getBrain();
|
||||
+ long modCount = brain.getMemoryModCount();
|
||||
+ if (this.cachedMemoryModCount == modCount) {
|
||||
+ return this.cachedHasRequiredMemoryState;
|
||||
+ }
|
||||
+ this.cachedMemoryModCount = modCount;
|
||||
+
|
||||
+ it.unimi.dsi.fastutil.objects.ObjectIterator<it.unimi.dsi.fastutil.objects.Reference2ObjectMap.Entry<net.minecraft.world.entity.ai.memory.MemoryModuleType<?>, net.minecraft.world.entity.ai.memory.MemoryStatus>> fastIterator = ((it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap<net.minecraft.world.entity.ai.memory.MemoryModuleType<?>, net.minecraft.world.entity.ai.memory.MemoryStatus>) this.entryCondition).reference2ObjectEntrySet().fastIterator();
|
||||
+ while (fastIterator.hasNext()) {
|
||||
+ it.unimi.dsi.fastutil.objects.Reference2ObjectMap.Entry<MemoryModuleType<?>, MemoryStatus> entry = fastIterator.next();
|
||||
+ if (!brain.checkMemory(entry.getKey(), entry.getValue())) {
|
||||
+ return this.cachedHasRequiredMemoryState = false;
|
||||
}
|
||||
}
|
||||
|
||||
- return true;
|
||||
+ return this.cachedHasRequiredMemoryState = true;
|
||||
}
|
||||
+ // DivineMC end - Optimize entities
|
||||
|
||||
public static enum Status {
|
||||
STOPPED,
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java b/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
|
||||
index 977afa268838304abdb34be253ca36ac1c22e99f..9fdb2ce7b72d0a10c2148027990a0048ca93f976 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
|
||||
@@ -119,6 +119,12 @@ public class LongJumpToRandomPos<E extends Mob> extends Behavior<E> {
|
||||
int x = blockPos.getX();
|
||||
int y = blockPos.getY();
|
||||
int z = blockPos.getZ();
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ if (this.maxLongJumpWidth < 128 && this.maxLongJumpHeight < 128) {
|
||||
+ this.jumpCandidates = org.bxteam.divinemc.util.collections.LongJumpChoiceList.forCenter(blockPos, (byte) this.maxLongJumpWidth, (byte) this.maxLongJumpHeight);
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Optimize entities
|
||||
this.jumpCandidates = BlockPos.betweenClosedStream(
|
||||
x - this.maxLongJumpWidth,
|
||||
y - this.maxLongJumpHeight,
|
||||
@@ -174,12 +180,25 @@ public class LongJumpToRandomPos<E extends Mob> extends Behavior<E> {
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize entities
|
||||
protected Optional<LongJumpToRandomPos.PossibleJump> getJumpCandidate(ServerLevel level) {
|
||||
- Optional<LongJumpToRandomPos.PossibleJump> randomItem = WeightedRandom.getRandomItem(
|
||||
- level.random, this.jumpCandidates, LongJumpToRandomPos.PossibleJump::weight
|
||||
- );
|
||||
- randomItem.ifPresent(this.jumpCandidates::remove);
|
||||
- return randomItem;
|
||||
+ Optional<LongJumpToRandomPos.PossibleJump> optional = getRandomFast(level.random, this.jumpCandidates);
|
||||
+ skipRemoveIfAlreadyRemoved(optional, this.jumpCandidates::remove);
|
||||
+ return optional;
|
||||
+ }
|
||||
+
|
||||
+ private Optional<LongJumpToRandomPos.PossibleJump> getRandomFast(net.minecraft.util.RandomSource random, List<LongJumpToRandomPos.PossibleJump> pool) {
|
||||
+ if (pool instanceof org.bxteam.divinemc.util.collections.LongJumpChoiceList longJumpChoiceList) {
|
||||
+ return Optional.ofNullable(longJumpChoiceList.removeRandomWeightedByDistanceSq(random));
|
||||
+ } else {
|
||||
+ return WeightedRandom.getRandomItem(random, pool, LongJumpToRandomPos.PossibleJump::weight);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void skipRemoveIfAlreadyRemoved(Optional<LongJumpToRandomPos.PossibleJump> result, java.util.function.Consumer<? super net.minecraft.world.entity.ai.behavior.LongJumpToRandomPos.PossibleJump> removeAction) {
|
||||
+ if (!(this.jumpCandidates instanceof org.bxteam.divinemc.util.collections.LongJumpChoiceList)) {
|
||||
+ result.ifPresent(removeAction);
|
||||
+ }
|
||||
}
|
||||
|
||||
private boolean isAcceptableLandingPosition(ServerLevel level, E entity, BlockPos pos) {
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
|
||||
index b0c5e41fefc7c9adf1a61bd5b52861736657d37e..dfc62772d5617f0dce72b45a1bebf1b2f051efd5 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/NearestLivingEntitySensor.java
|
||||
@@ -17,10 +17,10 @@ public class NearestLivingEntitySensor<T extends LivingEntity> extends Sensor<T>
|
||||
protected void doTick(ServerLevel level, T entity) {
|
||||
double attributeValue = entity.getAttributeValue(Attributes.FOLLOW_RANGE);
|
||||
AABB aabb = entity.getBoundingBox().inflate(attributeValue, attributeValue, attributeValue);
|
||||
- List<LivingEntity> entitiesOfClass = level.getEntitiesOfClass(
|
||||
+ it.unimi.dsi.fastutil.objects.ObjectArrayList<LivingEntity> entitiesOfClass = (it.unimi.dsi.fastutil.objects.ObjectArrayList<LivingEntity>) level.getEntitiesOfClass( // DivineMC - Optimize collections
|
||||
LivingEntity.class, aabb, matchableEntity -> matchableEntity != entity && matchableEntity.isAlive()
|
||||
);
|
||||
- entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
|
||||
+ entitiesOfClass.unstableSort(Comparator.comparingDouble(entity::distanceToSqr)); // DivineMC - Optimize collections
|
||||
Brain<?> brain = entity.getBrain();
|
||||
brain.setMemory(MemoryModuleType.NEAREST_LIVING_ENTITIES, entitiesOfClass);
|
||||
brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_LIVING_ENTITIES, new NearestVisibleLivingEntities(level, entity, entitiesOfClass));
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java b/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java
|
||||
index 24d1928445b5571e040a2b12d5c82e77a880d9bd..dac0a23aebf2dea1972c07d5c82079da7c9837ac 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/VillagerBabiesSensor.java
|
||||
@@ -21,9 +21,22 @@ public class VillagerBabiesSensor extends Sensor<LivingEntity> {
|
||||
entity.getBrain().setMemory(MemoryModuleType.VISIBLE_VILLAGER_BABIES, this.getNearestVillagerBabies(entity));
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize baby villager sensor
|
||||
private List<LivingEntity> getNearestVillagerBabies(LivingEntity livingEntity) {
|
||||
- return ImmutableList.copyOf(this.getVisibleEntities(livingEntity).findAll(this::isVillagerBaby));
|
||||
+ NearestVisibleLivingEntities visibleEntities = this.getVisibleEntities(livingEntity);
|
||||
+ ImmutableList.Builder<LivingEntity> babies = ImmutableList.builder();
|
||||
+
|
||||
+ for (LivingEntity target : visibleEntities.nearbyEntities) {
|
||||
+ if (target.getType() == EntityType.VILLAGER
|
||||
+ && target.isBaby()
|
||||
+ && visibleEntities.lineOfSightTest.test(target)) {
|
||||
+ babies.add(target);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return babies.build();
|
||||
}
|
||||
+ // DivineMC end - Optimize baby villager sensor
|
||||
|
||||
private boolean isVillagerBaby(LivingEntity livingEntity) {
|
||||
return livingEntity.getType() == EntityType.VILLAGER && livingEntity.isBaby();
|
||||
diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
|
||||
index 70b32e0d06f9b8b7999df5fdfd773c09394e23fb..188c233721d7a98c8a437dd5bd155b1f3de9134e 100644
|
||||
--- a/net/minecraft/world/entity/animal/goat/Goat.java
|
||||
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
|
||||
@@ -100,6 +100,13 @@ public class Goat extends Animal {
|
||||
this.getNavigation().setCanFloat(true);
|
||||
this.setPathfindingMalus(PathType.POWDER_SNOW, -1.0F);
|
||||
this.setPathfindingMalus(PathType.DANGER_POWDER_SNOW, -1.0F);
|
||||
+ // DivineMC start - Optimize entities
|
||||
+ if (!this.getBrain().hasMemoryValue(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM)) {
|
||||
+ org.bxteam.divinemc.util.entity.SensorHelper.disableSensor(this, SensorType.NEAREST_ITEMS);
|
||||
+ } else if (net.minecraft.SharedConstants.IS_RUNNING_IN_IDE) {
|
||||
+ throw new IllegalStateException("Goat Entity has a nearest visible wanted item memory module! This patch(Optimize-Brain, Goat.java changes) should probably be removed permanently!");
|
||||
+ }
|
||||
+ // DivineMC end - Optimize entities
|
||||
}
|
||||
|
||||
public ItemStack createHorn() {
|
||||
diff --git a/net/minecraft/world/entity/schedule/Activity.java b/net/minecraft/world/entity/schedule/Activity.java
|
||||
index 5a143bb6fabba3dc4e2272afb0be636d5722ea22..133a51ed45500aba7b0bc4a7acb19731a524d8c1 100644
|
||||
--- a/net/minecraft/world/entity/schedule/Activity.java
|
||||
+++ b/net/minecraft/world/entity/schedule/Activity.java
|
||||
@@ -32,10 +32,12 @@ public class Activity {
|
||||
public static final Activity DIG = register("dig");
|
||||
private final String name;
|
||||
private final int hashCode;
|
||||
+ public final int id; // DivineMC - Optimize entities - cache registry ID
|
||||
|
||||
- private Activity(String name) {
|
||||
+ private Activity(String name, int id) {
|
||||
this.name = name;
|
||||
this.hashCode = name.hashCode();
|
||||
+ this.id = id; // DivineMC - Optimize entities - cache registry ID
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@@ -43,7 +45,7 @@ public class Activity {
|
||||
}
|
||||
|
||||
private static Activity register(String key) {
|
||||
- return Registry.register(BuiltInRegistries.ACTIVITY, key, new Activity(key));
|
||||
+ return Registry.register(BuiltInRegistries.ACTIVITY, key, new Activity(key, BuiltInRegistries.ACTIVITY.size())); // DivineMC - Optimize entities - cache registry ID
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,59 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 19:50:02 +0300
|
||||
Subject: [PATCH] SparklyPaper: Skip distanceToSqr call in
|
||||
ServerEntity#sendChanges if the delta movement hasn't changed
|
||||
|
||||
Original project: https://github.com/SparklyPower/SparklyPaper
|
||||
|
||||
Patch description:
|
||||
|
||||
The "distanceToSqr" call is a bit expensive, so avoiding it is pretty nice, around ~15% calls are skipped with this check
|
||||
We could also check if the x,y,z coordinates are equal, but for now, let's just keep the identity check, which also helps us since Minecraft's code does reuse the original delta movement Vec3 object
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index e96d4dee14c05f2fa329bfb1588ec795d4e3d730..0868189fee30d40dfb82ae39592a65b510e96b54 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -209,23 +209,27 @@ public class ServerEntity {
|
||||
|
||||
if (this.entity.hasImpulse || this.trackDelta || this.entity instanceof LivingEntity && ((LivingEntity)this.entity).isFallFlying()) {
|
||||
Vec3 deltaMovement = this.entity.getDeltaMovement();
|
||||
- double d = deltaMovement.distanceToSqr(this.lastSentMovement);
|
||||
- if (d > 1.0E-7 || d > 0.0 && deltaMovement.lengthSqr() == 0.0) {
|
||||
- this.lastSentMovement = deltaMovement;
|
||||
- if (this.entity instanceof AbstractHurtingProjectile abstractHurtingProjectile) {
|
||||
- this.broadcast
|
||||
- .accept(
|
||||
- new ClientboundBundlePacket(
|
||||
- List.of(
|
||||
- new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement),
|
||||
- new ClientboundProjectilePowerPacket(abstractHurtingProjectile.getId(), abstractHurtingProjectile.accelerationPower)
|
||||
+ // DivineMC start - Skip "distanceToSqr" call in "ServerEntity#sendChanges" if the delta movement hasn't changed
|
||||
+ if (deltaMovement != this.lastSentMovement) {
|
||||
+ double d = deltaMovement.distanceToSqr(this.lastSentMovement);
|
||||
+ if (d > 1.0E-7 || d > 0.0 && deltaMovement.lengthSqr() == 0.0) {
|
||||
+ this.lastSentMovement = deltaMovement;
|
||||
+ if (this.entity instanceof AbstractHurtingProjectile abstractHurtingProjectile) {
|
||||
+ this.broadcast
|
||||
+ .accept(
|
||||
+ new ClientboundBundlePacket(
|
||||
+ List.of(
|
||||
+ new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement),
|
||||
+ new ClientboundProjectilePowerPacket(abstractHurtingProjectile.getId(), abstractHurtingProjectile.accelerationPower)
|
||||
+ )
|
||||
)
|
||||
- )
|
||||
- );
|
||||
- } else {
|
||||
- this.broadcast.accept(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement));
|
||||
+ );
|
||||
+ } else {
|
||||
+ this.broadcast.accept(new ClientboundSetEntityMotionPacket(this.entity.getId(), this.lastSentMovement));
|
||||
+ }
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Skip "distanceToSqr" call in "ServerEntity#sendChanges" if the delta movement hasn't changed
|
||||
}
|
||||
|
||||
if (packet != null) {
|
||||
@@ -1,119 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 6 Jul 2025 03:24:48 +0300
|
||||
Subject: [PATCH] Carpet-Fixes: Optimized getBiome method
|
||||
|
||||
Original license: MIT
|
||||
Original project: https://github.com/fxmorin/carpet-fixes
|
||||
|
||||
diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java
|
||||
index 73962e79a0f3d892e3155443a1b84508b0f4042e..c5fa1d7613410593f5b430968398c4ab1b40a98b 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 - Carpet-Fixes: Optimized getBiome method
|
||||
|
||||
public BiomeManager(BiomeManager.NoiseBiomeSource noiseBiomeSource, long biomeZoomSeed) {
|
||||
this.noiseBiomeSource = noiseBiomeSource;
|
||||
@@ -29,39 +30,68 @@ 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;
|
||||
-
|
||||
- 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;
|
||||
+ // DivineMC start - Carpet-Fixes: Optimized getBiome method
|
||||
+ 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;
|
||||
+
|
||||
+ 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);
|
||||
+
|
||||
+ if (smallestDist > biomeDist) {
|
||||
+ smallestX = biomeX;
|
||||
+ smallestDist = biomeDist;
|
||||
}
|
||||
}
|
||||
|
||||
- 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);
|
||||
+ return this.noiseBiomeSource.getNoiseBiome(
|
||||
+ (smallestX & 4) == 0 ? x : x + 1,
|
||||
+ (smallestX & 2) == 0 ? y : y + 1,
|
||||
+ (smallestX & 1) == 0 ? z : z + 1
|
||||
+ );
|
||||
+ // DivineMC end - Carpet-Fixes: Optimized getBiome method
|
||||
}
|
||||
|
||||
public Holder<Biome> getNoiseBiomeAtPosition(double x, double y, double z) {
|
||||
@@ -1,126 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 8 May 2025 16:49:29 +0300
|
||||
Subject: [PATCH] Carpet-Fixes: Sheep Optimization
|
||||
|
||||
This patch is based on the following mixins and classes:
|
||||
* "carpetfixes/helpers/Utils.java"
|
||||
* "carpetfixes/mixins/optimizations/SheepEntity_childColorMixin.java"
|
||||
By: fxmorin <28154542+fxmorin@users.noreply.github.com>
|
||||
As part of: carpet-fixes (https://github.com/fxmorin/carpet-fixes)
|
||||
Licensed under: MIT (https://opensource.org/licenses/MIT)
|
||||
|
||||
Patch description:
|
||||
|
||||
The game determines the child sheep's color by getting a wool block from the parents, putting them in a crafting
|
||||
recipe, getting the output wool and getting the color from that.
|
||||
I don't know in what world we would consider a data-driven method with that much overhead as a smart idea. Instead,
|
||||
we used a prebaked list of all the possible colors and combinations, however this means that you can't use a
|
||||
datapack to change it.
|
||||
|
||||
diff --git a/net/minecraft/world/item/DyeColor.java b/net/minecraft/world/item/DyeColor.java
|
||||
index c9cde255117b46690b2b6670d009a00b051af016..2c9f513e6ccd75959484f29a375671e21aab9590 100644
|
||||
--- a/net/minecraft/world/item/DyeColor.java
|
||||
+++ b/net/minecraft/world/item/DyeColor.java
|
||||
@@ -112,6 +112,15 @@ public enum DyeColor implements StringRepresentable {
|
||||
}
|
||||
|
||||
public static DyeColor getMixedColor(ServerLevel level, DyeColor first, DyeColor second) {
|
||||
+ // DivineMC start - Carpet-Fixes: Sheep Optimization
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.sheepOptimization) {
|
||||
+ DyeColor col = properDye(first, second);
|
||||
+
|
||||
+ if (col == null) col = level.random.nextBoolean() ? first : second;
|
||||
+
|
||||
+ return col;
|
||||
+ }
|
||||
+ // DivineMC end - Carpet-Fixes: Sheep Optimization
|
||||
CraftingInput craftingInput = makeCraftColorInput(first, second);
|
||||
return level.recipeAccess()
|
||||
.getRecipeFor(RecipeType.CRAFTING, craftingInput, level)
|
||||
@@ -132,4 +141,85 @@ public enum DyeColor implements StringRepresentable {
|
||||
return values()[random.nextInt(values().length)];
|
||||
}
|
||||
// Purpur end - Shulker spawn from bullet options
|
||||
+
|
||||
+ // DivineMC start - Carpet-Fixes: Sheep Optimization
|
||||
+ private static DyeColor properDye(DyeColor firstColor, DyeColor secondColor) {
|
||||
+ if (firstColor.equals(secondColor)) return firstColor;
|
||||
+
|
||||
+ switch (firstColor) {
|
||||
+ case WHITE -> {
|
||||
+ switch (secondColor) {
|
||||
+ case BLUE -> {
|
||||
+ return DyeColor.LIGHT_BLUE;
|
||||
+ }
|
||||
+ case GRAY -> {
|
||||
+ return DyeColor.LIGHT_GRAY;
|
||||
+ }
|
||||
+ case BLACK -> {
|
||||
+ return DyeColor.GRAY;
|
||||
+ }
|
||||
+ case GREEN -> {
|
||||
+ return DyeColor.LIME;
|
||||
+ }
|
||||
+ case RED -> {
|
||||
+ return DyeColor.PINK;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ case BLUE -> {
|
||||
+ switch (secondColor) {
|
||||
+ case WHITE -> {
|
||||
+ return DyeColor.LIGHT_BLUE;
|
||||
+ }
|
||||
+ case GREEN -> {
|
||||
+ return DyeColor.CYAN;
|
||||
+ }
|
||||
+ case RED -> {
|
||||
+ return DyeColor.PURPLE;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ case RED -> {
|
||||
+ switch (secondColor) {
|
||||
+ case YELLOW -> {
|
||||
+ return DyeColor.ORANGE;
|
||||
+ }
|
||||
+ case WHITE -> {
|
||||
+ return DyeColor.PINK;
|
||||
+ }
|
||||
+ case BLUE -> {
|
||||
+ return DyeColor.PURPLE;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ case GREEN -> {
|
||||
+ switch (secondColor) {
|
||||
+ case BLUE -> {
|
||||
+ return DyeColor.CYAN;
|
||||
+ }
|
||||
+ case WHITE -> {
|
||||
+ return DyeColor.LIME;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ case YELLOW -> {
|
||||
+ if (secondColor.equals(DyeColor.RED)) return DyeColor.ORANGE;
|
||||
+ }
|
||||
+ case PURPLE -> {
|
||||
+ if (secondColor.equals(DyeColor.PINK)) return DyeColor.MAGENTA;
|
||||
+ }
|
||||
+ case PINK -> {
|
||||
+ if (secondColor.equals(DyeColor.PURPLE)) return DyeColor.MAGENTA;
|
||||
+ }
|
||||
+ case GRAY -> {
|
||||
+ if (secondColor.equals(DyeColor.WHITE)) return DyeColor.LIGHT_GRAY;
|
||||
+ }
|
||||
+ case BLACK -> {
|
||||
+ if (secondColor.equals(DyeColor.WHITE)) return DyeColor.GRAY;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return null;
|
||||
+ }
|
||||
+ // DivineMC end - Carpet-Fixes: Sheep Optimization
|
||||
}
|
||||
@@ -1,111 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 11 Jun 2025 19:33:13 +0300
|
||||
Subject: [PATCH] Carpet-AMS-Addition: Optimized dragon respawn
|
||||
|
||||
This patch is based on the following mixins and classes:
|
||||
* "club/mcams/carpet/mixin/rule/optimizedDragonRespawn/BlockPatternMixin.java"
|
||||
* "club/mcams/carpet/mixin/rule/optimizedDragonRespawn/EnderDragonFightMixin.java"
|
||||
* "club/mcams/carpet/helpers/rule/optimizedDragonRespawn/BlockPatternHelper.java"
|
||||
By: 1024-byteeeee
|
||||
As part of: Carpet-AMS-Addition (https://github.com/Minecraft-AMS/Carpet-AMS-Addition)
|
||||
Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/state/pattern/BlockPattern.java b/net/minecraft/world/level/block/state/pattern/BlockPattern.java
|
||||
index f7bb979f08634a7e1b77c59040f59fb5e11aafa5..e0eca73d9e8a77b2a4972db61001394c6bf1d2c4 100644
|
||||
--- a/net/minecraft/world/level/block/state/pattern/BlockPattern.java
|
||||
+++ b/net/minecraft/world/level/block/state/pattern/BlockPattern.java
|
||||
@@ -59,7 +59,7 @@ public class BlockPattern {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
- private BlockPattern.BlockPatternMatch matches(BlockPos pos, Direction finger, Direction thumb, LoadingCache<BlockPos, BlockInWorld> cache) {
|
||||
+ public BlockPattern.BlockPatternMatch matches(BlockPos pos, Direction finger, Direction thumb, LoadingCache<BlockPos, BlockInWorld> cache) { // DivineMC - Carpet-AMS-Addition: Optimized dragon respawn - make public
|
||||
for (int i = 0; i < this.width; i++) {
|
||||
for (int i1 = 0; i1 < this.height; i1++) {
|
||||
for (int i2 = 0; i2 < this.depth; i2++) {
|
||||
diff --git a/net/minecraft/world/level/dimension/end/EndDragonFight.java b/net/minecraft/world/level/dimension/end/EndDragonFight.java
|
||||
index 8ccd40c70e150bd5a8d89818c229258642f2349e..d498dbdc5d29c9bb94ccbf2ae84d5d6caf2943f2 100644
|
||||
--- a/net/minecraft/world/level/dimension/end/EndDragonFight.java
|
||||
+++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java
|
||||
@@ -273,8 +273,68 @@ public class EndDragonFight {
|
||||
return false;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Carpet-AMS-Addition: Optimized dragon respawn
|
||||
+ private int cachePortalChunkIteratorX = -8;
|
||||
+ private int cachePortalChunkIteratorZ = -8;
|
||||
+ private int cachePortalOriginIteratorY = -1;
|
||||
+
|
||||
@Nullable
|
||||
public BlockPattern.BlockPatternMatch findExitPortal() {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.optimizedDragonRespawn) {
|
||||
+ int i, j;
|
||||
+ for (i = cachePortalChunkIteratorX; i <= 8; ++i) {
|
||||
+ for (j = cachePortalChunkIteratorZ; j <= 8; ++j) {
|
||||
+ LevelChunk worldChunk = this.level.getChunk(i, j);
|
||||
+ for (BlockEntity blockEntity : worldChunk.getBlockEntities().values()) {
|
||||
+ if (blockEntity instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity) {
|
||||
+ continue;
|
||||
+ }
|
||||
+ if (blockEntity instanceof TheEndPortalBlockEntity) {
|
||||
+ BlockPattern.BlockPatternMatch blockPatternMatch = this.exitPortalPattern.find(this.level, blockEntity.getBlockPos());
|
||||
+ if (blockPatternMatch != null) {
|
||||
+ BlockPos blockPos = blockPatternMatch.getBlock(3, 3, 3).getPos();
|
||||
+ if (this.portalLocation == null) {
|
||||
+ this.portalLocation = blockPos;
|
||||
+ }
|
||||
+
|
||||
+ cachePortalChunkIteratorX = i;
|
||||
+ cachePortalChunkIteratorZ = j;
|
||||
+ return blockPatternMatch;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (this.needsStateScanning || this.portalLocation == null) {
|
||||
+ if (cachePortalOriginIteratorY != -1) {
|
||||
+ i = cachePortalOriginIteratorY;
|
||||
+ } else {
|
||||
+ i = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(BlockPos.ZERO)).getY();
|
||||
+ }
|
||||
+ boolean notFirstSearch = false;
|
||||
+ for (j = i; j >= 0; --j) {
|
||||
+ BlockPattern.BlockPatternMatch result2 = null;
|
||||
+ if (notFirstSearch) {
|
||||
+ result2 = org.bxteam.divinemc.util.BlockPatternHelper.partialSearchAround(this.exitPortalPattern, this.level, new BlockPos(EndPodiumFeature.getLocation(BlockPos.ZERO).getY(), j, EndPodiumFeature.getLocation(BlockPos.ZERO).getZ()));
|
||||
+ } else {
|
||||
+ result2 = this.exitPortalPattern.find(this.level, new BlockPos(EndPodiumFeature.getLocation(BlockPos.ZERO).getX(), j, EndPodiumFeature.getLocation(BlockPos.ZERO).getZ()));
|
||||
+ }
|
||||
+ if (result2 != null) {
|
||||
+ if (this.portalLocation == null) {
|
||||
+ this.portalLocation = result2.getBlock(3, 3, 3).getPos();
|
||||
+ }
|
||||
+ cachePortalOriginIteratorY = j;
|
||||
+ return result2;
|
||||
+ }
|
||||
+ notFirstSearch = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return null;
|
||||
+ }
|
||||
+ // DivineMC end - Carpet-AMS-Addition: Optimized dragon respawn
|
||||
+
|
||||
ChunkPos chunkPos = new ChunkPos(this.origin);
|
||||
|
||||
for (int i = -8 + chunkPos.x; i <= 8 + chunkPos.x; i++) {
|
||||
@@ -572,6 +632,11 @@ public class EndDragonFight {
|
||||
}
|
||||
|
||||
public boolean respawnDragon(List<EndCrystal> crystals) { // CraftBukkit - return boolean
|
||||
+ // DivineMC start - Carpet-AMS-Addition: Optimized dragon respawn
|
||||
+ cachePortalChunkIteratorX = -8;
|
||||
+ cachePortalChunkIteratorZ = -8;
|
||||
+ cachePortalOriginIteratorY = -1;
|
||||
+ // DivineMC end - Carpet-AMS-Addition: Optimized dragon respawn
|
||||
if (this.dragonKilled && this.respawnStage == null) {
|
||||
for (BlockPattern.BlockPatternMatch blockPatternMatch = this.findExitPortal(); blockPatternMatch != null; blockPatternMatch = this.findExitPortal()) {
|
||||
for (int i = 0; i < this.exitPortalPattern.getWidth(); i++) {
|
||||
@@ -1,44 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 8 Mar 2025 13:27:07 +0300
|
||||
Subject: [PATCH] ModernFix: compact_bit_storage
|
||||
|
||||
This patch is based on following mixins:
|
||||
* "org/embeddedt/modernfix/common/mixin/perf/compact_bit_storage/PalettedContainerMixin.java"
|
||||
By: embeddedt <42941056+embeddedt@users.noreply.github.com>
|
||||
As part of: ModernFix (https://github.com/embeddedt/ModernFix)
|
||||
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
|
||||
index 9d892c1c3890e0aaf13fd5cd7b7d138afeaad260..ca3fab804e464a5db2b47495ecb588a96044265d 100644
|
||||
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
||||
@@ -291,6 +291,28 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
||||
data.palette.read(buffer);
|
||||
buffer.readFixedSizeLongArray(data.storage.getRaw());
|
||||
this.data = data;
|
||||
+ // DivineMC start - ModernFix: compact_bit_storage
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.useCompactBitStorage && _byte > 1) {
|
||||
+ long[] storageArray = this.data.storage.getRaw();
|
||||
+ boolean empty = true;
|
||||
+ for (long l : storageArray) {
|
||||
+ if (l != 0) {
|
||||
+ empty = false;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ if (empty && storageArray.length > 0) {
|
||||
+ T value;
|
||||
+ try {
|
||||
+ value = this.data.palette.valueFor(0);
|
||||
+ } catch (RuntimeException e) {
|
||||
+ return;
|
||||
+ }
|
||||
+ this.data = this.createOrReuseData(null, 0);
|
||||
+ this.data.palette.idFor(value);
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - ModernFix: compact_bit_storage
|
||||
this.addPresetValues(); // Paper - Anti-Xray - Add preset values (inefficient, but this isn't used by the server)
|
||||
this.updateData(this.data); // Paper - optimise palette reads
|
||||
} finally {
|
||||
@@ -1,53 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 3 Mar 2025 20:08:44 +0300
|
||||
Subject: [PATCH] Option to disable disconnect.spam
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 619133e907e1c3e6b05f50bf6c4092c08a2a3c44..b44afe316fc8d886b9a21102cddf20d977169c51 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -846,7 +846,7 @@ public class ServerGamePacketListenerImpl
|
||||
public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) {
|
||||
// PacketUtils.ensureRunningOnSameThread(packet, this, this.player.level()); // Paper - AsyncTabCompleteEvent; run this async
|
||||
// CraftBukkit start
|
||||
- if (!this.tabSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile())) { // Paper - configurable tab spam limits
|
||||
+ if (!this.tabSpamThrottler.isIncrementAndUnderThreshold() && !this.server.getPlayerList().isOp(this.player.getGameProfile()) && !this.server.isSingleplayerOwner(this.player.getGameProfile()) && !org.bxteam.divinemc.config.DivineConfig.NetworkCategory.disableDisconnectSpam) { // Paper - configurable tab spam limits // DivineMC - Option to disable disconnect.spam
|
||||
this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - Kick event cause // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
@@ -858,7 +858,7 @@ public class ServerGamePacketListenerImpl
|
||||
// Paper end - Don't suggest if tab-complete is disabled
|
||||
// Paper start
|
||||
final int index;
|
||||
- if (packet.getCommand().length() > 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64)) {
|
||||
+ if (packet.getCommand().length() > 64 && ((index = packet.getCommand().indexOf(' ')) == -1 || index >= 64) && !org.bxteam.divinemc.config.DivineConfig.NetworkCategory.disableDisconnectSpam) { // DivineMC - Option to disable disconnect.spam
|
||||
this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
@@ -918,6 +918,7 @@ public class ServerGamePacketListenerImpl
|
||||
ParseResults<CommandSourceStack> parseResults = this.server.getCommands().getDispatcher().parse(stringReader, this.player.createCommandSourceStack());
|
||||
// Paper start - Handle non-recoverable exceptions
|
||||
if (!parseResults.getExceptions().isEmpty()
|
||||
+ && !org.bxteam.divinemc.config.DivineConfig.NetworkCategory.disableDisconnectSpam // DivineMC - Option to disable disconnect.spam
|
||||
&& parseResults.getExceptions().values().stream().anyMatch(e -> e instanceof io.papermc.paper.brigadier.TagParseCommandSyntaxException)) {
|
||||
this.disconnect(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM);
|
||||
return;
|
||||
@@ -2631,6 +2632,7 @@ public class ServerGamePacketListenerImpl
|
||||
// this.chatSpamThrottler.increment();
|
||||
if (!this.chatSpamThrottler.isIncrementAndUnderThreshold()
|
||||
// CraftBukkit end
|
||||
+ && !org.bxteam.divinemc.config.DivineConfig.NetworkCategory.disableDisconnectSpam // DivineMC - Option to disable disconnect.spam
|
||||
&& !this.server.getPlayerList().isOp(this.player.getGameProfile())
|
||||
&& !this.server.isSingleplayerOwner(this.player.getGameProfile())) {
|
||||
this.disconnectAsync(Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause & add proper async disconnect
|
||||
@@ -3332,7 +3334,7 @@ public class ServerGamePacketListenerImpl
|
||||
public void handlePlaceRecipe(ServerboundPlaceRecipePacket packet) {
|
||||
// Paper start - auto recipe limit
|
||||
if (!org.bukkit.Bukkit.isPrimaryThread()) {
|
||||
- if (!this.recipeSpamPackets.isIncrementAndUnderThreshold()) {
|
||||
+ if (!this.recipeSpamPackets.isIncrementAndUnderThreshold() && !org.bxteam.divinemc.config.DivineConfig.NetworkCategory.disableDisconnectSpam) { // DivineMC - Option to disable disconnect.spam
|
||||
this.disconnectAsync(net.minecraft.network.chat.Component.translatable("disconnect.spam"), org.bukkit.event.player.PlayerKickEvent.Cause.SPAM); // Paper - kick event cause // Paper - add proper async disconnect
|
||||
return;
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 23 Feb 2025 01:04:29 +0300
|
||||
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
|
||||
index d8dc196ef92e97f831cf97cd1536a46f81f9d5d1..ed8c50f67f5a6deda74845e4bce9fd9aa42558c0 100644
|
||||
--- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
|
||||
+++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
|
||||
@@ -350,4 +350,14 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
|
||||
double d1 = entity.position().z - this.position().z;
|
||||
return DoubleDoubleImmutablePair.of(d, d1);
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Option to disable saving firework
|
||||
+ @Override
|
||||
+ public boolean shouldBeSaved() {
|
||||
+ if (this.level().divineConfig.disableFireworkSaving) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return super.shouldBeSaved();
|
||||
+ }
|
||||
+ // DivineMC end - Option to disable saving firework
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/projectile/Snowball.java b/net/minecraft/world/entity/projectile/Snowball.java
|
||||
index d8f9fb603fd2e3e5c1dfc05face7f42b4844daf4..42b2be469972e02671fa5a02aeecfb4e5be405c3 100644
|
||||
--- a/net/minecraft/world/entity/projectile/Snowball.java
|
||||
+++ b/net/minecraft/world/entity/projectile/Snowball.java
|
||||
@@ -94,4 +94,14 @@ public class Snowball extends ThrowableItemProjectile {
|
||||
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.HIT); // CraftBukkit - add Bukkit remove cause
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Option to disable snowball saving
|
||||
+ @Override
|
||||
+ public boolean shouldBeSaved() {
|
||||
+ if (this.level().divineConfig.disableSnowballSaving) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ return super.shouldBeSaved();
|
||||
+ }
|
||||
+ // DivineMC end - Option to disable snowball saving
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 19:24:47 +0300
|
||||
Subject: [PATCH] Snowball and Egg knockback
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/projectile/Snowball.java b/net/minecraft/world/entity/projectile/Snowball.java
|
||||
index 42b2be469972e02671fa5a02aeecfb4e5be405c3..0f611169a4ed2a059b9231bedf94a903600b73f0 100644
|
||||
--- a/net/minecraft/world/entity/projectile/Snowball.java
|
||||
+++ b/net/minecraft/world/entity/projectile/Snowball.java
|
||||
@@ -54,6 +54,12 @@ public class Snowball extends ThrowableItemProjectile {
|
||||
Entity entity = result.getEntity();
|
||||
int i = entity.level().purpurConfig.snowballDamage >= 0 ? entity.level().purpurConfig.snowballDamage : entity instanceof Blaze ? 3 : 0; // Purpur - Add configurable snowball damage
|
||||
entity.hurt(this.damageSources().thrown(this, this.getOwner()), i);
|
||||
+ // DivineMC start - Make snowball can knockback player
|
||||
+ if (this.level().divineConfig.snowballCanKnockback && entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
|
||||
+ entity.hurt(this.damageSources().thrown(this, this.getOwner()), 0.0000001F);
|
||||
+ serverPlayer.knockback(0.4000000059604645D, this.getX() - entity.getX(), this.getZ() - entity.getZ());
|
||||
+ }
|
||||
+ // DivineMC end - Make snowball can knockback player
|
||||
}
|
||||
|
||||
// Purpur start - options to extinguish fire blocks with snowballs - borrowed and modified code from ThrownPotion#onHitBlock and ThrownPotion#dowseFire
|
||||
diff --git a/net/minecraft/world/entity/projectile/ThrownEgg.java b/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
index 73ec34b43f3fb2aa3edc3f1cb48a923d1fa32036..fe605f728020b42a61ea6703401e08f0efc3a69c 100644
|
||||
--- a/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
+++ b/net/minecraft/world/entity/projectile/ThrownEgg.java
|
||||
@@ -54,7 +54,14 @@ public class ThrownEgg extends ThrowableItemProjectile {
|
||||
@Override
|
||||
protected void onHitEntity(EntityHitResult result) {
|
||||
super.onHitEntity(result);
|
||||
+ net.minecraft.world.entity.Entity entity = result.getEntity(); // DivineMC - make egg can knockback player
|
||||
result.getEntity().hurt(this.damageSources().thrown(this, this.getOwner()), 0.0F);
|
||||
+ // DivineMC start - Make egg can knockback player
|
||||
+ if (this.level().divineConfig.eggCanKnockback && entity instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
|
||||
+ entity.hurt(this.damageSources().thrown(this, this.getOwner()), 0.0000001F);
|
||||
+ serverPlayer.knockback(0.4000000059604645D, this.getX() - entity.getX(), this.getZ() - entity.getZ());
|
||||
+ }
|
||||
+ // DivineMC end - Make egg can knockback player
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,34 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 11 Jun 2025 16:40:43 +0300
|
||||
Subject: [PATCH] Optimize suffocation
|
||||
|
||||
Original license: GPL v3
|
||||
Original project: https://github.com/pufferfish-gg/Pufferfish
|
||||
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 8df6ceea1536b12d87755c8a69e1b652d280600c..33f33a51a7016e214bca1aec8e6cc3910ec3bb42 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -420,6 +420,12 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
return this.getDeltaMovement().y() < 1.0E-5F && this.isInLiquid();
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize suffocation
|
||||
+ public boolean couldPossiblyBeHurt(float amount) {
|
||||
+ return !((float) this.invulnerableTime > (float) this.invulnerableDuration / 2.0F) || !(amount <= this.lastHurt);
|
||||
+ }
|
||||
+ // DivineMC end - Optimize suffocation
|
||||
+
|
||||
@Override
|
||||
public void baseTick() {
|
||||
this.oAttackAnim = this.attackAnim;
|
||||
@@ -438,7 +444,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
|
||||
if (this.isAlive() && this.level() instanceof ServerLevel serverLevel1) {
|
||||
boolean flag = this instanceof Player;
|
||||
- if (this.isInWall()) {
|
||||
+ if ((!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableSuffocationOptimization || this instanceof WitherBoss || (tickCount % 10 == 0 && couldPossiblyBeHurt(1.0F))) && this.isInWall()) { // DivineMC - Optimize suffocation
|
||||
this.hurtServer(serverLevel1, this.damageSources().inWall(), 1.0F);
|
||||
} else if (flag && !serverLevel1.getWorldBorder().isWithinBounds(this.getBoundingBox())) {
|
||||
double d = serverLevel1.getWorldBorder().getDistanceToBorder(this) + serverLevel1.getWorldBorder().getDamageSafeZone();
|
||||
@@ -1,44 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 11 Jun 2025 19:12:00 +0300
|
||||
Subject: [PATCH] Reduce chunk loading & lookups
|
||||
|
||||
Original license: GPL v3
|
||||
Original project: https://github.com/pufferfish-gg/Pufferfish
|
||||
|
||||
diff --git a/net/minecraft/world/entity/monster/EnderMan.java b/net/minecraft/world/entity/monster/EnderMan.java
|
||||
index fcdb3ee493e65bf002e78862f00061336e731ede..a8c11c6d7d107987dc04e5b741cfabf5ea0e8090 100644
|
||||
--- a/net/minecraft/world/entity/monster/EnderMan.java
|
||||
+++ b/net/minecraft/world/entity/monster/EnderMan.java
|
||||
@@ -330,11 +330,28 @@ public class EnderMan extends Monster implements NeutralMob {
|
||||
private boolean teleport(double x, double y, double z) {
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(x, y, z);
|
||||
|
||||
- while (mutableBlockPos.getY() > this.level().getMinY() && !this.level().getBlockState(mutableBlockPos).blocksMotion()) {
|
||||
- mutableBlockPos.move(Direction.DOWN);
|
||||
+ // DivineMC start - Reduce chunk loading & lookups
|
||||
+ BlockState blockState;
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.reduceChuckLoadAndLookup) {
|
||||
+ net.minecraft.world.level.chunk.LevelChunk chunk = this.level().getChunkIfLoaded(mutableBlockPos);
|
||||
+ if (chunk == null) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ while (mutableBlockPos.getY() > this.level().getMinY() && !chunk.getBlockState(mutableBlockPos).blocksMotion()) {
|
||||
+ mutableBlockPos.move(Direction.DOWN);
|
||||
+ }
|
||||
+
|
||||
+ blockState = chunk.getBlockState(mutableBlockPos);
|
||||
+ } else {
|
||||
+ while (mutableBlockPos.getY() > this.level().getMinY() && !this.level().getBlockState(mutableBlockPos).blocksMotion()) {
|
||||
+ mutableBlockPos.move(Direction.DOWN);
|
||||
+ }
|
||||
+
|
||||
+ blockState = this.level().getBlockState(mutableBlockPos);
|
||||
}
|
||||
+ // DivineMC end - Reduce chunk loading & lookups
|
||||
|
||||
- BlockState blockState = this.level().getBlockState(mutableBlockPos);
|
||||
boolean flag = blockState.blocksMotion();
|
||||
boolean isWater = blockState.getFluidState().is(FluidTags.WATER);
|
||||
if (flag && !isWater) {
|
||||
@@ -1,82 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 23 Mar 2025 01:26:54 +0300
|
||||
Subject: [PATCH] Configurable movement speed for entities
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
|
||||
index 2e6d0f035a01277aa28bbe912d5df8dc4cf04547..2a13332ebabf2e63a8f51a5d794fab3d66c7a1db 100644
|
||||
--- a/net/minecraft/world/entity/monster/Drowned.java
|
||||
+++ b/net/minecraft/world/entity/monster/Drowned.java
|
||||
@@ -98,6 +98,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
||||
public void initAttributes() {
|
||||
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.drownedMaxHealth);
|
||||
this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.drownedScale);
|
||||
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.drownedMovementSpeed); // DivineMC - Configurable movement speed for entities
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/monster/Husk.java b/net/minecraft/world/entity/monster/Husk.java
|
||||
index a4ce65911a5d778f60bcedb3acd9fe59a5094c96..f359bfedd2d6fbd1c2d77d664157c4725fef014b 100644
|
||||
--- a/net/minecraft/world/entity/monster/Husk.java
|
||||
+++ b/net/minecraft/world/entity/monster/Husk.java
|
||||
@@ -43,6 +43,7 @@ public class Husk extends Zombie {
|
||||
@Override
|
||||
public void initAttributes() {
|
||||
this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.huskMaxHealth);
|
||||
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.huskMovementSpeed); // DivineMC - Configurable movement speed for entities
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/monster/Zombie.java b/net/minecraft/world/entity/monster/Zombie.java
|
||||
index ab4dc7b3a7593d255dbd7d1df667fce3504af3ed..86fd1eb0b9e235f58fb9eca3f384f001b2330907 100644
|
||||
--- a/net/minecraft/world/entity/monster/Zombie.java
|
||||
+++ b/net/minecraft/world/entity/monster/Zombie.java
|
||||
@@ -126,6 +126,7 @@ public class Zombie extends Monster {
|
||||
public void initAttributes() {
|
||||
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieMaxHealth);
|
||||
this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zombieScale);
|
||||
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.zombieMovementSpeed); // DivineMC - Configurable movement speed for entities
|
||||
}
|
||||
// Purpur end - Configurable entity base attributes
|
||||
|
||||
@@ -193,7 +194,6 @@ public class Zombie extends Monster {
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Monster.createMonsterAttributes()
|
||||
.add(Attributes.FOLLOW_RANGE, 35.0)
|
||||
- .add(Attributes.MOVEMENT_SPEED, 0.23F)
|
||||
.add(Attributes.ATTACK_DAMAGE, 3.0)
|
||||
.add(Attributes.ARMOR, 2.0)
|
||||
.add(Attributes.SPAWN_REINFORCEMENTS_CHANCE);
|
||||
diff --git a/net/minecraft/world/entity/monster/ZombieVillager.java b/net/minecraft/world/entity/monster/ZombieVillager.java
|
||||
index 00af89717bf2459b315baf70a515a0e68267fb9f..438e07863f85d83874373b9d2407c0c383ba5722 100644
|
||||
--- a/net/minecraft/world/entity/monster/ZombieVillager.java
|
||||
+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
|
||||
@@ -97,6 +97,7 @@ public class ZombieVillager extends Zombie implements VillagerDataHolder {
|
||||
@Override
|
||||
public void initAttributes() {
|
||||
this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombieVillagerMaxHealth);
|
||||
+ this.getAttribute(net.minecraft.world.entity.ai.attributes.Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.zombieVillagerMovementSpeed); // DivineMC - Configurable movement speed for entities
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/monster/ZombifiedPiglin.java b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
|
||||
index f58c48d9de85fda3d13079f3e56b31af75b3c725..db43ea25cb817c10bde1a30076d4b1f6266651d6 100644
|
||||
--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
|
||||
+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
|
||||
@@ -86,6 +86,7 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
|
||||
public void initAttributes() {
|
||||
this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(this.level().purpurConfig.zombifiedPiglinMaxHealth);
|
||||
this.getAttribute(Attributes.SCALE).setBaseValue(this.level().purpurConfig.zombifiedPiglinScale);
|
||||
+ this.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(this.level().purpurConfig.zombifiedPiglinMovementSpeed); // DivineMC - Configurable movement speed for entities
|
||||
}
|
||||
// Purpur end - Configurable entity base attributes
|
||||
|
||||
@@ -137,7 +138,6 @@ public class ZombifiedPiglin extends Zombie implements NeutralMob {
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
return Zombie.createAttributes()
|
||||
.add(Attributes.SPAWN_REINFORCEMENTS_CHANCE, 0.0)
|
||||
- .add(Attributes.MOVEMENT_SPEED, 0.23F)
|
||||
.add(Attributes.ATTACK_DAMAGE, 5.0);
|
||||
}
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 18:03:13 +0300
|
||||
Subject: [PATCH] Option to allow weird movement and disable teleporting
|
||||
players when they move too quickly
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index b44afe316fc8d886b9a21102cddf20d977169c51..b58fc16f9054f36d5ddb2dffabd9274969e56897 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -609,7 +609,7 @@ public class ServerGamePacketListenerImpl
|
||||
return;
|
||||
}
|
||||
// Paper end - Prevent moving into unloaded chunks
|
||||
- if (d7 - d6 > Math.max(100.0, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed)) && !this.isSingleplayerOwner()) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.FixesCategory.alwaysAllowWeirdMovement && (d7 - d6 > Math.max(100.0, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed)) && !this.isSingleplayerOwner())) { // DivineMC - stop weird movement
|
||||
// CraftBukkit end
|
||||
LOGGER.warn(
|
||||
"{} (vehicle of {}) moved too quickly! {},{},{}", rootVehicle.getName().getString(), this.player.getName().getString(), d3, d4, d5
|
||||
@@ -639,7 +639,7 @@ public class ServerGamePacketListenerImpl
|
||||
d5 = d2 - rootVehicle.getZ();
|
||||
d7 = d3 * d3 + d4 * d4 + d5 * d5;
|
||||
boolean flag1 = false;
|
||||
- if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.FixesCategory.alwaysAllowWeirdMovement && (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold)) { // Spigot // DivineMC - stop weird movement
|
||||
flag1 = true; // Paper - diff on change, this should be moved wrongly
|
||||
LOGGER.warn("{} (vehicle of {}) moved wrongly! {}", rootVehicle.getName().getString(), this.player.getName().getString(), Math.sqrt(d7));
|
||||
}
|
||||
@@ -1557,20 +1557,24 @@ public class ServerGamePacketListenerImpl
|
||||
if (this.shouldCheckPlayerMovement(isFallFlying)) {
|
||||
float f2 = isFallFlying ? 300.0F : 100.0F;
|
||||
if (d7 - d6 > Math.max(f2, Mth.square(org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed))) {
|
||||
- // CraftBukkit end
|
||||
- // Paper start - Add fail move event
|
||||
- io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY,
|
||||
+ // DivineMC start - Stop teleporting players when they move too quickly
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.FixesCategory.alwaysAllowWeirdMovement && !(org.bxteam.divinemc.config.DivineConfig.FixesCategory.ignoreMovedTooQuicklyWhenLagging && player.level().getServer().lagging)) {
|
||||
+ // CraftBukkit end
|
||||
+ // Paper start - Add fail move event
|
||||
+ io.papermc.paper.event.player.PlayerFailMoveEvent event = fireFailMove(io.papermc.paper.event.player.PlayerFailMoveEvent.FailReason.MOVED_TOO_QUICKLY,
|
||||
toX, toY, toZ, toYaw, toPitch, true);
|
||||
- if (!event.isAllowed()) {
|
||||
- if (event.getLogWarning()) {
|
||||
- LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getName().getString(), d3, d4, d5);
|
||||
- }
|
||||
- this.teleport(
|
||||
+ if (!event.isAllowed()) {
|
||||
+ if (event.getLogWarning()) {
|
||||
+ LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getName().getString(), d3, d4, d5);
|
||||
+ }
|
||||
+ this.teleport(
|
||||
this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot()
|
||||
- );
|
||||
- return;
|
||||
+ );
|
||||
+ return;
|
||||
+ }
|
||||
+ // Paper end - Add fail move event
|
||||
}
|
||||
- // Paper end - Add fail move event
|
||||
+ // DivineMC end - Stop teleporting players when they move too quickly
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1631,6 +1635,7 @@ public class ServerGamePacketListenerImpl
|
||||
d7 = d3 * d3 + d4 * d4 + d5 * d5;
|
||||
boolean movedWrongly = false; // Paper - Add fail move event; rename
|
||||
if (!this.player.isChangingDimension()
|
||||
+ && !org.bxteam.divinemc.config.DivineConfig.FixesCategory.alwaysAllowWeirdMovement // DivineMC - Stop teleporting players when they move too quickly
|
||||
&& d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold // Spigot
|
||||
&& !this.player.isSleeping()
|
||||
&& !this.player.isCreative()
|
||||
@@ -1,137 +0,0 @@
|
||||
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 5f2c27800f047f128857044493a6d9325ffd759b..4a2cace22512fe06c1713bc8735e775e3012f3bc 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -215,6 +215,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
public boolean hasEntityMoveEvent; // Paper - Add EntityMoveEvent
|
||||
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 net.minecraft.world.item.ItemStack ominousBanner; // DivineMC - Optimize Raids
|
||||
|
||||
@Override
|
||||
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
|
||||
@@ -694,6 +695,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Paper end - rewrite chunk system
|
||||
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
||||
this.preciseTime = this.serverLevelData.getDayTime(); // Purpur - Configurable daylight cycle
|
||||
+ 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 eb62402b7ed4cc76b4d510b1c8781b6f7b5be6ab..9183b8e8c54383a489a1f446d36bef41d11667ba 100644
|
||||
--- a/net/minecraft/world/entity/raid/Raid.java
|
||||
+++ b/net/minecraft/world/entity/raid/Raid.java
|
||||
@@ -126,6 +126,7 @@ public class Raid {
|
||||
private Raid.RaidStatus status;
|
||||
private int celebrationTicks;
|
||||
private Optional<BlockPos> waveSpawnPos = Optional.empty();
|
||||
+ private boolean isBarDirty; // DivineMC - Optimize Raids
|
||||
|
||||
public Raid(BlockPos center, Difficulty difficulty) {
|
||||
this.active = true;
|
||||
@@ -278,6 +279,12 @@ public class Raid {
|
||||
}
|
||||
|
||||
public void tick(ServerLevel level) {
|
||||
+ // 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;
|
||||
@@ -588,7 +595,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 2254493c889b8967011c09dc448ba375d82e2035..7802c5235a543c9f7147d27e122f4936f305f8ba 100644
|
||||
--- a/net/minecraft/world/entity/raid/Raider.java
|
||||
+++ b/net/minecraft/world/entity/raid/Raider.java
|
||||
@@ -43,9 +43,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
|
||||
private static final int DEFAULT_WAVE = 0;
|
||||
private static final boolean DEFAULT_CAN_JOIN_RAID = false;
|
||||
@Nullable
|
||||
@@ -150,7 +166,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;
|
||||
}
|
||||
@@ -213,7 +229,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;
|
||||
@@ -400,6 +416,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 (!getServerLevel(this.mob).getGameRules().getBoolean(net.minecraft.world.level.GameRules.RULE_MOBGRIEFING, this.mob.level().purpurConfig.pillagerMobGriefingOverride)) return true; // Paper - respect game and entity rules for picking up items // Purpur - Add mobGriefing override to everything affected
|
||||
if (!this.mob.hasActiveRaid()) {
|
||||
@@ -409,7 +435,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 {
|
||||
@@ -1,63 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 7 Jul 2025 04:21:38 +0300
|
||||
Subject: [PATCH] Small optimization to LinearPalette
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LinearPalette.java b/net/minecraft/world/level/chunk/LinearPalette.java
|
||||
index 2073f6ff41aa570102621d183ee890b076267d54..93cb815032fada7b8abc7301a7005114eea8384d 100644
|
||||
--- a/net/minecraft/world/level/chunk/LinearPalette.java
|
||||
+++ b/net/minecraft/world/level/chunk/LinearPalette.java
|
||||
@@ -12,7 +12,7 @@ public class LinearPalette<T> implements Palette<T>, ca.spottedleaf.moonrise.pat
|
||||
private final T[] values;
|
||||
private final PaletteResize<T> resizeHandler;
|
||||
private final int bits;
|
||||
- private int size;
|
||||
+ private volatile int size; // DivineMC - Small optimization to LinearPalette
|
||||
|
||||
// Paper start - optimise palette reads
|
||||
@Override
|
||||
@@ -49,11 +49,14 @@ public class LinearPalette<T> implements Palette<T>, ca.spottedleaf.moonrise.pat
|
||||
|
||||
@Override
|
||||
public int idFor(T state) {
|
||||
- for (int i = 0; i < this.size; i++) {
|
||||
- if (this.values[i] == state) {
|
||||
+ // DivineMC start - Small optimization to LinearPalette
|
||||
+ final T[] values = this.values;
|
||||
+ for (int i = 0; i < values.length; i++) {
|
||||
+ if (values[i] == state) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Small optimization to LinearPalette
|
||||
|
||||
int ix = this.size;
|
||||
if (ix < this.values.length) {
|
||||
@@ -67,17 +70,23 @@ public class LinearPalette<T> implements Palette<T>, ca.spottedleaf.moonrise.pat
|
||||
|
||||
@Override
|
||||
public boolean maybeHas(Predicate<T> filter) {
|
||||
- for (int i = 0; i < this.size; i++) {
|
||||
- if (filter.test(this.values[i])) {
|
||||
+ // DivineMC start - Small optimization to LinearPalette
|
||||
+ final T[] values = this.values;
|
||||
+ final int currentSize = this.size;
|
||||
+
|
||||
+ for (int i = 0; i < currentSize; i++) {
|
||||
+ T value = values[i];
|
||||
+ if (value != null && filter.test(value)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Small optimization to LinearPalette
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
- public T valueFor(int id) {
|
||||
+ public synchronized T valueFor(int id) { // DivineMC - Small optimization to LinearPalette
|
||||
if (id >= 0 && id < this.size) {
|
||||
return this.values[id];
|
||||
} else {
|
||||
@@ -1,213 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 9 Jul 2025 02:08:35 +0300
|
||||
Subject: [PATCH] Optimize VarInt and VarLong write
|
||||
|
||||
This patch is based on the following commit:
|
||||
"Reapply "Optimize varint writing""
|
||||
By: Andrew Steinborn <git@steinborn.me>
|
||||
As part of: Velocity (https://github.com/PaperMC/Velocity)
|
||||
Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/network/VarInt.java b/net/minecraft/network/VarInt.java
|
||||
index 4897ff4648083ebe737ae5b32bae344af27357e4..e138b64c4b09d83e5f38d7421fc23e9cc5e5d5a7 100644
|
||||
--- a/net/minecraft/network/VarInt.java
|
||||
+++ b/net/minecraft/network/VarInt.java
|
||||
@@ -50,28 +50,45 @@ public class VarInt {
|
||||
return i;
|
||||
}
|
||||
|
||||
- public static ByteBuf write(ByteBuf buffer, int value) {
|
||||
- // Paper start - Optimize VarInts
|
||||
- // Peel the one and two byte count cases explicitly as they are the most common VarInt sizes
|
||||
- // that the proxy will write, to improve inlining.
|
||||
- if ((value & (0xFFFFFFFF << 7)) == 0) {
|
||||
- buffer.writeByte(value);
|
||||
- } else if ((value & (0xFFFFFFFF << 14)) == 0) {
|
||||
- int w = (value & 0x7F | 0x80) << 8 | (value >>> 7);
|
||||
- buffer.writeShort(w);
|
||||
- } else {
|
||||
- writeOld(buffer, value);
|
||||
- }
|
||||
- return buffer;
|
||||
- }
|
||||
- public static ByteBuf writeOld(ByteBuf buffer, int value) {
|
||||
- // Paper end - Optimize VarInts
|
||||
- while ((value & -128) != 0) {
|
||||
- buffer.writeByte(value & 127 | 128);
|
||||
- value >>>= 7;
|
||||
+ // DivineMC start - Optimize VarInt
|
||||
+ public static ByteBuf write(ByteBuf buffer, int value) {
|
||||
+ int bytesNeeded = getByteSize(value);
|
||||
+
|
||||
+ switch (bytesNeeded) {
|
||||
+ case 1:
|
||||
+ buffer.writeByte(value);
|
||||
+ break;
|
||||
+ case 2:
|
||||
+ int w2 = ((value & 0x7F) << 8) | (value >>> 7) | 0x00008000;
|
||||
+ buffer.writeShort(w2);
|
||||
+ break;
|
||||
+ case 3:
|
||||
+ int w3 = (value & 0x7F) << 16
|
||||
+ | (value & 0x3F80) << 1
|
||||
+ | (value >>> 14)
|
||||
+ | 0x00808000;
|
||||
+ buffer.writeMedium(w3);
|
||||
+ break;
|
||||
+ case 4:
|
||||
+ int w4 = (value & 0x7F) << 24
|
||||
+ | ((value & 0x3F80) << 9)
|
||||
+ | (value & 0x1FC000) >> 6
|
||||
+ | (value >>> 21)
|
||||
+ | 0x80808000;
|
||||
+ buffer.writeInt(w4);
|
||||
+ break;
|
||||
+ case 5:
|
||||
+ int w5 = (value & 0x7F) << 24
|
||||
+ | (value & 0x3F80) << 9
|
||||
+ | (value & 0x1FC000) >> 6
|
||||
+ | ((value >>> 21) & 0x7F)
|
||||
+ | 0x80808080;
|
||||
+ buffer.writeInt(w5);
|
||||
+ buffer.writeByte(value >>> 28);
|
||||
+ break;
|
||||
}
|
||||
|
||||
- buffer.writeByte(value);
|
||||
return buffer;
|
||||
}
|
||||
+ // DivineMC end - Optimize VarInt
|
||||
}
|
||||
diff --git a/net/minecraft/network/VarLong.java b/net/minecraft/network/VarLong.java
|
||||
index df9a85b19a9767c85f02837af6835f7ddb6c7dc3..77f090bc1b9225dd5a61d8c57c902fcdea8ed7cd 100644
|
||||
--- a/net/minecraft/network/VarLong.java
|
||||
+++ b/net/minecraft/network/VarLong.java
|
||||
@@ -38,13 +38,122 @@ public class VarLong {
|
||||
return l;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize VarLong
|
||||
public static ByteBuf write(ByteBuf buffer, long value) {
|
||||
- while ((value & -128L) != 0L) {
|
||||
- buffer.writeByte((int)(value & 127L) | 128);
|
||||
- value >>>= 7;
|
||||
+ if ((value & 0xFFFFFFFFFFFFFF80L) == 0) {
|
||||
+ buffer.writeByte((int) value);
|
||||
+ } else if (value < 0) {
|
||||
+ int least7bits = (int) (value & 0xFFFFFFFL);
|
||||
+ int w = (least7bits & 0x7F) << 24
|
||||
+ | (least7bits & 0x3F80) << 9
|
||||
+ | (least7bits & 0x1FC000) >> 6
|
||||
+ | ((least7bits >>> 21) & 0x7F)
|
||||
+ | 0x80808080;
|
||||
+ long nonLeast7Bits = value >>> 28;
|
||||
+ int secondLeast7bits = (int) (nonLeast7Bits & 0xFFFFFFFL);
|
||||
+ int w2 = (secondLeast7bits & 0x7F) << 24
|
||||
+ | ((secondLeast7bits & 0x3F80) << 9)
|
||||
+ | (secondLeast7bits & 0x1FC000) >> 6
|
||||
+ | (secondLeast7bits >>> 21)
|
||||
+ | 0x80808080;
|
||||
+ int thirdLeast7Bits = (int) (nonLeast7Bits >>> 28);
|
||||
+ int w3 = (thirdLeast7Bits & 0x7F) << 8
|
||||
+ | (thirdLeast7Bits >>> 7)
|
||||
+ | 0x00008000;
|
||||
+ buffer.writeInt(w);
|
||||
+ buffer.writeInt(w2);
|
||||
+ buffer.writeShort(w3);
|
||||
+ } else if ((value & 0xFFFFFFFFFFFFC000L) == 0) {
|
||||
+ int least7bits = (int) value;
|
||||
+ int w = (least7bits & 0x7F) << 8
|
||||
+ | (least7bits >>> 7)
|
||||
+ | 0x00008000;
|
||||
+ buffer.writeShort(w);
|
||||
+ } else if ((value & 0xFFFFFFFFFFE00000L) == 0) {
|
||||
+ int least7bits = (int) value;
|
||||
+ int w = (least7bits & 0x7F) << 16
|
||||
+ | (least7bits & 0x3F80) << 1
|
||||
+ | (least7bits >>> 14)
|
||||
+ | 0x00808000;
|
||||
+ buffer.writeMedium(w);
|
||||
+ } else if ((value & 0xFFFFFFFFF0000000L) == 0) {
|
||||
+ int least7bits = (int) value;
|
||||
+ int w = (least7bits & 0x7F) << 24
|
||||
+ | ((least7bits & 0x3F80) << 9)
|
||||
+ | (least7bits & 0x1FC000) >> 6
|
||||
+ | (least7bits >>> 21)
|
||||
+ | 0x80808000;
|
||||
+ buffer.writeInt(w);
|
||||
+ } else if ((value & 0xFFFFFFF800000000L) == 0) {
|
||||
+ int least7bits = (int) (value & 0xFFFFFFFL);
|
||||
+ int w = (least7bits & 0x7F) << 24
|
||||
+ | (least7bits & 0x3F80) << 9
|
||||
+ | (least7bits & 0x1FC000) >> 6
|
||||
+ | ((least7bits >>> 21) & 0x7F)
|
||||
+ | 0x80808080;
|
||||
+ buffer.writeInt(w);
|
||||
+ buffer.writeByte((int) (value >>> 28));
|
||||
+ } else if ((value & 0xFFFFFC0000000000L) == 0) {
|
||||
+ int least7bits = (int) (value & 0xFFFFFFFL);
|
||||
+ int w = (least7bits & 0x7F) << 24
|
||||
+ | (least7bits & 0x3F80) << 9
|
||||
+ | (least7bits & 0x1FC000) >> 6
|
||||
+ | ((least7bits >>> 21) & 0x7F)
|
||||
+ | 0x80808080;
|
||||
+ int secondLeast7bits = (int) (value >>> 28);
|
||||
+ int w2 = (secondLeast7bits & 0x7F) << 8
|
||||
+ | (secondLeast7bits >>> 7)
|
||||
+ | 0x00008000;
|
||||
+ buffer.writeInt(w);
|
||||
+ buffer.writeShort(w2);
|
||||
+ } else if ((value & 0xFFFE000000000000L) == 0) {
|
||||
+ int least7bits = (int) (value & 0xFFFFFFFL);
|
||||
+ int w = (least7bits & 0x7F) << 24
|
||||
+ | (least7bits & 0x3F80) << 9
|
||||
+ | (least7bits & 0x1FC000) >> 6
|
||||
+ | ((least7bits >>> 21) & 0x7F)
|
||||
+ | 0x80808080;
|
||||
+ int secondLeast7bits = (int) (value >>> 28);
|
||||
+ int w2 = (secondLeast7bits & 0x7F) << 16
|
||||
+ | (secondLeast7bits & 0x3F80) << 1
|
||||
+ | (secondLeast7bits >>> 14)
|
||||
+ | 0x00808000;
|
||||
+ buffer.writeInt(w);
|
||||
+ buffer.writeMedium(w2);
|
||||
+ } else if ((value & 0xFF00000000000000L) == 0) {
|
||||
+ int least7bits = (int) (value & 0xFFFFFFFL);
|
||||
+ int w = (least7bits & 0x7F) << 24
|
||||
+ | (least7bits & 0x3F80) << 9
|
||||
+ | (least7bits & 0x1FC000) >> 6
|
||||
+ | ((least7bits >>> 21) & 0x7F)
|
||||
+ | 0x80808080;
|
||||
+ int secondLeast7bits = (int) (value >>> 28);
|
||||
+ int w2 = (secondLeast7bits & 0x7F) << 24
|
||||
+ | ((secondLeast7bits & 0x3F80) << 9)
|
||||
+ | (secondLeast7bits & 0x1FC000) >> 6
|
||||
+ | (secondLeast7bits >>> 21)
|
||||
+ | 0x80808000;
|
||||
+ buffer.writeInt(w);
|
||||
+ buffer.writeInt(w2);
|
||||
+ } else {
|
||||
+ int least7bits = (int) (value & 0xFFFFFFFL);
|
||||
+ int w = (least7bits & 0x7F) << 24
|
||||
+ | (least7bits & 0x3F80) << 9
|
||||
+ | (least7bits & 0x1FC000) >> 6
|
||||
+ | ((least7bits >>> 21) & 0x7F)
|
||||
+ | 0x80808080;
|
||||
+ long nonLeast7Bits = value >>> 28;
|
||||
+ int secondLeast7bits = (int) (nonLeast7Bits & 0xFFFFFFFL);
|
||||
+ int w2 = (secondLeast7bits & 0x7F) << 24
|
||||
+ | ((secondLeast7bits & 0x3F80) << 9)
|
||||
+ | (secondLeast7bits & 0x1FC000) >> 6
|
||||
+ | (secondLeast7bits >>> 21)
|
||||
+ | 0x80808080;
|
||||
+ buffer.writeInt(w);
|
||||
+ buffer.writeInt(w2);
|
||||
+ buffer.writeByte((int) (nonLeast7Bits >>> 28));
|
||||
}
|
||||
-
|
||||
- buffer.writeByte((int)value);
|
||||
return buffer;
|
||||
}
|
||||
+ // DivineMC end - Optimize VarLong
|
||||
}
|
||||
@@ -1,145 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Fri, 31 Jan 2025 22:40:54 +0300
|
||||
Subject: [PATCH] Optimize Fluids
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/LiquidBlock.java b/net/minecraft/world/level/block/LiquidBlock.java
|
||||
index ae609e0603a78423c4c89b7efb9c41ab8fe7aa52..5c143e3227371c701f36362e24bd3c1fc8061ed2 100644
|
||||
--- a/net/minecraft/world/level/block/LiquidBlock.java
|
||||
+++ b/net/minecraft/world/level/block/LiquidBlock.java
|
||||
@@ -193,6 +193,7 @@ public class LiquidBlock extends Block implements BucketPickup {
|
||||
Block block = level.getFluidState(pos).isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE;
|
||||
// CraftBukkit start
|
||||
if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, block.defaultBlockState(), 3)) {
|
||||
+ level.setBlock(pos, block.defaultBlockState(), 3); // DivineMC - Optimize Fluids
|
||||
this.fizz(level, pos);
|
||||
}
|
||||
// CraftBukkit end
|
||||
diff --git a/net/minecraft/world/level/material/FlowingFluid.java b/net/minecraft/world/level/material/FlowingFluid.java
|
||||
index 1b06e44a267d2d4af844997ac0c557f30aaf9b15..abf1866c26330fc3ec61a4457a7c6966cf0f38a7 100644
|
||||
--- a/net/minecraft/world/level/material/FlowingFluid.java
|
||||
+++ b/net/minecraft/world/level/material/FlowingFluid.java
|
||||
@@ -199,6 +199,7 @@ public abstract class FlowingFluid extends Fluid {
|
||||
BlockPos blockPos = pos.relative(direction);
|
||||
final BlockState blockStateIfLoaded = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing
|
||||
if (blockStateIfLoaded == null) continue; // Paper - Prevent chunk loading from fluid flowing
|
||||
+ if (!shouldSpreadLiquid(level, blockPos, blockStateIfLoaded)) continue; // DivineMC - Optimize Fluids
|
||||
// CraftBukkit start
|
||||
org.bukkit.block.Block source = org.bukkit.craftbukkit.block.CraftBlock.at(level, pos);
|
||||
org.bukkit.event.block.BlockFromToEvent event = new org.bukkit.event.block.BlockFromToEvent(source, org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(direction));
|
||||
@@ -213,6 +214,39 @@ public abstract class FlowingFluid extends Fluid {
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize Fluids
|
||||
+ private boolean shouldSpreadLiquid(Level level, BlockPos pos, BlockState state) {
|
||||
+ if (state.is(Blocks.LAVA)) {
|
||||
+ boolean isSoulSoil = level.getBlockState(pos.below()).is(Blocks.SOUL_SOIL);
|
||||
+
|
||||
+ for (Direction direction : net.minecraft.world.level.block.LiquidBlock.POSSIBLE_FLOW_DIRECTIONS) {
|
||||
+ BlockPos blockPos = pos.relative(direction.getOpposite());
|
||||
+ if (level.getFluidState(blockPos).is(net.minecraft.tags.FluidTags.WATER)) {
|
||||
+ Block block = level.getFluidState(pos).isSource() ? Blocks.OBSIDIAN : Blocks.COBBLESTONE;
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, block.defaultBlockState(), 3)) {
|
||||
+ this.fizz(level, pos);
|
||||
+ level.setBlock(pos, block.defaultBlockState(), 3);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ if (isSoulSoil && level.getBlockState(blockPos).is(Blocks.BLUE_ICE)) {
|
||||
+ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, pos, Blocks.BASALT.defaultBlockState(), 3)) {
|
||||
+ this.fizz(level, pos);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ private void fizz(LevelAccessor level, BlockPos pos) {
|
||||
+ level.levelEvent(1501, pos, 0);
|
||||
+ }
|
||||
+ // DivineMC end - Optimize Fluids
|
||||
+
|
||||
protected FluidState getNewLiquid(ServerLevel level, BlockPos pos, BlockState state) {
|
||||
int i = 0;
|
||||
int i1 = 0;
|
||||
@@ -342,33 +376,46 @@ public abstract class FlowingFluid extends Fluid {
|
||||
|
||||
protected abstract void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state);
|
||||
|
||||
+ // DivineMC start - Optimize Fluids
|
||||
protected int getSlopeDistance(LevelReader level, BlockPos pos, int depth, Direction direction, BlockState state, FlowingFluid.SpreadContext spreadContext) {
|
||||
- int i = 1000;
|
||||
+ int slopeFindDistance = this.getSlopeFindDistance(level);
|
||||
+ int minDistance = slopeFindDistance;
|
||||
|
||||
- for (Direction direction1 : Direction.Plane.HORIZONTAL) {
|
||||
- if (direction1 != direction) {
|
||||
- BlockPos blockPos = pos.relative(direction1);
|
||||
- BlockState blockState = spreadContext.getBlockStateIfLoaded(blockPos); // Paper - Prevent chunk loading from fluid flowing
|
||||
- if (blockState == null) continue; // Paper - Prevent chunk loading from fluid flowing
|
||||
- FluidState fluidState = blockState.getFluidState();
|
||||
- if (this.canPassThrough(level, this.getFlowing(), pos, state, direction1, blockPos, blockState, fluidState)) {
|
||||
- if (spreadContext.isHole(blockPos)) {
|
||||
- return depth;
|
||||
+ java.util.Deque<net.minecraft.world.level.material.FlowingFluid.Node> stack = new java.util.ArrayDeque<>();
|
||||
+ stack.push(new Node(pos, depth, direction));
|
||||
+
|
||||
+ while (!stack.isEmpty()) {
|
||||
+ Node current = stack.pop();
|
||||
+ BlockPos currentPos = current.pos;
|
||||
+ int currentDepth = current.depth;
|
||||
+ Direction fromDirection = current.direction;
|
||||
+
|
||||
+ for (Direction dir : Direction.Plane.HORIZONTAL) {
|
||||
+ if (dir == fromDirection) continue;
|
||||
+
|
||||
+ BlockPos neighborPos = currentPos.relative(dir);
|
||||
+ BlockState neighborState = spreadContext.getBlockStateIfLoaded(neighborPos);
|
||||
+ if (neighborState == null) continue; // Prevent chunk loading
|
||||
+
|
||||
+ FluidState fluidState = neighborState.getFluidState();
|
||||
+ if (this.canPassThrough(level, this.getFlowing(), currentPos, state, dir, neighborPos, neighborState, fluidState)) {
|
||||
+ if (spreadContext.isHole(neighborPos)) {
|
||||
+ return currentDepth;
|
||||
}
|
||||
|
||||
- if (depth < this.getSlopeFindDistance(level)) {
|
||||
- int slopeDistance = this.getSlopeDistance(level, blockPos, depth + 1, direction1.getOpposite(), blockState, spreadContext);
|
||||
- if (slopeDistance < i) {
|
||||
- i = slopeDistance;
|
||||
- }
|
||||
+ if (currentDepth + 1 < slopeFindDistance && currentDepth + 1 < minDistance) {
|
||||
+ stack.push(new Node(neighborPos, currentDepth + 1, dir.getOpposite()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- return i;
|
||||
+ return minDistance;
|
||||
}
|
||||
|
||||
+ private record Node(BlockPos pos, int depth, Direction direction) { }
|
||||
+ // DivineMC end - Optimize Fluids
|
||||
+
|
||||
boolean isWaterHole(BlockGetter level, BlockPos pos, BlockState state, BlockPos belowPos, BlockState belowState) {
|
||||
return canPassThroughWall(Direction.DOWN, level, pos, state, belowPos, belowState)
|
||||
&& (belowState.getFluidState().getType().isSame(this) || canHoldFluid(level, belowPos, belowState, this.getFlowing()));
|
||||
diff --git a/net/minecraft/world/level/material/LavaFluid.java b/net/minecraft/world/level/material/LavaFluid.java
|
||||
index 43cdc2f8fdfdeb1426e386e0084087779ef62754..e7ae29a4da3bf36b99fdab39af78f03c06696dbc 100644
|
||||
--- a/net/minecraft/world/level/material/LavaFluid.java
|
||||
+++ b/net/minecraft/world/level/material/LavaFluid.java
|
||||
@@ -236,6 +236,7 @@ public abstract class LavaFluid extends FlowingFluid {
|
||||
// CraftBukkit end
|
||||
}
|
||||
|
||||
+ level.setBlock(pos, Blocks.STONE.defaultBlockState(), 3); // DivineMC - Optimize Fluids
|
||||
this.fizz(level, pos);
|
||||
return;
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Tue, 4 Feb 2025 19:52:24 +0300
|
||||
Subject: [PATCH] Optimize Structure Generation
|
||||
|
||||
Original project: https://github.com/TelepathicGrunt/StructureLayoutOptimizer
|
||||
Original license: MIT
|
||||
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
|
||||
index 1cfa0fcd28685736fcdce4aef817e4d4cc4061cb..cd3b24a760053dcd650a1a263b3c0093a0cbb175 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
|
||||
@@ -4,6 +4,8 @@ import com.google.common.collect.Lists;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
+import java.util.ArrayList;
|
||||
+import java.util.LinkedHashSet;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
@@ -288,6 +290,108 @@ public class JigsawPlacement {
|
||||
this.random = random;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ private boolean structureLayoutOptimizer$optimizeJigsawConnecting(StructureTemplate.JigsawBlockInfo jigsaw1, StructureTemplate.JigsawBlockInfo jigsaw2) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
|
||||
+ return JigsawBlock.canAttach(jigsaw1, jigsaw2);
|
||||
+ }
|
||||
+ return org.bxteam.divinemc.util.structure.GeneralUtils.canJigsawsAttach(jigsaw1, jigsaw2);
|
||||
+ }
|
||||
+
|
||||
+ private void structureLayoutOptimizer$replaceVoxelShape3(MutableObject<VoxelShape> instance, BoundingBox pieceBounds) {
|
||||
+ org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape = new org.bxteam.divinemc.util.structure.TrojanVoxelShape(new org.bxteam.divinemc.util.structure.BoxOctree(AABB.of(pieceBounds)));
|
||||
+ instance.setValue(trojanVoxelShape);
|
||||
+ }
|
||||
+
|
||||
+ private void structureLayoutOptimizer$replaceVoxelShape4(MutableObject<VoxelShape> instance, BoundingBox pieceBounds) {
|
||||
+ if (instance.getValue() instanceof org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape) {
|
||||
+ trojanVoxelShape.boxOctree.addBox(AABB.of(pieceBounds));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private List<StructurePoolElement> structureLayoutOptimizer$removeDuplicateTemplatePoolElementLists(StructureTemplatePool instance, RandomSource random) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer || !org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.deduplicateShuffledTemplatePoolElementList) {
|
||||
+ return instance.getShuffledTemplates(random);
|
||||
+ }
|
||||
+
|
||||
+ // Linked hashset keeps order of elements.
|
||||
+ LinkedHashSet<StructurePoolElement> uniquePieces = new LinkedHashSet<>((instance).rawTemplates.size());
|
||||
+
|
||||
+ // Don't use addAll. Want to keep it simple in case of inefficiency in collection's addAll.
|
||||
+ // Set will ignore duplicates after first appearance of an element.
|
||||
+ for (StructurePoolElement piece : instance.getShuffledTemplates(random)) {
|
||||
+ //noinspection UseBulkOperation
|
||||
+ uniquePieces.add(piece);
|
||||
+ }
|
||||
+
|
||||
+ // Move the elements from set to the list in the same order.
|
||||
+ int uniquePiecesFound = uniquePieces.size();
|
||||
+ List<StructurePoolElement> deduplicatedListOfPieces = new ArrayList<>(uniquePiecesFound);
|
||||
+ for (int i = 0; i < uniquePiecesFound; i++) {
|
||||
+ deduplicatedListOfPieces.add(uniquePieces.removeFirst());
|
||||
+ }
|
||||
+
|
||||
+ return deduplicatedListOfPieces;
|
||||
+ }
|
||||
+
|
||||
+ private ArrayList<StructurePoolElement> structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists1() {
|
||||
+ // Swap with trojan list, so we can record what pieces we visited
|
||||
+ return org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.deduplicateShuffledTemplatePoolElementList ? Lists.newArrayList() : new org.bxteam.divinemc.util.structure.TrojanArrayList<>();
|
||||
+ }
|
||||
+
|
||||
+ private List structureLayoutOptimizer$skipBlockedJigsaws(
|
||||
+ List original,
|
||||
+ boolean useExpansionHack,
|
||||
+ MutableObject<VoxelShape> voxelShapeMutableObject,
|
||||
+ StructurePoolElement structurePoolElement,
|
||||
+ StructureTemplate.StructureBlockInfo parentJigsawBlockInfo,
|
||||
+ BlockPos parentTargetPosition)
|
||||
+ {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
|
||||
+ return original;
|
||||
+ }
|
||||
+ if (voxelShapeMutableObject.getValue() instanceof org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape) {
|
||||
+ // If rigid and target position is already an invalid spot, do not run rest of logic.
|
||||
+ StructureTemplatePool.Projection candidatePlacementBehavior = structurePoolElement.getProjection();
|
||||
+ boolean isCandidateRigid = candidatePlacementBehavior == StructureTemplatePool.Projection.RIGID;
|
||||
+ if (isCandidateRigid && (!trojanVoxelShape.boxOctree.boundaryContains(parentTargetPosition) || trojanVoxelShape.boxOctree.withinAnyBox(parentTargetPosition))) {
|
||||
+ return new ArrayList<>();
|
||||
+ }
|
||||
+ }
|
||||
+ return original;
|
||||
+ }
|
||||
+
|
||||
+ private List<Rotation> structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists2(List<Rotation> original,
|
||||
+ List<StructurePoolElement> list,
|
||||
+ StructurePoolElement structurepoolelement1)
|
||||
+ {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
|
||||
+ return original;
|
||||
+ }
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.deduplicateShuffledTemplatePoolElementList && list instanceof org.bxteam.divinemc.util.structure.TrojanArrayList<net.minecraft.world.level.levelgen.structure.pools.StructurePoolElement> trojanArrayList) {
|
||||
+ // Do not run this piece's logic since we already checked its 4 rotations in the past.
|
||||
+ if (trojanArrayList.elementsAlreadyParsed.contains(structurepoolelement1)) {
|
||||
+
|
||||
+ // Prime the random with the random calls we would've skipped.
|
||||
+ // Maintains vanilla compat.
|
||||
+ for (Rotation rotation1 : original) {
|
||||
+ structurepoolelement1.getShuffledJigsawBlocks(this.structureTemplateManager, BlockPos.ZERO, rotation1, this.random);
|
||||
+ }
|
||||
+
|
||||
+ // Short circuit the Rotation loop
|
||||
+ return new ArrayList<>();
|
||||
+ }
|
||||
+ // Record piece as it will go through the 4 rotation checks for spawning.
|
||||
+ else {
|
||||
+ trojanArrayList.elementsAlreadyParsed.add(structurepoolelement1);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // Allow the vanilla code to run normally.
|
||||
+ return original;
|
||||
+ }
|
||||
+ // DivineMC end - Optimize Structure Generation
|
||||
+
|
||||
void tryPlacingChildren(
|
||||
PoolElementStructurePiece piece,
|
||||
MutableObject<VoxelShape> free,
|
||||
@@ -345,9 +449,9 @@ public class JigsawPlacement {
|
||||
mutableObject1 = free;
|
||||
}
|
||||
|
||||
- List<StructurePoolElement> list = Lists.newArrayList();
|
||||
+ List<StructurePoolElement> list = structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists1(); // DivineMC - Optimize Structure Generation
|
||||
if (depth != this.maxDepth) {
|
||||
- list.addAll(holder.value().getShuffledTemplates(this.random));
|
||||
+ list.addAll(structureLayoutOptimizer$removeDuplicateTemplatePoolElementLists(holder.value(), this.random)); // DivineMC - Optimize Structure Generation
|
||||
}
|
||||
|
||||
list.addAll(fallback.value().getShuffledTemplates(this.random));
|
||||
@@ -358,10 +462,14 @@ public class JigsawPlacement {
|
||||
break;
|
||||
}
|
||||
|
||||
- for (Rotation rotation1 : Rotation.getShuffled(this.random)) {
|
||||
- List<StructureTemplate.JigsawBlockInfo> shuffledJigsawBlocks = structurePoolElement.getShuffledJigsawBlocks(
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ for (Rotation rotation1 : structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists2(Rotation.getShuffled(this.random), list, structurePoolElement)) {
|
||||
+ List<StructureTemplate.JigsawBlockInfo> shuffledJigsawBlocks = structureLayoutOptimizer$skipBlockedJigsaws(
|
||||
+ structurePoolElement.getShuffledJigsawBlocks(
|
||||
this.structureTemplateManager, BlockPos.ZERO, rotation1, this.random
|
||||
+ ), useExpansionHack, mutableObject1, structurePoolElement, structureBlockInfo, blockPos1
|
||||
);
|
||||
+ // DivineMC end - Optimize Structure Generation
|
||||
BoundingBox boundingBox1 = structurePoolElement.getBoundingBox(this.structureTemplateManager, BlockPos.ZERO, rotation1);
|
||||
int i2;
|
||||
if (useExpansionHack && boundingBox1.getYSpan() <= 16) {
|
||||
@@ -394,7 +502,7 @@ public class JigsawPlacement {
|
||||
}
|
||||
|
||||
for (StructureTemplate.JigsawBlockInfo jigsawBlockInfo1 : shuffledJigsawBlocks) {
|
||||
- if (JigsawBlock.canAttach(jigsawBlockInfo, jigsawBlockInfo1)) {
|
||||
+ if (structureLayoutOptimizer$optimizeJigsawConnecting(jigsawBlockInfo, jigsawBlockInfo1)) { // DivineMC - Optimize Structure Generation
|
||||
BlockPos blockPos2 = jigsawBlockInfo1.info().pos();
|
||||
BlockPos blockPos3 = blockPos1.subtract(blockPos2);
|
||||
BoundingBox boundingBox2 = structurePoolElement.getBoundingBox(this.structureTemplateManager, blockPos3, rotation1);
|
||||
@@ -423,9 +531,26 @@ public class JigsawPlacement {
|
||||
boundingBox3.encapsulate(new BlockPos(boundingBox3.minX(), boundingBox3.minY() + max, boundingBox3.minZ()));
|
||||
}
|
||||
|
||||
- if (!Shapes.joinIsNotEmpty(
|
||||
- mutableObject1.getValue(), Shapes.create(AABB.of(boundingBox3).deflate(0.25)), BooleanOp.ONLY_SECOND
|
||||
- )) {
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ boolean internal$joinIsNotEmpty;
|
||||
+ VoxelShape parentBounds = mutableObject1.getValue();
|
||||
+ java.util.function.Supplier<Boolean> original = () -> Shapes.joinIsNotEmpty(
|
||||
+ parentBounds, Shapes.create(AABB.of(boundingBox3).deflate(0.25)), BooleanOp.ONLY_SECOND
|
||||
+ );
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
|
||||
+ if (parentBounds instanceof org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape) {
|
||||
+ AABB pieceAABB = AABB.of(boundingBox3).deflate(0.25D);
|
||||
+
|
||||
+ // Have to inverse because of an ! outside our wrap
|
||||
+ internal$joinIsNotEmpty = !trojanVoxelShape.boxOctree.withinBoundsButNotIntersectingChildren(pieceAABB);
|
||||
+ } else {
|
||||
+ internal$joinIsNotEmpty = original.get();
|
||||
+ }
|
||||
+ } else {
|
||||
+ internal$joinIsNotEmpty = original.get();
|
||||
+ }
|
||||
+ if (!internal$joinIsNotEmpty) {
|
||||
+ // DivineMC end - Optimize Structure Generation
|
||||
mutableObject1.setValue(
|
||||
Shapes.joinUnoptimized(
|
||||
mutableObject1.getValue(), Shapes.create(AABB.of(boundingBox3)), BooleanOp.ONLY_FIRST
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java b/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java
|
||||
index 5c081a5b3d10f713e4e82fe1a43758f553fe50e0..85e84603a19964f05d9d5e62eb096ca76c36ab00 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java
|
||||
@@ -119,8 +119,16 @@ public class SinglePoolElement extends StructurePoolElement {
|
||||
StructureTemplateManager structureTemplateManager, BlockPos pos, Rotation rotation, RandomSource random
|
||||
) {
|
||||
List<StructureTemplate.JigsawBlockInfo> jigsaws = this.getTemplate(structureTemplateManager).getJigsaws(pos, rotation);
|
||||
- Util.shuffle(jigsaws, random);
|
||||
- sortBySelectionPriority(jigsaws);
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
|
||||
+ structureLayoutOptimizer$fasterJigsawListShuffling1(jigsaws, random);
|
||||
+ structureLayoutOptimizer$fasterJigsawListShuffling2(jigsaws);
|
||||
+ } else {
|
||||
+ Util.shuffle(jigsaws, random);
|
||||
+ sortBySelectionPriority(jigsaws);
|
||||
+ }
|
||||
+ // DivineMC end - Optimize Structure Generation
|
||||
+
|
||||
return jigsaws;
|
||||
}
|
||||
|
||||
@@ -196,4 +204,12 @@ public class SinglePoolElement extends StructurePoolElement {
|
||||
public ResourceLocation getTemplateLocation() {
|
||||
return this.template.orThrow();
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ private void structureLayoutOptimizer$fasterJigsawListShuffling1(List<StructureTemplate.JigsawBlockInfo> list, RandomSource randomSource) {
|
||||
+ org.bxteam.divinemc.util.structure.GeneralUtils.shuffleAndPrioritize(list, randomSource);
|
||||
+ }
|
||||
+
|
||||
+ private void structureLayoutOptimizer$fasterJigsawListShuffling2(List<StructureTemplate.JigsawBlockInfo> structureBlockInfos) { }
|
||||
+ // DivineMC 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
|
||||
index f21e612a35d6ac4482dbf5d14e506959659e371a..c02c3b1fddd513cb477cbb7400c30a9ad57f80a6 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
|
||||
@@ -255,6 +255,12 @@ public class StructureTemplate {
|
||||
return transform(pos, decorator.getMirror(), decorator.getRotation(), decorator.getRotationPivot());
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ private List<StructureTemplate.StructureBlockInfo> structureLayoutOptimizer$shrinkStructureTemplateBlocksList(StructureTemplate.Palette palette, BlockPos offset, StructurePlaceSettings settings) {
|
||||
+ return org.bxteam.divinemc.util.structure.StructureTemplateOptimizer.getStructureBlockInfosInBounds(palette, offset, settings);
|
||||
+ }
|
||||
+ // DivineMC end - Optimize Structure Generation
|
||||
+
|
||||
public boolean placeInWorld(ServerLevelAccessor serverLevel, BlockPos offset, BlockPos pos, StructurePlaceSettings settings, RandomSource random, int flags) {
|
||||
if (this.palettes.isEmpty()) {
|
||||
return false;
|
||||
@@ -272,7 +278,11 @@ public class StructureTemplate {
|
||||
}
|
||||
}
|
||||
// CraftBukkit end
|
||||
- List<StructureTemplate.StructureBlockInfo> list = settings.getRandomPalette(this.palettes, offset).blocks();
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ List<StructureTemplate.StructureBlockInfo> list = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer
|
||||
+ ? structureLayoutOptimizer$shrinkStructureTemplateBlocksList(settings.getRandomPalette(this.palettes, offset), offset, settings)
|
||||
+ : settings.getRandomPalette(this.palettes, offset).blocks();
|
||||
+ // DivineMC end - Optimize Structure Generation
|
||||
if ((!list.isEmpty() || !settings.isIgnoreEntities() && !this.entityInfoList.isEmpty())
|
||||
&& this.size.getX() >= 1
|
||||
&& this.size.getY() >= 1
|
||||
@@ -882,7 +892,11 @@ public class StructureTemplate {
|
||||
private List<StructureTemplate.JigsawBlockInfo> cachedJigsaws;
|
||||
|
||||
Palette(List<StructureTemplate.StructureBlockInfo> blocks) {
|
||||
- this.blocks = blocks;
|
||||
+ // DivineMC start - Optimize Structure Generation
|
||||
+ this.blocks = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer
|
||||
+ ? new org.bxteam.divinemc.util.structure.PalettedStructureBlockInfoList(blocks)
|
||||
+ : blocks;
|
||||
+ // DivineMC end - Optimize Structure Generation
|
||||
}
|
||||
|
||||
public List<StructureTemplate.JigsawBlockInfo> jigsaws() {
|
||||
@@ -1,309 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Tue, 4 Feb 2025 01:49:17 +0300
|
||||
Subject: [PATCH] Implement NoChatReports
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/FriendlyByteBuf.java b/net/minecraft/network/FriendlyByteBuf.java
|
||||
index bef92cfa7eb86fbc6bc1b7d862eaca575eeeadec..b8701c45a6fa635f3ea18616f7c841de9df32877 100644
|
||||
--- a/net/minecraft/network/FriendlyByteBuf.java
|
||||
+++ b/net/minecraft/network/FriendlyByteBuf.java
|
||||
@@ -106,7 +106,28 @@ public class FriendlyByteBuf extends ByteBuf {
|
||||
return this;
|
||||
}
|
||||
|
||||
+ @SuppressWarnings({"unchecked", "rawtypes"}) // DivineMC - Implement NoChatReports
|
||||
public <T> T readLenientJsonWithCodec(Codec<T> codec) {
|
||||
+ // DivineMC start - Implement NoChatReports
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) {
|
||||
+ if (codec == net.minecraft.network.protocol.status.ServerStatus.CODEC) {
|
||||
+ JsonElement jsonElement = LenientJsonParser.parse(this.readUtf());
|
||||
+ DataResult dataResult = codec.parse(JsonOps.INSTANCE, jsonElement);
|
||||
+ Object result;
|
||||
+ try {
|
||||
+ result = dataResult.getOrThrow(string -> new DecoderException("Failed to decode json: " + string));
|
||||
+ } catch (Throwable e) {
|
||||
+ throw new RuntimeException("Unable to decode json!", e);
|
||||
+ }
|
||||
+
|
||||
+ if (jsonElement.getAsJsonObject().has("preventsChatReports")) {
|
||||
+ ((net.minecraft.network.protocol.status.ServerStatus) result).setPreventsChatReports(jsonElement.getAsJsonObject().get("preventsChatReports").getAsBoolean());
|
||||
+ }
|
||||
+
|
||||
+ return (T) (result);
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
JsonElement jsonElement = LenientJsonParser.parse(this.readUtf());
|
||||
DataResult<T> dataResult = codec.parse(JsonOps.INSTANCE, jsonElement);
|
||||
return dataResult.getOrThrow(string -> new DecoderException("Failed to decode JSON: " + string));
|
||||
@@ -118,6 +139,19 @@ public class FriendlyByteBuf extends ByteBuf {
|
||||
}
|
||||
public <T> void writeJsonWithCodec(Codec<T> codec, T value, int maxLength) {
|
||||
// Paper end - Adventure; add max length parameter
|
||||
+ // DivineMC start - Implement NoChatReports
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsAddQueryData && codec == net.minecraft.network.protocol.status.ServerStatus.CODEC) {
|
||||
+ DataResult<JsonElement> dataResult = codec.encodeStart(JsonOps.INSTANCE, value);
|
||||
+ JsonElement element = dataResult.getOrThrow(string -> new EncoderException("Failed to encode: " + string + " " + value));
|
||||
+
|
||||
+ element.getAsJsonObject().addProperty("preventsChatReports", true);
|
||||
+
|
||||
+ this.writeUtf(GSON.toJson(element));
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
DataResult<JsonElement> dataResult = codec.encodeStart(JsonOps.INSTANCE, value);
|
||||
this.writeUtf(GSON.toJson(dataResult.getOrThrow(exception -> new EncoderException("Failed to encode: " + exception + " " + value))), maxLength); // Paper - Adventure; add max length parameter
|
||||
}
|
||||
diff --git a/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java b/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java
|
||||
index 07943553b562b95076bdce232d6f0796f469400f..478c07e8c569d35761ce138cf1deed9511b826d6 100644
|
||||
--- a/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ServerboundChatCommandSignedPacket.java
|
||||
@@ -36,4 +36,15 @@ public record ServerboundChatCommandSignedPacket(
|
||||
public void handle(ServerGamePacketListener handler) {
|
||||
handler.handleSignedChatCommand(this);
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Implement NoChatReports
|
||||
+ @Override
|
||||
+ public ArgumentSignatures argumentSignatures() {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) {
|
||||
+ return ArgumentSignatures.EMPTY;
|
||||
+ }
|
||||
+
|
||||
+ return argumentSignatures;
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
}
|
||||
diff --git a/net/minecraft/network/protocol/game/ServerboundChatPacket.java b/net/minecraft/network/protocol/game/ServerboundChatPacket.java
|
||||
index b5afc05924ae899e020c303c8b86398e1d4ab8a0..2a6fdec4faae3512060cbb21a2043129765a480e 100644
|
||||
--- a/net/minecraft/network/protocol/game/ServerboundChatPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ServerboundChatPacket.java
|
||||
@@ -36,4 +36,16 @@ public record ServerboundChatPacket(String message, Instant timeStamp, long salt
|
||||
public void handle(ServerGamePacketListener handler) {
|
||||
handler.handleChat(this);
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Implement NoChatReports
|
||||
+ @Override
|
||||
+ @Nullable
|
||||
+ public MessageSignature signature() {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ return signature;
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
}
|
||||
diff --git a/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java b/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java
|
||||
index 1df628ac0b414511aaed6e09d78f884c4170f730..1543f730843c1736c4db9a6ebe30be9cc9fbe36a 100644
|
||||
--- a/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java
|
||||
@@ -26,6 +26,19 @@ public record ServerboundChatSessionUpdatePacket(RemoteChatSession.Data chatSess
|
||||
|
||||
@Override
|
||||
public void handle(ServerGamePacketListener handler) {
|
||||
+ // DivineMC start - Implement NoChatReports
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) {
|
||||
+ var impl = (net.minecraft.server.network.ServerGamePacketListenerImpl) handler;
|
||||
+
|
||||
+ if (!impl.getPlayer().getServer().isSingleplayerOwner(impl.getPlayer().getGameProfile())) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsDemandOnClient) {
|
||||
+ impl.disconnect(net.minecraft.network.chat.Component.literal(org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsDisconnectDemandOnClientMessage));
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
handler.handleChatSessionUpdate(this);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/network/protocol/status/ServerStatus.java b/net/minecraft/network/protocol/status/ServerStatus.java
|
||||
index a491be4250de3199c3e1aa9e5482b568692bd2f5..c88826db76c28c536e6c36c5592d69c12de395d0 100644
|
||||
--- a/net/minecraft/network/protocol/status/ServerStatus.java
|
||||
+++ b/net/minecraft/network/protocol/status/ServerStatus.java
|
||||
@@ -15,13 +15,7 @@ import net.minecraft.network.chat.CommonComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.ComponentSerialization;
|
||||
|
||||
-public record ServerStatus(
|
||||
- Component description,
|
||||
- Optional<ServerStatus.Players> players,
|
||||
- Optional<ServerStatus.Version> version,
|
||||
- Optional<ServerStatus.Favicon> favicon,
|
||||
- boolean enforcesSecureChat
|
||||
-) {
|
||||
+public final class ServerStatus {
|
||||
public static final Codec<ServerStatus> CODEC = RecordCodecBuilder.create(
|
||||
instance -> instance.group(
|
||||
ComponentSerialization.CODEC.lenientOptionalFieldOf("description", CommonComponents.EMPTY).forGetter(ServerStatus::description),
|
||||
@@ -33,6 +27,63 @@ public record ServerStatus(
|
||||
.apply(instance, ServerStatus::new)
|
||||
);
|
||||
|
||||
+ // DivineMC start - Implement NoChatReports - convert to class
|
||||
+ private final Component description;
|
||||
+ private final Optional<Players> players;
|
||||
+ private final Optional<Version> version;
|
||||
+ private final Optional<Favicon> favicon;
|
||||
+ private final boolean enforcesSecureChat;
|
||||
+ private boolean preventsChatReports;
|
||||
+
|
||||
+ public ServerStatus(
|
||||
+ Component description,
|
||||
+ Optional<Players> players,
|
||||
+ Optional<Version> version,
|
||||
+ Optional<Favicon> favicon,
|
||||
+ boolean enforcesSecureChat
|
||||
+ ) {
|
||||
+ this.description = description;
|
||||
+ this.players = players;
|
||||
+ this.version = version;
|
||||
+ this.favicon = favicon;
|
||||
+ this.enforcesSecureChat = enforcesSecureChat;
|
||||
+ }
|
||||
+
|
||||
+ public Component description() {
|
||||
+ return description;
|
||||
+ }
|
||||
+
|
||||
+ public Optional<Players> players() {
|
||||
+ return players;
|
||||
+ }
|
||||
+
|
||||
+ public Optional<Version> version() {
|
||||
+ return version;
|
||||
+ }
|
||||
+
|
||||
+ public Optional<Favicon> favicon() {
|
||||
+ return favicon;
|
||||
+ }
|
||||
+
|
||||
+ public boolean enforcesSecureChat() {
|
||||
+ return enforcesSecureChat;
|
||||
+ }
|
||||
+
|
||||
+ public boolean preventsChatReports() {
|
||||
+ var self = (ServerStatus) (Object) this;
|
||||
+
|
||||
+ if (self.version().isPresent() && self.version().get().protocol() < 759
|
||||
+ && self.version().get().protocol() > 0)
|
||||
+ return true;
|
||||
+
|
||||
+ return this.preventsChatReports;
|
||||
+ }
|
||||
+
|
||||
+ public void setPreventsChatReports(boolean prevents) {
|
||||
+ this.preventsChatReports = prevents;
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
+
|
||||
public record Favicon(byte[] iconBytes) {
|
||||
private static final String PREFIX = "data:image/png;base64,";
|
||||
public static final Codec<ServerStatus.Favicon> CODEC = Codec.STRING.comapFlatMap(string -> {
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 104a9ec97bd39e15f6707f19865fa6fcf47f6e4f..46adbe6ccf1e4291e33a52a6612f624558c18f96 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -623,6 +623,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
|
||||
@Override
|
||||
public boolean enforceSecureProfile() {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) return false; // DivineMC - Implement NoChatReports
|
||||
DedicatedServerProperties properties = this.getProperties();
|
||||
// Paper start - Add setting for proxy online mode status
|
||||
return properties.enforceSecureProfile
|
||||
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index 1975aeecbfdebaacecae1c43005d4ff26fa6a263..e5d6e5ec12168936d6d50b2f38a3cb58150b0af1 100644
|
||||
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -343,10 +343,64 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
}
|
||||
|
||||
public void send(Packet<?> packet) {
|
||||
+ // DivineMC start - Implement NoChatReports
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) {
|
||||
+ Object self = this;
|
||||
+ boolean cancel = false;
|
||||
+
|
||||
+ if (self instanceof ServerGamePacketListenerImpl listener) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsDebugLog && packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket chat) {
|
||||
+ MinecraftServer.LOGGER.info("Sending message: {}", chat.unsignedContent() != null ? chat.unsignedContent()
|
||||
+ : chat.body().content());
|
||||
+ }
|
||||
+
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsConvertToGameMessage) {
|
||||
+ if (packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket chat) {
|
||||
+ packet = new net.minecraft.network.protocol.game.ClientboundSystemChatPacket(chat.chatType().decorate(
|
||||
+ chat.unsignedContent() != null ? chat.unsignedContent()
|
||||
+ : Component.literal(chat.body().content())
|
||||
+ ), false);
|
||||
+
|
||||
+ cancel = true;
|
||||
+ listener.send(packet);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (cancel) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
this.send(packet, null);
|
||||
}
|
||||
|
||||
public void send(Packet<?> packet, @Nullable ChannelFutureListener channelFutureListener) {
|
||||
+ // DivineMC start - Implement NoChatReports
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) {
|
||||
+ Object self = this;
|
||||
+ boolean cancel = false;
|
||||
+
|
||||
+ if (self instanceof ServerGamePacketListenerImpl listenerImpl) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsDebugLog && packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket chat) {
|
||||
+ MinecraftServer.LOGGER.info("Sending message: {}", chat.unsignedContent() != null ? chat.unsignedContent()
|
||||
+ : chat.body().content());
|
||||
+ }
|
||||
+
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsConvertToGameMessage) {
|
||||
+ if (packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket chat && channelFutureListener != null) {
|
||||
+ cancel = true;
|
||||
+ listenerImpl.send(chat);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ if (cancel) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Implement NoChatReports
|
||||
// CraftBukkit start
|
||||
if (packet == null || this.processedDisconnect) { // Spigot
|
||||
return;
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 1e4ebfa25e63c148fe7bf6cf5789e602d8e5ca83..259572797f17c3c660de9fd42bb1cebe600fbf27 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -276,7 +276,7 @@ public abstract class PlayerList {
|
||||
!_boolean,
|
||||
_boolean2,
|
||||
player.createCommonSpawnInfo(serverLevel),
|
||||
- this.server.enforceSecureProfile()
|
||||
+ org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled || this.server.enforceSecureProfile() // DivineMC - Implement NoChatReports
|
||||
)
|
||||
);
|
||||
player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit
|
||||
@@ -1331,6 +1331,7 @@ public abstract class PlayerList {
|
||||
}
|
||||
|
||||
public boolean verifyChatTrusted(PlayerChatMessage message) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.noChatReportsEnabled) return true; // DivineMC - Implement NoChatReports
|
||||
return message.hasSignature() && !message.hasExpiredServer(Instant.now());
|
||||
}
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 18:38:26 +0300
|
||||
Subject: [PATCH] Lag compensation
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 221afb586fa0a0826809fb2c0c956450b461b341..2a03d85b15377f5c5286a6fea5b592b9ff76b791 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -288,6 +288,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
|
||||
public boolean lagging = false; // Purpur - Lagging threshold
|
||||
protected boolean upnp = false; // Purpur - UPnP Port Forwarding
|
||||
+ 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) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
@@ -1536,6 +1537,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
|
||||
this.server.spark.tickStart(); // Paper - spark
|
||||
+ this.tpsCalculator.doTick(); // DivineMC - Lag compenstation
|
||||
new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper - Server Tick Events
|
||||
this.tickCount++;
|
||||
this.tickRateManager.tick();
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 4a2cace22512fe06c1713bc8735e775e3012f3bc..85c4d709b6d04e8f43baf7b900ee59eae5d98fe0 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -216,6 +216,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 net.minecraft.world.item.ItemStack ominousBanner; // DivineMC - Optimize Raids
|
||||
+ public org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag Compensation
|
||||
|
||||
@Override
|
||||
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
|
||||
@@ -763,6 +764,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
}
|
||||
|
||||
+ this.tpsCalculator.doTick(); // DivineMC - Lag compensation
|
||||
+
|
||||
this.updateSkyBrightness();
|
||||
if (runsNormally) {
|
||||
this.tickTime();
|
||||
@@ -844,11 +847,18 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.setDayTime(this.preciseTime);
|
||||
} else
|
||||
// Purpur end - Configurable daylight cycle
|
||||
- this.setDayTime(this.levelData.getDayTime() + 1L);
|
||||
+ this.setDayTime(lagCompensation(this.levelData.getDayTime()) + 1L); // DivineMC - Lag compensation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private long lagCompensation(long original) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.timeAcceleration) return original;
|
||||
+ return original + this.tpsCalculator.applicableMissedTicks();
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
public void setDayTime(long time) {
|
||||
this.serverLevelData.setDayTime(time);
|
||||
// Purpur start - Configurable daylight cycle
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 3344c477a55b3ed28e8e9847be642ce2cf233995..76a7898c040cd46df6a889535b1d77c8e6de5a91 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -523,6 +523,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
}
|
||||
}
|
||||
|
||||
+ lagCompensation(); // DivineMC - Lag Compensation
|
||||
this.tickEffects();
|
||||
this.yHeadRotO = this.yHeadRot;
|
||||
this.yBodyRotO = this.yBodyRot;
|
||||
@@ -530,6 +531,17 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
this.xRotO = this.getXRot();
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag Compensation
|
||||
+ private void lagCompensation() {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.potionEffectAcceleration) return;
|
||||
+ if (this.level().isClientSide()) return;
|
||||
+
|
||||
+ for (int i = 0; i < ((ServerLevel) this.level()).tpsCalculator.applicableMissedTicks(); i++) {
|
||||
+ tickEffects();
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Lag Compensation
|
||||
+
|
||||
@Override
|
||||
protected float getBlockSpeedFactor() {
|
||||
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
|
||||
index 88b07fbb96b20124777889830afa480673629d43..91f6d43b3785ddad7db8eb529ba3293c45f3588d 100644
|
||||
--- a/net/minecraft/world/entity/PortalProcessor.java
|
||||
+++ b/net/minecraft/world/entity/PortalProcessor.java
|
||||
@@ -24,10 +24,20 @@ public class PortalProcessor {
|
||||
return false;
|
||||
} else {
|
||||
this.insidePortalThisTick = false;
|
||||
- return canChangeDimensions && this.portalTime++ >= this.portal.getPortalTransitionTime(level, entity);
|
||||
+ return canChangeDimensions && lagCompensation(this.portalTime++, level) >= this.portal.getPortalTransitionTime(level, entity); // DivineMC - Lag compensation
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private int lagCompensation(int original, ServerLevel world) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.portalAcceleration) return original;
|
||||
+ if (world.isClientSide()) return original;
|
||||
+
|
||||
+ portalTime = portalTime + world.tpsCalculator.applicableMissedTicks();
|
||||
+ return portalTime;
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
@Nullable
|
||||
public TeleportTransition getPortalDestination(ServerLevel level, Entity entity) {
|
||||
return this.portal.getPortalDestination(level, entity, this.entryPosition);
|
||||
diff --git a/net/minecraft/world/entity/item/ItemEntity.java b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
index d650d4f34fde0682ab76360408f7ff6a7d4b4c3a..f738db4aa54a5961e1484737b99de133f7e92b68 100644
|
||||
--- a/net/minecraft/world/entity/item/ItemEntity.java
|
||||
+++ b/net/minecraft/world/entity/item/ItemEntity.java
|
||||
@@ -158,8 +158,25 @@ public class ItemEntity extends Entity implements TraceableEntity {
|
||||
}
|
||||
// Paper end - EAR 2
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private void lagCompensation() {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.pickupAcceleration) return;
|
||||
+ if ((this).level().isClientSide()) return;
|
||||
+
|
||||
+ if (pickupDelay == 0) return;
|
||||
+
|
||||
+ if (pickupDelay - ((ServerLevel) this.level()).tpsCalculator.applicableMissedTicks() <= 0) {
|
||||
+ pickupDelay = 0;
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ pickupDelay = pickupDelay - ((ServerLevel) this.level()).tpsCalculator.applicableMissedTicks();
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
@Override
|
||||
public void tick() {
|
||||
+ lagCompensation(); // DivineMC - Lag compensation
|
||||
if (this.getItem().isEmpty()) {
|
||||
this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
|
||||
} else {
|
||||
diff --git a/net/minecraft/world/item/Item.java b/net/minecraft/world/item/Item.java
|
||||
index 40cb5e6bbcf9dbdb400f1503e86c0804b60e07be..d5352cbb4a64631a0a831de880efa21e1b3f6092 100644
|
||||
--- a/net/minecraft/world/item/Item.java
|
||||
+++ b/net/minecraft/world/item/Item.java
|
||||
@@ -286,10 +286,25 @@ public class Item implements FeatureElement, ItemLike {
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private int lagCompensation(int original, net.minecraft.server.level.ServerLevel level) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.eatingAcceleration || original == 0) return original;
|
||||
+ return org.bxteam.divinemc.util.tps.TPSUtil.tt20(original, true, level);
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
public int getUseDuration(ItemStack stack, LivingEntity entity) {
|
||||
Consumable consumable = stack.get(DataComponents.CONSUMABLE);
|
||||
if (consumable != null) {
|
||||
- return consumable.consumeTicks();
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ int original = consumable.consumeTicks();
|
||||
+
|
||||
+ if (entity.level() instanceof net.minecraft.server.level.ServerLevel serverLevel) {
|
||||
+ return lagCompensation(original, serverLevel);
|
||||
+ }
|
||||
+
|
||||
+ return original;
|
||||
+ // DivineMC end - Lag compensation
|
||||
} else {
|
||||
BlocksAttacks blocksAttacks = stack.get(DataComponents.BLOCKS_ATTACKS);
|
||||
return blocksAttacks != null ? 72000 : 0;
|
||||
diff --git a/net/minecraft/world/level/GameRules.java b/net/minecraft/world/level/GameRules.java
|
||||
index c78a68df7f088338b18b6c2511d8db62bb809c52..5ad9ad7303b1322e811f178f03b1853afcd13c96 100644
|
||||
--- a/net/minecraft/world/level/GameRules.java
|
||||
+++ b/net/minecraft/world/level/GameRules.java
|
||||
@@ -366,8 +366,31 @@ public class GameRules {
|
||||
}
|
||||
|
||||
public int getInt(GameRules.Key<GameRules.IntegerValue> key) {
|
||||
- return this.getRule(key).get();
|
||||
+ return lagCompensation(this.getRule(key).get(), key); // DivineMC - Lag compensation
|
||||
+ }
|
||||
+
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private final java.util.concurrent.atomic.AtomicReference<net.minecraft.server.level.ServerLevel> level = new java.util.concurrent.atomic.AtomicReference<>();
|
||||
+
|
||||
+ private int lagCompensation(int original, GameRules.Key<GameRules.IntegerValue> rule) {
|
||||
+ ServerLevel level = getOrCacheLevel();
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.randomTickSpeedAcceleration) return original;
|
||||
+ if (!(rule == GameRules.RULE_RANDOMTICKING)) return original;
|
||||
+ return (int) (original * org.bxteam.divinemc.util.tps.TPSCalculator.MAX_TPS / (float) level.tpsCalculator.getMostAccurateTPS());
|
||||
+ }
|
||||
+
|
||||
+ private ServerLevel getOrCacheLevel() {
|
||||
+ if (level.get() == null) {
|
||||
+ for (final ServerLevel level : MinecraftServer.getServer().getAllLevels()) {
|
||||
+ if (level.getGameRules() == this) {
|
||||
+ this.level.set(level);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return level.get();
|
||||
}
|
||||
+ // DivineMC end - Lag compensation
|
||||
|
||||
public static class BooleanValue extends GameRules.Value<GameRules.BooleanValue> {
|
||||
private boolean value;
|
||||
diff --git a/net/minecraft/world/level/block/state/BlockBehaviour.java b/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
index 8db95b74f88f8096de93115ae8d3fb2e6184ad3b..e044830439fe9821ab3f62695d318a6321b8a266 100644
|
||||
--- a/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
+++ b/net/minecraft/world/level/block/state/BlockBehaviour.java
|
||||
@@ -347,13 +347,21 @@ public abstract class BlockBehaviour implements FeatureElement {
|
||||
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private float lagCompensation(float original, Player player) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.blockBreakingAcceleration) return original;
|
||||
+ if (player.level().isClientSide) return original;
|
||||
+ return original * org.bxteam.divinemc.util.tps.TPSCalculator.MAX_TPS / (float) ((ServerLevel) player.level()).tpsCalculator.getMostAccurateTPS();
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
protected float getDestroyProgress(BlockState state, Player player, BlockGetter level, BlockPos pos) {
|
||||
float destroySpeed = state.getDestroySpeed(level, pos);
|
||||
if (destroySpeed == -1.0F) {
|
||||
- return 0.0F;
|
||||
+ return lagCompensation(0.0F, player); // DivineMC - Lag compensation
|
||||
} else {
|
||||
int i = player.hasCorrectToolForDrops(state) ? 30 : 100;
|
||||
- return player.getDestroySpeed(state) / destroySpeed / i;
|
||||
+ return lagCompensation(player.getDestroySpeed(state) / destroySpeed / i, player); // DivineMC - Lag compensation
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 6d9274f0da9507d0152611d6b7785e0524dedb2d..1ffd82f8459525c73ea2f4a57568eb5966b312dd 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -917,6 +917,19 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
this.ticker = ticker;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private <T extends BlockEntity> void lagCompensation(Runnable original) {
|
||||
+ original.run();
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled) return;
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.blockEntityAcceleration) return;
|
||||
+ if (LevelChunk.this.level.isClientSide()) return;
|
||||
+
|
||||
+ for (int i = 0; i < ((ServerLevel) this.blockEntity.getLevel()).tpsCalculator.applicableMissedTicks(); i++) {
|
||||
+ original.run();
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
@Override
|
||||
public void tick() {
|
||||
if (!this.blockEntity.isRemoved() && this.blockEntity.hasLevel()) {
|
||||
@@ -925,7 +938,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
try {
|
||||
BlockState blockState = LevelChunk.this.getBlockState(blockPos);
|
||||
if (this.blockEntity.getType().isValid(blockState)) {
|
||||
- this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity);
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ lagCompensation(() -> {
|
||||
+ this.ticker.tick(LevelChunk.this.level, this.blockEntity.getBlockPos(), blockState, this.blockEntity);
|
||||
+ });
|
||||
+ // DivineMC end - Lag compensation
|
||||
this.loggedInvalidBlockState = false;
|
||||
// Paper start - Remove the Block Entity if it's invalid
|
||||
} else {
|
||||
diff --git a/net/minecraft/world/level/material/LavaFluid.java b/net/minecraft/world/level/material/LavaFluid.java
|
||||
index e7ae29a4da3bf36b99fdab39af78f03c06696dbc..6ae99a4dc04f48342b948fcfeaffc68babe60f96 100644
|
||||
--- a/net/minecraft/world/level/material/LavaFluid.java
|
||||
+++ b/net/minecraft/world/level/material/LavaFluid.java
|
||||
@@ -187,9 +187,22 @@ public abstract class LavaFluid extends FlowingFluid {
|
||||
return fluidState.getHeight(blockReader, pos) >= 0.44444445F && fluid.is(FluidTags.WATER);
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private int lagCompensation(int original, ServerLevel level) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.fluidAcceleration) return original;
|
||||
+ return org.bxteam.divinemc.util.tps.TPSUtil.tt20(original, true, level);
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
@Override
|
||||
public int getTickDelay(LevelReader level) {
|
||||
- return level.dimensionType().ultraWarm() ? level.getWorldBorder().world.purpurConfig.lavaSpeedNether : level.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur - Make lava flow speed configurable
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ int original = level.dimensionType().ultraWarm() ? level.getWorldBorder().world.purpurConfig.lavaSpeedNether : level.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur - Make lava flow speed configurable
|
||||
+ if (level instanceof ServerLevel serverLevel) {
|
||||
+ return lagCompensation(original, serverLevel);
|
||||
+ }
|
||||
+ return original;
|
||||
+ // DivineMC end - Lag compensation
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/level/material/WaterFluid.java b/net/minecraft/world/level/material/WaterFluid.java
|
||||
index b248fe1d66940c05d56fc322df61c52ece72e77f..2a35dcf66dc01e787f9767a90c08a6cb283576e4 100644
|
||||
--- a/net/minecraft/world/level/material/WaterFluid.java
|
||||
+++ b/net/minecraft/world/level/material/WaterFluid.java
|
||||
@@ -124,8 +124,16 @@ public abstract class WaterFluid extends FlowingFluid {
|
||||
return 1;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Lag compensation
|
||||
+ private int lagCompensation(ServerLevel level) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.lagCompensationEnabled || !org.bxteam.divinemc.config.DivineConfig.MiscCategory.fluidAcceleration) return 5;
|
||||
+ return org.bxteam.divinemc.util.tps.TPSUtil.tt20(5, true, level);
|
||||
+ }
|
||||
+ // DivineMC end - Lag compensation
|
||||
+
|
||||
@Override
|
||||
public int getTickDelay(LevelReader level) {
|
||||
+ if (level instanceof ServerLevel serverLevel) return lagCompensation(serverLevel); // DivineMC - Lag compensation
|
||||
return 5;
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 24 Feb 2025 19:29:58 +0300
|
||||
Subject: [PATCH] Virtual Threads
|
||||
|
||||
|
||||
diff --git a/net/minecraft/Util.java b/net/minecraft/Util.java
|
||||
index 138a58c5e5698b926b01e0170733dc3dbc5589ec..bfe52d5a93a35cafcb8965482b1c1d6c398255e4 100644
|
||||
--- a/net/minecraft/Util.java
|
||||
+++ b/net/minecraft/Util.java
|
||||
@@ -98,7 +98,12 @@ public class Util {
|
||||
public static final TracingExecutor DIMENSION_DATA_IO_POOL = makeExtraIoExecutor("Dimension-Data-IO-Worker-"); // Paper - Separate dimension data IO pool
|
||||
private static final TracingExecutor DOWNLOAD_POOL = makeIoExecutor("Download-", true);
|
||||
// Paper start - don't submit BLOCKING PROFILE LOOKUPS to the world gen thread
|
||||
- public static final ExecutorService PROFILE_EXECUTOR = Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory() {
|
||||
+ // DivineMC start - Virtual Threads
|
||||
+ public static final ExecutorService PROFILE_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualProfileLookupPool
|
||||
+ ? Executors.newVirtualThreadPerTaskExecutor()
|
||||
+ : Executors.newFixedThreadPool(2, new java.util.concurrent.ThreadFactory()
|
||||
+ {
|
||||
+ // DivineMC end - Virtual Threads
|
||||
|
||||
private final AtomicInteger count = new AtomicInteger();
|
||||
|
||||
diff --git a/net/minecraft/commands/Commands.java b/net/minecraft/commands/Commands.java
|
||||
index 758ce439d2e10e6ef42a58d147a77093667e0acd..de622982f864d96a5b76efcd69f1836ef541317b 100644
|
||||
--- a/net/minecraft/commands/Commands.java
|
||||
+++ b/net/minecraft/commands/Commands.java
|
||||
@@ -481,7 +481,7 @@ public class Commands {
|
||||
}
|
||||
|
||||
// Fixed pool, but with discard policy
|
||||
- public static final java.util.concurrent.ExecutorService COMMAND_SENDING_POOL = new java.util.concurrent.ThreadPoolExecutor(
|
||||
+ public static final java.util.concurrent.ExecutorService COMMAND_SENDING_POOL = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualCommandBuilderScheduler ? java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor() : new java.util.concurrent.ThreadPoolExecutor( // DivineMC - Virtual Threads
|
||||
2, 2, 0, java.util.concurrent.TimeUnit.MILLISECONDS,
|
||||
new java.util.concurrent.LinkedBlockingQueue<>(),
|
||||
new com.google.common.util.concurrent.ThreadFactoryBuilder()
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 2a03d85b15377f5c5286a6fea5b592b9ff76b791..1877ee1431b0f858b6a5da7347d72fe90374e27a 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -2644,8 +2644,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
}
|
||||
}
|
||||
|
||||
- public final java.util.concurrent.ExecutorService chatExecutor = java.util.concurrent.Executors.newCachedThreadPool(
|
||||
- new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Chat Thread - #%d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
|
||||
+ // DivineMC start - Virtual Threads
|
||||
+ public final java.util.concurrent.ExecutorService chatExecutor = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualChatScheduler
|
||||
+ ? java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()
|
||||
+ : java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Chat Thread - #%d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(net.minecraft.server.MinecraftServer.LOGGER)).build()); // Paper
|
||||
+ // DivineMC end - Virtual Threads
|
||||
public final ChatDecorator improvedChatDecorator = new io.papermc.paper.adventure.ImprovedChatDecorator(this); // Paper - adventure
|
||||
|
||||
public ChatDecorator getChatDecorator() {
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index b58fc16f9054f36d5ddb2dffabd9274969e56897..2d3200834e46a24156659a32170aa4974caf8060 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -838,8 +838,11 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
// Paper start - AsyncTabCompleteEvent
|
||||
- private static final java.util.concurrent.ExecutorService TAB_COMPLETE_EXECUTOR = java.util.concurrent.Executors.newFixedThreadPool(4,
|
||||
- new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Tab Complete Thread - #%d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)).build());
|
||||
+ // DivineMC start - Virtual Threads
|
||||
+ private static final java.util.concurrent.ExecutorService TAB_COMPLETE_EXECUTOR = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualTabCompleteScheduler
|
||||
+ ? java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()
|
||||
+ : java.util.concurrent.Executors.newFixedThreadPool(4, new com.google.common.util.concurrent.ThreadFactoryBuilder().setDaemon(true).setNameFormat("Async Tab Complete Thread - #%d").setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(MinecraftServer.LOGGER)).build());
|
||||
+ // DivineMC end - Virtual Threads
|
||||
// Paper end - AsyncTabCompleteEvent
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/server/network/ServerTextFilter.java b/net/minecraft/server/network/ServerTextFilter.java
|
||||
index b3d46e7687c572d9847124eb58e4a6011a78066c..9d2e2b1cff68383cd19b42e24559e3009ef1df54 100644
|
||||
--- a/net/minecraft/server/network/ServerTextFilter.java
|
||||
+++ b/net/minecraft/server/network/ServerTextFilter.java
|
||||
@@ -48,7 +48,11 @@ public abstract class ServerTextFilter implements AutoCloseable {
|
||||
final ExecutorService workerPool;
|
||||
|
||||
protected static ExecutorService createWorkerPool(int size) {
|
||||
- return Executors.newFixedThreadPool(size, THREAD_FACTORY);
|
||||
+ // DivineMC start - Virtual Threads
|
||||
+ return org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualThreadsEnabled && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.virtualServerTextFilterPool
|
||||
+ ? Executors.newVirtualThreadPerTaskExecutor()
|
||||
+ : Executors.newFixedThreadPool(size, THREAD_FACTORY);
|
||||
+ // DivineMC end - Virtual Threads
|
||||
}
|
||||
|
||||
protected ServerTextFilter(
|
||||
@@ -1,185 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 3 Mar 2025 19:29:13 +0300
|
||||
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
|
||||
index 1ed2ae41e47b2446bf1835efc8bad369408d52da..c4a1e3908cf8e1b0614ff6c3a0f5f6708a7667e5 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -441,7 +441,13 @@ public final class RegionizedPlayerChunkLoader {
|
||||
// Note: drop isAlive() check so that chunks properly unload client-side when the player dies
|
||||
((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$removeReceivedChunk(this.player);
|
||||
- this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)));
|
||||
+ // DivineMC start - Async Chunk Sending
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) {
|
||||
+ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ))));
|
||||
+ } else {
|
||||
+ this.player.connection.send(new ClientboundForgetLevelChunkPacket(new ChunkPos(chunkX, chunkZ)));
|
||||
+ }
|
||||
+ // DivineMC end - Async Chunk Sending
|
||||
// Paper start - PlayerChunkUnloadEvent
|
||||
if (io.papermc.paper.event.packet.PlayerChunkUnloadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
new io.papermc.paper.event.packet.PlayerChunkUnloadEvent(player.getBukkitEntity().getWorld().getChunkAt(new ChunkPos(chunkX, chunkZ).longKey), player.getBukkitEntity()).callEvent();
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
index 9f6d7c5dc0e591488a8a3763d8a1f1b3671d5299..4983a34e42ef972f2d5ad8a12dfad99ca88d7032 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkPacketData.java
|
||||
@@ -75,6 +75,52 @@ public class ClientboundLevelChunkPacketData {
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Async Chunk Sending
|
||||
+ public ClientboundLevelChunkPacketData(LevelChunk levelChunk, io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo, BlockEntity[] blockEntities, Map<Heightmap.Types, long[]> heightmaps) {
|
||||
+ this.heightmaps = heightmaps;
|
||||
+
|
||||
+ if (Thread.currentThread() instanceof org.bxteam.divinemc.async.AsyncChunkSend.AsyncChunkSendThread) {
|
||||
+ int size = calculateChunkSize(levelChunk);
|
||||
+ ByteBuf buffer = Unpooled.buffer(size);
|
||||
+ extractChunkData(new FriendlyByteBuf(buffer), levelChunk, chunkPacketInfo);
|
||||
+ // make sure all sections is latest
|
||||
+ while (size != buffer.writerIndex()) {
|
||||
+ buffer.writerIndex(0);
|
||||
+ size = calculateChunkSize(levelChunk);
|
||||
+ extractChunkData(new FriendlyByteBuf(buffer), levelChunk, chunkPacketInfo);
|
||||
+ }
|
||||
+ byte[] array = it.unimi.dsi.fastutil.bytes.ByteArrays.setLength(buffer.array(), buffer.writerIndex());
|
||||
+ if (chunkPacketInfo != null) {
|
||||
+ chunkPacketInfo.setBuffer(array);
|
||||
+ }
|
||||
+ this.buffer = array;
|
||||
+ } else {
|
||||
+ this.buffer = new byte[calculateChunkSize(levelChunk)];
|
||||
+ // Paper start - Anti-Xray - Add chunk packet info
|
||||
+ if (chunkPacketInfo != null) {
|
||||
+ chunkPacketInfo.setBuffer(this.buffer);
|
||||
+ }
|
||||
+ extractChunkData(new FriendlyByteBuf(this.getWriteBuffer()), levelChunk, chunkPacketInfo);
|
||||
+ }
|
||||
+
|
||||
+ this.blockEntitiesData = Lists.newArrayList();
|
||||
+ int totalTileEntities = 0; // Paper - Handle oversized block entities in chunks
|
||||
+
|
||||
+ for (BlockEntity blockEntity : blockEntities) {
|
||||
+ // Paper start - Handle oversized block entities in chunks
|
||||
+ if (++totalTileEntities > BLOCK_ENTITY_LIMIT) {
|
||||
+ net.minecraft.network.protocol.Packet<ClientGamePacketListener> packet = blockEntity.getUpdatePacket();
|
||||
+ if (packet != null) {
|
||||
+ this.extraPackets.add(packet);
|
||||
+ continue;
|
||||
+ }
|
||||
+ }
|
||||
+ // Paper end - Handle oversized block entities in chunks
|
||||
+ this.blockEntitiesData.add(ClientboundLevelChunkPacketData.BlockEntityInfo.create(blockEntity));
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Async Chunk Sending
|
||||
+
|
||||
public ClientboundLevelChunkPacketData(RegistryFriendlyByteBuf buffer, int x, int z) {
|
||||
this.heightmaps = HEIGHTMAPS_STREAM_CODEC.decode(buffer);
|
||||
int varInt = buffer.readVarInt();
|
||||
@@ -123,6 +169,8 @@ public class ClientboundLevelChunkPacketData {
|
||||
// Paper end - Anti-Xray - Add chunk packet info
|
||||
}
|
||||
|
||||
+ if (Thread.currentThread() instanceof org.bxteam.divinemc.async.AsyncChunkSend.AsyncChunkSendThread) return; // DivineMC - Async Chunk Sending
|
||||
+
|
||||
if (buffer.writerIndex() != buffer.capacity()) {
|
||||
throw new IllegalStateException("Didn't fill chunk buffer: expected " + buffer.capacity() + " bytes, got " + buffer.writerIndex());
|
||||
}
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
index 8578d1f78ddd1bb75f3230f04bfaa35af9f5f822..7c55fabd264e4e813d68798433dfccfb170537a2 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundLevelChunkWithLightPacket.java
|
||||
@@ -45,6 +45,18 @@ public class ClientboundLevelChunkWithLightPacket implements Packet<ClientGamePa
|
||||
chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
||||
}
|
||||
|
||||
+ // DivineMC start - Async Chunk Sending
|
||||
+ public ClientboundLevelChunkWithLightPacket(LevelChunk chunk, LevelLightEngine lightEngine, @Nullable BitSet skyLight, @Nullable BitSet blockLight, boolean modifyBlocks, net.minecraft.world.level.block.entity.BlockEntity[] blockEntities, java.util.Map<net.minecraft.world.level.levelgen.Heightmap.Types, long[]> heightmaps) {
|
||||
+ ChunkPos pos = chunk.getPos();
|
||||
+ this.x = pos.x;
|
||||
+ this.z = pos.z;
|
||||
+ io.papermc.paper.antixray.ChunkPacketInfo<net.minecraft.world.level.block.state.BlockState> chunkPacketInfo = modifyBlocks ? chunk.getLevel().chunkPacketBlockController.getChunkPacketInfo(this, chunk) : null; // Paper - Ant-Xray
|
||||
+ this.chunkData = new ClientboundLevelChunkPacketData(chunk, chunkPacketInfo, blockEntities, heightmaps); // Paper - Anti-Xray
|
||||
+ this.lightData = new ClientboundLightUpdatePacketData(pos, lightEngine, skyLight, blockLight);
|
||||
+ chunk.getLevel().chunkPacketBlockController.modifyBlocks(this, chunkPacketInfo); // Paper - Anti-Xray - Modify blocks
|
||||
+ }
|
||||
+ // DivineMC end - Async Chunk Sending
|
||||
+
|
||||
private ClientboundLevelChunkWithLightPacket(RegistryFriendlyByteBuf buffer) {
|
||||
this.x = buffer.readInt();
|
||||
this.z = buffer.readInt();
|
||||
diff --git a/net/minecraft/server/network/PlayerChunkSender.java b/net/minecraft/server/network/PlayerChunkSender.java
|
||||
index 0376a10ee0544b13e8fd629a7b13f78811e57a30..68c34ebf4dcf280aca6be27f3e34a5a74934ff45 100644
|
||||
--- a/net/minecraft/server/network/PlayerChunkSender.java
|
||||
+++ b/net/minecraft/server/network/PlayerChunkSender.java
|
||||
@@ -64,13 +64,25 @@ public class PlayerChunkSender {
|
||||
if (!list.isEmpty()) {
|
||||
ServerGamePacketListenerImpl serverGamePacketListenerImpl = player.connection;
|
||||
this.unacknowledgedBatches++;
|
||||
- serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE);
|
||||
+ // DivineMC start - Async Chunk Sending
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) {
|
||||
+ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE));
|
||||
+ } else {
|
||||
+ serverGamePacketListenerImpl.send(ClientboundChunkBatchStartPacket.INSTANCE);
|
||||
+ }
|
||||
+ // DivineMC end - Async Chunk Sending
|
||||
|
||||
for (LevelChunk levelChunk : list) {
|
||||
sendChunk(serverGamePacketListenerImpl, serverLevel, levelChunk);
|
||||
}
|
||||
|
||||
- serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()));
|
||||
+ // DivineMC start - Async Chunk Sending
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) {
|
||||
+ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size())));
|
||||
+ } else {
|
||||
+ serverGamePacketListenerImpl.send(new ClientboundChunkBatchFinishedPacket(list.size()));
|
||||
+ }
|
||||
+ // DivineMC end - Async Chunk Sending
|
||||
this.batchQuota = this.batchQuota - list.size();
|
||||
}
|
||||
}
|
||||
@@ -81,7 +93,24 @@ public class PlayerChunkSender {
|
||||
// Paper start - Anti-Xray
|
||||
public static void sendChunk(ServerGamePacketListenerImpl packetListener, ServerLevel level, LevelChunk chunk) {
|
||||
final boolean shouldModify = level.chunkPacketBlockController.shouldModify(packetListener.player, chunk);
|
||||
- packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
||||
+
|
||||
+ // DivineMC start - Async Chunk Sending
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncChunkSendingEnabled) {
|
||||
+ var blockEntities = chunk.blockEntities.values().toArray(new net.minecraft.world.level.block.entity.BlockEntity[0]);
|
||||
+ java.util.Map<net.minecraft.world.level.levelgen.Heightmap.Types, long[]> heightmaps = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
+
|
||||
+ for (var entry : chunk.getHeightmaps()) {
|
||||
+ if (entry.getKey().sendToClient()) {
|
||||
+ heightmaps.put(entry.getKey(), entry.getValue().getRawData());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ org.bxteam.divinemc.async.AsyncChunkSend.POOL.execute(() -> packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify, blockEntities, heightmaps)));
|
||||
+ } else {
|
||||
+ packetListener.send(new ClientboundLevelChunkWithLightPacket(chunk, level.getLightEngine(), null, null, shouldModify));
|
||||
+ }
|
||||
+ // DivineMC end - Async Chunk Sending
|
||||
+
|
||||
// Paper end - Anti-Xray
|
||||
// Paper start - PlayerChunkLoadEvent
|
||||
if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
index df717c545472006b99532280c38c1fbef12bcf82..ba4c20df405f41a526273a6216d2aedf4e5c435e 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
|
||||
@@ -18,7 +18,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
|
||||
public static final int SECTION_HEIGHT = 16;
|
||||
public static final int SECTION_SIZE = 4096;
|
||||
public static final int BIOME_CONTAINER_BITS = 2;
|
||||
- short nonEmptyBlockCount; // Paper - package private
|
||||
+ volatile short nonEmptyBlockCount; // Paper - package private // DivineMC - Async Chunk Sending
|
||||
private short tickingBlockCount;
|
||||
private short tickingFluidCount;
|
||||
public final PalettedContainer<BlockState> states;
|
||||
@@ -1,83 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 15 Mar 2025 22:01:08 +0300
|
||||
Subject: [PATCH] Command block parse results caching
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/BaseCommandBlock.java b/net/minecraft/world/level/BaseCommandBlock.java
|
||||
index 13950339598f4ec705c54275342fa17ff2e74ca9..5791910babe010d3bdc00a5dd4486f00358df14f 100644
|
||||
--- a/net/minecraft/world/level/BaseCommandBlock.java
|
||||
+++ b/net/minecraft/world/level/BaseCommandBlock.java
|
||||
@@ -34,6 +34,10 @@ public abstract class BaseCommandBlock implements CommandSource {
|
||||
private String command = "";
|
||||
@Nullable
|
||||
private Component customName;
|
||||
+ // DivineMC start - Caching command block parse results
|
||||
+ private String lastExecutedCommand;
|
||||
+ private com.mojang.brigadier.ParseResults<CommandSourceStack> parseResultsCache;
|
||||
+ // DivineMC end - Caching command block parse results
|
||||
// CraftBukkit start
|
||||
@Override
|
||||
public abstract org.bukkit.command.CommandSender getBukkitSender(CommandSourceStack wrapper);
|
||||
@@ -113,13 +117,41 @@ public abstract class BaseCommandBlock implements CommandSource {
|
||||
this.successCount++;
|
||||
}
|
||||
});
|
||||
- // Paper start - ServerCommandEvent
|
||||
- org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), net.minecraft.commands.Commands.trimOptionalPrefix(this.command));
|
||||
- if (!event.callEvent()) {
|
||||
- return true;
|
||||
+ // DivineMC start - Command block parse results caching
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.commandBlockParseResultsCaching) {
|
||||
+ String commandCache = this.command;
|
||||
+ // noinspection DuplicatedCode
|
||||
+ com.google.common.base.Joiner joiner = com.google.common.base.Joiner.on(" ");
|
||||
+
|
||||
+ if (commandCache.startsWith("/")) {
|
||||
+ commandCache = commandCache.substring(1);
|
||||
+ }
|
||||
+
|
||||
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), commandCache);
|
||||
+ org.bukkit.Bukkit.getPluginManager().callEvent(event);
|
||||
+ if (!event.isCancelled()) {
|
||||
+ commandCache = event.getCommand();
|
||||
+ String[] args = commandCache.split(" ");
|
||||
+
|
||||
+ if (args.length != 0) {
|
||||
+ String newCommand = joiner.join(args);
|
||||
+ if (!newCommand.equals(lastExecutedCommand) || parseResultsCache == null) {
|
||||
+ MinecraftServer.LOGGER.info("Recompiling parse results cache for command block at ({}, {}, {})", this.getPosition().x, this.getPosition().y, this.getPosition().z);
|
||||
+ this.cache(server.getCommands().getDispatcher(), commandSourceStack, newCommand);
|
||||
+ }
|
||||
+ server.getCommands().performCommand(parseResultsCache, newCommand);
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ // Paper start - ServerCommandEvent
|
||||
+ org.bukkit.event.server.ServerCommandEvent event = new org.bukkit.event.server.ServerCommandEvent(commandSourceStack.getBukkitSender(), net.minecraft.commands.Commands.trimOptionalPrefix(this.command));
|
||||
+ if (!event.callEvent()) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ server.getCommands().performPrefixedCommand(commandSourceStack, event.getCommand());
|
||||
+ // Paper end - ServerCommandEvent
|
||||
}
|
||||
- server.getCommands().performPrefixedCommand(commandSourceStack, event.getCommand());
|
||||
- // Paper end - ServerCommandEvent
|
||||
+ // DivineMC end - Command block parse results caching
|
||||
} catch (Throwable var6) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(var6, "Executing command block");
|
||||
CrashReportCategory crashReportCategory = crashReport.addCategory("Command to be executed");
|
||||
@@ -139,6 +171,13 @@ public abstract class BaseCommandBlock implements CommandSource {
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Command block parse results caching
|
||||
+ private void cache(com.mojang.brigadier.CommandDispatcher<CommandSourceStack> dispatcher, CommandSourceStack commandSourceStack, String commandCache) {
|
||||
+ this.parseResultsCache = dispatcher.parse(commandCache, commandSourceStack);
|
||||
+ this.lastExecutedCommand = commandCache;
|
||||
+ }
|
||||
+ // DivineMC end - Command block parse results caching
|
||||
+
|
||||
public Component getName() {
|
||||
return this.customName != null ? this.customName : DEFAULT_NAME;
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 26 Apr 2025 22:30:35 +0300
|
||||
Subject: [PATCH] Player ProfileResult caching
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 20ba45054c243fbb85e50cf0bdf75648730cb0bc..443aebb71b2a55ee9dcd2dd4bf9a30fbb8da9e49 100644
|
||||
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -71,6 +71,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
public @Nullable java.util.UUID requestedUuid; // Paper
|
||||
private final io.papermc.paper.connection.PaperPlayerLoginConnection paperLoginConnection; // Paper - Config API
|
||||
private volatile boolean disconnecting = false; // Paper - Fix disconnect still ticking login
|
||||
+ // DivineMC start - Player ProfileResult caching
|
||||
+ private static final com.google.common.cache.Cache<String, ProfileResult> playerProfileResultCache = com.google.common.cache.CacheBuilder.newBuilder()
|
||||
+ .expireAfterWrite(org.bxteam.divinemc.config.DivineConfig.NetworkCategory.playerProfileResultCachingTimeout, java.util.concurrent.TimeUnit.MINUTES)
|
||||
+ .build();
|
||||
+ // DivineMC end - Player ProfileResult caching
|
||||
|
||||
public ServerLoginPacketListenerImpl(MinecraftServer server, Connection connection, boolean transferred) {
|
||||
this.server = server;
|
||||
@@ -256,9 +261,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized");
|
||||
|
||||
try {
|
||||
- ProfileResult profileResult = ServerLoginPacketListenerImpl.this.server
|
||||
- .getSessionService()
|
||||
- .hasJoinedServer(string1, string, this.getAddress());
|
||||
+ // DivineMC start - Player ProfileResult caching
|
||||
+ ProfileResult profileResult;
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.playerProfileResultCachingEnabled) {
|
||||
+ profileResult = playerProfileResultCache.getIfPresent(string1);
|
||||
+
|
||||
+ if (profileResult == null) {
|
||||
+ profileResult = ServerLoginPacketListenerImpl.this.server
|
||||
+ .getSessionService()
|
||||
+ .hasJoinedServer(string1, string, this.getAddress());
|
||||
+ playerProfileResultCache.put(string1, profileResult);
|
||||
+ }
|
||||
+ } else {
|
||||
+ profileResult = ServerLoginPacketListenerImpl.this.server
|
||||
+ .getSessionService()
|
||||
+ .hasJoinedServer(string1, string, this.getAddress());
|
||||
+ }
|
||||
+ // DivineMC end - Player ProfileResult caching
|
||||
if (profileResult != null) {
|
||||
GameProfile gameProfile = profileResult.profile();
|
||||
// CraftBukkit start - fire PlayerPreLoginEvent
|
||||
@@ -1,430 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Tue, 28 Jan 2025 00:54:57 +0300
|
||||
Subject: [PATCH] Implement Secure Seed
|
||||
|
||||
Original license: GPLv3
|
||||
Original project: https://github.com/plasmoapp/matter
|
||||
|
||||
diff --git a/net/minecraft/server/commands/SeedCommand.java b/net/minecraft/server/commands/SeedCommand.java
|
||||
index 7c1e18d8362be5ae885c32b05e98b9ef45942d93..a414de3768972157d3031222fd160556d9b99bf4 100644
|
||||
--- a/net/minecraft/server/commands/SeedCommand.java
|
||||
+++ b/net/minecraft/server/commands/SeedCommand.java
|
||||
@@ -12,6 +12,17 @@ public class SeedCommand {
|
||||
long seed = commandContext.getSource().getLevel().getSeed();
|
||||
Component component = ComponentUtils.copyOnClickText(String.valueOf(seed));
|
||||
commandContext.getSource().sendSuccess(() -> Component.translatable("commands.seed.success", component), false);
|
||||
+
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed) {
|
||||
+ su.plo.matter.Globals.setupGlobals(commandContext.getSource().getLevel());
|
||||
+ String seedStr = su.plo.matter.Globals.seedToString(su.plo.matter.Globals.worldSeed);
|
||||
+ Component featureSeedComponent = ComponentUtils.copyOnClickText(seedStr);
|
||||
+
|
||||
+ commandContext.getSource().sendSuccess(() -> Component.translatable(("Feature seed: %s"), featureSeedComponent), false);
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
+
|
||||
return (int)seed;
|
||||
}));
|
||||
}
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServerProperties.java b/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
index b286dc17cda16fca3af9374d2a4a8bd137c24450..b42ad5b411af2a52daac040347647fa37460022b 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java
|
||||
@@ -116,7 +116,17 @@ public class DedicatedServerProperties extends Settings<DedicatedServerPropertie
|
||||
String string = this.get("level-seed", "");
|
||||
boolean flag = this.get("generate-structures", true);
|
||||
long l = WorldOptions.parseSeed(string).orElse(WorldOptions.randomSeed());
|
||||
- this.worldOptions = new WorldOptions(l, flag, false);
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed) {
|
||||
+ String featureSeedStr = this.get("feature-level-seed", "");
|
||||
+ long[] featureSeed = su.plo.matter.Globals.parseSeed(featureSeedStr)
|
||||
+ .orElse(su.plo.matter.Globals.createRandomWorldSeed());
|
||||
+
|
||||
+ this.worldOptions = new WorldOptions(l, featureSeed, flag, false);
|
||||
+ } else {
|
||||
+ this.worldOptions = new WorldOptions(l, flag, false);
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
this.worldDimensionData = new DedicatedServerProperties.WorldDimensionData(
|
||||
this.get("generator-settings", property -> GsonHelper.parse(!property.isEmpty() ? property : "{}"), new JsonObject()),
|
||||
this.get("level-type", property -> property.toLowerCase(Locale.ROOT), WorldPresets.NORMAL.location().toString())
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 25150731bb3f3d04b248ebc47fc9b453e49a705e..75c8ce32e68f92e20201e9c243f46f2be716eac8 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -619,6 +619,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
}
|
||||
|
||||
public ChunkGenerator getGenerator() {
|
||||
+ su.plo.matter.Globals.setupGlobals(level); // DivineMC - Implement Secure Seed
|
||||
return this.chunkMap.generator();
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 85c4d709b6d04e8f43baf7b900ee59eae5d98fe0..421b59b24bda3d03dea8fd0fc6237a71900e1cdc 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -629,6 +629,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
chunkGenerator = new org.bukkit.craftbukkit.generator.CustomChunkGenerator(this, chunkGenerator, gen);
|
||||
}
|
||||
// CraftBukkit end
|
||||
+ su.plo.matter.Globals.setupGlobals(this); // DivineMC - Implement Secure Seed
|
||||
boolean flag = server.forceSynchronousWrites();
|
||||
DataFixer fixerUpper = server.getFixerUpper();
|
||||
// Paper - rewrite chunk system
|
||||
diff --git a/net/minecraft/world/entity/monster/Slime.java b/net/minecraft/world/entity/monster/Slime.java
|
||||
index b299fc08fe900b4d48ce3e6986bcea000253053e..4dc68a03f607cacbf7f1bf9c08a4cbc1edf86ace 100644
|
||||
--- a/net/minecraft/world/entity/monster/Slime.java
|
||||
+++ b/net/minecraft/world/entity/monster/Slime.java
|
||||
@@ -413,7 +413,11 @@ public class Slime extends Mob implements Enemy {
|
||||
}
|
||||
|
||||
ChunkPos chunkPos = new ChunkPos(pos);
|
||||
- boolean flag = level.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel) level).getSeed(), level.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ boolean flag = level.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed
|
||||
+ ? level.getChunk(chunkPos.x, chunkPos.z).isSlimeChunk()
|
||||
+ : WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel) level).getSeed(), level.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
// Paper start - Replace rules for Height in Slime Chunks
|
||||
final double maxHeightSlimeChunk = level.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum;
|
||||
if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) {
|
||||
diff --git a/net/minecraft/world/level/chunk/ChunkAccess.java b/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
index 81511de113c292549fe5fe720a15bf3e0497ca84..19f74518923783d8d5560b526a1f267dabd23156 100644
|
||||
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
|
||||
@@ -83,6 +83,10 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
|
||||
public final Map<BlockPos, BlockEntity> blockEntities = new Object2ObjectOpenHashMap<>();
|
||||
protected final LevelHeightAccessor levelHeightAccessor;
|
||||
protected final LevelChunkSection[] sections;
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ private boolean slimeChunk;
|
||||
+ private boolean hasComputedSlimeChunk;
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
// CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading.
|
||||
private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||
public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY);
|
||||
@@ -193,6 +197,17 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
|
||||
return GameEventListenerRegistry.NOOP;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ public boolean isSlimeChunk() {
|
||||
+ if (!hasComputedSlimeChunk) {
|
||||
+ hasComputedSlimeChunk = true;
|
||||
+ slimeChunk = su.plo.matter.WorldgenCryptoRandom.seedSlimeChunk(chunkPos.x, chunkPos.z).nextInt(10) == 0;
|
||||
+ }
|
||||
+
|
||||
+ return slimeChunk;
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
+
|
||||
public abstract BlockState getBlockState(final int x, final int y, final int z); // Paper
|
||||
|
||||
@Nullable
|
||||
diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||
index 854578c7880dc124980142941ee471072668c8e2..ef59461d9685fc33bd9b98a5c3fc5ec17b57841f 100644
|
||||
--- a/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||
+++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
|
||||
@@ -342,7 +342,11 @@ public abstract class ChunkGenerator {
|
||||
Registry<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
Map<Integer, List<Structure>> map = registry.stream().collect(Collectors.groupingBy(structure1 -> structure1.step().ordinal()));
|
||||
List<FeatureSorter.StepFeatureData> list = this.featuresPerStep.get();
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom = org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed
|
||||
+ ? new su.plo.matter.WorldgenCryptoRandom(blockPos.getX(), blockPos.getZ(), su.plo.matter.Globals.Salt.UNDEFINED, 0)
|
||||
+ : new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
long l = worldgenRandom.setDecorationSeed(level.getSeed(), blockPos.getX(), blockPos.getZ());
|
||||
Set<Holder<Biome>> set = new ObjectArraySet<>();
|
||||
ChunkPos.rangeClosed(sectionPos.chunk(), 1).forEach(chunkPos -> {
|
||||
@@ -551,8 +555,18 @@ public abstract class ChunkGenerator {
|
||||
} else {
|
||||
ArrayList<StructureSet.StructureSelectionEntry> list1 = new ArrayList<>(list.size());
|
||||
list1.addAll(list);
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
- worldgenRandom.setLargeFeatureSeed(structureState.getLevelSeed(), pos.x, pos.z);
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom;
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed) {
|
||||
+ worldgenRandom = new su.plo.matter.WorldgenCryptoRandom(
|
||||
+ pos.x, pos.z, su.plo.matter.Globals.Salt.GENERATE_FEATURE, 0
|
||||
+ );
|
||||
+ } else {
|
||||
+ worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
+
|
||||
+ worldgenRandom.setLargeFeatureSeed(structureState.getLevelSeed(), pos.x, pos.z);
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
int i = 0;
|
||||
|
||||
for (StructureSet.StructureSelectionEntry structureSelectionEntry1 : list1) {
|
||||
diff --git a/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java b/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
|
||||
index 619b98e42e254c0c260c171a26a2472ddf59b885..7c110c3ab9b659fb26afddbe3541eb4e45503e4a 100644
|
||||
--- a/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
|
||||
+++ b/net/minecraft/world/level/chunk/ChunkGeneratorStructureState.java
|
||||
@@ -205,14 +205,21 @@ public class ChunkGeneratorStructureState {
|
||||
List<CompletableFuture<ChunkPos>> list = new ArrayList<>(count);
|
||||
int spread = placement.spread();
|
||||
HolderSet<Biome> holderSet = placement.preferredBiomes();
|
||||
- RandomSource randomSource = RandomSource.create();
|
||||
- // Paper start - Add missing structure set seed configs
|
||||
- if (this.conf.strongholdSeed != null && structureSet.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) {
|
||||
- randomSource.setSeed(this.conf.strongholdSeed);
|
||||
- } else {
|
||||
- // Paper end - Add missing structure set seed configs
|
||||
- randomSource.setSeed(this.concentricRingsSeed);
|
||||
- } // Paper - Add missing structure set seed configs
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ RandomSource randomSource = org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed
|
||||
+ ? new su.plo.matter.WorldgenCryptoRandom(0, 0, su.plo.matter.Globals.Salt.STRONGHOLDS, 0)
|
||||
+ : RandomSource.create();
|
||||
+
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed) {
|
||||
+ // Paper start - Add missing structure set seed configs
|
||||
+ if (this.conf.strongholdSeed != null && structureSet.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) {
|
||||
+ randomSource.setSeed(this.conf.strongholdSeed);
|
||||
+ } else {
|
||||
+ // Paper end - Add missing structure set seed configs
|
||||
+ randomSource.setSeed(this.concentricRingsSeed);
|
||||
+ } // Paper - Add missing structure set seed configs
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
double d = randomSource.nextDouble() * Math.PI * 2.0;
|
||||
int i = 0;
|
||||
int i1 = 0;
|
||||
diff --git a/net/minecraft/world/level/chunk/status/ChunkStep.java b/net/minecraft/world/level/chunk/status/ChunkStep.java
|
||||
index b8348976e80578d9eff64eea68c04c603fed49ad..9494e559113798fe451a6d0226be3ae0449021dc 100644
|
||||
--- a/net/minecraft/world/level/chunk/status/ChunkStep.java
|
||||
+++ b/net/minecraft/world/level/chunk/status/ChunkStep.java
|
||||
@@ -60,6 +60,7 @@ public final class ChunkStep implements ca.spottedleaf.moonrise.patches.chunk_sy
|
||||
}
|
||||
|
||||
public CompletableFuture<ChunkAccess> apply(WorldGenContext worldGenContext, StaticCache2D<GenerationChunkHolder> cache, ChunkAccess chunk) {
|
||||
+ su.plo.matter.Globals.setupGlobals(worldGenContext.level()); // DivineMC - Implement Secure Seed
|
||||
if (chunk.getPersistedStatus().isBefore(this.targetStatus)) {
|
||||
ProfiledDuration profiledDuration = JvmProfiler.INSTANCE
|
||||
.onChunkGenerate(chunk.getPos(), worldGenContext.level().dimension(), this.targetStatus.getName());
|
||||
diff --git a/net/minecraft/world/level/levelgen/WorldOptions.java b/net/minecraft/world/level/levelgen/WorldOptions.java
|
||||
index c92508741439a8d0d833ea02d0104416adb83c92..c4afe1cc270e6d7b4ffeada75da8265b46afd694 100644
|
||||
--- a/net/minecraft/world/level/levelgen/WorldOptions.java
|
||||
+++ b/net/minecraft/world/level/levelgen/WorldOptions.java
|
||||
@@ -9,17 +9,28 @@ import net.minecraft.util.RandomSource;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
public class WorldOptions {
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ private static final boolean isSecureSeedEnabled = org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed;
|
||||
public static final MapCodec<WorldOptions> CODEC = RecordCodecBuilder.mapCodec(
|
||||
- instance -> instance.group(
|
||||
+ instance -> isSecureSeedEnabled
|
||||
+ ? instance.group(
|
||||
Codec.LONG.fieldOf("seed").stable().forGetter(WorldOptions::seed),
|
||||
+ Codec.LONG_STREAM.fieldOf("feature_seed").stable().forGetter(WorldOptions::featureSeedStream),
|
||||
Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldOptions::generateStructures),
|
||||
Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldOptions::generateBonusChest),
|
||||
- Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(worldOptions -> worldOptions.legacyCustomOptions)
|
||||
- )
|
||||
- .apply(instance, instance.stable(WorldOptions::new))
|
||||
+ Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(generatorOptions -> generatorOptions.legacyCustomOptions)).apply(instance, instance.stable(WorldOptions::new))
|
||||
+ : instance.group(
|
||||
+ Codec.LONG.fieldOf("seed").stable().forGetter(WorldOptions::seed),
|
||||
+ Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldOptions::generateStructures),
|
||||
+ Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldOptions::generateBonusChest),
|
||||
+ Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(worldOptions -> worldOptions.legacyCustomOptions)).apply(instance, instance.stable(WorldOptions::new))
|
||||
);
|
||||
- public static final WorldOptions DEMO_OPTIONS = new WorldOptions("North Carolina".hashCode(), true, true);
|
||||
+ public static final WorldOptions DEMO_OPTIONS = isSecureSeedEnabled
|
||||
+ ? new WorldOptions("North Carolina".hashCode(), su.plo.matter.Globals.createRandomWorldSeed(), true, true)
|
||||
+ : new WorldOptions("North Carolina".hashCode(), true, true);
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
private final long seed;
|
||||
+ private long[] featureSeed = su.plo.matter.Globals.createRandomWorldSeed(); // DivineMC - Implement Secure Seed
|
||||
private final boolean generateStructures;
|
||||
private final boolean generateBonusChest;
|
||||
private final Optional<String> legacyCustomOptions;
|
||||
@@ -28,9 +39,21 @@ public class WorldOptions {
|
||||
this(seed, generateStructures, generateBonusChest, Optional.empty());
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ public WorldOptions(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest) {
|
||||
+ this(seed, featureSeed, generateStructures, bonusChest, Optional.empty());
|
||||
+ }
|
||||
+
|
||||
public static WorldOptions defaultWithRandomSeed() {
|
||||
- return new WorldOptions(randomSeed(), true, false);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(randomSeed(), su.plo.matter.Globals.createRandomWorldSeed(), true, false)
|
||||
+ : new WorldOptions(randomSeed(), true, false);
|
||||
+ }
|
||||
+
|
||||
+ private WorldOptions(long seed, java.util.stream.LongStream featureSeed, boolean generateStructures, boolean bonusChest, Optional<String> legacyCustomOptions) {
|
||||
+ this(seed, featureSeed.toArray(), generateStructures, bonusChest, legacyCustomOptions);
|
||||
}
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
|
||||
public static WorldOptions testWorldWithRandomSeed() {
|
||||
return new WorldOptions(randomSeed(), false, false);
|
||||
@@ -43,10 +66,27 @@ public class WorldOptions {
|
||||
this.legacyCustomOptions = legacyCustomOptions;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ private WorldOptions(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest, Optional<String> legacyCustomOptions) {
|
||||
+ this(seed, generateStructures, bonusChest, legacyCustomOptions);
|
||||
+ this.featureSeed = featureSeed;
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
+
|
||||
public long seed() {
|
||||
return this.seed;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ public long[] featureSeed() {
|
||||
+ return this.featureSeed;
|
||||
+ }
|
||||
+
|
||||
+ public java.util.stream.LongStream featureSeedStream() {
|
||||
+ return java.util.stream.LongStream.of(this.featureSeed);
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
+
|
||||
public boolean generateStructures() {
|
||||
return this.generateStructures;
|
||||
}
|
||||
@@ -59,17 +99,25 @@ public class WorldOptions {
|
||||
return this.legacyCustomOptions.isPresent();
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
public WorldOptions withBonusChest(boolean generateBonusChest) {
|
||||
- return new WorldOptions(this.seed, this.generateStructures, generateBonusChest, this.legacyCustomOptions);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(this.seed, this.featureSeed, this.generateStructures, generateBonusChest, this.legacyCustomOptions)
|
||||
+ : new WorldOptions(this.seed, this.generateStructures, generateBonusChest, this.legacyCustomOptions);
|
||||
}
|
||||
|
||||
public WorldOptions withStructures(boolean generateStructures) {
|
||||
- return new WorldOptions(this.seed, generateStructures, this.generateBonusChest, this.legacyCustomOptions);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(this.seed, this.featureSeed, generateStructures, this.generateBonusChest, this.legacyCustomOptions)
|
||||
+ : new WorldOptions(this.seed, generateStructures, this.generateBonusChest, this.legacyCustomOptions);
|
||||
}
|
||||
|
||||
public WorldOptions withSeed(OptionalLong seed) {
|
||||
- return new WorldOptions(seed.orElse(randomSeed()), this.generateStructures, this.generateBonusChest, this.legacyCustomOptions);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(seed.orElse(randomSeed()), su.plo.matter.Globals.createRandomWorldSeed(), this.generateStructures, this.generateBonusChest, this.legacyCustomOptions)
|
||||
+ : new WorldOptions(seed.orElse(randomSeed()), this.generateStructures, this.generateBonusChest, this.legacyCustomOptions);
|
||||
}
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
|
||||
public static OptionalLong parseSeed(String seed) {
|
||||
seed = seed.trim();
|
||||
diff --git a/net/minecraft/world/level/levelgen/feature/GeodeFeature.java b/net/minecraft/world/level/levelgen/feature/GeodeFeature.java
|
||||
index 4e72eb49dbf4c70ae7556ba6eb210fcd5ef36aaa..00e20c8c76ff8d902c3ea85ed96dfa3649c8e301 100644
|
||||
--- a/net/minecraft/world/level/levelgen/feature/GeodeFeature.java
|
||||
+++ b/net/minecraft/world/level/levelgen/feature/GeodeFeature.java
|
||||
@@ -41,7 +41,11 @@ public class GeodeFeature extends Feature<GeodeConfiguration> {
|
||||
int i1 = geodeConfiguration.maxGenOffset;
|
||||
List<Pair<BlockPos, Integer>> list = Lists.newLinkedList();
|
||||
int i2 = geodeConfiguration.distributionPoints.sample(randomSource);
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(worldGenLevel.getSeed()));
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom = org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed
|
||||
+ ? new su.plo.matter.WorldgenCryptoRandom(0, 0, su.plo.matter.Globals.Salt.GEODE_FEATURE, 0)
|
||||
+ : new WorldgenRandom(new LegacyRandomSource(worldGenLevel.getSeed()));
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
NormalNoise normalNoise = NormalNoise.create(worldgenRandom, -4, 1.0);
|
||||
List<BlockPos> list1 = Lists.newLinkedList();
|
||||
double d = (double)i2 / geodeConfiguration.outerWallDistance.getMaxValue();
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/Structure.java b/net/minecraft/world/level/levelgen/structure/Structure.java
|
||||
index 8328e864c72b7a358d6bb1f33459b8c4df2ecb1a..95881be2b7a5d16df22e8842acaba037b91a7009 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/Structure.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/Structure.java
|
||||
@@ -249,6 +249,14 @@ public abstract class Structure {
|
||||
}
|
||||
|
||||
private static WorldgenRandom makeRandom(long seed, ChunkPos chunkPos) {
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed) {
|
||||
+ return new su.plo.matter.WorldgenCryptoRandom(
|
||||
+ chunkPos.x, chunkPos.z, su.plo.matter.Globals.Salt.GENERATE_FEATURE, seed
|
||||
+ );
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
+
|
||||
WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
worldgenRandom.setLargeFeatureSeed(seed, chunkPos.x, chunkPos.z);
|
||||
return worldgenRandom;
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java b/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java
|
||||
index ee0d9dddb36b6879fa113299e24f1aa3b2b151cc..3af3bf800215ef78b98a4866df572f3ba263055d 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/placement/RandomSpreadStructurePlacement.java
|
||||
@@ -67,8 +67,17 @@ public class RandomSpreadStructurePlacement extends StructurePlacement {
|
||||
public ChunkPos getPotentialStructureChunk(long seed, int regionX, int regionZ) {
|
||||
int i = Math.floorDiv(regionX, this.spacing);
|
||||
int i1 = Math.floorDiv(regionZ, this.spacing);
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
- worldgenRandom.setLargeFeatureWithSalt(seed, i, i1, this.salt());
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom;
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed) {
|
||||
+ worldgenRandom = new su.plo.matter.WorldgenCryptoRandom(
|
||||
+ i, i1, su.plo.matter.Globals.Salt.POTENTIONAL_FEATURE, this.salt
|
||||
+ );
|
||||
+ } else {
|
||||
+ worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
+ worldgenRandom.setLargeFeatureWithSalt(seed, i, i1, this.salt());
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
int i2 = this.spacing - this.separation;
|
||||
int i3 = this.spreadType.evaluate(worldgenRandom, i2);
|
||||
int i4 = this.spreadType.evaluate(worldgenRandom, i2);
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java b/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
|
||||
index f2eb0572b9d97d97bc847082461515a852310dfc..2d046320457de81a47b7e0be5134d54b8013ac7e 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
|
||||
@@ -119,8 +119,17 @@ public abstract class StructurePlacement {
|
||||
public abstract StructurePlacementType<?> type();
|
||||
|
||||
private static boolean probabilityReducer(long levelSeed, int regionX, int regionZ, int salt, float probability, @org.jetbrains.annotations.Nullable Integer saltOverride) { // Paper - Add missing structure set seed configs; ignore here
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
- worldgenRandom.setLargeFeatureWithSalt(levelSeed, regionX, regionZ, salt);
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom;
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed) {
|
||||
+ worldgenRandom = new su.plo.matter.WorldgenCryptoRandom(
|
||||
+ regionX, regionZ, su.plo.matter.Globals.Salt.UNDEFINED, salt
|
||||
+ );
|
||||
+ } else {
|
||||
+ worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
+ worldgenRandom.setLargeFeatureWithSalt(levelSeed, regionX, regionZ, salt);
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
return worldgenRandom.nextFloat() < probability;
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
|
||||
index cd3b24a760053dcd650a1a263b3c0093a0cbb175..e4ca880b5d16ae30676ec25c39c3d5b5f6cb3c24 100644
|
||||
--- a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
|
||||
+++ b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
|
||||
@@ -66,7 +66,11 @@ public class JigsawPlacement {
|
||||
ChunkGenerator chunkGenerator = context.chunkGenerator();
|
||||
StructureTemplateManager structureTemplateManager = context.structureTemplateManager();
|
||||
LevelHeightAccessor levelHeightAccessor = context.heightAccessor();
|
||||
- WorldgenRandom worldgenRandom = context.random();
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom = org.bxteam.divinemc.config.DivineConfig.MiscCategory.enableSecureSeed
|
||||
+ ? new su.plo.matter.WorldgenCryptoRandom(context.chunkPos().x, context.chunkPos().z, su.plo.matter.Globals.Salt.JIGSAW_PLACEMENT, 0)
|
||||
+ : context.random();
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
Registry<StructureTemplatePool> registry = registryAccess.lookupOrThrow(Registries.TEMPLATE_POOL);
|
||||
Rotation random = Rotation.getRandom(worldgenRandom);
|
||||
StructureTemplatePool structureTemplatePool = startPool.unwrapKey()
|
||||
@@ -1,445 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 23 Mar 2025 01:16:35 +0300
|
||||
Subject: [PATCH] Dynamic Activation of Brain
|
||||
|
||||
|
||||
diff --git a/io/papermc/paper/entity/activation/ActivationRange.java b/io/papermc/paper/entity/activation/ActivationRange.java
|
||||
index ca21597263cb430e2a5ae07e8cecfb0d53a270d2..226088405c019922085285ba5d04d7c131470c69 100644
|
||||
--- a/io/papermc/paper/entity/activation/ActivationRange.java
|
||||
+++ b/io/papermc/paper/entity/activation/ActivationRange.java
|
||||
@@ -167,6 +167,21 @@ public final class ActivationRange {
|
||||
}
|
||||
|
||||
ActivationRange.activateEntity(entity);
|
||||
+
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.dabEnabled && entity.getType().dabEnabled && (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.dabDontEnableIfInWater || entity.getType().is(net.minecraft.tags.EntityTypeTags.CAN_BREATHE_UNDER_WATER) || !entity.isInWaterOrRain())) {
|
||||
+ if (!entity.activatedPriorityReset) {
|
||||
+ entity.activatedPriorityReset = true;
|
||||
+ entity.activatedPriority = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.dabMaximumActivationFrequency;
|
||||
+ }
|
||||
+ int squaredDistance = (int) player.distanceToSqr(entity);
|
||||
+ entity.activatedPriority = squaredDistance > org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.dabStartDistanceSquared ?
|
||||
+ Math.max(1, Math.min(squaredDistance >> org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.dabActivationDistanceMod, entity.activatedPriority)) :
|
||||
+ 1;
|
||||
+ } else {
|
||||
+ entity.activatedPriority = 1;
|
||||
+ }
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 421b59b24bda3d03dea8fd0fc6237a71900e1cdc..78bf3365b426e7090182af84630111d410a2460e 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -802,6 +802,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.entityTickList
|
||||
.forEach(
|
||||
entity -> {
|
||||
+ entity.activatedPriorityReset = false; // DivineMC - Dynamic Activation of Brain
|
||||
if (!entity.isRemoved()) {
|
||||
if (!tickRateManager.isEntityFrozen(entity)) {
|
||||
entity.checkDespawn();
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index 8808424481bf0c1f89f67d25ba502014d55ebc49..9e53b4297fa786ee863d0cf1855aa0ebd9afc221 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -365,6 +365,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
public boolean fixedPose = false; // Paper - Expand Pose API
|
||||
private final int despawnTime; // Paper - entity despawn time limit
|
||||
public int totalEntityAge; // Paper - age-like counter for all entities
|
||||
+ public boolean activatedPriorityReset = false; // DivineMC - Dynamic Activation of Brain
|
||||
+ public int activatedPriority = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.dabMaximumActivationFrequency; // DivineMC - Dynamic Activation of Brain
|
||||
public final io.papermc.paper.entity.activation.ActivationType activationType = io.papermc.paper.entity.activation.ActivationType.activationTypeFor(this); // Paper - EAR 2/tracking ranges
|
||||
// Paper start - EAR 2
|
||||
public final boolean defaultActivationState;
|
||||
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
|
||||
index 9950fccc0a708e701b81fcabc9e8f370e6d3a19d..0159627e2c9a540d062073faf9018f5215e10866 100644
|
||||
--- a/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/net/minecraft/world/entity/EntityType.java
|
||||
@@ -1085,6 +1085,7 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
||||
private final boolean canSpawnFarFromPlayer;
|
||||
private final int clientTrackingRange;
|
||||
private final int updateInterval;
|
||||
+ public boolean dabEnabled = false; // DivineMC - Dynamic Activation of Brain
|
||||
private final String descriptionId;
|
||||
@Nullable
|
||||
private Component description;
|
||||
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
|
||||
index 74bd00f5f8ab628d3f35d0f2e39fb1dbf7045c23..faf29073db00f8e10136e03dc877dcfb38f795d0 100644
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -210,10 +210,10 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
@Override
|
||||
public void inactiveTick() {
|
||||
super.inactiveTick();
|
||||
- if (this.goalSelector.inactiveTick()) {
|
||||
+ if (this.goalSelector.inactiveTick(this.activatedPriority, true)) { // DivineMC - Dynamic Activation of Brain
|
||||
this.goalSelector.tick();
|
||||
}
|
||||
- if (this.targetSelector.inactiveTick()) {
|
||||
+ if (this.targetSelector.inactiveTick(this.activatedPriority, true)) { // DivineMC - Dynamic Activation of Brain
|
||||
this.targetSelector.tick();
|
||||
}
|
||||
}
|
||||
@@ -773,13 +773,19 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
|
||||
// Paper end - Allow nerfed mobs to jump and float
|
||||
this.sensing.tick();
|
||||
int i = this.tickCount + this.getId();
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
if (i % 2 != 0 && this.tickCount > 1) {
|
||||
- this.targetSelector.tickRunningGoals(false);
|
||||
- this.goalSelector.tickRunningGoals(false);
|
||||
+ if (this.targetSelector.inactiveTick(this.activatedPriority, false))
|
||||
+ this.targetSelector.tickRunningGoals(false);
|
||||
+ if (this.goalSelector.inactiveTick(this.activatedPriority, false))
|
||||
+ this.goalSelector.tickRunningGoals(false);
|
||||
} else {
|
||||
- this.targetSelector.tick();
|
||||
- this.goalSelector.tick();
|
||||
+ if (this.targetSelector.inactiveTick(this.activatedPriority, false))
|
||||
+ this.targetSelector.tick();
|
||||
+ if (this.goalSelector.inactiveTick(this.activatedPriority, false))
|
||||
+ this.goalSelector.tick();
|
||||
}
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
|
||||
this.navigation.tick();
|
||||
this.customServerAiStep((ServerLevel)this.level());
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java b/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java
|
||||
index f6c673b1abe53afcb14fd68d590431027ed29f67..1e5312e02298c63c168526a960d688dc03581cee 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/VillagerPanicTrigger.java
|
||||
@@ -36,7 +36,11 @@ public class VillagerPanicTrigger extends Behavior<Villager> {
|
||||
|
||||
@Override
|
||||
protected void tick(ServerLevel level, Villager owner, long gameTime) {
|
||||
- if (gameTime % 100L == 0L) {
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if (owner.nextGolemPanic < 0) owner.nextGolemPanic = gameTime + 100;
|
||||
+ if (--owner.nextGolemPanic < gameTime) {
|
||||
+ owner.nextGolemPanic = -1;
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
owner.spawnGolemIfNeeded(level, gameTime, 3);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/GoalSelector.java b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
index 653c58c7637c46c8b46a5082f671324a2221d431..a4328a427636aa845d6627ecb75a9efe7320bb15 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
|
||||
@@ -34,10 +34,14 @@ public class GoalSelector {
|
||||
}
|
||||
|
||||
// Paper start - EAR 2
|
||||
- public boolean inactiveTick() {
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ public boolean inactiveTick(int tickRate, boolean inactive) {
|
||||
+ if (inactive && !org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.dabEnabled) tickRate = 4;
|
||||
+ tickRate = Math.min(tickRate, 3);
|
||||
this.curRate++;
|
||||
- return this.curRate % 3 == 0; // TODO newGoalRate was already unused in 1.20.4, check if this is correct
|
||||
+ return this.curRate % tickRate == 0;
|
||||
}
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
|
||||
public boolean hasTasks() {
|
||||
for (WrappedGoal task : this.availableGoals) {
|
||||
diff --git a/net/minecraft/world/entity/animal/allay/Allay.java b/net/minecraft/world/entity/animal/allay/Allay.java
|
||||
index dd10b0535baf48aea47020d890f102800b0af11a..e0c4dc78c669fd53e0c03c3013eb439e4a07c690 100644
|
||||
--- a/net/minecraft/world/entity/animal/allay/Allay.java
|
||||
+++ b/net/minecraft/world/entity/animal/allay/Allay.java
|
||||
@@ -113,6 +113,7 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
|
||||
private float spinningAnimationTicks0;
|
||||
public boolean forceDancing = false; // CraftBukkit
|
||||
private org.purpurmc.purpur.controller.FlyingMoveControllerWASD purpurController; // Purpur - Ridables
|
||||
+ private int behaviorTick = 0; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Allay(EntityType<? extends Allay> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -267,10 +268,13 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- AllayAi.updateActivity(this);
|
||||
- super.customServerAiStep(level);
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ AllayAi.updateActivity(this);
|
||||
+ super.customServerAiStep(level);
|
||||
+ }
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/animal/axolotl/Axolotl.java b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
|
||||
index deb2fdea7be9dda1c4b267ac25326bb9b05ae739..ab13d9c2aedda17c8cbc911e678aac8b6b28801d 100644
|
||||
--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
|
||||
+++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
|
||||
@@ -112,6 +112,7 @@ public class Axolotl extends Animal implements Bucketable {
|
||||
public final BinaryAnimator onGroundAnimator = new BinaryAnimator(10, Mth::easeInOutSine);
|
||||
public final BinaryAnimator movingAnimator = new BinaryAnimator(10, Mth::easeInOutSine);
|
||||
private static final int REGEN_BUFF_BASE_DURATION = 100;
|
||||
+ private int behaviorTick = 0; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Axolotl(EntityType<? extends Axolotl> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -373,13 +374,16 @@ public class Axolotl extends Animal implements Bucketable {
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- AxolotlAi.updateActivity(this);
|
||||
- if (!this.isNoAi()) {
|
||||
- Optional<Integer> memory = this.getBrain().getMemory(MemoryModuleType.PLAY_DEAD_TICKS);
|
||||
- this.setPlayingDead(memory.isPresent() && memory.get() > 0);
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ AxolotlAi.updateActivity(this);
|
||||
+ if (!this.isNoAi()) {
|
||||
+ Optional<Integer> memory = this.getBrain().getMemory(MemoryModuleType.PLAY_DEAD_TICKS);
|
||||
+ this.setPlayingDead(memory.isPresent() && memory.get() > 0);
|
||||
+ }
|
||||
}
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
|
||||
index f67d18f32f73e0e6be35939781bd0bd0188cdfbd..f526a426d02f8fb1ce6c1b16e0ed3edae8ab5271 100644
|
||||
--- a/net/minecraft/world/entity/animal/frog/Frog.java
|
||||
+++ b/net/minecraft/world/entity/animal/frog/Frog.java
|
||||
@@ -106,6 +106,7 @@ public class Frog extends Animal {
|
||||
public final AnimationState swimIdleAnimationState = new AnimationState();
|
||||
private org.purpurmc.purpur.controller.MoveControllerWASD purpurLandController; // Purpur - Ridables
|
||||
private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurWaterController; // Purpur - Ridables
|
||||
+ private int behaviorTick = 0; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Frog(EntityType<? extends Animal> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -259,10 +260,13 @@ public class Frog extends Animal {
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- FrogAi.updateActivity(this);
|
||||
- super.customServerAiStep(level);
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ FrogAi.updateActivity(this);
|
||||
+ super.customServerAiStep(level);
|
||||
+ }
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java
|
||||
index c25cfd8f176819efd64e5ce45632b0cc1b69d420..f654228b59950e1f866d8decf208eb4f1a5ff603 100644
|
||||
--- a/net/minecraft/world/entity/animal/frog/Tadpole.java
|
||||
+++ b/net/minecraft/world/entity/animal/frog/Tadpole.java
|
||||
@@ -65,6 +65,7 @@ public class Tadpole extends AbstractFish {
|
||||
);
|
||||
public boolean ageLocked; // Paper
|
||||
private org.purpurmc.purpur.controller.WaterMoveControllerWASD purpurController; // Purpur - Ridables
|
||||
+ private int behaviorTick = 0; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Tadpole(EntityType<? extends AbstractFish> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -135,10 +136,13 @@ public class Tadpole extends AbstractFish {
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- TadpoleAi.updateActivity(this);
|
||||
- super.customServerAiStep(level);
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ TadpoleAi.updateActivity(this);
|
||||
+ super.customServerAiStep(level);
|
||||
+ }
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
public static AttributeSupplier.Builder createAttributes() {
|
||||
diff --git a/net/minecraft/world/entity/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
|
||||
index 934853721c000186e4a97b05ad26c59d7e84dd55..4913e44112da5c43b36e4e4e456ccebecc8e7cc3 100644
|
||||
--- a/net/minecraft/world/entity/animal/goat/Goat.java
|
||||
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
|
||||
@@ -94,6 +94,7 @@ public class Goat extends Animal {
|
||||
private static final boolean DEFAULT_HAS_RIGHT_HORN = true;
|
||||
private boolean isLoweringHead;
|
||||
private int lowerHeadTick;
|
||||
+ private int behaviorTick = 0; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Goat(EntityType<? extends Goat> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -233,10 +234,13 @@ public class Goat extends Animal {
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- GoatAi.updateActivity(this);
|
||||
- super.customServerAiStep(level);
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ GoatAi.updateActivity(this);
|
||||
+ super.customServerAiStep(level);
|
||||
+ }
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/monster/hoglin/Hoglin.java b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
|
||||
index 952fba6d141576089e563e829cae4a177f19d639..ba0ec0eb69742df84435102f6871cf1ab94b3aca 100644
|
||||
--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
|
||||
+++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
|
||||
@@ -88,6 +88,7 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
|
||||
MemoryModuleType.PACIFIED,
|
||||
MemoryModuleType.IS_PANICKING
|
||||
);
|
||||
+ private int behaviorTick; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Hoglin(EntityType<? extends Hoglin> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -206,18 +207,21 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- HoglinAi.updateActivity(this);
|
||||
- if (this.isConverting()) {
|
||||
- this.timeInOverworld++;
|
||||
- if (this.timeInOverworld > 300) {
|
||||
- this.makeSound(SoundEvents.HOGLIN_CONVERTED_TO_ZOMBIFIED);
|
||||
- this.finishConversion();
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ HoglinAi.updateActivity(this);
|
||||
+ if (this.isConverting()) {
|
||||
+ this.timeInOverworld++;
|
||||
+ if (this.timeInOverworld > 300) {
|
||||
+ this.makeSound(SoundEvents.HOGLIN_CONVERTED_TO_ZOMBIFIED);
|
||||
+ this.finishConversion();
|
||||
+ }
|
||||
+ } else {
|
||||
+ this.timeInOverworld = 0;
|
||||
}
|
||||
- } else {
|
||||
- this.timeInOverworld = 0;
|
||||
}
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/monster/piglin/Piglin.java b/net/minecraft/world/entity/monster/piglin/Piglin.java
|
||||
index 03b6640c95c86ea9f6219d6e39feffa4643dd648..74e753a9a2b4e4132558c39d3d8a5424d819e78b 100644
|
||||
--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
|
||||
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
|
||||
@@ -129,6 +129,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
|
||||
private static final com.mojang.serialization.Codec<java.util.Set<net.minecraft.world.item.Item>> ITEM_SET_CODEC = net.minecraft.core.registries.BuiltInRegistries.ITEM
|
||||
.byNameCodec().listOf().xmap(java.util.HashSet::new, List::copyOf);
|
||||
// CraftBukkit end
|
||||
+ private int behaviorTick; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Piglin(EntityType<? extends AbstractPiglin> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -357,10 +358,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- PiglinAi.updateActivity(this);
|
||||
- super.customServerAiStep(level);
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ PiglinAi.updateActivity(this);
|
||||
+ super.customServerAiStep(level);
|
||||
+ }
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/monster/warden/Warden.java b/net/minecraft/world/entity/monster/warden/Warden.java
|
||||
index 091b9cc338e37efbecdd4187a9824dae7bff2af9..808661fdefacfffa65ebde1aa3193a82497706b7 100644
|
||||
--- a/net/minecraft/world/entity/monster/warden/Warden.java
|
||||
+++ b/net/minecraft/world/entity/monster/warden/Warden.java
|
||||
@@ -108,6 +108,7 @@ public class Warden extends Monster implements VibrationSystem {
|
||||
private final VibrationSystem.User vibrationUser;
|
||||
private VibrationSystem.Data vibrationData;
|
||||
AngerManagement angerManagement = new AngerManagement(this::canTargetEntity, Collections.emptyList());
|
||||
+ private int behaviorTick = 0; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Warden(EntityType<? extends Monster> entityType, Level level) {
|
||||
super(entityType, level);
|
||||
@@ -301,19 +302,22 @@ public class Warden extends Monster implements VibrationSystem {
|
||||
|
||||
@Override
|
||||
protected void customServerAiStep(ServerLevel level) {
|
||||
- if ((getRider() == null || !this.isControllable())) // Purpur - only use brain if no rider
|
||||
- this.getBrain().tick(level, this);
|
||||
- super.customServerAiStep(level);
|
||||
- if ((this.tickCount + this.getId()) % 120 == 0) {
|
||||
- applyDarknessAround(level, this.position(), this, 20);
|
||||
- }
|
||||
+ // DivineMC start - Dynamic Activation of Brain
|
||||
+ if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) { // Purpur - only use brain if no rider
|
||||
+ this.getBrain().tick(level, this);
|
||||
+ super.customServerAiStep(level);
|
||||
+ if ((this.tickCount + this.getId()) % 120 == 0) {
|
||||
+ applyDarknessAround(level, this.position(), this, 20);
|
||||
+ }
|
||||
|
||||
- if (this.tickCount % 20 == 0) {
|
||||
- this.angerManagement.tick(level, this::canTargetEntity);
|
||||
- this.syncClientAngerLevel();
|
||||
- }
|
||||
+ if (this.tickCount % 20 == 0) {
|
||||
+ this.angerManagement.tick(level, this::canTargetEntity);
|
||||
+ this.syncClientAngerLevel();
|
||||
+ }
|
||||
|
||||
- WardenAi.updateActivity(this);
|
||||
+ WardenAi.updateActivity(this);
|
||||
+ }
|
||||
+ // DivineMC end - Dynamic Activation of Brain
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/entity/npc/Villager.java b/net/minecraft/world/entity/npc/Villager.java
|
||||
index db5c287161c50bafd672b9cb439b3a06b1ff16d7..c2c6f5e8837ae2ac685b56562686b552b3e1bd8f 100644
|
||||
--- a/net/minecraft/world/entity/npc/Villager.java
|
||||
+++ b/net/minecraft/world/entity/npc/Villager.java
|
||||
@@ -178,6 +178,8 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
);
|
||||
private boolean isLobotomized = false; public boolean isLobotomized() { return this.isLobotomized; } // Purpur - Lobotomize stuck villagers
|
||||
private int notLobotomizedCount = 0; // Purpur - Lobotomize stuck villagers
|
||||
+ public long nextGolemPanic = -1; // DivineMC - Dynamic Activation of Brain
|
||||
+ private int behaviorTick = 0; // DivineMC - Dynamic Activation of Brain
|
||||
|
||||
public Villager(EntityType<? extends Villager> entityType, Level level) {
|
||||
this(entityType, level, VillagerType.PLAINS);
|
||||
@@ -399,7 +401,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
|
||||
this.isLobotomized = false;
|
||||
}
|
||||
// Purpur end - Lobotomize stuck villagers
|
||||
- if (!inactive && (getRider() == null || !this.isControllable())) { // Purpur - Ridables
|
||||
+ if (!inactive && this.behaviorTick++ % this.activatedPriority == 0 && (getRider() == null || !this.isControllable())) { // Purpur - Ridables // DivineMC - Dynamic Activation of Brain
|
||||
this.getBrain().tick(level, this); // Paper - EAR 2
|
||||
}
|
||||
else if (this.isLobotomized && shouldRestock()) restock(); // Purpur - Lobotomize stuck villagers
|
||||
@@ -1,813 +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:04:55 +0300
|
||||
Subject: [PATCH] Petal: Async Pathfinding
|
||||
|
||||
Original code by Bloom-host, licensed under GPL v3
|
||||
You can find the original code on https://github.com/Bloom-host/Petal
|
||||
|
||||
Makes most pathfinding-related work happen asynchronously
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
index b0ca555cc3b565a8be8d01fe10b139ed27a2a2c3..47169b95032f10bf64ec5af5faf69edf8df19b8c 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
|
||||
@@ -94,21 +94,18 @@ public class AcquirePoi {
|
||||
}
|
||||
}
|
||||
// Paper end - optimise POI access
|
||||
- Path path = findPathToPois(mob, set);
|
||||
- if (path != null && path.canReach()) {
|
||||
- BlockPos target = path.getTarget();
|
||||
- poiManager.getType(target).ifPresent(holder -> {
|
||||
- poiManager.take(acquirablePois, (holder1, blockPos) -> blockPos.equals(target), target, 1);
|
||||
- memoryAccessor.set(GlobalPos.of(level.dimension(), target));
|
||||
- entityEventId.ifPresent(id -> level.broadcastEntityEvent(mob, id));
|
||||
- map.clear();
|
||||
- DebugPackets.sendPoiTicketCountPacket(level, target);
|
||||
+ // DivineMC start - Async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ Path possiblePath = findPathToPois(mob, set);
|
||||
+
|
||||
+ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> {
|
||||
+ processPath(acquirablePois, entityEventId, (Long2ObjectMap<JitteredLinearRetry>) map, memoryAccessor, level, mob, time, poiManager, set, path);
|
||||
});
|
||||
} else {
|
||||
- for (Pair<Holder<PoiType>, BlockPos> pair : set) {
|
||||
- map.computeIfAbsent(pair.getSecond().asLong(), l -> new AcquirePoi.JitteredLinearRetry(level.random, time));
|
||||
- }
|
||||
+ Path path = findPathToPois(mob, set);
|
||||
+ processPath(acquirablePois, entityEventId, (Long2ObjectMap<JitteredLinearRetry>) map, memoryAccessor, level, mob, time, poiManager, set, path);
|
||||
}
|
||||
+ // DivineMC end - Async path processing
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -120,6 +117,34 @@ public class AcquirePoi {
|
||||
: BehaviorBuilder.create(instance -> instance.group(instance.absent(existingAbsentMemory)).apply(instance, memoryAccessor -> oneShot));
|
||||
}
|
||||
|
||||
+ // DivineMC start - Async path processing
|
||||
+ private static void processPath(Predicate<Holder<PoiType>> acquirablePois,
|
||||
+ Optional<Byte> entityEventId,
|
||||
+ Long2ObjectMap<JitteredLinearRetry> map,
|
||||
+ net.minecraft.world.entity.ai.behavior.declarative.MemoryAccessor<com.mojang.datafixers.kinds.Const.Mu<com.mojang.datafixers.util.Unit>, GlobalPos> memoryAccessor,
|
||||
+ ServerLevel level,
|
||||
+ PathfinderMob mob,
|
||||
+ long time,
|
||||
+ PoiManager poiManager,
|
||||
+ Set<Pair<Holder<PoiType>, BlockPos>> set,
|
||||
+ Path path) {
|
||||
+ if (path != null && path.canReach()) {
|
||||
+ BlockPos target = path.getTarget();
|
||||
+ poiManager.getType(target).ifPresent(holder -> {
|
||||
+ poiManager.take(acquirablePois, (holder1, blockPos) -> blockPos.equals(target), target, 1);
|
||||
+ memoryAccessor.set(GlobalPos.of(level.dimension(), target));
|
||||
+ entityEventId.ifPresent(id -> level.broadcastEntityEvent(mob, id));
|
||||
+ map.clear();
|
||||
+ DebugPackets.sendPoiTicketCountPacket(level, target);
|
||||
+ });
|
||||
+ } else {
|
||||
+ for (Pair<Holder<PoiType>, BlockPos> pair : set) {
|
||||
+ map.computeIfAbsent(pair.getSecond().asLong(), l -> new JitteredLinearRetry(level.random, time));
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Async path processing
|
||||
+
|
||||
@Nullable
|
||||
public static Path findPathToPois(Mob mob, Set<Pair<Holder<PoiType>, BlockPos>> poiPositions) {
|
||||
if (poiPositions.isEmpty()) {
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java b/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java
|
||||
index 621ba76784f2b92790eca62be4d0688834335ab6..92d8899ff7d42ecc987a7bf2035cc72484ea9e82 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java
|
||||
@@ -21,6 +21,7 @@ public class MoveToTargetSink extends Behavior<Mob> {
|
||||
private int remainingCooldown;
|
||||
@Nullable
|
||||
private Path path;
|
||||
+ private boolean finishedProcessing; // DivineMC - async path processing
|
||||
@Nullable
|
||||
private BlockPos lastTargetPos;
|
||||
private float speedModifier;
|
||||
@@ -53,9 +54,11 @@ public class MoveToTargetSink extends Behavior<Mob> {
|
||||
Brain<?> brain = owner.getBrain();
|
||||
WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get();
|
||||
boolean flag = this.reachedTarget(owner, walkTarget);
|
||||
- if (!flag && this.tryComputePath(owner, walkTarget, level.getGameTime())) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding && !flag && this.tryComputePath(owner, walkTarget, level.getGameTime())) { // DivineMC - async path processing
|
||||
this.lastTargetPos = walkTarget.getTarget().currentBlockPosition();
|
||||
return true;
|
||||
+ } else if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding && !flag) { // DivineMC - async pathfinding
|
||||
+ return true;
|
||||
} else {
|
||||
brain.eraseMemory(MemoryModuleType.WALK_TARGET);
|
||||
if (flag) {
|
||||
@@ -69,6 +72,7 @@ public class MoveToTargetSink extends Behavior<Mob> {
|
||||
|
||||
@Override
|
||||
protected boolean canStillUse(ServerLevel level, Mob entity, long gameTime) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding && !this.finishedProcessing) return true; // DivineMC - wait for processing
|
||||
if (this.path != null && this.lastTargetPos != null) {
|
||||
Optional<WalkTarget> memory = entity.getBrain().getMemory(MemoryModuleType.WALK_TARGET);
|
||||
boolean flag = memory.map(MoveToTargetSink::isWalkTargetSpectator).orElse(false);
|
||||
@@ -95,27 +99,98 @@ public class MoveToTargetSink extends Behavior<Mob> {
|
||||
|
||||
@Override
|
||||
protected void start(ServerLevel level, Mob entity, long gameTime) {
|
||||
+ // DivineMC start - start processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ Brain<?> brain = entity.getBrain();
|
||||
+ WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get();
|
||||
+
|
||||
+ this.finishedProcessing = false;
|
||||
+ this.lastTargetPos = walkTarget.getTarget().currentBlockPosition();
|
||||
+ this.path = this.computePath(entity, walkTarget);
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - start processing
|
||||
entity.getBrain().setMemory(MemoryModuleType.PATH, this.path);
|
||||
entity.getNavigation().moveTo(this.path, (double)this.speedModifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tick(ServerLevel level, Mob owner, long gameTime) {
|
||||
- Path path = owner.getNavigation().getPath();
|
||||
- Brain<?> brain = owner.getBrain();
|
||||
- if (this.path != path) {
|
||||
- this.path = path;
|
||||
- brain.setMemory(MemoryModuleType.PATH, path);
|
||||
- }
|
||||
+ // DivineMC start - Async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ if (this.path != null && !this.path.isProcessed()) return; // wait for processing
|
||||
|
||||
- if (path != null && this.lastTargetPos != null) {
|
||||
- WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get();
|
||||
- if (walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4.0 && this.tryComputePath(owner, walkTarget, level.getGameTime())) {
|
||||
- this.lastTargetPos = walkTarget.getTarget().currentBlockPosition();
|
||||
- this.start(level, owner, gameTime);
|
||||
+ if (!this.finishedProcessing) {
|
||||
+ this.finishedProcessing = true;
|
||||
+
|
||||
+ Brain<?> brain = owner.getBrain();
|
||||
+ boolean canReach = this.path != null && this.path.canReach();
|
||||
+ if (canReach) {
|
||||
+ brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
|
||||
+ } else if (!brain.hasMemoryValue(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE)) {
|
||||
+ brain.setMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE, gameTime);
|
||||
+ }
|
||||
+
|
||||
+ if (!canReach) {
|
||||
+ Optional<WalkTarget> walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET);
|
||||
+
|
||||
+ if (!walkTarget.isPresent()) return;
|
||||
+
|
||||
+ BlockPos blockPos = walkTarget.get().getTarget().currentBlockPosition();
|
||||
+ Vec3 vec3 = DefaultRandomPos.getPosTowards((PathfinderMob) owner, 10, 7, Vec3.atBottomCenterOf(blockPos), (float) Math.PI / 2F);
|
||||
+ if (vec3 != null) {
|
||||
+ // try recalculating the path using a random position
|
||||
+ this.path = owner.getNavigation().createPath(vec3.x, vec3.y, vec3.z, 0);
|
||||
+ this.finishedProcessing = false;
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ owner.getBrain().setMemory(MemoryModuleType.PATH, this.path);
|
||||
+ owner.getNavigation().moveTo(this.path, this.speedModifier);
|
||||
}
|
||||
+
|
||||
+ Path path = owner.getNavigation().getPath();
|
||||
+ Brain<?> brain = owner.getBrain();
|
||||
+
|
||||
+ if (path != null && this.lastTargetPos != null && brain.hasMemoryValue(MemoryModuleType.WALK_TARGET)) {
|
||||
+ WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); // we know isPresent = true
|
||||
+ if (walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4.0D) {
|
||||
+ this.start(level, owner, gameTime);
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ Path path = owner.getNavigation().getPath();
|
||||
+ Brain<?> brain = owner.getBrain();
|
||||
+ if (this.path != path) {
|
||||
+ this.path = path;
|
||||
+ brain.setMemory(MemoryModuleType.PATH, path);
|
||||
+ }
|
||||
+
|
||||
+ if (path != null && this.lastTargetPos != null) {
|
||||
+ WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get();
|
||||
+ if (walkTarget.getTarget().currentBlockPosition().distSqr(this.lastTargetPos) > 4.0
|
||||
+ && this.tryComputePath(owner, walkTarget, level.getGameTime())) {
|
||||
+ this.lastTargetPos = walkTarget.getTarget().currentBlockPosition();
|
||||
+ this.start(level, owner, gameTime);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Async path processing
|
||||
+ }
|
||||
+
|
||||
+ // DivineMC start - Async path processing
|
||||
+ @Nullable
|
||||
+ private Path computePath(Mob entity, WalkTarget walkTarget) {
|
||||
+ BlockPos blockPos = walkTarget.getTarget().currentBlockPosition();
|
||||
+ this.speedModifier = walkTarget.getSpeedModifier();
|
||||
+ Brain<?> brain = entity.getBrain();
|
||||
+ if (this.reachedTarget(entity, walkTarget)) {
|
||||
+ brain.eraseMemory(MemoryModuleType.CANT_REACH_WALK_TARGET_SINCE);
|
||||
}
|
||||
+ return entity.getNavigation().createPath(blockPos, 0);
|
||||
}
|
||||
+ // DivineMC end - Async path processing
|
||||
|
||||
private boolean tryComputePath(Mob mob, WalkTarget target, long time) {
|
||||
BlockPos blockPos = target.getTarget().currentBlockPosition();
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java b/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java
|
||||
index 4f9f3367b1ca3903df03a80fa2b01a3d24e6e77d..48b7e91191192266d57f4d4692d1865cbddae5c0 100644
|
||||
--- a/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java
|
||||
+++ b/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java
|
||||
@@ -60,17 +60,18 @@ public class SetClosestHomeAsWalkTarget {
|
||||
poi -> poi.is(PoiTypes.HOME), predicate, mob.blockPosition(), 48, PoiManager.Occupancy.ANY
|
||||
)
|
||||
.collect(Collectors.toSet());
|
||||
- Path path = AcquirePoi.findPathToPois(mob, set);
|
||||
- if (path != null && path.canReach()) {
|
||||
- BlockPos target = path.getTarget();
|
||||
- Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
- if (type.isPresent()) {
|
||||
- walkTarget.set(new WalkTarget(target, speedModifier, 1));
|
||||
- DebugPackets.sendPoiTicketCountPacket(level, target);
|
||||
- }
|
||||
- } else if (mutableInt.getValue() < 5) {
|
||||
- map.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < mutableLong.getValue());
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ Path possiblePath = AcquirePoi.findPathToPois(mob, set);
|
||||
+
|
||||
+ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> {
|
||||
+ processPath(speedModifier, map, mutableLong, walkTarget, level, poiManager, mutableInt, path);
|
||||
+ });
|
||||
+ } else {
|
||||
+ Path path = AcquirePoi.findPathToPois(mob, set);
|
||||
+ processPath(speedModifier, map, mutableLong, walkTarget, level, poiManager, mutableInt, path);
|
||||
}
|
||||
+ // DivineMC end - async path processing
|
||||
|
||||
return true;
|
||||
} else {
|
||||
@@ -81,4 +82,26 @@ public class SetClosestHomeAsWalkTarget {
|
||||
)
|
||||
);
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - async path processing
|
||||
+ private static void processPath(float speedModifier,
|
||||
+ Long2LongMap map,
|
||||
+ MutableLong mutableLong,
|
||||
+ net.minecraft.world.entity.ai.behavior.declarative.MemoryAccessor<com.mojang.datafixers.kinds.Const.Mu<com.mojang.datafixers.util.Unit>, WalkTarget> walkTarget,
|
||||
+ net.minecraft.server.level.ServerLevel level,
|
||||
+ PoiManager poiManager,
|
||||
+ MutableInt mutableInt,
|
||||
+ @org.jetbrains.annotations.Nullable Path path) {
|
||||
+ if (path != null && path.canReach()) {
|
||||
+ BlockPos target = path.getTarget();
|
||||
+ Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
+ if (type.isPresent()) {
|
||||
+ walkTarget.set(new WalkTarget(target, speedModifier, 1));
|
||||
+ DebugPackets.sendPoiTicketCountPacket(level, target);
|
||||
+ }
|
||||
+ } else if (mutableInt.getValue() < 5) {
|
||||
+ map.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < mutableLong.getValue());
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java b/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
|
||||
index 73bba480f3f017a8aed14562bd82ba33db04391c..b31976b68eec3cd0ab0620a487e99ecd49f78186 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
|
||||
@@ -54,7 +54,7 @@ public abstract class DoorInteractGoal extends Goal {
|
||||
return false;
|
||||
} else {
|
||||
Path path = this.mob.getNavigation().getPath();
|
||||
- if (path != null && !path.isDone()) {
|
||||
+ if (path != null && path.isProcessed() && !path.isDone()) { // DivineMC - Async Pathfinding
|
||||
for (int i = 0; i < Math.min(path.getNextNodeIndex() + 2, path.getNodeCount()); i++) {
|
||||
Node node = path.getNode(i);
|
||||
this.doorPos = new BlockPos(node.x, node.y + 1, node.z);
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java b/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java
|
||||
index 458ceec68ca138b0aa9b70d6c934473c01d468f4..ff06ba3ede2f2e40aae8f9a0b997150cfaaeecb7 100644
|
||||
--- a/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java
|
||||
+++ b/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java
|
||||
@@ -12,9 +12,25 @@ public class AmphibiousPathNavigation extends PathNavigation {
|
||||
super(mob, level);
|
||||
}
|
||||
|
||||
+ // DivineMC start - async path processing
|
||||
+ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> {
|
||||
+ AmphibiousNodeEvaluator nodeEvaluator = new AmphibiousNodeEvaluator(false);
|
||||
+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors());
|
||||
+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat());
|
||||
+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences());
|
||||
+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors());
|
||||
+ return nodeEvaluator;
|
||||
+ };
|
||||
+ // DivineMC end - async path processing
|
||||
+
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
this.nodeEvaluator = new AmphibiousNodeEvaluator(false);
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ return new PathFinder(this.nodeEvaluator, maxVisitedNodes, nodeEvaluatorGenerator);
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
return new PathFinder(this.nodeEvaluator, maxVisitedNodes);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
index 077863b758fbc3e51f25bcf842d00a2cc07c6a2f..b544685d191af2dcf3742abe45693b1eab0507e8 100644
|
||||
--- a/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
+++ b/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java
|
||||
@@ -16,9 +16,25 @@ public class FlyingPathNavigation extends PathNavigation {
|
||||
super(mob, level);
|
||||
}
|
||||
|
||||
+ // DivineMC start - async path processing
|
||||
+ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> {
|
||||
+ FlyNodeEvaluator nodeEvaluator = new FlyNodeEvaluator();
|
||||
+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors());
|
||||
+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat());
|
||||
+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences());
|
||||
+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors());
|
||||
+ return nodeEvaluator;
|
||||
+ };
|
||||
+ // DivineMC end - async path processing
|
||||
+
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
this.nodeEvaluator = new FlyNodeEvaluator();
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ return new PathFinder(this.nodeEvaluator, maxVisitedNodes, nodeEvaluatorGenerator);
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
return new PathFinder(this.nodeEvaluator, maxVisitedNodes);
|
||||
}
|
||||
|
||||
@@ -48,6 +64,7 @@ public class FlyingPathNavigation extends PathNavigation {
|
||||
if (this.hasDelayedRecomputation) {
|
||||
this.recomputePath();
|
||||
}
|
||||
+ if (this.path != null && !this.path.isProcessed()) return; // DivineMC - async path processing
|
||||
|
||||
if (!this.isDone()) {
|
||||
if (this.canUpdatePath()) {
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||
index 86fccf3617a32f3791b03d8067e2eaf6b8d8bebb..348fe5b7f8f3d7c87891704115d911a271e8882a 100644
|
||||
--- a/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||
+++ b/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java
|
||||
@@ -24,9 +24,25 @@ public class GroundPathNavigation extends PathNavigation {
|
||||
super(mob, level);
|
||||
}
|
||||
|
||||
+ // DivineMC start - async path processing
|
||||
+ protected static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> {
|
||||
+ WalkNodeEvaluator nodeEvaluator = new WalkNodeEvaluator();
|
||||
+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors());
|
||||
+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat());
|
||||
+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences());
|
||||
+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors());
|
||||
+ return nodeEvaluator;
|
||||
+ };
|
||||
+ // DivineMC end - async path processing
|
||||
+
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
this.nodeEvaluator = new WalkNodeEvaluator();
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ return new PathFinder(this.nodeEvaluator, maxVisitedNodes, nodeEvaluatorGenerator);
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
return new PathFinder(this.nodeEvaluator, maxVisitedNodes);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
index 24dd92449f70144c79f25bf24942ebd666655ed2..90035d61f705094507e1738a77bd624bcab3d235 100644
|
||||
--- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
+++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java
|
||||
@@ -167,6 +167,10 @@ public abstract class PathNavigation {
|
||||
return null;
|
||||
} else if (!this.canUpdatePath()) {
|
||||
return null;
|
||||
+ // DivineMC start - catch early if it's still processing these positions let it keep processing
|
||||
+ } else if (this.path instanceof org.bxteam.divinemc.async.pathfinding.AsyncPath asyncPath && !asyncPath.isProcessed() && asyncPath.hasSameProcessingPositions(targets)) {
|
||||
+ return this.path;
|
||||
+ // DivineMC end - catch early if it's still processing these positions let it keep processing
|
||||
} else if (this.path != null && !this.path.isDone() && targets.contains(this.targetPos)) {
|
||||
return this.path;
|
||||
} else {
|
||||
@@ -191,11 +195,29 @@ public abstract class PathNavigation {
|
||||
int i = (int)(followRange + regionOffset);
|
||||
PathNavigationRegion pathNavigationRegion = new PathNavigationRegion(this.level, blockPos.offset(-i, -i, -i), blockPos.offset(i, i, i));
|
||||
Path path = this.pathFinder.findPath(pathNavigationRegion, this.mob, targets, followRange, accuracy, this.maxVisitedNodesMultiplier);
|
||||
- if (path != null && path.getTarget() != null) {
|
||||
- this.targetPos = path.getTarget();
|
||||
- this.reachRange = accuracy;
|
||||
- this.resetStuckTimeout();
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ // assign early a target position. most calls will only have 1 position
|
||||
+ if (!targets.isEmpty()) this.targetPos = targets.iterator().next();
|
||||
+
|
||||
+ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(path, processedPath -> {
|
||||
+ // check that processing didn't take so long that we calculated a new path
|
||||
+ if (processedPath != this.path) return;
|
||||
+
|
||||
+ if (processedPath != null && processedPath.getTarget() != null) {
|
||||
+ this.targetPos = processedPath.getTarget();
|
||||
+ this.reachRange = accuracy;
|
||||
+ this.resetStuckTimeout();
|
||||
+ }
|
||||
+ });
|
||||
+ } else {
|
||||
+ if (path != null && path.getTarget() != null) {
|
||||
+ this.targetPos = path.getTarget();
|
||||
+ this.reachRange = accuracy;
|
||||
+ this.resetStuckTimeout();
|
||||
+ }
|
||||
}
|
||||
+ // DivineMC end - async path processing
|
||||
|
||||
return path;
|
||||
}
|
||||
@@ -246,8 +268,8 @@ public abstract class PathNavigation {
|
||||
if (this.isDone()) {
|
||||
return false;
|
||||
} else {
|
||||
- this.trimPath();
|
||||
- if (this.path.getNodeCount() <= 0) {
|
||||
+ if (path.isProcessed()) this.trimPath(); // DivineMC - only trim if processed
|
||||
+ if (path.isProcessed() && this.path.getNodeCount() <= 0) { // DivineMC - only check node count if processed
|
||||
return false;
|
||||
} else {
|
||||
this.speedModifier = speed;
|
||||
@@ -270,6 +292,7 @@ public abstract class PathNavigation {
|
||||
if (this.hasDelayedRecomputation) {
|
||||
this.recomputePath();
|
||||
}
|
||||
+ if (this.path != null && !this.path.isProcessed()) return; // DivineMC - skip pathfinding if we're still processing
|
||||
|
||||
if (!this.isDone()) {
|
||||
if (this.canUpdatePath()) {
|
||||
@@ -299,6 +322,7 @@ public abstract class PathNavigation {
|
||||
}
|
||||
|
||||
protected void followThePath() {
|
||||
+ if (!this.path.isProcessed()) return; // DivineMC - skip if not processed
|
||||
Vec3 tempMobPos = this.getTempMobPos();
|
||||
this.maxDistanceToWaypoint = this.mob.getBbWidth() > 0.75F ? this.mob.getBbWidth() / 2.0F : 0.75F - this.mob.getBbWidth() / 2.0F;
|
||||
Vec3i nextNodePos = this.path.getNextNodePos();
|
||||
@@ -455,7 +479,7 @@ public abstract class PathNavigation {
|
||||
public boolean shouldRecomputePath(BlockPos pos) {
|
||||
if (this.hasDelayedRecomputation) {
|
||||
return false;
|
||||
- } else if (this.path != null && !this.path.isDone() && this.path.getNodeCount() != 0) {
|
||||
+ } else if (this.path != null && this.path.isProcessed() && !this.path.isDone() && this.path.getNodeCount() != 0) { // DivineMC - Skip if not processed
|
||||
Node endNode = this.path.getEndNode();
|
||||
Vec3 vec3 = new Vec3((endNode.x + this.mob.getX()) / 2.0, (endNode.y + this.mob.getY()) / 2.0, (endNode.z + this.mob.getZ()) / 2.0);
|
||||
return pos.closerToCenterThan(vec3, this.path.getNodeCount() - this.path.getNextNodeIndex());
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java b/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java
|
||||
index ea0f6a19e4a79538e68917ba86cbc98be4dbca8d..030d90f93dbbc07e94d4776198c368650539bf91 100644
|
||||
--- a/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java
|
||||
+++ b/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java
|
||||
@@ -15,11 +15,27 @@ public class WaterBoundPathNavigation extends PathNavigation {
|
||||
super(mob, level);
|
||||
}
|
||||
|
||||
+ // DivineMC start - async path processing
|
||||
+ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> {
|
||||
+ SwimNodeEvaluator nodeEvaluator = new SwimNodeEvaluator(nodeEvaluatorFeatures.allowBreaching());
|
||||
+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors());
|
||||
+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat());
|
||||
+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences());
|
||||
+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors());
|
||||
+ return nodeEvaluator;
|
||||
+ };
|
||||
+ // DivineMC end - async path processing
|
||||
+
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
this.allowBreaching = this.mob.getType() == EntityType.DOLPHIN;
|
||||
this.nodeEvaluator = new SwimNodeEvaluator(this.allowBreaching);
|
||||
this.nodeEvaluator.setCanPassDoors(false);
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ return new PathFinder(this.nodeEvaluator, maxVisitedNodes, nodeEvaluatorGenerator);
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
return new PathFinder(this.nodeEvaluator, maxVisitedNodes);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
index 1f96fd5085bacb4c584576c7cb9f51e7898e9b03..d975b89c7bb57562852596751a4ff881d3ecf193 100644
|
||||
--- a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
+++ b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
|
||||
@@ -57,17 +57,32 @@ public class NearestBedSensor extends Sensor<Mob> {
|
||||
java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
||||
// don't ask me why it's unbounded. ask mojang.
|
||||
io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), level.purpurConfig.villagerNearestBedSensorSearchRadius, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); // Purpur - Configurable villager search radius
|
||||
- Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
||||
- // Paper end - optimise POI access
|
||||
- if (path != null && path.canReach()) {
|
||||
- BlockPos target = path.getTarget();
|
||||
- Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
- if (type.isPresent()) {
|
||||
- entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, target);
|
||||
- }
|
||||
- } else if (this.triedCount < 5) {
|
||||
- this.batchCache.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < this.lastUpdate);
|
||||
+ // DivineMC start - async pathfinding
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ Path possiblePath = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
||||
+ org.bxteam.divinemc.async.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> {
|
||||
+ processPath(entity, poiManager, path);
|
||||
+ });
|
||||
+ } else {
|
||||
+ Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
||||
+ // Paper end - optimise POI access
|
||||
+ processPath(entity, poiManager, path);
|
||||
+ }
|
||||
+ // DivineMC end - async pathfinding
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // DivineMC start - async pathfinding
|
||||
+ private void processPath(Mob entity, PoiManager poiManager, @org.jetbrains.annotations.Nullable Path path) {
|
||||
+ if (path != null && path.canReach()) {
|
||||
+ BlockPos target = path.getTarget();
|
||||
+ Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
+ if (type.isPresent()) {
|
||||
+ entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, target);
|
||||
}
|
||||
+ } else if (this.triedCount < 5) {
|
||||
+ this.batchCache.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < this.lastUpdate);
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - async pathfinding
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
|
||||
index 7573f1be88ca23096e02efe2fa933429fa4421ba..e5f4520afa2d396ab0e88aa282c408b272279e7d 100644
|
||||
--- a/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -937,7 +937,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
} else {
|
||||
Bee.this.pathfindRandomlyTowards(Bee.this.hivePos);
|
||||
}
|
||||
- } else {
|
||||
+ } else if (navigation.getPath() != null && navigation.getPath().isProcessed()) { // DivineMC - check processing
|
||||
boolean flag = this.pathfindDirectlyTowards(Bee.this.hivePos);
|
||||
if (!flag) {
|
||||
this.dropAndBlacklistHive();
|
||||
@@ -991,7 +991,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
return true;
|
||||
} else {
|
||||
Path path = Bee.this.navigation.getPath();
|
||||
- return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
|
||||
+ return path != null && path.isProcessed() && path.getTarget().equals(pos) && path.canReach() && path.isDone(); // DivineMC - ensure path is processed
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
|
||||
index f526a426d02f8fb1ce6c1b16e0ed3edae8ab5271..59693b73138ebd64d05d6ea5e94a15c7b1a760c0 100644
|
||||
--- a/net/minecraft/world/entity/animal/frog/Frog.java
|
||||
+++ b/net/minecraft/world/entity/animal/frog/Frog.java
|
||||
@@ -487,6 +487,17 @@ public class Frog extends Animal {
|
||||
super(mob, level);
|
||||
}
|
||||
|
||||
+ // DivineMC start - async path processing
|
||||
+ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> {
|
||||
+ Frog.FrogNodeEvaluator nodeEvaluator = new Frog.FrogNodeEvaluator(true);
|
||||
+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors());
|
||||
+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat());
|
||||
+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences());
|
||||
+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors());
|
||||
+ return nodeEvaluator;
|
||||
+ };
|
||||
+ // DivineMC end - async path processing
|
||||
+
|
||||
@Override
|
||||
public boolean canCutCorner(PathType pathType) {
|
||||
return pathType != PathType.WATER_BORDER && super.canCutCorner(pathType);
|
||||
@@ -495,6 +506,11 @@ public class Frog extends Animal {
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
this.nodeEvaluator = new Frog.FrogNodeEvaluator(true);
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ return new PathFinder(this.nodeEvaluator, maxVisitedNodes, nodeEvaluatorGenerator);
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
return new PathFinder(this.nodeEvaluator, maxVisitedNodes);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/monster/Drowned.java b/net/minecraft/world/entity/monster/Drowned.java
|
||||
index 2a13332ebabf2e63a8f51a5d794fab3d66c7a1db..d4e7fc0a5bda4f44bcfed3d1adae7cdaf815784b 100644
|
||||
--- a/net/minecraft/world/entity/monster/Drowned.java
|
||||
+++ b/net/minecraft/world/entity/monster/Drowned.java
|
||||
@@ -309,7 +309,7 @@ public class Drowned extends Zombie implements RangedAttackMob {
|
||||
|
||||
protected boolean closeToNextPos() {
|
||||
Path path = this.getNavigation().getPath();
|
||||
- if (path != null) {
|
||||
+ if (path != null && path.isProcessed()) { // DivineMC - ensure path is processed
|
||||
BlockPos target = path.getTarget();
|
||||
if (target != null) {
|
||||
double d = this.distanceToSqr(target.getX(), target.getY(), target.getZ());
|
||||
diff --git a/net/minecraft/world/entity/monster/Strider.java b/net/minecraft/world/entity/monster/Strider.java
|
||||
index fe31c4a45afd61be8b74efe9d0858ccd0aced075..e2e42bbdba1daf6783d10a62aa4c4b1bcf138fe6 100644
|
||||
--- a/net/minecraft/world/entity/monster/Strider.java
|
||||
+++ b/net/minecraft/world/entity/monster/Strider.java
|
||||
@@ -560,9 +560,25 @@ public class Strider extends Animal implements ItemSteerable {
|
||||
super(strider, level);
|
||||
}
|
||||
|
||||
+ // DivineMC start - async path processing
|
||||
+ private static final org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.async.pathfinding.NodeEvaluatorFeatures nodeEvaluatorFeatures) -> {
|
||||
+ WalkNodeEvaluator nodeEvaluator = new WalkNodeEvaluator();
|
||||
+ nodeEvaluator.setCanPassDoors(nodeEvaluatorFeatures.canPassDoors());
|
||||
+ nodeEvaluator.setCanFloat(nodeEvaluatorFeatures.canFloat());
|
||||
+ nodeEvaluator.setCanWalkOverFences(nodeEvaluatorFeatures.canWalkOverFences());
|
||||
+ nodeEvaluator.setCanOpenDoors(nodeEvaluatorFeatures.canOpenDoors());
|
||||
+ return nodeEvaluator;
|
||||
+ };
|
||||
+ // DivineMC end - async path processing
|
||||
+
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
this.nodeEvaluator = new WalkNodeEvaluator();
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ return new PathFinder(this.nodeEvaluator, maxVisitedNodes, nodeEvaluatorGenerator);
|
||||
+ }
|
||||
+ // DivineMC end
|
||||
return new PathFinder(this.nodeEvaluator, maxVisitedNodes);
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/entity/monster/warden/Warden.java b/net/minecraft/world/entity/monster/warden/Warden.java
|
||||
index 808661fdefacfffa65ebde1aa3193a82497706b7..1c08e246dc1ae139befbdca1c4ed66dd26fc07a1 100644
|
||||
--- a/net/minecraft/world/entity/monster/warden/Warden.java
|
||||
+++ b/net/minecraft/world/entity/monster/warden/Warden.java
|
||||
@@ -579,6 +579,16 @@ public class Warden extends Monster implements VibrationSystem {
|
||||
@Override
|
||||
protected PathFinder createPathFinder(int maxVisitedNodes) {
|
||||
this.nodeEvaluator = new WalkNodeEvaluator();
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding) {
|
||||
+ return new PathFinder(this.nodeEvaluator, maxVisitedNodes, GroundPathNavigation.nodeEvaluatorGenerator) {
|
||||
+ @Override
|
||||
+ protected float distance(Node first, Node second) {
|
||||
+ return first.distanceToXZ(second);
|
||||
+ }
|
||||
+ };
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
return new PathFinder(this.nodeEvaluator, maxVisitedNodes) {
|
||||
@Override
|
||||
protected float distance(Node first, Node second) {
|
||||
diff --git a/net/minecraft/world/level/pathfinder/Path.java b/net/minecraft/world/level/pathfinder/Path.java
|
||||
index d6d3c8f5e5dd4a8cab0d3fcc131c3a59f06130c6..839653a997f1e10970fa2956fadaf493808cb206 100644
|
||||
--- a/net/minecraft/world/level/pathfinder/Path.java
|
||||
+++ b/net/minecraft/world/level/pathfinder/Path.java
|
||||
@@ -26,6 +26,17 @@ public class Path {
|
||||
this.reached = reached;
|
||||
}
|
||||
|
||||
+ // DivineMC start - async path processing
|
||||
+ /**
|
||||
+ * checks if the path is completely processed in the case of it being computed async
|
||||
+ *
|
||||
+ * @return true if the path is processed
|
||||
+ */
|
||||
+ public boolean isProcessed() {
|
||||
+ return true;
|
||||
+ }
|
||||
+ // DivineMC end - async path processing
|
||||
+
|
||||
public void advance() {
|
||||
this.nextNodeIndex++;
|
||||
}
|
||||
@@ -99,6 +110,7 @@ public class Path {
|
||||
}
|
||||
|
||||
public boolean sameAs(@Nullable Path pathentity) {
|
||||
+ if (pathentity == this) return true; // DivineMC - async path processing
|
||||
if (pathentity == null) {
|
||||
return false;
|
||||
} else if (pathentity.nodes.size() != this.nodes.size()) {
|
||||
diff --git a/net/minecraft/world/level/pathfinder/PathFinder.java b/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
index c2baadcdceb1df6a881d6f73aa4eb4dd264bcdfe..38c8019f3cdfa351c120e80e312219416b157e6d 100644
|
||||
--- a/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
+++ b/net/minecraft/world/level/pathfinder/PathFinder.java
|
||||
@@ -22,11 +22,19 @@ public class PathFinder {
|
||||
public final NodeEvaluator nodeEvaluator;
|
||||
private static final boolean DEBUG = false;
|
||||
private final BinaryHeap openSet = new BinaryHeap();
|
||||
+ private final @Nullable org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator; // DivineMC - we use this later to generate an evaluator
|
||||
|
||||
- public PathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes) {
|
||||
+ // DivineMC start - support nodeEvaluatorgenerators
|
||||
+ public PathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes, @Nullable org.bxteam.divinemc.async.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator) { // DivineMC - add nodeEvaluatorGenerator
|
||||
this.nodeEvaluator = nodeEvaluator;
|
||||
this.maxVisitedNodes = maxVisitedNodes;
|
||||
+ this.nodeEvaluatorGenerator = nodeEvaluatorGenerator;
|
||||
+ }
|
||||
+
|
||||
+ public PathFinder(NodeEvaluator nodeEvaluator, int maxVisitedNodes) {
|
||||
+ this(nodeEvaluator, maxVisitedNodes, null);
|
||||
}
|
||||
+ // DivineMC end - support nodeEvaluatorgenerators
|
||||
|
||||
public void setMaxVisitedNodes(int maxVisitedNodes) {
|
||||
this.maxVisitedNodes = maxVisitedNodes;
|
||||
@@ -34,26 +42,63 @@ public class PathFinder {
|
||||
|
||||
@Nullable
|
||||
public Path findPath(PathNavigationRegion region, Mob mob, Set<BlockPos> targetPositions, float maxRange, int accuracy, float searchDepthMultiplier) {
|
||||
- this.openSet.clear();
|
||||
- this.nodeEvaluator.prepare(region, mob);
|
||||
- Node start = this.nodeEvaluator.getStart();
|
||||
+ // DivineMC start - use a generated evaluator if we have one otherwise run sync
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.asyncPathfinding)
|
||||
+ this.openSet.clear(); // it's always cleared in processPath
|
||||
+ NodeEvaluator nodeEvaluator = this.nodeEvaluatorGenerator == null
|
||||
+ ? this.nodeEvaluator
|
||||
+ : org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.takeNodeEvaluator(this.nodeEvaluatorGenerator, this.nodeEvaluator);
|
||||
+ nodeEvaluator.prepare(region, mob);
|
||||
+ Node start = nodeEvaluator.getStart();
|
||||
+ // DivineMC end - use a generated evaluator if we have one otherwise run sync
|
||||
if (start == null) {
|
||||
+ org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); // DivineMC - handle nodeEvaluatorGenerator
|
||||
return null;
|
||||
} else {
|
||||
// Paper start - Perf: remove streams and optimize collection
|
||||
List<Map.Entry<Target, BlockPos>> map = Lists.newArrayList();
|
||||
for (BlockPos pos : targetPositions) {
|
||||
- map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos));
|
||||
+ map.add(new java.util.AbstractMap.SimpleEntry<>(nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos)); // DivineMC - handle nodeEvaluatorGenerator
|
||||
}
|
||||
// Paper end - Perf: remove streams and optimize collection
|
||||
- Path path = this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier);
|
||||
- this.nodeEvaluator.done();
|
||||
- return path;
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (this.nodeEvaluatorGenerator == null) {
|
||||
+ // run sync :(
|
||||
+ org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator);
|
||||
+ return this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier);
|
||||
+ }
|
||||
+
|
||||
+ return new org.bxteam.divinemc.async.pathfinding.AsyncPath(Lists.newArrayList(), targetPositions, () -> {
|
||||
+ try {
|
||||
+ return this.processPath(nodeEvaluator, start, map, maxRange, accuracy, searchDepthMultiplier);
|
||||
+ } catch (Exception e) {
|
||||
+ e.printStackTrace();
|
||||
+ return null;
|
||||
+ } finally {
|
||||
+ nodeEvaluator.done();
|
||||
+ org.bxteam.divinemc.async.pathfinding.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator);
|
||||
+ }
|
||||
+ });
|
||||
+ // DivineMC end - async path processing
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Path findPath(Node node, List<Map.Entry<Target, BlockPos>> positions, float maxRange, int accuracy, float searchDepthMultiplier) { // Paper - optimize collection
|
||||
+ // DivineMC start - split pathfinding into the original sync method for compat and processing for delaying
|
||||
+ try {
|
||||
+ return this.processPath(this.nodeEvaluator, node, positions, maxRange, accuracy, searchDepthMultiplier);
|
||||
+ } catch (Exception e) {
|
||||
+ e.printStackTrace();
|
||||
+ return null;
|
||||
+ } finally {
|
||||
+ this.nodeEvaluator.done();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private synchronized @org.jetbrains.annotations.NotNull Path processPath(NodeEvaluator nodeEvaluator, Node node, List<Map.Entry<Target, BlockPos>> positions, float maxRange, int accuracy, float searchDepthMultiplier) { // sync to only use the caching functions in this class on a single thread
|
||||
+ org.apache.commons.lang3.Validate.isTrue(!positions.isEmpty()); // ensure that we have at least one position, which means we'll always return a path
|
||||
+ // DivineMC end - split pathfinding into the original sync method for compat and processing for delaying
|
||||
// Set<Target> set = targetPositions.keySet(); // Paper
|
||||
node.g = 0.0F;
|
||||
node.h = this.getBestH(node, positions); // Paper - optimize collection
|
||||
@@ -89,7 +134,7 @@ public class PathFinder {
|
||||
}
|
||||
|
||||
if (!(node1.distanceTo(node) >= maxRange)) {
|
||||
- int neighbors = this.nodeEvaluator.getNeighbors(this.neighbors, node1);
|
||||
+ int neighbors = nodeEvaluator.getNeighbors(this.neighbors, node1); // DivineMC - use provided nodeEvaluator
|
||||
|
||||
for (int i2 = 0; i2 < neighbors; i2++) {
|
||||
Node node2 = this.neighbors[i2];
|
||||
@@ -1,661 +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:18:49 +0300
|
||||
Subject: [PATCH] Petal: Multithreaded Tracker
|
||||
|
||||
Original project: https://github.com/Bloom-host/Petal
|
||||
Original license: GPL v3
|
||||
|
||||
Patch description:
|
||||
|
||||
We made much of tracking logic asynchronously, and fixed visible issue
|
||||
for the case of some NPC plugins which using real entity type, e.g. Citizens.
|
||||
|
||||
But it is still recommending to use those packet based, virtual entity
|
||||
based NPC plugins, e.g. ZNPC Plus, Adyeshach, Fancy NPC, etc.
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
index 1b8193587814225c2ef2c5d9e667436eb50ff6c5..93272808d94e81d31af728ebe85df9a2bc7aedab 100644
|
||||
--- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
@@ -60,7 +60,16 @@ public final class NearbyPlayers {
|
||||
|
||||
private final ServerLevel world;
|
||||
private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
|
||||
- private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
|
||||
+ // DivineMC start - Multithreaded Tracker
|
||||
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<TrackedChunk> byChunk;
|
||||
+ {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled) {
|
||||
+ byChunk = it.unimi.dsi.fastutil.longs.Long2ReferenceMaps.synchronize(new Long2ReferenceOpenHashMap<>());
|
||||
+ } else {
|
||||
+ byChunk = new Long2ReferenceOpenHashMap<>();
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded Tracker
|
||||
private final Long2ReferenceOpenHashMap<ReferenceList<ServerPlayer>>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES];
|
||||
{
|
||||
for (int i = 0; i < this.directByChunk.length; ++i) {
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index c4a1e3908cf8e1b0614ff6c3a0f5f6708a7667e5..fef167837e05d6e80246d4fccd037cc1c9500f97 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -345,7 +345,11 @@ public final class RegionizedPlayerChunkLoader {
|
||||
private boolean canGenerateChunks = true;
|
||||
|
||||
private final ArrayDeque<ChunkHolderManager.TicketOperation<?, ?>> delayedTicketOps = new ArrayDeque<>();
|
||||
- private final LongOpenHashSet sentChunks = new LongOpenHashSet();
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ private final LongOpenHashSet sentChunks = org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled && !org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedCompatModeEnabled
|
||||
+ ? new org.bxteam.divinemc.util.map.ConcurrentLongHashSet()
|
||||
+ : new LongOpenHashSet();
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
|
||||
private static final byte CHUNK_TICKET_STAGE_NONE = 0;
|
||||
private static final byte CHUNK_TICKET_STAGE_LOADING = 1;
|
||||
diff --git a/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java b/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java
|
||||
index 9c0c99b936b4a82ebfe924866e53ec71f7bbe9ad..01ed1e3572e9c2ccfd19df117cda0d5cf65b9bcb 100644
|
||||
--- a/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java
|
||||
+++ b/net/minecraft/network/protocol/game/ClientboundUpdateAttributesPacket.java
|
||||
@@ -32,6 +32,7 @@ public class ClientboundUpdateAttributesPacket implements Packet<ClientGamePacke
|
||||
this.attributes = Lists.newArrayList();
|
||||
|
||||
for (AttributeInstance attributeInstance : attributes) {
|
||||
+ if (attributeInstance == null) continue; // DivineMC - Multithreaded Tracker
|
||||
this.attributes
|
||||
.add(
|
||||
new ClientboundUpdateAttributesPacket.AttributeSnapshot(
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index c0d996fb99f053863ce623889add3feb70d7137d..7ca147cf9da67c399806056e5092841f7ca32321 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -255,9 +255,19 @@ 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.config.DivineConfig.AsyncCategory.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
|
||||
@@ -1013,6 +1023,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// Paper end - optimise entity tracker
|
||||
|
||||
protected void tick() {
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled) {
|
||||
+ final ServerLevel level = this.level;
|
||||
+ org.bxteam.divinemc.async.tracking.MultithreadedTracker.tick(level);
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
// Paper start - optimise entity tracker
|
||||
if (true) {
|
||||
this.newTrackerTick();
|
||||
@@ -1135,7 +1152,44 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final Entity entity;
|
||||
private final int range;
|
||||
SectionPos lastSectionPos;
|
||||
- public final Set<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ public static final ServerPlayerConnection[] EMPTY_OBJECT_ARRAY = new ServerPlayerConnection[0];
|
||||
+ private final it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<ServerPlayerConnection> nonSyncSeenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>() {
|
||||
+ @Override
|
||||
+ public boolean add(ServerPlayerConnection serverPlayerConnection) {
|
||||
+ seenByUpdated = true;
|
||||
+ return super.add(serverPlayerConnection);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean remove(Object k) {
|
||||
+ seenByUpdated = true;
|
||||
+ return super.remove(k);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void clear() {
|
||||
+ seenByUpdated = true;
|
||||
+ super.clear();
|
||||
+ }
|
||||
+ };
|
||||
+ public final Set<ServerPlayerConnection> seenBy = org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled ? it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(nonSyncSeenBy) : nonSyncSeenBy; // Paper - Perf: optimise map impl
|
||||
+ private volatile boolean seenByUpdated = true;
|
||||
+ private volatile ServerPlayerConnection[] seenByArray = EMPTY_OBJECT_ARRAY;
|
||||
+
|
||||
+ public ServerPlayerConnection[] seenBy() {
|
||||
+ if (!seenByUpdated) {
|
||||
+ return seenByArray;
|
||||
+ } else {
|
||||
+ return seenBy.toArray(EMPTY_OBJECT_ARRAY);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ public void seenByUpdated() {
|
||||
+ this.seenByArray = this.seenBy.toArray(EMPTY_OBJECT_ARRAY);
|
||||
+ seenByUpdated = false;
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
|
||||
// Paper start - optimise entity tracker
|
||||
private long lastChunkUpdate = -1L;
|
||||
@@ -1162,22 +1216,92 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.lastTrackedChunk = chunk;
|
||||
|
||||
final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
|
||||
+ final int playersLength = Math.min(playersRaw.length, players.size()); // DivineMC - Multithreaded tracker
|
||||
|
||||
- for (int i = 0, len = players.size(); i < len; ++i) {
|
||||
+ for (int i = 0; i < playersLength; ++i) { // DivineMC - Multithreaded tracker
|
||||
final ServerPlayer player = playersRaw[i];
|
||||
this.updatePlayer(player);
|
||||
}
|
||||
|
||||
if (lastChunkUpdate != currChunkUpdate || lastTrackedChunk != chunk) {
|
||||
// need to purge any players possible not in the chunk list
|
||||
- for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ boolean removed = false;
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) {
|
||||
final ServerPlayer player = conn.getPlayer();
|
||||
if (!players.contains(player)) {
|
||||
- this.removePlayer(player);
|
||||
+ removed |= this.removePlayerMulti(player);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (removed) {
|
||||
+ this.seenByUpdated();
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ public final @Nullable Runnable tickCompact(final ca.spottedleaf.moonrise.common.misc.NearbyPlayers.TrackedChunk chunk) {
|
||||
+ if (chunk == null) {
|
||||
+ this.moonrise$clearPlayers();
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<ServerPlayer> players = chunk.getPlayers(ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.VIEW_DISTANCE);
|
||||
+
|
||||
+ if (players == null) {
|
||||
+ this.moonrise$clearPlayers();
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ final long lastChunkUpdate = this.lastChunkUpdate;
|
||||
+ final long currChunkUpdate = chunk.getUpdateCount();
|
||||
+ final ca.spottedleaf.moonrise.common.misc.NearbyPlayers.TrackedChunk lastTrackedChunk = this.lastTrackedChunk;
|
||||
+ this.lastChunkUpdate = currChunkUpdate;
|
||||
+ this.lastTrackedChunk = chunk;
|
||||
+
|
||||
+ final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
|
||||
+ final int playersLen = players.size(); // Ensure length won't change in the future tasks
|
||||
+
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled || !org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedCompatModeEnabled) {
|
||||
+ throw new IllegalStateException();
|
||||
+ }
|
||||
+ final boolean isServerPlayer = this.entity instanceof ServerPlayer;
|
||||
+ final boolean isRealPlayer = isServerPlayer && ((ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer) this.entity).moonrise$isRealPlayer();
|
||||
+ Runnable updatePlayerTasks = () -> {
|
||||
+ for (int i = 0; i < playersLen; ++i) {
|
||||
+ final ServerPlayer player = playersRaw[i];
|
||||
+ this.updatePlayer(player);
|
||||
+ }
|
||||
+
|
||||
+ if (lastChunkUpdate != currChunkUpdate || lastTrackedChunk != chunk) {
|
||||
+ // need to purge any players possible not in the chunk list
|
||||
+ boolean removed = false;
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) {
|
||||
+ final ServerPlayer player = conn.getPlayer();
|
||||
+ if (!players.contains(player)) {
|
||||
+ removed |= this.removePlayerMulti(player);
|
||||
+ }
|
||||
+ }
|
||||
+ if (removed) {
|
||||
+ this.seenByUpdated();
|
||||
}
|
||||
}
|
||||
+ };
|
||||
+
|
||||
+ // Only update asynchronously for real player, and sync update for fake players
|
||||
+ // This can fix compatibility issue with NPC plugins using real entity type, like Citizens
|
||||
+ // To prevent visible issue with player type NPCs
|
||||
+ // btw, still recommend to use packet based NPC plugins, like ZNPC Plus, Adyeshach, Fancy NPC, etc.
|
||||
+ if (isRealPlayer || !isServerPlayer) {
|
||||
+ return updatePlayerTasks;
|
||||
+ } else {
|
||||
+ updatePlayerTasks.run();
|
||||
+ return null;
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
|
||||
@Override
|
||||
public final void moonrise$removeNonTickThreadPlayers() {
|
||||
@@ -1193,12 +1317,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
return;
|
||||
}
|
||||
|
||||
- for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) { // DivineMC - Multithreaded tracker
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
if (!ca.spottedleaf.moonrise.common.util.TickThread.isTickThreadFor(player)) {
|
||||
- this.removePlayer(player);
|
||||
+ this.removePlayerMulti(player); // DivineMC - Multithreaded tracker
|
||||
}
|
||||
}
|
||||
+ this.seenByUpdated(); // DivineMC - Multithreaded tracker
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1208,10 +1333,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
if (this.seenBy.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
- for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
|
||||
+ for (final ServerPlayerConnection conn : this.seenBy()) { // DivineMC - Multithreaded tracker
|
||||
ServerPlayer player = conn.getPlayer();
|
||||
- this.removePlayer(player);
|
||||
+ this.removePlayerMulti(player); // DivineMC - Multithreaded tracker
|
||||
}
|
||||
+ this.seenByUpdated(); // DivineMC - Multithreaded tracker
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1238,7 +1364,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
public void broadcast(Packet<?> packet) {
|
||||
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
|
||||
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy()) { // DivineMC - Multithreaded tracker
|
||||
serverPlayerConnection.send(packet);
|
||||
}
|
||||
}
|
||||
@@ -1259,21 +1385,32 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
}
|
||||
|
||||
public void broadcastRemoved() {
|
||||
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
|
||||
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy()) { // DivineMC - Multithreaded tracker
|
||||
this.serverEntity.removePairing(serverPlayerConnection.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ public boolean removePlayerMulti(ServerPlayer player) {
|
||||
+ if (this.seenBy.remove(player.connection)) {
|
||||
+ this.serverEntity.removePairing(player);
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
+
|
||||
public void removePlayer(ServerPlayer player) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
|
||||
if (this.seenBy.remove(player.connection)) {
|
||||
this.serverEntity.removePairing(player);
|
||||
}
|
||||
+ this.seenByUpdated(); // DivineMC - Multithreaded tracker
|
||||
}
|
||||
|
||||
public void updatePlayer(ServerPlayer player) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
|
||||
if (player != this.entity) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled && player == null) return; // DivineMC - Multithreaded tracker
|
||||
// Paper start - remove allocation of Vec3D here
|
||||
// Vec3 vec3 = player.position().subtract(this.entity.position());
|
||||
double vec3_dx = player.getX() - this.entity.getX();
|
||||
@@ -1301,6 +1438,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
// CraftBukkit end
|
||||
if (flag) {
|
||||
if (this.seenBy.add(player.connection)) {
|
||||
+ this.seenByUpdated(); // DivineMC - Multithreaded tracker
|
||||
// Paper start - entity tracking events
|
||||
if (io.papermc.paper.event.player.PlayerTrackEntityEvent.getHandlerList().getRegisteredListeners().length == 0 || new io.papermc.paper.event.player.PlayerTrackEntityEvent(player.getBukkitEntity(), this.entity.getBukkitEntity()).callEvent()) {
|
||||
this.serverEntity.addPairing(player);
|
||||
@@ -1309,6 +1447,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
this.serverEntity.onPlayerAdd(); // Paper - fix desync when a player is added to the tracker
|
||||
}
|
||||
} else if (this.seenBy.remove(player.connection)) {
|
||||
+ this.seenByUpdated(); // DivineMC - Multithreaded tracker
|
||||
this.serverEntity.removePairing(player);
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerBossEvent.java b/net/minecraft/server/level/ServerBossEvent.java
|
||||
index f106373ef3ac4a8685c2939c9e8361688a285913..b844b6dd89bc53b74c0d1bdbf4657c115a892dc7 100644
|
||||
--- a/net/minecraft/server/level/ServerBossEvent.java
|
||||
+++ b/net/minecraft/server/level/ServerBossEvent.java
|
||||
@@ -13,7 +13,11 @@ import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.BossEvent;
|
||||
|
||||
public class ServerBossEvent extends BossEvent {
|
||||
- private final Set<ServerPlayer> players = Sets.newHashSet();
|
||||
+ // DivineMC start - Multithreaded tracker - players can be removed in async tracking
|
||||
+ private final Set<ServerPlayer> players = org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled
|
||||
+ ? Sets.newConcurrentHashSet()
|
||||
+ : Sets.newHashSet();
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
private final Set<ServerPlayer> unmodifiablePlayers = Collections.unmodifiableSet(this.players);
|
||||
public boolean visible = true;
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 0868189fee30d40dfb82ae39592a65b510e96b54..39e28ad0cbb4617a80d7f197723233d4bdc1eed5 100644
|
||||
--- a/net/minecraft/server/level/ServerEntity.java
|
||||
+++ b/net/minecraft/server/level/ServerEntity.java
|
||||
@@ -134,7 +134,7 @@ public class ServerEntity {
|
||||
MapId mapId = itemFrame.cachedMapId; // Paper - Perf: Cache map ids on item frames
|
||||
MapItemSavedData savedData = MapItem.getSavedData(mapId, this.level);
|
||||
if (savedData != null) {
|
||||
- for (final net.minecraft.server.network.ServerPlayerConnection connection : this.trackedPlayers) { // Paper
|
||||
+ for (final net.minecraft.server.network.ServerPlayerConnection connection : this.trackedPlayers.toArray(ChunkMap.TrackedEntity.EMPTY_OBJECT_ARRAY)) { // Paper // DivineMC - Multithreaded tracker
|
||||
final ServerPlayer serverPlayer = connection.getPlayer(); // Paper
|
||||
savedData.tickCarriedBy(serverPlayer, item);
|
||||
Packet<?> updatePacket = savedData.getUpdatePacket(mapId, serverPlayer);
|
||||
@@ -428,8 +428,6 @@ public class ServerEntity {
|
||||
// CraftBukkit end
|
||||
this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync));
|
||||
}
|
||||
-
|
||||
- attributesToSync.clear();
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 78bf3365b426e7090182af84630111d410a2460e..3c1795eb56900cd80cfec38bd1d922d566463ecb 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -2517,7 +2517,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
@Override
|
||||
public LevelEntityGetter<Entity> getEntities() {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
|
||||
return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system
|
||||
}
|
||||
|
||||
@@ -2784,7 +2783,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
|
||||
index 2d3200834e46a24156659a32170aa4974caf8060..4d37b16adc5491db24fce1ce656f6cde575e10f4 100644
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -1936,7 +1936,6 @@ public class ServerGamePacketListenerImpl
|
||||
}
|
||||
|
||||
public void internalTeleport(PositionMoveRotation posMoveRotation, Set<Relative> relatives) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper
|
||||
// Paper start - Prevent teleporting dead entities
|
||||
if (this.player.isRemoved()) {
|
||||
LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index 76a7898c040cd46df6a889535b1d77c8e6de5a91..e903e60c8914899d9be14cce9fdef9cc33ee71d5 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1353,13 +1353,13 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
}
|
||||
|
||||
private void refreshDirtyAttributes() {
|
||||
- Set<AttributeInstance> attributesToUpdate = this.getAttributes().getAttributesToUpdate();
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ int[] attributesToUpdate = this.getAttributes().getAttributesToUpdateIds();
|
||||
|
||||
- for (AttributeInstance attributeInstance : attributesToUpdate) {
|
||||
- this.onAttributeUpdated(attributeInstance.getAttribute());
|
||||
+ for (int attribute : attributesToUpdate) {
|
||||
+ this.onAttributeUpdated(net.minecraft.core.registries.BuiltInRegistries.ATTRIBUTE.get(attribute).orElseThrow());
|
||||
}
|
||||
-
|
||||
- attributesToUpdate.clear();
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
}
|
||||
|
||||
protected void onAttributeUpdated(Holder<Attribute> attribute) {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/Attribute.java b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
index 18563961e9dba1a11265c6ea708881d4e46846ff..355e552f77e7639ddf1c8b4da9868775017563c3 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/Attribute.java
|
||||
@@ -16,10 +16,15 @@ public class Attribute {
|
||||
private boolean syncable;
|
||||
private final String descriptionId;
|
||||
public Attribute.Sentiment sentiment = Attribute.Sentiment.POSITIVE;
|
||||
+ // DivineMC start - Multithreaded Tracker
|
||||
+ public final int uid;
|
||||
+ private static final java.util.concurrent.atomic.AtomicInteger SIZE = new java.util.concurrent.atomic.AtomicInteger();
|
||||
+ // DivineMC end - Multithreaded Tracker
|
||||
|
||||
protected Attribute(String descriptionId, double defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
this.descriptionId = descriptionId;
|
||||
+ this.uid = SIZE.getAndAdd(1); // DivineMC - Multithreaded Tracker
|
||||
}
|
||||
|
||||
public double getDefaultValue() {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
index 42ad600c6a5cb20e1d820f169f6a1a17ef3a5195..c93b2c684d773551b14cc2ce024923536780ee17 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
@@ -22,8 +22,24 @@ public class AttributeInstance {
|
||||
private final Map<AttributeModifier.Operation, Map<ResourceLocation, AttributeModifier>> modifiersByOperation = Maps.newEnumMap(
|
||||
AttributeModifier.Operation.class
|
||||
);
|
||||
- private final Map<ResourceLocation, AttributeModifier> modifierById = new Object2ObjectArrayMap<>();
|
||||
- private final Map<ResourceLocation, AttributeModifier> permanentModifiers = new Object2ObjectArrayMap<>();
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ private final Map<ResourceLocation, AttributeModifier> modifierById;
|
||||
+ {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled) {
|
||||
+ modifierById = it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this);
|
||||
+ } else {
|
||||
+ modifierById = new Object2ObjectArrayMap<>();
|
||||
+ }
|
||||
+ }
|
||||
+ private final Map<ResourceLocation, AttributeModifier> permanentModifiers;
|
||||
+ {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled) {
|
||||
+ permanentModifiers = it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this);
|
||||
+ } else {
|
||||
+ permanentModifiers = new Object2ObjectArrayMap<>();
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
private double baseValue;
|
||||
private boolean dirty = true;
|
||||
private double cachedValue;
|
||||
@@ -52,7 +68,13 @@ public class AttributeInstance {
|
||||
|
||||
@VisibleForTesting
|
||||
Map<ResourceLocation, AttributeModifier> getModifiers(AttributeModifier.Operation operation) {
|
||||
- return this.modifiersByOperation.computeIfAbsent(operation, operation1 -> new Object2ObjectOpenHashMap<>());
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ return this.modifiersByOperation.computeIfAbsent(operation, operation1 -> {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled)
|
||||
+ return it.unimi.dsi.fastutil.objects.Object2ObjectMaps.synchronize(new Object2ObjectArrayMap<>(), this);
|
||||
+ else return new Object2ObjectArrayMap<>();
|
||||
+ });
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
}
|
||||
|
||||
public Set<AttributeModifier> getModifiers() {
|
||||
@@ -140,8 +162,12 @@ public class AttributeInstance {
|
||||
|
||||
public double getValue() {
|
||||
if (this.dirty) {
|
||||
- this.cachedValue = this.calculateValue();
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ double value = this.calculateValue();
|
||||
+ this.cachedValue = value;
|
||||
this.dirty = false;
|
||||
+ return value;
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
}
|
||||
|
||||
return this.cachedValue;
|
||||
@@ -184,7 +210,15 @@ public class AttributeInstance {
|
||||
}
|
||||
|
||||
public AttributeInstance.Packed pack() {
|
||||
- return new AttributeInstance.Packed(this.attribute, this.baseValue, List.copyOf(this.permanentModifiers.values()));
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled) {
|
||||
+ synchronized (this) {
|
||||
+ return new AttributeInstance.Packed(this.attribute, this.baseValue, List.copyOf(this.permanentModifiers.values()));
|
||||
+ }
|
||||
+ } else {
|
||||
+ return new AttributeInstance.Packed(this.attribute, this.baseValue, List.copyOf(this.permanentModifiers.values()));
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
}
|
||||
|
||||
public void apply(AttributeInstance.Packed instance) {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
index 7dd8c1c8e27410854ce1ee90defc607c2710b5a2..290a7fa565f695c7afe3cf0791f6cf1da6a39663 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
@@ -14,9 +14,11 @@ import net.minecraft.core.Holder;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
public class AttributeMap {
|
||||
- private final Map<Holder<Attribute>, AttributeInstance> attributes = new Object2ObjectOpenHashMap<>();
|
||||
- private final Set<AttributeInstance> attributesToSync = new ObjectOpenHashSet<>();
|
||||
- private final Set<AttributeInstance> attributesToUpdate = new ObjectOpenHashSet<>();
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ private final Map<Holder<Attribute>, AttributeInstance> attributes = new org.bxteam.divinemc.util.map.AttributeInstanceArrayMap();
|
||||
+ private final org.bxteam.divinemc.util.map.AttributeInstanceSet attributesToSync = new org.bxteam.divinemc.util.map.AttributeInstanceSet((org.bxteam.divinemc.util.map.AttributeInstanceArrayMap) attributes);
|
||||
+ private final org.bxteam.divinemc.util.map.AttributeInstanceSet attributesToUpdate = new org.bxteam.divinemc.util.map.AttributeInstanceSet((org.bxteam.divinemc.util.map.AttributeInstanceArrayMap) attributes);
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
private final AttributeSupplier supplier;
|
||||
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
|
||||
|
||||
@@ -30,28 +32,52 @@ public class AttributeMap {
|
||||
this.supplier = defaultAttributes;
|
||||
}
|
||||
|
||||
- private void onAttributeModified(AttributeInstance instance) {
|
||||
+ private synchronized void onAttributeModified(AttributeInstance instance) { // DivineMC - Multithreaded Tracker
|
||||
this.attributesToUpdate.add(instance);
|
||||
if (instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))) { // Purpur - Ridables
|
||||
this.attributesToSync.add(instance);
|
||||
}
|
||||
}
|
||||
|
||||
- public Set<AttributeInstance> getAttributesToSync() {
|
||||
- return this.attributesToSync;
|
||||
+ // DivineMC start - Multithreaded Tracker
|
||||
+ private static final AttributeInstance[] EMPTY_ATTRIBUTE_INSTANCE = new AttributeInstance[0];
|
||||
+ public synchronized Set<AttributeInstance> getAttributesToSync() {
|
||||
+ var clone = it.unimi.dsi.fastutil.objects.ReferenceArraySet.ofUnchecked(attributesToSync.toArray(EMPTY_ATTRIBUTE_INSTANCE));
|
||||
+ this.attributesToSync.clear();
|
||||
+ return clone;
|
||||
}
|
||||
|
||||
- public Set<AttributeInstance> getAttributesToUpdate() {
|
||||
- return this.attributesToUpdate;
|
||||
+ public synchronized Set<AttributeInstance> getAttributesToUpdate() {
|
||||
+ var clone = it.unimi.dsi.fastutil.objects.ReferenceArraySet.ofUnchecked(attributesToUpdate.toArray(EMPTY_ATTRIBUTE_INSTANCE));
|
||||
+ this.attributesToUpdate.clear();
|
||||
+ return clone;
|
||||
}
|
||||
|
||||
+ public synchronized int[] getAttributesToUpdateIds() {
|
||||
+ int[] clone = attributesToUpdate.inner.toIntArray();
|
||||
+ this.attributesToUpdate.clear();
|
||||
+ return clone;
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded Tracker
|
||||
+
|
||||
public Collection<AttributeInstance> getSyncableAttributes() {
|
||||
return this.attributes.values().stream().filter(instance -> instance.getAttribute().value().isClientSyncable() && (entity == null || entity.shouldSendAttribute(instance.getAttribute().value()))).collect(Collectors.toList()); // Purpur - Ridables
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public AttributeInstance getInstance(Holder<Attribute> attribute) {
|
||||
- return this.attributes.computeIfAbsent(attribute, holder -> this.supplier.createInstance(this::onAttributeModified, (Holder<Attribute>)holder));
|
||||
+ // DivineMC start - Multithreaded Tracker
|
||||
+ AttributeInstance v;
|
||||
+ if ((v = this.attributes.get(attribute)) == null) {
|
||||
+ AttributeInstance newValue;
|
||||
+ if ((newValue = this.supplier.createInstance(this::onAttributeModified, attribute)) != null) {
|
||||
+ attributes.put(attribute, newValue);
|
||||
+ return newValue;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return v;
|
||||
+ // DivineMC end - Multithreaded Tracker
|
||||
}
|
||||
|
||||
public boolean hasAttribute(Holder<Attribute> attribute) {
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
index 24710041ccbc70e5506d8d89ae34f0141977f209..dbcff8bdd6911843bc42f64d5dcf1bb854128075 100644
|
||||
--- a/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
+++ b/net/minecraft/world/entity/ai/attributes/AttributeSupplier.java
|
||||
@@ -11,7 +11,7 @@ public class AttributeSupplier {
|
||||
private final Map<Holder<Attribute>, AttributeInstance> instances;
|
||||
|
||||
AttributeSupplier(Map<Holder<Attribute>, AttributeInstance> instances) {
|
||||
- this.instances = instances;
|
||||
+ this.instances = new org.bxteam.divinemc.util.map.AttributeInstanceArrayMap(instances); // DivineMC - Multithreaded Tracker
|
||||
}
|
||||
|
||||
public AttributeInstance getAttributeInstance(Holder<Attribute> attribute) {
|
||||
diff --git a/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java b/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
||||
index 325ec57df2885f5e81b8a6b61e3a9fed9484b30f..1796f0a6f647c94b0943a6003a1307795294805e 100644
|
||||
--- a/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
||||
+++ b/net/minecraft/world/entity/vehicle/NewMinecartBehavior.java
|
||||
@@ -35,13 +35,20 @@ public class NewMinecartBehavior extends MinecartBehavior {
|
||||
private int cachedLerpDelay;
|
||||
private float cachedPartialTick;
|
||||
private int lerpDelay = 0;
|
||||
- public final List<NewMinecartBehavior.MinecartStep> lerpSteps = new LinkedList<>();
|
||||
+ public final List<NewMinecartBehavior.MinecartStep> lerpSteps; // DivineMC - Multithreaded Tracker
|
||||
public final List<NewMinecartBehavior.MinecartStep> currentLerpSteps = new LinkedList<>();
|
||||
public double currentLerpStepsTotalWeight = 0.0;
|
||||
public NewMinecartBehavior.MinecartStep oldLerp = NewMinecartBehavior.MinecartStep.ZERO;
|
||||
|
||||
public NewMinecartBehavior(AbstractMinecart minecart) {
|
||||
super(minecart);
|
||||
+ // DivineMC start - Multithreaded Tracker
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.multithreadedEnabled) {
|
||||
+ this.lerpSteps = it.unimi.dsi.fastutil.objects.ObjectLists.synchronize(new it.unimi.dsi.fastutil.objects.ObjectArrayList<>());
|
||||
+ } else {
|
||||
+ this.lerpSteps = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>();
|
||||
+ }
|
||||
+ // DivineMC end - Multithreaded Tracker
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
index ebb0b7e5047efa65e8b6986f12dd5a7d6c0e9613..a77665abefdf653e65393cc6908506a5812b5596 100644
|
||||
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
|
||||
@@ -212,6 +212,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,177 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 19 Mar 2025 23:24:32 +0300
|
||||
Subject: [PATCH] Pufferfish: Optimize mob spawning
|
||||
|
||||
Original license: GPL v3
|
||||
Original project: https://github.com/pufferfish-gg/Pufferfish
|
||||
|
||||
This patch reduces the main-thread impact of mob spawning by moving spawning work to other threads
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 1877ee1431b0f858b6a5da7347d72fe90374e27a..dddcde2716bbdca1240bd60bc5ca17aeb1999d57 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
public boolean lagging = false; // Purpur - Lagging threshold
|
||||
protected boolean upnp = false; // Purpur - UPnP Port Forwarding
|
||||
public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
|
||||
+ public gg.pufferfish.pufferfish.util.AsyncExecutor mobSpawnExecutor = new gg.pufferfish.pufferfish.util.AsyncExecutor("Mob Spawning"); // DivineMC - Pufferfish: Optimize mob spawning
|
||||
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
index 46adbe6ccf1e4291e33a52a6612f624558c18f96..d90341ff814bb2b14867b7d9a401ae9672076f5b 100644
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -367,6 +367,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
||||
|
||||
org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur - Implement TPSBar
|
||||
if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur - Give bee counts in beehives to Purpur clients
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) mobSpawnExecutor.start(); // DivineMC - Pufferfish: Optimize mob spawning
|
||||
return true;
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 75c8ce32e68f92e20201e9c243f46f2be716eac8..bf680624bc6c618dfa0eeeb74c103ff6716fd27e 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -182,6 +182,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
}
|
||||
// Paper end - chunk tick iteration optimisations
|
||||
|
||||
+ // DivineMC start - Pufferfish: Optimize mob spawning
|
||||
+ public boolean firstRunSpawnCounts = true;
|
||||
+ public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false);
|
||||
+ // DivineMC end - Pufferfish: Optimize mob spawning
|
||||
|
||||
public ServerChunkCache(
|
||||
ServerLevel level,
|
||||
@@ -506,6 +510,47 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
|
||||
this.broadcastChangedChunks();
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Pufferfish: Optimize mob spawning
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) {
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) {
|
||||
+ player.mobCounts[ii] = 0;
|
||||
+
|
||||
+ int newBackoff = Math.max(0, player.mobBackoffCounts[ii] - 1);
|
||||
+ player.mobBackoffCounts[ii] = newBackoff;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (firstRunSpawnCounts) {
|
||||
+ firstRunSpawnCounts = false;
|
||||
+ spawnCountsReady.set(true);
|
||||
+ }
|
||||
+
|
||||
+ if (spawnCountsReady.getAndSet(false)) {
|
||||
+ net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> {
|
||||
+ int mapped = distanceManager.getNaturalSpawnChunkCount();
|
||||
+ ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator<Entity> objectiterator = level.entityTickList.entities.iterator(ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS);
|
||||
+
|
||||
+ try {
|
||||
+ gg.pufferfish.pufferfish.util.IterableWrapper<Entity> wrappedIterator = new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator);
|
||||
+ LocalMobCapCalculator mobCapCalculator = !level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(chunkMap) : null;
|
||||
+
|
||||
+ lastSpawnState = NaturalSpawner.createState(
|
||||
+ mapped,
|
||||
+ wrappedIterator,
|
||||
+ ServerChunkCache.this::getFullChunk,
|
||||
+ mobCapCalculator,
|
||||
+ level.paperConfig().entities.spawning.perPlayerMobSpawns
|
||||
+ );
|
||||
+ } finally {
|
||||
+ objectiterator.finishedIterating();
|
||||
+ }
|
||||
+ spawnCountsReady.set(true);
|
||||
+ });
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Pufferfish: Optimize mob spawning
|
||||
}
|
||||
|
||||
private void broadcastChangedChunks() {
|
||||
@@ -523,27 +568,31 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount();
|
||||
// Paper start - Optional per player mob spawns
|
||||
NaturalSpawner.SpawnState spawnState;
|
||||
+ // DivineMC start - Pufferfish: Optimize mob spawning
|
||||
if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled
|
||||
- // re-set mob counts
|
||||
- for (ServerPlayer player : this.level.players) {
|
||||
- // Paper start - per player mob spawning backoff
|
||||
- for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) {
|
||||
- player.mobCounts[ii] = 0;
|
||||
-
|
||||
- int newBackoff = player.mobBackoffCounts[ii] - 1; // TODO make configurable bleed // TODO use nonlinear algorithm?
|
||||
- if (newBackoff < 0) {
|
||||
- newBackoff = 0;
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) {
|
||||
+ // re-set mob counts
|
||||
+ for (ServerPlayer player : this.level.players) {
|
||||
+ // Paper start - per player mob spawning backoff
|
||||
+ for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) {
|
||||
+ player.mobCounts[ii] = 0;
|
||||
+
|
||||
+ int newBackoff = player.mobBackoffCounts[ii] - 1; // TODO make configurable bleed // TODO use nonlinear algorithm?
|
||||
+ if (newBackoff < 0) {
|
||||
+ newBackoff = 0;
|
||||
+ }
|
||||
+ player.mobBackoffCounts[ii] = newBackoff;
|
||||
}
|
||||
- player.mobBackoffCounts[ii] = newBackoff;
|
||||
+ // Paper end - per player mob spawning backoff
|
||||
}
|
||||
- // Paper end - per player mob spawning backoff
|
||||
+ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), true);
|
||||
}
|
||||
- spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
|
||||
} else {
|
||||
- spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
|
||||
+ lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), false);
|
||||
+ spawnCountsReady.set(true);
|
||||
}
|
||||
+ // DivineMC end - Pufferfish: Optimize mob spawning
|
||||
// Paper end - Optional per player mob spawns
|
||||
- this.lastSpawnState = spawnState;
|
||||
boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit
|
||||
int _int = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
||||
List<MobCategory> filteredSpawningCategories;
|
||||
@@ -557,7 +606,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
}
|
||||
// Paper end - PlayerNaturallySpawnCreaturesEvent
|
||||
boolean flag = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit
|
||||
- filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit
|
||||
+ filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit // DivineMC - Pufferfish: Optimize mob spawning
|
||||
} else {
|
||||
filteredSpawningCategories = List.of();
|
||||
}
|
||||
@@ -572,7 +621,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
// Paper end - chunk tick iteration optimisation
|
||||
|
||||
for (LevelChunk levelChunk : list) {
|
||||
- this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, spawnState);
|
||||
+ this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning
|
||||
}
|
||||
} finally {
|
||||
list.clear();
|
||||
@@ -591,11 +640,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
this.level.tickThunder(chunk);
|
||||
}
|
||||
|
||||
- if (!spawnCategories.isEmpty()) {
|
||||
- if (this.level.getWorldBorder().isWithinBounds(pos)) { // Paper - rewrite chunk system
|
||||
- NaturalSpawner.spawnForChunk(this.level, chunk, spawnState, spawnCategories);
|
||||
- }
|
||||
+ // DivineMC start - Pufferfish: Optimize mob spawning
|
||||
+ if (!spawnCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning || spawnCountsReady.get())) { // Paper - rewrite chunk system
|
||||
+ NaturalSpawner.spawnForChunk(this.level, chunk, spawnState, spawnCategories);
|
||||
}
|
||||
+ // DivineMC end - Pufferfish: Optimize mob spawning
|
||||
}
|
||||
|
||||
private void getFullChunk(long chunkPos, Consumer<LevelChunk> fullChunkGetter) {
|
||||
@@ -1,68 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 9 Jul 2025 03:06:02 +0300
|
||||
Subject: [PATCH] Pufferfish: Simpler ShapelessRecipes comparison for Vanilla
|
||||
|
||||
Original license: GPL v3
|
||||
Original project: https://github.com/pufferfish-gg/Pufferfish
|
||||
|
||||
Patch description:
|
||||
|
||||
Paper added a fancy sorting comparison due to Bukkit recipes breaking
|
||||
the vanilla one, however this is far more advanced than what you need
|
||||
for all the vanilla recipes.
|
||||
|
||||
diff --git a/net/minecraft/world/item/crafting/ShapelessRecipe.java b/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
index d601b54b1de2f2ae44fe2b20c8116c71a6340e45..658c950e18a5a4ff992c8720e60f505a11ab2efd 100644
|
||||
--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
+++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java
|
||||
@@ -23,13 +23,21 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
final List<Ingredient> ingredients;
|
||||
@Nullable
|
||||
private PlacementInfo placementInfo;
|
||||
+ // DivineMC start - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla
|
||||
+ private final boolean isBukkit;
|
||||
|
||||
public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, List<Ingredient> ingredients) {
|
||||
+ this(group, category, result, ingredients, false);
|
||||
+ }
|
||||
+
|
||||
+ public ShapelessRecipe(String group, CraftingBookCategory category, ItemStack result, List<Ingredient> ingredients, boolean isBukkit) {
|
||||
this.group = group;
|
||||
this.category = category;
|
||||
this.result = result;
|
||||
this.ingredients = ingredients;
|
||||
+ this.isBukkit = isBukkit;
|
||||
}
|
||||
+ // DivineMC end - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla
|
||||
|
||||
// CraftBukkit start
|
||||
@Override
|
||||
@@ -72,6 +80,27 @@ public class ShapelessRecipe implements CraftingRecipe {
|
||||
|
||||
@Override
|
||||
public boolean matches(CraftingInput input, Level level) {
|
||||
+ // DivineMC start - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla
|
||||
+ if (!this.isBukkit) {
|
||||
+ java.util.List<Ingredient> ingredients = com.google.common.collect.Lists.newArrayList(this.ingredients.toArray(new Ingredient[0]));
|
||||
+
|
||||
+ inventory: for (int index = 0; index < input.size(); index++) {
|
||||
+ ItemStack itemStack = input.getItem(index);
|
||||
+
|
||||
+ if (!itemStack.isEmpty()) {
|
||||
+ for (int i = 0; i < ingredients.size(); i++) {
|
||||
+ if (ingredients.get(i).test(itemStack)) {
|
||||
+ ingredients.remove(i);
|
||||
+ continue inventory;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ingredients.isEmpty();
|
||||
+ }
|
||||
+ // DivineMC end - Pufferfish: Simpler ShapelessRecipes comparison for Vanilla
|
||||
// Paper start - Improve exact choice recipe ingredients & unwrap ternary
|
||||
if (input.ingredientCount() != this.ingredients.size()) {
|
||||
return false;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,214 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 16:47:09 +0300
|
||||
Subject: [PATCH] Clump experience orbs
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java
|
||||
index 66ae0b340c7e9ebccfeaee786577e27916ace38c..c3144a0e2a839c0d8ae2d1c450213fa6a56a58c4 100644
|
||||
--- a/net/minecraft/world/entity/ExperienceOrb.java
|
||||
+++ b/net/minecraft/world/entity/ExperienceOrb.java
|
||||
@@ -50,6 +50,10 @@ public class ExperienceOrb extends Entity {
|
||||
@Nullable
|
||||
public java.util.UUID triggerEntityId;
|
||||
public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ public java.util.Map<Integer, Integer> clumps$clumpedMap;
|
||||
+ public Optional<EnchantedItemInUse> clumps$currentEntry;
|
||||
+ // DivineMC end - Clump experience orbs
|
||||
|
||||
private void loadPaperNBT(ValueInput input) {
|
||||
input.read("Paper.ExpData", net.minecraft.nbt.CompoundTag.CODEC).ifPresent(expData -> {
|
||||
@@ -272,6 +276,28 @@ public class ExperienceOrb extends Entity {
|
||||
}
|
||||
|
||||
private static boolean tryMergeToExisting(ServerLevel level, Vec3 pos, int amount) {
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.clumpOrbs) {
|
||||
+ AABB aABB = AABB.ofSize(pos, 1.0D, 1.0D, 1.0D);
|
||||
+ int id = level.getRandom().nextInt(40);
|
||||
+ List<ExperienceOrb> list = level.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), aABB, (experienceOrbx) -> canMerge(experienceOrbx, id, amount));
|
||||
+ if (!list.isEmpty()) {
|
||||
+ ExperienceOrb experienceOrb = list.getFirst();
|
||||
+ java.util.Map<Integer, Integer> clumpedMap = (experienceOrb).clumps$getClumpedMap();
|
||||
+ (experienceOrb).clumps$setClumpedMap(java.util.stream.Stream.of(clumpedMap, java.util.Collections.singletonMap(amount, 1))
|
||||
+ .flatMap(map -> map.entrySet().stream())
|
||||
+ .collect(java.util.stream.Collectors.toMap(java.util.Map.Entry::getKey, java.util.Map.Entry::getValue, Integer::sum)));
|
||||
+ (experienceOrb).count = (clumpedMap.values()
|
||||
+ .stream()
|
||||
+ .reduce(Integer::sum)
|
||||
+ .orElse(1));
|
||||
+ (experienceOrb).age = (0);
|
||||
+ return true;
|
||||
+ } else {
|
||||
+ return false;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Clump experience orbs
|
||||
// Paper - TODO some other event for this kind of merge
|
||||
AABB aabb = AABB.ofSize(pos, 1.0, 1.0, 1.0);
|
||||
int randomInt = level.getRandom().nextInt(io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA)); // Paper - Configure how many orb groups per area
|
||||
@@ -289,11 +315,11 @@ public class ExperienceOrb extends Entity {
|
||||
}
|
||||
|
||||
private boolean canMerge(ExperienceOrb orb) {
|
||||
- return orb != this && canMerge(orb, this.getId(), this.getValue());
|
||||
+ return org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.clumpOrbs ? orb.isAlive() && !this.is(orb) : orb != this && ExperienceOrb.canMerge(orb, this.getId(), this.getValue()); // DivineMC - Clump experience orbs
|
||||
}
|
||||
|
||||
private static boolean canMerge(ExperienceOrb orb, int amount, int other) {
|
||||
- return !orb.isRemoved() && (orb.getId() - amount) % io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA) == 0 && orb.getValue() == other; // Paper - Configure how many orbs will merge together
|
||||
+ return org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.clumpOrbs ? orb.isAlive() : !orb.isRemoved() && (orb.getId() - amount) % io.papermc.paper.configuration.GlobalConfiguration.get().misc.xpOrbGroupsPerArea.or(ORB_GROUPS_PER_AREA) == 0 && orb.getValue() == other; // Paper - Configure how many orbs will merge together // Canvas - optimize orbs
|
||||
}
|
||||
|
||||
private void merge(ExperienceOrb orb) {
|
||||
@@ -302,6 +328,18 @@ public class ExperienceOrb extends Entity {
|
||||
return;
|
||||
}
|
||||
// Paper end - call orb merge event
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.clumpOrbs) {
|
||||
+ java.util.Map<Integer, Integer> otherMap = (orb).clumps$getClumpedMap();
|
||||
+ this.count = clumps$getClumpedMap().values().stream().reduce(Integer::sum).orElse(1);
|
||||
+ this.age = Math.min(this.age, (orb).age);
|
||||
+ clumps$setClumpedMap(java.util.stream.Stream.of(clumps$getClumpedMap(), otherMap)
|
||||
+ .flatMap(map -> map.entrySet().stream())
|
||||
+ .collect(java.util.stream.Collectors.toMap(java.util.Map.Entry::getKey, java.util.Map.Entry::getValue, Integer::sum)));
|
||||
+ orb.discard();
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Clump experience orbs
|
||||
this.count = this.count + orb.count;
|
||||
this.age = Math.min(this.age, orb.age);
|
||||
orb.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause
|
||||
@@ -343,6 +381,13 @@ public class ExperienceOrb extends Entity {
|
||||
output.putInt("Value", this.getValue()); // Paper - save as Integer
|
||||
output.putInt("Count", this.count);
|
||||
this.savePaperNBT(output); // Paper
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ if (clumps$clumpedMap != null) {
|
||||
+ net.minecraft.nbt.CompoundTag map = new net.minecraft.nbt.CompoundTag();
|
||||
+ clumps$getClumpedMap().forEach((value, count) -> map.putInt(String.valueOf(value), count));
|
||||
+ output.store("clumpedMap", net.minecraft.nbt.CompoundTag.CODEC, map);
|
||||
+ }
|
||||
+ // DivineMC end - Clump experience orbs
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -352,10 +397,52 @@ public class ExperienceOrb extends Entity {
|
||||
this.setValue(input.getIntOr("Value", 0)); // Paper - load as Integer
|
||||
this.count = input.read("Count", ExtraCodecs.POSITIVE_INT).orElse(1);
|
||||
this.loadPaperNBT(input); // Paper
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ java.util.Map<Integer, Integer> map = new java.util.HashMap<>();
|
||||
+ input.read("clumpedMap", net.minecraft.nbt.CompoundTag.CODEC).ifPresentOrElse(clumpedMap -> {
|
||||
+ for (String s : clumpedMap.keySet()) {
|
||||
+ clumpedMap.getInt(s).ifPresent(value -> {
|
||||
+ map.put(Integer.parseInt(s), value);
|
||||
+ });
|
||||
+ }
|
||||
+ }, () -> map.put(getValue(), count));
|
||||
+
|
||||
+ clumps$setClumpedMap(map);
|
||||
+ // DivineMC end - Clump experience orbs
|
||||
}
|
||||
|
||||
@Override
|
||||
public void playerTouch(Player entity) {
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ if (entity instanceof ServerPlayer serverPlayer && org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.clumpOrbs && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) {
|
||||
+ entity.takeXpDelay = 0;
|
||||
+ entity.take(this, 1);
|
||||
+
|
||||
+ if (this.getValue() != 0 || clumps$resolve()) {
|
||||
+ java.util.concurrent.atomic.AtomicInteger toGive = new java.util.concurrent.atomic.AtomicInteger();
|
||||
+ clumps$getClumpedMap().forEach((value, amount) -> {
|
||||
+ int actualValue = value;
|
||||
+ for (int i = 0; i < amount; i++) {
|
||||
+ int leftOver = actualValue;
|
||||
+ if (leftOver == actualValue) {
|
||||
+ leftOver = this.repairPlayerItems((ServerPlayer) entity, actualValue);
|
||||
+ }
|
||||
+ if (leftOver > 0) {
|
||||
+ toGive.addAndGet(leftOver);
|
||||
+ }
|
||||
+ }
|
||||
+ });
|
||||
+ if (toGive.get() > 0) {
|
||||
+ entity.giveExperiencePoints(toGive.get());
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.count = 0;
|
||||
+ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP);
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
+ // Canvas end
|
||||
if (entity instanceof ServerPlayer serverPlayer) {
|
||||
if (entity.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent
|
||||
entity.takeXpDelay = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerXpCooldownEvent(entity, this.level().purpurConfig.playerExpPickupDelay, org.bukkit.event.player.PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entity.takeXpDelay = 2; // Purpur - Configurable player pickup exp delay
|
||||
@@ -373,10 +460,60 @@ public class ExperienceOrb extends Entity {
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ public Optional<EnchantedItemInUse> clumps$captureCurrentEntry(Optional<EnchantedItemInUse> entry) {
|
||||
+ clumps$currentEntry = entry;
|
||||
+ return entry;
|
||||
+ }
|
||||
+
|
||||
+ public java.util.Map<Integer, Integer> clumps$getClumpedMap() {
|
||||
+ if (clumps$clumpedMap == null) {
|
||||
+ clumps$clumpedMap = new java.util.HashMap<>();
|
||||
+ clumps$clumpedMap.put(this.getValue(), 1);
|
||||
+ }
|
||||
+
|
||||
+ return clumps$clumpedMap;
|
||||
+ }
|
||||
+
|
||||
+ public void clumps$setClumpedMap(java.util.Map<Integer, Integer> map) {
|
||||
+ clumps$clumpedMap = map;
|
||||
+ clumps$resolve();
|
||||
+ }
|
||||
+
|
||||
+ public boolean clumps$resolve() {
|
||||
+ this.setValue(clumps$getClumpedMap().entrySet()
|
||||
+ .stream()
|
||||
+ .map(entry -> entry.getKey() * entry.getValue())
|
||||
+ .reduce(Integer::sum)
|
||||
+ .orElse(1));
|
||||
+
|
||||
+ return this.getValue() > 0;
|
||||
+ }
|
||||
+ // DivineMC end - Clump experience orbs
|
||||
+
|
||||
private int repairPlayerItems(ServerPlayer player, int value) {
|
||||
- Optional<EnchantedItemInUse> randomItemWith = level().purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player) : EnchantmentHelper.getRandomItemWith( // Purpur - Add option to mend the most damaged equipment first
|
||||
- EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged
|
||||
- );
|
||||
+ Optional<EnchantedItemInUse> randomItemWith = clumps$captureCurrentEntry(level().purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player) : EnchantmentHelper.getRandomItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged)); // Purpur - Add option to mend the most damaged equipment first // DivineMC - Clump experience orbs
|
||||
+
|
||||
+ // DivineMC start - Clump experience orbs
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.clumpOrbs) {
|
||||
+ return clumps$currentEntry
|
||||
+ .map(foundItem -> {
|
||||
+ ItemStack itemstack = foundItem.itemStack();
|
||||
+ int xpToRepair = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.level(), itemstack, (int) (value * 1));
|
||||
+ int toRepair = Math.min(xpToRepair, itemstack.getDamageValue());
|
||||
+ itemstack.setDamageValue(itemstack.getDamageValue() - toRepair);
|
||||
+ if (toRepair > 0) {
|
||||
+ int used = value - toRepair * value / xpToRepair;
|
||||
+ if (used > 0) {
|
||||
+ return this.repairPlayerItems(player, used);
|
||||
+ }
|
||||
+ }
|
||||
+ return 0;
|
||||
+ })
|
||||
+ .orElse(value);
|
||||
+ }
|
||||
+ // DivineMC end - Clump experience orbs
|
||||
+
|
||||
if (randomItemWith.isPresent()) {
|
||||
ItemStack itemStack = randomItemWith.get().itemStack();
|
||||
int i = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.level(), itemStack, value);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,43 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sat, 1 Feb 2025 18:55:59 +0300
|
||||
Subject: [PATCH] MSPT Tracking for each world
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index aad1f6dffc6831baa8a573add5bbd229cd7b2a9d..a7871b4591593e6b1efa3dc17053de9df600f24c 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1678,7 +1678,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// DivineMC start - Parallel world ticking
|
||||
private void tickLevel(ServerLevel serverLevel, BooleanSupplier hasTimeLeft) {
|
||||
try {
|
||||
+ // DivineMC start - MSPT Tracking for each world
|
||||
+ long i = Util.getNanos();
|
||||
serverLevel.tick(hasTimeLeft);
|
||||
+ long j = Util.getNanos() - i;
|
||||
+
|
||||
+ serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||
+ // DivineMC end - MSPT Tracking for each world
|
||||
} catch (Throwable levelTickingException) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world");
|
||||
serverLevel.fillReportDetails(crashReport);
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index b752bcc03b558a26f9c592c829efb44a299be8de..f9091b2daf735fd0788f8d6d60e3c812fd6dd4f2 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -569,6 +569,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper end - chunk tick iteration
|
||||
|
||||
+ // DivineMC start - MSPT Tracking for each world
|
||||
+ public final MinecraftServer.TickTimes tickTimes5s = new MinecraftServer.TickTimes(100);
|
||||
+ public final MinecraftServer.TickTimes tickTimes10s = new MinecraftServer.TickTimes(200);
|
||||
+ public final MinecraftServer.TickTimes tickTimes60s = new MinecraftServer.TickTimes(1200);
|
||||
+ // DivineMC end - MSPT Tracking for each world
|
||||
+
|
||||
public ServerLevel(
|
||||
MinecraftServer server,
|
||||
Executor dispatcher,
|
||||
@@ -1,83 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 23 Feb 2025 01:14:54 +0300
|
||||
Subject: [PATCH] Catch update suppressors
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java
|
||||
index 4535858701b2bb232b9d2feb2af6551526232ddc..aa4dd7517e8be167aef1eaf7aa907e3ce7cc0e62 100644
|
||||
--- a/net/minecraft/network/protocol/PacketUtils.java
|
||||
+++ b/net/minecraft/network/protocol/PacketUtils.java
|
||||
@@ -27,6 +27,10 @@ public class PacketUtils {
|
||||
if (processor.shouldHandleMessage(packet)) {
|
||||
try {
|
||||
packet.handle(processor);
|
||||
+ // DivineMC start - Catch update suppressors
|
||||
+ } catch (org.bxteam.divinemc.util.exception.UpdateSuppressorException e) {
|
||||
+ LOGGER.info(e.getMessage());
|
||||
+ // DivineMC end - Catch update suppressors
|
||||
} catch (Exception var4) {
|
||||
if (var4 instanceof ReportedException reportedException && reportedException.getCause() instanceof OutOfMemoryError) {
|
||||
throw makeReportedException(var4, packet, processor);
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index a7871b4591593e6b1efa3dc17053de9df600f24c..7f5f7d82ac8748758964c24f6c9377dda1dabb14 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1687,6 +1687,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||
serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||
// DivineMC end - MSPT Tracking for each world
|
||||
+ // DivineMC start - Catch update suppressors
|
||||
+ } catch (org.bxteam.divinemc.util.exception.UpdateSuppressorException e) {
|
||||
+ LOGGER.info(e.getMessage());
|
||||
+ // DivineMC end - Catch update suppressors
|
||||
} catch (Throwable levelTickingException) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world");
|
||||
serverLevel.fillReportDetails(crashReport);
|
||||
diff --git a/net/minecraft/world/level/block/ShulkerBoxBlock.java b/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
index 49bac7af90b0a7c490141be6357563447783c6ca..3eecfb18b11c91e6105eb1ba23b4a6061872751b 100644
|
||||
--- a/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
+++ b/net/minecraft/world/level/block/ShulkerBoxBlock.java
|
||||
@@ -183,7 +183,17 @@ public class ShulkerBoxBlock extends BaseEntityBlock {
|
||||
|
||||
@Override
|
||||
protected int getAnalogOutputSignal(BlockState blockState, Level level, BlockPos pos) {
|
||||
- return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
|
||||
+ // DivineMC start - Catch update suppressors
|
||||
+ try {
|
||||
+ return AbstractContainerMenu.getRedstoneSignalFromBlockEntity(level.getBlockEntity(pos));
|
||||
+ } catch (ClassCastException ex) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.updateSuppressionCrashFix) {
|
||||
+ throw new org.bxteam.divinemc.util.exception.UpdateSuppressorException(pos, this);
|
||||
+ } else {
|
||||
+ throw ex;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Catch update suppressors
|
||||
}
|
||||
|
||||
public static Block getBlockByColor(@Nullable DyeColor color) {
|
||||
diff --git a/net/minecraft/world/level/redstone/NeighborUpdater.java b/net/minecraft/world/level/redstone/NeighborUpdater.java
|
||||
index 332b33a004ab11150cca0cc2cefc26d0286648f5..261f3fb9981342330a31d4a4f317d1c93120012d 100644
|
||||
--- a/net/minecraft/world/level/redstone/NeighborUpdater.java
|
||||
+++ b/net/minecraft/world/level/redstone/NeighborUpdater.java
|
||||
@@ -60,9 +60,19 @@ public interface NeighborUpdater {
|
||||
state.handleNeighborChanged(level, pos, neighborBlock, orientation, movedByPiston);
|
||||
// Spigot start
|
||||
} catch (StackOverflowError ex) {
|
||||
+ // DivineMC start - Catch update suppressors
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.updateSuppressionCrashFix) {
|
||||
+ throw new org.bxteam.divinemc.util.exception.UpdateSuppressorException(pos, neighborBlock);
|
||||
+ }
|
||||
+ // DivineMC end - Catch update suppressors
|
||||
level.lastPhysicsProblem = pos.immutable();
|
||||
// Spigot end
|
||||
} catch (Throwable var9) {
|
||||
+ // DivineMC start - Catch update suppressors
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.FixesCategory.updateSuppressionCrashFix) {
|
||||
+ throw new org.bxteam.divinemc.util.exception.UpdateSuppressorException(pos, neighborBlock);
|
||||
+ }
|
||||
+ // DivineMC end - Catch update suppressors
|
||||
CrashReport crashReport = CrashReport.forThrowable(var9, "Exception while updating neighbours");
|
||||
CrashReportCategory crashReportCategory = crashReport.addCategory("Block being updated");
|
||||
crashReportCategory.setDetail(
|
||||
@@ -1,528 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 9 Jun 2025 13:51:43 +0300
|
||||
Subject: [PATCH] Regionized Chunk Ticking
|
||||
|
||||
This patch adds regionized chunk ticking feature, by grouping adjacent chunks into regions and processing each region on its own thread.
|
||||
|
||||
Original idea by Dueris, modified by NONPLAYT and heavily optimized by dan28000
|
||||
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index 411e1284a208ca1a097cf6eaa92e1e0d2203d83d..3f60d1b0ac91cfd3418e791222cd7267774b367a 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -327,7 +327,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
|
||||
private static void syncAfterConfigurationChange(ChannelFuture future) {
|
||||
try {
|
||||
- future.syncUninterruptibly();
|
||||
+ future.awaitUninterruptibly(5000L); // DivineMC - In rare cases this can get stuck, so we time out instead in worst case 5s of lag
|
||||
} catch (Exception var2) {
|
||||
if (var2 instanceof ClosedChannelException) {
|
||||
LOGGER.info("Connection closed during protocol change");
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 2039e636b1a52aff5403621e7281d618e4b87864..45bf13dc23b886ea2d660c38c74becf0e3754963 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -57,6 +57,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final DistanceManager distanceManager;
|
||||
private final ServerLevel level;
|
||||
+ public static final Executor REGION_EXECUTOR = java.util.concurrent.Executors.newFixedThreadPool(org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadCount, new org.bxteam.divinemc.util.NamedAgnosticThreadFactory<>("Region Ticking", ca.spottedleaf.moonrise.common.util.TickThread::new, org.bxteam.divinemc.config.DivineConfig.AsyncCategory.regionizedChunkTickingExecutorThreadPriority)); // DivineMC - Regionized Chunk Ticking
|
||||
public final Thread mainThread;
|
||||
final ThreadedLevelLightEngine lightEngine;
|
||||
public final ServerChunkCache.MainThreadExecutor mainThreadProcessor;
|
||||
@@ -70,8 +71,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
private final long[] lastChunkPos = new long[4];
|
||||
private final ChunkStatus[] lastChunkStatus = new ChunkStatus[4];
|
||||
private final ChunkAccess[] lastChunk = new ChunkAccess[4];
|
||||
- private final List<LevelChunk> spawningChunks = new ObjectArrayList<>();
|
||||
- private final Set<ChunkHolder> chunkHoldersToBroadcast = new ReferenceOpenHashSet<>();
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ private final ObjectArrayList<LevelChunk> spawningChunks = new ObjectArrayList<>();
|
||||
+ private final Set<ChunkHolder> chunkHoldersToBroadcast = java.util.Collections.synchronizedSet(new ReferenceOpenHashSet<>());
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
@Nullable
|
||||
@VisibleForDebug
|
||||
private NaturalSpawner.SpawnState lastSpawnState;
|
||||
@@ -153,36 +156,253 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
return load ? this.syncLoad(chunkX, chunkZ, toStatus) : null;
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
+
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ private record RegionData(it.unimi.dsi.fastutil.longs.LongOpenHashSet chunks, Set<Entity> entities) {
|
||||
+ public boolean isEmpty() {
|
||||
+ return chunks.isEmpty();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private record Output(RegionData[] regions, Set<Entity> entities) {}
|
||||
+
|
||||
+ private Output computePlayerRegionsParallel() {
|
||||
+ int tickViewDistance = level.moonrise$getViewDistanceHolder().getViewDistances().tickViewDistance();
|
||||
+ List<ServerPlayer> players = new java.util.ArrayList<>(level.players);
|
||||
+ int max = maxChunksForViewDistance();
|
||||
+
|
||||
+ List<it.unimi.dsi.fastutil.longs.LongOpenHashSet> playerChunkSets = players.parallelStream()
|
||||
+ .map(player -> {
|
||||
+ ChunkPos playerChunk = player.chunkPosition();
|
||||
+ int px = playerChunk.x;
|
||||
+ int pz = playerChunk.z;
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet chunkKeys = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(max);
|
||||
+ for (int dx = -tickViewDistance; dx <= tickViewDistance; dx++) {
|
||||
+ for (int dz = -tickViewDistance; dz <= tickViewDistance; dz++) {
|
||||
+ long key = ca.spottedleaf.moonrise.common.util.CoordinateUtils.getChunkKey(px + dx, pz + dz);
|
||||
+ chunkKeys.add(key);
|
||||
+ }
|
||||
+ }
|
||||
+ return chunkKeys;
|
||||
+ }).toList();
|
||||
+
|
||||
+ List<it.unimi.dsi.fastutil.longs.LongOpenHashSet> mergedRegions = new java.util.ArrayList<>();
|
||||
+ boolean[] merged = new boolean[playerChunkSets.size()];
|
||||
+
|
||||
+ for (int i = 0; i < playerChunkSets.size(); i++) {
|
||||
+ if (merged[i]) continue;
|
||||
+
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet region = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(playerChunkSets.get(i));
|
||||
+ merged[i] = true;
|
||||
+
|
||||
+ boolean madeChanges;
|
||||
+ do {
|
||||
+ madeChanges = false;
|
||||
+ for (int j = i + 1; j < playerChunkSets.size(); j++) {
|
||||
+ if (merged[j]) continue;
|
||||
+
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet set = playerChunkSets.get(j);
|
||||
+
|
||||
+ boolean hasIntersection = false;
|
||||
+ it.unimi.dsi.fastutil.longs.LongIterator iter = set.iterator();
|
||||
+ while (iter.hasNext()) {
|
||||
+ if (region.contains(iter.nextLong())) {
|
||||
+ hasIntersection = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (hasIntersection) {
|
||||
+ region.addAll(set);
|
||||
+ merged[j] = true;
|
||||
+ madeChanges = true;
|
||||
+ }
|
||||
+ }
|
||||
+ } while (madeChanges);
|
||||
+
|
||||
+ mergedRegions.add(region);
|
||||
+ }
|
||||
+
|
||||
+ ObjectArrayList<RegionData> regions = new ObjectArrayList<>();
|
||||
+ it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap chunkToRegion = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(max * mergedRegions.size());
|
||||
+ chunkToRegion.defaultReturnValue(-1);
|
||||
+ for (int i = 0; i < mergedRegions.size(); i++) {
|
||||
+ regions.add(new RegionData(mergedRegions.get(i), java.util.Collections.newSetFromMap(new java.util.concurrent.ConcurrentHashMap<>())));
|
||||
+ for (long key : mergedRegions.get(i)) {
|
||||
+ chunkToRegion.put(key, i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ final Set<Entity> firstTick = java.util.Collections.newSetFromMap(new java.util.concurrent.ConcurrentHashMap<>());
|
||||
+
|
||||
+ synchronized (level.entityTickList.entities) {
|
||||
+ final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = level.entityTickList.entities.iterator();
|
||||
+ try {
|
||||
+ while (iterator.hasNext()) {
|
||||
+ Entity entity = iterator.next();
|
||||
+ long chunkKey = entity.chunkPosition().longKey;
|
||||
+ int regionIndex = chunkToRegion.get(chunkKey);
|
||||
+ if (regionIndex != -1) {
|
||||
+ regions.get(regionIndex).entities().add(entity);
|
||||
+ } else {
|
||||
+ firstTick.add(entity);
|
||||
+ }
|
||||
+ }
|
||||
+ } finally {
|
||||
+ iterator.finishedIterating();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return new Output(regions.toArray(new RegionData[0]), firstTick);
|
||||
+ }
|
||||
+
|
||||
+ // Should be max safe estimate of ticking chunks in a region
|
||||
+ private int maxChunksForViewDistance() {
|
||||
+ ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader.ViewDistances distances = level.moonrise$getViewDistanceHolder().getViewDistances();
|
||||
+ int diameter = 2 * distances.tickViewDistance() + 1;
|
||||
+ return diameter * diameter;
|
||||
+ }
|
||||
+
|
||||
+ private void tickEntity(Entity entity) {
|
||||
+ if (!entity.isRemoved()) {
|
||||
+ if (!level.tickRateManager().isEntityFrozen(entity)) {
|
||||
+ entity.checkDespawn();
|
||||
+ // Paper - rewrite chunk system
|
||||
+ Entity vehicle = entity.getVehicle();
|
||||
+ if (vehicle != null) {
|
||||
+ if (!vehicle.isRemoved() && vehicle.hasPassenger(entity)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ entity.stopRiding();
|
||||
+ }
|
||||
+
|
||||
+ level.guardEntityTick(level::tickNonPassenger, entity);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
+
|
||||
// Paper start - chunk tick iteration optimisations
|
||||
private final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom shuffleRandom = new ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom(0L);
|
||||
- private void iterateTickingChunksFaster() {
|
||||
+ private void iterateTickingChunksFaster(final java.util.concurrent.CompletableFuture<Void> spawns) { // DivineMC - Regionized Chunk Ticking
|
||||
final ServerLevel world = this.level;
|
||||
final int randomTickSpeed = world.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
||||
|
||||
// TODO check on update: impl of forEachBlockTickingChunk will only iterate ENTITY ticking chunks!
|
||||
// TODO check on update: consumer just runs tickChunk
|
||||
- final ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.world.level.chunk.LevelChunk> entityTickingChunks = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getEntityTickingChunks();
|
||||
+ final ca.spottedleaf.moonrise.common.list.ReferenceList<LevelChunk> entityTickingChunks = ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)world).moonrise$getEntityTickingChunks(); // DivineMC - Regionized Chunk Ticking
|
||||
|
||||
// note: we can use the backing array here because:
|
||||
// 1. we do not care about new additions
|
||||
// 2. _removes_ are impossible at this stage in the tick
|
||||
- final LevelChunk[] raw = entityTickingChunks.getRawDataUnchecked();
|
||||
+ final LevelChunk[] raw = entityTickingChunks.toArray(new LevelChunk[0]); // DivineMC - use toArray instead of getRawDataUnchecked this way is safe and doesn't have performance impact
|
||||
final int size = entityTickingChunks.size();
|
||||
|
||||
- java.util.Objects.checkFromToIndex(0, size, raw.length);
|
||||
- for (int i = 0; i < size; ++i) {
|
||||
- world.tickChunk(raw[i], randomTickSpeed);
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableRegionizedChunkTicking) {
|
||||
+ final Output output = computePlayerRegionsParallel();
|
||||
+ final RegionData[] regions = output.regions();
|
||||
+ int regionCount = regions.length;
|
||||
+
|
||||
+ java.util.concurrent.CountDownLatch latch = new java.util.concurrent.CountDownLatch(regionCount);
|
||||
+ io.papermc.paper.entity.activation.ActivationRange.activateEntities(level); // Paper - EAR
|
||||
+
|
||||
+ try {
|
||||
+ java.util.concurrent.ForkJoinPool.managedBlock(new java.util.concurrent.ForkJoinPool.ManagedBlocker() {
|
||||
+ @Override
|
||||
+ public boolean block() throws InterruptedException {
|
||||
+ ObjectArrayList<java.util.concurrent.CompletableFuture<it.unimi.dsi.fastutil.longs.LongOpenHashSet>> ticked = new ObjectArrayList<>(regionCount);
|
||||
+ for (final RegionData region : regions) {
|
||||
+ if (region == null || region.isEmpty()) {
|
||||
+ latch.countDown();
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ ticked.add(java.util.concurrent.CompletableFuture.supplyAsync(() -> {
|
||||
+ ObjectArrayList<LevelChunk> regionChunks = new ObjectArrayList<>(region.chunks().size());
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet regionChunksIDs = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(region.chunks().size());
|
||||
+ for (long key : region.chunks()) {
|
||||
+ LevelChunk chunk = fullChunks.get(key);
|
||||
+ if (chunk != null) {
|
||||
+ regionChunks.add(chunk);
|
||||
+ regionChunksIDs.add(key);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ for (LevelChunk chunk : regionChunks) {
|
||||
+ world.tickChunk(chunk, randomTickSpeed);
|
||||
+ }
|
||||
+ for (net.minecraft.world.entity.Entity entity : region.entities()) {
|
||||
+ tickEntity(entity);
|
||||
+ }
|
||||
+ } finally {
|
||||
+ latch.countDown();
|
||||
+ }
|
||||
+ return regionChunksIDs;
|
||||
+ }, REGION_EXECUTOR));
|
||||
+ }
|
||||
|
||||
- // call mid-tick tasks for chunk system
|
||||
- if ((i & 7) == 0) {
|
||||
- // DivineMC start - Parallel world ticking
|
||||
- if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking) {
|
||||
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer) this.level.getServer()).moonrise$executeMidTickTasks();
|
||||
- continue;
|
||||
+ CompletableFuture.runAsync(() -> {
|
||||
+ try {
|
||||
+ CompletableFuture.allOf(ticked.toArray(new CompletableFuture[0])).join();
|
||||
+ } catch (java.util.concurrent.CompletionException ex) {
|
||||
+ LOGGER.error("Error during region chunk ticking", ex.getCause());
|
||||
+ }
|
||||
+
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet tickedChunkKeys = new it.unimi.dsi.fastutil.longs.LongOpenHashSet(raw.length);
|
||||
+
|
||||
+ for (CompletableFuture<it.unimi.dsi.fastutil.longs.LongOpenHashSet> future : ticked) {
|
||||
+ if (!future.isCompletedExceptionally()) {
|
||||
+ try {
|
||||
+ it.unimi.dsi.fastutil.longs.LongOpenHashSet regionChunks = future.join();
|
||||
+ tickedChunkKeys.addAll(regionChunks);
|
||||
+ } catch (Exception e) {
|
||||
+ LOGGER.error("Exception in region ticking future", e);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ for (LevelChunk chunk : raw) {
|
||||
+ if (!tickedChunkKeys.contains(chunk.coordinateKey)) {
|
||||
+ world.tickChunk(chunk, randomTickSpeed);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ output.entities.forEach(ServerChunkCache.this::tickEntity);
|
||||
+ spawns.join();
|
||||
+ }, REGION_EXECUTOR).join();
|
||||
+
|
||||
+ latch.await();
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isReleasable() {
|
||||
+ return latch.getCount() == 0;
|
||||
+ }
|
||||
+ });
|
||||
+ } catch (InterruptedException ex) {
|
||||
+ throw new RuntimeException("Interrupted managed block during region ticking", ex);
|
||||
+ }
|
||||
+ } else {
|
||||
+ java.util.Objects.checkFromToIndex(0, size, raw.length);
|
||||
+ for (int i = 0; i < size; ++i) {
|
||||
+ world.tickChunk(raw[i], randomTickSpeed);
|
||||
+
|
||||
+ // call mid-tick tasks for chunk system
|
||||
+ if ((i & 7) == 0) {
|
||||
+ // DivineMC start - Parallel world ticking
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking) {
|
||||
+ ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer) this.level.getServer()).moonrise$executeMidTickTasks();
|
||||
+ continue;
|
||||
+ }
|
||||
+ // DivineMC end - Parallel world ticking
|
||||
}
|
||||
- // DivineMC end - Parallel world ticking
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
}
|
||||
// Paper end - chunk tick iteration optimisations
|
||||
|
||||
@@ -507,14 +727,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
long gameTime = this.level.getGameTime();
|
||||
long l = gameTime - this.lastInhabitedUpdate;
|
||||
this.lastInhabitedUpdate = gameTime;
|
||||
- if (!this.level.isDebug()) {
|
||||
- if (this.level.tickRateManager().runsNormally()) {
|
||||
- this.tickChunks(l);
|
||||
- }
|
||||
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ if (this.level.isDebug()) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ if (!this.level.tickRateManager().runsNormally()) { // DivineMC - when frozen only broadcast changed chunks and don't run async mob spawning
|
||||
this.broadcastChangedChunks();
|
||||
+ return;
|
||||
}
|
||||
|
||||
+ this.tickChunks(l);
|
||||
+ this.broadcastChangedChunks();
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
+
|
||||
// DivineMC start - Pufferfish: Optimize mob spawning
|
||||
if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) {
|
||||
for (ServerPlayer player : this.level.players) {
|
||||
@@ -558,14 +785,18 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
}
|
||||
|
||||
private void broadcastChangedChunks() {
|
||||
- for (ChunkHolder chunkHolder : this.chunkHoldersToBroadcast) {
|
||||
- LevelChunk tickingChunk = chunkHolder.getChunkToSend(); // Paper - rewrite chunk system
|
||||
- if (tickingChunk != null) {
|
||||
- chunkHolder.broadcastChanges(tickingChunk);
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ synchronized (chunkHoldersToBroadcast) {
|
||||
+ for (ChunkHolder chunkHolder : this.chunkHoldersToBroadcast) {
|
||||
+ LevelChunk tickingChunk = chunkHolder.getChunkToSend(); // Paper - rewrite chunk system
|
||||
+ if (tickingChunk != null) {
|
||||
+ chunkHolder.broadcastChanges(tickingChunk);
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
|
||||
- this.chunkHoldersToBroadcast.clear();
|
||||
+ this.chunkHoldersToBroadcast.clear();
|
||||
+ }
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
}
|
||||
|
||||
private void tickChunks(long timeInhabited) {
|
||||
@@ -615,23 +846,28 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||
filteredSpawningCategories = List.of();
|
||||
}
|
||||
|
||||
- List<LevelChunk> list = this.spawningChunks;
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ final java.util.concurrent.CompletableFuture<Void> spawns = java.util.concurrent.CompletableFuture.runAsync(() -> {
|
||||
+ List<LevelChunk> list = this.spawningChunks;
|
||||
|
||||
- try {
|
||||
- this.chunkMap.collectSpawningChunks(list);
|
||||
- // Paper start - chunk tick iteration optimisation
|
||||
- this.shuffleRandom.setSeed(this.level.random.nextLong());
|
||||
- if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
|
||||
- // Paper end - chunk tick iteration optimisation
|
||||
-
|
||||
- for (LevelChunk levelChunk : list) {
|
||||
- this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning
|
||||
+ try {
|
||||
+ this.chunkMap.collectSpawningChunks(list);
|
||||
+ // Paper start - chunk tick iteration optimisation
|
||||
+ this.shuffleRandom.setSeed(this.level.random.nextLong());
|
||||
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns)
|
||||
+ Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled
|
||||
+ // Paper end - chunk tick iteration optimisation
|
||||
+
|
||||
+ for (LevelChunk levelChunk : list) {
|
||||
+ this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Pufferfish: Optimize mob spawning
|
||||
+ }
|
||||
+ } finally {
|
||||
+ list.clear();
|
||||
}
|
||||
- } finally {
|
||||
- list.clear();
|
||||
- }
|
||||
+ }, REGION_EXECUTOR);
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
|
||||
- this.iterateTickingChunksFaster(); // Paper - chunk tick iteration optimisations
|
||||
+ this.iterateTickingChunksFaster(spawns); // Paper - chunk tick iteration optimisations // DivineMC - Regionized Chunk Ticking
|
||||
if (_boolean) {
|
||||
this.level.tickCustomSpawners(this.spawnEnemies, this.spawnFriendlies);
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index f9091b2daf735fd0788f8d6d60e3c812fd6dd4f2..0ad18866c323308ad9b87322932e03a283f740b1 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -191,7 +191,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
private final LevelTicks<Block> blockTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
|
||||
private final LevelTicks<Fluid> fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
|
||||
private final PathTypeCache pathTypesByPosCache = new PathTypeCache();
|
||||
- final Set<Mob> navigatingMobs = new ObjectOpenHashSet<>();
|
||||
+ final Set<Mob> navigatingMobs = java.util.Collections.synchronizedSet(new ObjectOpenHashSet<>()); // DivineMC - Regionized Chunk Ticking
|
||||
volatile boolean isUpdatingNavigations;
|
||||
protected final Raids raids;
|
||||
private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents = new ObjectLinkedOpenHashSet<>();
|
||||
@@ -806,6 +806,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
this.dragonFight.tick();
|
||||
}
|
||||
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableRegionizedChunkTicking) {
|
||||
+ this.tickBlockEntities();
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
+
|
||||
io.papermc.paper.entity.activation.ActivationRange.activateEntities(this); // Paper - EAR
|
||||
this.entityTickList
|
||||
.forEach(
|
||||
@@ -1828,22 +1835,16 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
if (Shapes.joinIsNotEmpty(collisionShape, collisionShape1, BooleanOp.NOT_SAME)) {
|
||||
List<PathNavigation> list = new ObjectArrayList<>();
|
||||
|
||||
- try { // Paper - catch CME see below why
|
||||
- for (Mob mob : this.navigatingMobs) {
|
||||
- PathNavigation navigation = mob.getNavigation();
|
||||
- if (navigation.shouldRecomputePath(pos)) {
|
||||
- list.add(navigation);
|
||||
+ // DivineMC start - Regionized Chunk Ticking
|
||||
+ synchronized (this.navigatingMobs) {
|
||||
+ for (Mob mob : this.navigatingMobs) {
|
||||
+ PathNavigation navigation = mob.getNavigation();
|
||||
+ if (navigation.shouldRecomputePath(pos)) {
|
||||
+ list.add(navigation);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
- // Paper start - catch CME see below why
|
||||
- } catch (final java.util.ConcurrentModificationException concurrentModificationException) {
|
||||
- // This can happen because the pathfinder update below may trigger a chunk load, which in turn may cause more navigators to register
|
||||
- // In this case we just run the update again across all the iterators as the chunk will then be loaded
|
||||
- // As this is a relative edge case it is much faster than copying navigators (on either read or write)
|
||||
- this.sendBlockUpdated(pos, oldState, newState, flags);
|
||||
- return;
|
||||
- }
|
||||
- // Paper end - catch CME see below why
|
||||
+ // DivineMC end - Regionized Chunk Ticking
|
||||
|
||||
try {
|
||||
this.isUpdatingNavigations = true;
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 22a2b6b31f6f9b9b613586f7d674302304be3232..66ba223dacefb3531c46b144c4499b2b2285eafe 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -106,7 +106,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
|
||||
public final org.bxteam.divinemc.util.BlockEntityTickersList blockEntityTickers = new org.bxteam.divinemc.util.BlockEntityTickersList(); // Paper - public // DivineMC - optimize block entity removals - Fix MC-117075
|
||||
protected final NeighborUpdater neighborUpdater;
|
||||
- private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
||||
+ private final List<TickingBlockEntity> pendingBlockEntityTickers = java.util.Collections.synchronizedList(Lists.newArrayList()); // DivineMC - Regionized Chunk Ticking
|
||||
private boolean tickingBlockEntities;
|
||||
public final Thread thread;
|
||||
private final boolean isDebug;
|
||||
@@ -138,7 +138,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
|
||||
public boolean captureBlockStates = false;
|
||||
public boolean captureTreeGeneration = false;
|
||||
- public Map<BlockPos, org.bukkit.craftbukkit.block.CraftBlockState> capturedBlockStates = new java.util.LinkedHashMap<>(); // Paper
|
||||
+ public Map<BlockPos, org.bukkit.craftbukkit.block.CraftBlockState> capturedBlockStates = java.util.Collections.synchronizedMap(new java.util.LinkedHashMap<>()); // Paper // DivineMC - Regionized Chunk Ticking
|
||||
public Map<BlockPos, BlockEntity> capturedTileEntities = new java.util.LinkedHashMap<>(); // Paper - Retain block place order when capturing blockstates
|
||||
@Nullable
|
||||
public List<net.minecraft.world.entity.item.ItemEntity> captureDrops;
|
||||
@@ -1503,10 +1503,14 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
|
||||
protected void tickBlockEntities() {
|
||||
this.tickingBlockEntities = true;
|
||||
- if (!this.pendingBlockEntityTickers.isEmpty()) {
|
||||
- this.blockEntityTickers.addAll(this.pendingBlockEntityTickers);
|
||||
- this.pendingBlockEntityTickers.clear();
|
||||
+ // DivineMC start - Regionized Chunk Ticking - synchronization fix
|
||||
+ synchronized (pendingBlockEntityTickers) {
|
||||
+ if (!this.pendingBlockEntityTickers.isEmpty()) {
|
||||
+ this.blockEntityTickers.addAll(this.pendingBlockEntityTickers);
|
||||
+ this.pendingBlockEntityTickers.clear();
|
||||
+ }
|
||||
}
|
||||
+ // DivineMC end - Regionized Chunk Ticking - synchronization fix
|
||||
|
||||
// Spigot start
|
||||
boolean runsNormally = this.tickRateManager().runsNormally();
|
||||
diff --git a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
||||
index 028eae2f9a459b60e92f3344091083aa93b54485..51e5a54aff069cac14deef6c04899d3a469842ce 100644
|
||||
--- a/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
||||
+++ b/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
|
||||
@@ -46,7 +46,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||
this.addAndRun(pos, new CollectingNeighborUpdater.MultiNeighborUpdate(pos.immutable(), block, orientation, facing));
|
||||
}
|
||||
|
||||
- private void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates updates) {
|
||||
+ private synchronized void addAndRun(BlockPos pos, CollectingNeighborUpdater.NeighborUpdates updates) { // DivineMC - Regionized Chunk Ticking - synchronized
|
||||
boolean flag = this.count > 0;
|
||||
boolean flag1 = this.maxChainedNeighborUpdates >= 0 && this.count >= this.maxChainedNeighborUpdates;
|
||||
this.count++;
|
||||
@@ -65,7 +65,7 @@ public class CollectingNeighborUpdater implements NeighborUpdater {
|
||||
}
|
||||
}
|
||||
|
||||
- private void runUpdates() {
|
||||
+ private synchronized void runUpdates() { // DivineMC - Regionized Chunk Ticking - synchronized
|
||||
try {
|
||||
while (!this.stack.isEmpty() || !this.addedThisLayer.isEmpty()) {
|
||||
for (int i = this.addedThisLayer.size() - 1; i >= 0; i--) {
|
||||
@@ -1,54 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 9 Jul 2025 04:37:59 +0300
|
||||
Subject: [PATCH] C2ME: Limit NBT cache
|
||||
|
||||
This patch is based on the following mixins:
|
||||
* "com/ishland/c2me/opts/chunkio/mixin/limit_nbt_cache/MixinStorageIoWorker.java"
|
||||
By: ishland <ishlandmc@yeah.net>
|
||||
As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric)
|
||||
Licensed under: MIT (https://opensource.org/licenses/MIT)
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java
|
||||
index 27e1edbd8d8ffd80c1a3df17bc47f4a6936619f7..c3326e753ecf8a0ba1930d8c7573ebd2c594cf45 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 - C2ME: Limit NBT cache
|
||||
+ private void checkHardLimit() {
|
||||
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit) {
|
||||
+ LOGGER.warn("Chunk data cache size exceeded hard limit ({} >= {}), forcing writes to disk (you can increase chunkDataCacheLimit in divinemc.yml)", this.pendingWrites.size(), org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheLimit);
|
||||
+ while (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.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 - C2ME: Limit NBT cache
|
||||
+
|
||||
private void storePendingChunk() {
|
||||
+ // DivineMC start - C2ME: Limit NBT cache
|
||||
+ if (!this.pendingWrites.isEmpty()) {
|
||||
+ checkHardLimit();
|
||||
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) {
|
||||
+ int writeFrequency = Math.min(1, (this.pendingWrites.size() - (int) org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.chunkDataCacheSoftLimit) / 16);
|
||||
+ for (int i = 0; i < writeFrequency; i++) {
|
||||
+ writeResult0();
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - C2ME: Limit NBT cache
|
||||
Entry<ChunkPos, IOWorker.PendingStore> entry = this.pendingWrites.pollFirstEntry();
|
||||
if (entry != null) {
|
||||
this.runStore(entry.getKey(), entry.getValue());
|
||||
@@ -1,705 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 10 Jul 2025 03:48:14 +0300
|
||||
Subject: [PATCH] C2ME: Optimize Aquifer and Beardifier
|
||||
|
||||
This patch is based on the following mixins:
|
||||
* "com/ishland/c2me/opts/worldgen/vanilla/mixin/aquifer/MixinAquiferSamplerImpl.java"
|
||||
* "com/ishland/c2me/opts/worldgen/general/common/random_instances/RandomUtils.java"
|
||||
By: ishland <ishlandmc@yeah.net>
|
||||
As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric)
|
||||
Licensed under: MIT (https://opensource.org/licenses/MIT)
|
||||
|
||||
diff --git a/net/minecraft/world/level/levelgen/Aquifer.java b/net/minecraft/world/level/levelgen/Aquifer.java
|
||||
index c62a15ea4a1bb22e7bcc2fc544acf8a601892029..06419ac3b18365b27b522baba24736c1add5bd9a 100644
|
||||
--- a/net/minecraft/world/level/levelgen/Aquifer.java
|
||||
+++ b/net/minecraft/world/level/levelgen/Aquifer.java
|
||||
@@ -85,6 +85,15 @@ public interface Aquifer {
|
||||
private final int minGridZ;
|
||||
private final int gridSizeX;
|
||||
private final int gridSizeZ;
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
+ private int c2me$dist1;
|
||||
+ private int c2me$dist2;
|
||||
+ private int c2me$dist3;
|
||||
+ private long c2me$pos1;
|
||||
+ private long c2me$pos2;
|
||||
+ private long c2me$pos3;
|
||||
+ private double c2me$mutableDoubleThingy;
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
private static final int[][] SURFACE_SAMPLING_OFFSETS_IN_CHUNKS = new int[][]{
|
||||
{0, 0}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {-3, 0}, {-2, 0}, {-1, 0}, {1, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1}
|
||||
};
|
||||
@@ -120,6 +129,36 @@ public interface Aquifer {
|
||||
this.aquiferCache = new Aquifer.FluidStatus[i4];
|
||||
this.aquiferLocationCache = new long[i4];
|
||||
Arrays.fill(this.aquiferLocationCache, Long.MAX_VALUE);
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
+ if (this.aquiferLocationCache.length % (this.gridSizeX * this.gridSizeZ) != 0) {
|
||||
+ throw new AssertionError("Array length");
|
||||
+ }
|
||||
+
|
||||
+ int sizeY = this.aquiferLocationCache.length / (this.gridSizeX * this.gridSizeZ);
|
||||
+
|
||||
+ final RandomSource random = com.ishland.c2me.opts.worldgen.general.common.random_instances.RandomUtils.getRandom(this.positionalRandomFactory);
|
||||
+ // index: y, z, x
|
||||
+ for (int y = 0; y < sizeY; y++) {
|
||||
+ for (int z = 0; z < this.gridSizeZ; z++) {
|
||||
+ for (int x = 0; x < this.gridSizeX; x++) {
|
||||
+ final int x1 = x + this.minGridX;
|
||||
+ final int y1 = y + this.minGridY;
|
||||
+ final int z1 = z + this.minGridZ;
|
||||
+ com.ishland.c2me.opts.worldgen.general.common.random_instances.RandomUtils.derive(this.positionalRandomFactory, random, x1, y1, z1);
|
||||
+ int x2 = x1 * 16 + random.nextInt(10);
|
||||
+ int y2 = y1 * 12 + random.nextInt(9);
|
||||
+ int z2 = z1 * 16 + random.nextInt(10);
|
||||
+ int index = this.getIndex(x1, y1, z1);
|
||||
+ this.aquiferLocationCache[index] = BlockPos.asLong(x2, y2, z2);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ for (long blockPosition : this.aquiferLocationCache) {
|
||||
+ if (blockPosition == Long.MAX_VALUE) {
|
||||
+ throw new AssertionError("Array initialization");
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
}
|
||||
|
||||
private int getIndex(int gridX, int gridY, int gridZ) {
|
||||
@@ -132,140 +171,24 @@ public interface Aquifer {
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockState computeSubstance(DensityFunction.FunctionContext context, double substance) {
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
int i = context.blockX();
|
||||
- int i1 = context.blockY();
|
||||
- int i2 = context.blockZ();
|
||||
+ int j = context.blockY();
|
||||
+ int k = context.blockZ();
|
||||
if (substance > 0.0) {
|
||||
this.shouldScheduleFluidUpdate = false;
|
||||
return null;
|
||||
} else {
|
||||
- Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(i, i1, i2);
|
||||
- if (fluidStatus.at(i1).is(Blocks.LAVA)) {
|
||||
+ Aquifer.FluidStatus fluidLevel = this.globalFluidPicker.computeFluid(i, j, k);
|
||||
+ if (fluidLevel.at(j).is(Blocks.LAVA)) {
|
||||
this.shouldScheduleFluidUpdate = false;
|
||||
return Blocks.LAVA.defaultBlockState();
|
||||
} else {
|
||||
- int i3 = Math.floorDiv(i - 5, 16);
|
||||
- int i4 = Math.floorDiv(i1 + 1, 12);
|
||||
- int i5 = Math.floorDiv(i2 - 5, 16);
|
||||
- int i6 = Integer.MAX_VALUE;
|
||||
- int i7 = Integer.MAX_VALUE;
|
||||
- int i8 = Integer.MAX_VALUE;
|
||||
- int i9 = Integer.MAX_VALUE;
|
||||
- long l = 0L;
|
||||
- long l1 = 0L;
|
||||
- long l2 = 0L;
|
||||
- long l3 = 0L;
|
||||
-
|
||||
- for (int i10 = 0; i10 <= 1; i10++) {
|
||||
- for (int i11 = -1; i11 <= 1; i11++) {
|
||||
- for (int i12 = 0; i12 <= 1; i12++) {
|
||||
- int i13 = i3 + i10;
|
||||
- int i14 = i4 + i11;
|
||||
- int i15 = i5 + i12;
|
||||
- int index = this.getIndex(i13, i14, i15);
|
||||
- long l4 = this.aquiferLocationCache[index];
|
||||
- long l5;
|
||||
- if (l4 != Long.MAX_VALUE) {
|
||||
- l5 = l4;
|
||||
- } else {
|
||||
- RandomSource randomSource = this.positionalRandomFactory.at(i13, i14, i15);
|
||||
- l5 = BlockPos.asLong(
|
||||
- i13 * 16 + randomSource.nextInt(10), i14 * 12 + randomSource.nextInt(9), i15 * 16 + randomSource.nextInt(10)
|
||||
- );
|
||||
- this.aquiferLocationCache[index] = l5;
|
||||
- }
|
||||
-
|
||||
- int i16 = BlockPos.getX(l5) - i;
|
||||
- int i17 = BlockPos.getY(l5) - i1;
|
||||
- int i18 = BlockPos.getZ(l5) - i2;
|
||||
- int i19 = i16 * i16 + i17 * i17 + i18 * i18;
|
||||
- if (i6 >= i19) {
|
||||
- l3 = l2;
|
||||
- l2 = l1;
|
||||
- l1 = l;
|
||||
- l = l5;
|
||||
- i9 = i8;
|
||||
- i8 = i7;
|
||||
- i7 = i6;
|
||||
- i6 = i19;
|
||||
- } else if (i7 >= i19) {
|
||||
- l3 = l2;
|
||||
- l2 = l1;
|
||||
- l1 = l5;
|
||||
- i9 = i8;
|
||||
- i8 = i7;
|
||||
- i7 = i19;
|
||||
- } else if (i8 >= i19) {
|
||||
- l3 = l2;
|
||||
- l2 = l5;
|
||||
- i9 = i8;
|
||||
- i8 = i19;
|
||||
- } else if (i9 >= i19) {
|
||||
- l3 = l5;
|
||||
- i9 = i19;
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- Aquifer.FluidStatus aquiferStatus = this.getAquiferStatus(l);
|
||||
- double d = similarity(i6, i7);
|
||||
- BlockState blockState = aquiferStatus.at(i1);
|
||||
- if (d <= 0.0) {
|
||||
- if (d >= FLOWING_UPDATE_SIMULARITY) {
|
||||
- Aquifer.FluidStatus aquiferStatus1 = this.getAquiferStatus(l1);
|
||||
- this.shouldScheduleFluidUpdate = !aquiferStatus.equals(aquiferStatus1);
|
||||
- } else {
|
||||
- this.shouldScheduleFluidUpdate = false;
|
||||
- }
|
||||
-
|
||||
- return blockState;
|
||||
- } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, i1 - 1, i2).at(i1 - 1).is(Blocks.LAVA)) {
|
||||
- this.shouldScheduleFluidUpdate = true;
|
||||
- return blockState;
|
||||
- } else {
|
||||
- MutableDouble mutableDouble = new MutableDouble(Double.NaN);
|
||||
- Aquifer.FluidStatus aquiferStatus2 = this.getAquiferStatus(l1);
|
||||
- double d1 = d * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus2);
|
||||
- if (substance + d1 > 0.0) {
|
||||
- this.shouldScheduleFluidUpdate = false;
|
||||
- return null;
|
||||
- } else {
|
||||
- Aquifer.FluidStatus aquiferStatus3 = this.getAquiferStatus(l2);
|
||||
- double d2 = similarity(i6, i8);
|
||||
- if (d2 > 0.0) {
|
||||
- double d3 = d * d2 * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus3);
|
||||
- if (substance + d3 > 0.0) {
|
||||
- this.shouldScheduleFluidUpdate = false;
|
||||
- return null;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- double d3 = similarity(i7, i8);
|
||||
- if (d3 > 0.0) {
|
||||
- double d4 = d * d3 * this.calculatePressure(context, mutableDouble, aquiferStatus2, aquiferStatus3);
|
||||
- if (substance + d4 > 0.0) {
|
||||
- this.shouldScheduleFluidUpdate = false;
|
||||
- return null;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- boolean flag = !aquiferStatus.equals(aquiferStatus2);
|
||||
- boolean flag1 = d3 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus2.equals(aquiferStatus3);
|
||||
- boolean flag2 = d2 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus.equals(aquiferStatus3);
|
||||
- if (!flag && !flag1 && !flag2) {
|
||||
- this.shouldScheduleFluidUpdate = d2 >= FLOWING_UPDATE_SIMULARITY
|
||||
- && similarity(i6, i9) >= FLOWING_UPDATE_SIMULARITY
|
||||
- && !aquiferStatus.equals(this.getAquiferStatus(l3));
|
||||
- } else {
|
||||
- this.shouldScheduleFluidUpdate = true;
|
||||
- }
|
||||
-
|
||||
- return blockState;
|
||||
- }
|
||||
- }
|
||||
+ aquiferExtracted$refreshDistPosIdx(i, j, k);
|
||||
+ return aquiferExtracted$applyPost(context, substance, j, i, k);
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -278,65 +201,28 @@ public interface Aquifer {
|
||||
return 1.0 - Math.abs(secondDistance - firstDistance) / 25.0;
|
||||
}
|
||||
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
private double calculatePressure(
|
||||
- DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus firstFluid, Aquifer.FluidStatus secondFluid
|
||||
+ DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 // DivineMC - rename args
|
||||
) {
|
||||
int i = context.blockY();
|
||||
- BlockState blockState = firstFluid.at(i);
|
||||
- BlockState blockState1 = secondFluid.at(i);
|
||||
- if ((!blockState.is(Blocks.LAVA) || !blockState1.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState1.is(Blocks.LAVA))) {
|
||||
- int abs = Math.abs(firstFluid.fluidLevel - secondFluid.fluidLevel);
|
||||
+ BlockState blockState = fluidLevel.at(i);
|
||||
+ BlockState blockState2 = fluidLevel2.at(i);
|
||||
+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) {
|
||||
+ int abs = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel);
|
||||
if (abs == 0) {
|
||||
return 0.0;
|
||||
} else {
|
||||
- double d = 0.5 * (firstFluid.fluidLevel + secondFluid.fluidLevel);
|
||||
- double d1 = i + 0.5 - d;
|
||||
- double d2 = abs / 2.0;
|
||||
- double d3 = 0.0;
|
||||
- double d4 = 2.5;
|
||||
- double d5 = 1.5;
|
||||
- double d6 = 3.0;
|
||||
- double d7 = 10.0;
|
||||
- double d8 = 3.0;
|
||||
- double d9 = d2 - Math.abs(d1);
|
||||
- double d11;
|
||||
- if (d1 > 0.0) {
|
||||
- double d10 = 0.0 + d9;
|
||||
- if (d10 > 0.0) {
|
||||
- d11 = d10 / 1.5;
|
||||
- } else {
|
||||
- d11 = d10 / 2.5;
|
||||
- }
|
||||
- } else {
|
||||
- double d10 = 3.0 + d9;
|
||||
- if (d10 > 0.0) {
|
||||
- d11 = d10 / 3.0;
|
||||
- } else {
|
||||
- d11 = d10 / 10.0;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
- double d10x = 2.0;
|
||||
- double d12;
|
||||
- if (!(d11 < -2.0) && !(d11 > 2.0)) {
|
||||
- double value = substance.getValue();
|
||||
- if (Double.isNaN(value)) {
|
||||
- double d13 = this.barrierNoise.compute(context);
|
||||
- substance.setValue(d13);
|
||||
- d12 = d13;
|
||||
- } else {
|
||||
- d12 = value;
|
||||
- }
|
||||
- } else {
|
||||
- d12 = 0.0;
|
||||
- }
|
||||
+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel);
|
||||
+ final double q = aquiferExtracted$getQ(i, d, abs);
|
||||
|
||||
- return 2.0 * (d12 + d11);
|
||||
+ return aquiferExtracted$postCalculateDensity(context, substance, q);
|
||||
}
|
||||
} else {
|
||||
return 2.0;
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
|
||||
private int gridX(int x) {
|
||||
return Math.floorDiv(x, 16);
|
||||
@@ -350,23 +236,25 @@ public interface Aquifer {
|
||||
return Math.floorDiv(z, 16);
|
||||
}
|
||||
|
||||
- private Aquifer.FluidStatus getAquiferStatus(long packedPos) {
|
||||
- int x = BlockPos.getX(packedPos);
|
||||
- int y = BlockPos.getY(packedPos);
|
||||
- int z = BlockPos.getZ(packedPos);
|
||||
- int i = this.gridX(x);
|
||||
- int i1 = this.gridY(y);
|
||||
- int i2 = this.gridZ(z);
|
||||
- int index = this.getIndex(i, i1, i2);
|
||||
- Aquifer.FluidStatus fluidStatus = this.aquiferCache[index];
|
||||
- if (fluidStatus != null) {
|
||||
- return fluidStatus;
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
+ private Aquifer.FluidStatus getAquiferStatus(long pos) {
|
||||
+ int i = BlockPos.getX(pos);
|
||||
+ int j = BlockPos.getY(pos);
|
||||
+ int k = BlockPos.getZ(pos);
|
||||
+ int l = i >> 4; // C2ME - inline: floorDiv(i, 16)
|
||||
+ int m = Math.floorDiv(j, 12); // C2ME - inline
|
||||
+ int n = k >> 4; // C2ME - inline: floorDiv(k, 16)
|
||||
+ int o = this.getIndex(l, m, n);
|
||||
+ Aquifer.FluidStatus fluidLevel = this.aquiferCache[o];
|
||||
+ if (fluidLevel != null) {
|
||||
+ return fluidLevel;
|
||||
} else {
|
||||
- Aquifer.FluidStatus fluidStatus1 = this.computeFluid(x, y, z);
|
||||
- this.aquiferCache[index] = fluidStatus1;
|
||||
- return fluidStatus1;
|
||||
+ Aquifer.FluidStatus fluidLevel2 = this.computeFluid(i, j, k);
|
||||
+ this.aquiferCache[o] = fluidLevel2;
|
||||
+ return fluidLevel2;
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
|
||||
private Aquifer.FluidStatus computeFluid(int x, int y, int z) {
|
||||
Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(x, y, z);
|
||||
@@ -407,22 +295,21 @@ public interface Aquifer {
|
||||
}
|
||||
|
||||
private int computeSurfaceLevel(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int maxSurfaceLevel, boolean fluidPresent) {
|
||||
- DensityFunction.SinglePointContext singlePointContext = new DensityFunction.SinglePointContext(x, y, z);
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
+ DensityFunction.SinglePointContext unblendedNoisePos = new DensityFunction.SinglePointContext(x, y, z);
|
||||
double d;
|
||||
double d1;
|
||||
- if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, singlePointContext)) {
|
||||
+ if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, unblendedNoisePos)) {
|
||||
d = -1.0;
|
||||
d1 = -1.0;
|
||||
} else {
|
||||
int i = maxSurfaceLevel + 8 - y;
|
||||
- int i1 = 64;
|
||||
- double d2 = fluidPresent ? Mth.clampedMap((double)i, 0.0, 64.0, 1.0, 0.0) : 0.0;
|
||||
- double d3 = Mth.clamp(this.fluidLevelFloodednessNoise.compute(singlePointContext), -1.0, 1.0);
|
||||
- double d4 = Mth.map(d2, 1.0, 0.0, -0.3, 0.8);
|
||||
- double d5 = Mth.map(d2, 1.0, 0.0, -0.8, 0.4);
|
||||
- d = d3 - d5;
|
||||
- d1 = d3 - d4;
|
||||
+ double f = fluidPresent ? Mth.clampedLerp(1.0, 0.0, ((double) i) / 64.0) : 0.0; // inline
|
||||
+ double g = Mth.clamp(this.fluidLevelFloodednessNoise.compute(unblendedNoisePos), -1.0, 1.0);
|
||||
+ d = g + 0.8 + (f - 1.0) * 1.2; // inline
|
||||
+ d1 = g + 0.3 + (f - 1.0) * 1.1; // inline
|
||||
}
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
|
||||
int i;
|
||||
if (d1 > 0.0) {
|
||||
@@ -453,12 +340,12 @@ public interface Aquifer {
|
||||
private BlockState computeFluidType(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int surfaceLevel) {
|
||||
BlockState blockState = fluidStatus.fluidType;
|
||||
if (surfaceLevel <= -10 && surfaceLevel != DimensionType.WAY_BELOW_MIN_Y && fluidStatus.fluidType != Blocks.LAVA.defaultBlockState()) {
|
||||
- int i = 64;
|
||||
- int i1 = 40;
|
||||
- int i2 = Math.floorDiv(x, 64);
|
||||
- int i3 = Math.floorDiv(y, 40);
|
||||
- int i4 = Math.floorDiv(z, 64);
|
||||
- double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(i2, i3, i4));
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
+ int k = x >> 6;
|
||||
+ int l = Math.floorDiv(y, 40);
|
||||
+ int m = z >> 6;
|
||||
+ double d = this.lavaNoise.compute(new DensityFunction.SinglePointContext(k, l, m));
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
if (Math.abs(d) > 0.3) {
|
||||
blockState = Blocks.LAVA.defaultBlockState();
|
||||
}
|
||||
@@ -466,5 +353,183 @@ public interface Aquifer {
|
||||
|
||||
return blockState;
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - C2ME: Optimize Aquifer
|
||||
+ private @org.jetbrains.annotations.Nullable BlockState aquiferExtracted$applyPost(DensityFunction.FunctionContext pos, double density, int j, int i, int k) {
|
||||
+ Aquifer.FluidStatus fluidLevel2 = this.getAquiferStatus(this.c2me$pos1);
|
||||
+ double d = similarity(this.c2me$dist1, this.c2me$dist2);
|
||||
+ BlockState blockState = fluidLevel2.at(j);
|
||||
+ if (d <= 0.0) {
|
||||
+ this.shouldScheduleFluidUpdate = d >= FLOWING_UPDATE_SIMULARITY;
|
||||
+ return blockState;
|
||||
+ } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, j - 1, k).at(j - 1).is(Blocks.LAVA)) {
|
||||
+ this.shouldScheduleFluidUpdate = true;
|
||||
+ return blockState;
|
||||
+ } else {
|
||||
+ this.c2me$mutableDoubleThingy = Double.NaN;
|
||||
+ Aquifer.FluidStatus fluidLevel3 = this.getAquiferStatus(this.c2me$pos2);
|
||||
+ double e = d * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel3);
|
||||
+ if (density + e > 0.0) {
|
||||
+ this.shouldScheduleFluidUpdate = false;
|
||||
+ return null;
|
||||
+ } else {
|
||||
+ return aquiferExtracted$getFinalBlockState(pos, density, d, fluidLevel2, fluidLevel3, blockState);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private BlockState aquiferExtracted$getFinalBlockState(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, Aquifer.FluidStatus fluidLevel3, BlockState blockState) {
|
||||
+ Aquifer.FluidStatus fluidLevel4 = this.getAquiferStatus(this.c2me$pos3);
|
||||
+ double f = similarity(this.c2me$dist1, this.c2me$dist3);
|
||||
+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel2, f, fluidLevel4)) return null;
|
||||
+
|
||||
+ double g = similarity(this.c2me$dist2, this.c2me$dist3);
|
||||
+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel3, g, fluidLevel4)) return null;
|
||||
+
|
||||
+ this.shouldScheduleFluidUpdate = true;
|
||||
+ return blockState;
|
||||
+ }
|
||||
+
|
||||
+ private boolean aquiferExtracted$extractedCheckFG(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, double f, Aquifer.FluidStatus fluidLevel4) {
|
||||
+ if (f > 0.0) {
|
||||
+ double g = d * f * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel4);
|
||||
+ if (density + g > 0.0) {
|
||||
+ this.shouldScheduleFluidUpdate = false;
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ private void aquiferExtracted$refreshDistPosIdx(int x, int y, int z) {
|
||||
+ int gx = (x - 5) >> 4;
|
||||
+ int gy = Math.floorDiv(y + 1, 12);
|
||||
+ int gz = (z - 5) >> 4;
|
||||
+ int dist1 = Integer.MAX_VALUE;
|
||||
+ int dist2 = Integer.MAX_VALUE;
|
||||
+ int dist3 = Integer.MAX_VALUE;
|
||||
+ long pos1 = 0;
|
||||
+ long pos2 = 0;
|
||||
+ long pos3 = 0;
|
||||
+
|
||||
+ for (int offY = -1; offY <= 1; ++offY) {
|
||||
+ for (int offZ = 0; offZ <= 1; ++offZ) {
|
||||
+ for (int offX = 0; offX <= 1; ++offX) {
|
||||
+ int posIdx = this.getIndex(gx + offX, gy + offY, gz + offZ);
|
||||
+
|
||||
+ long position = this.aquiferLocationCache[posIdx];
|
||||
+
|
||||
+ int dx = BlockPos.getX(position) - x;
|
||||
+ int dy = BlockPos.getY(position) - y;
|
||||
+ int dz = BlockPos.getZ(position) - z;
|
||||
+ int dist = dx * dx + dy * dy + dz * dz;
|
||||
+
|
||||
+ if (dist3 >= dist) {
|
||||
+ pos3 = position;
|
||||
+ dist3 = dist;
|
||||
+ }
|
||||
+ if (dist2 >= dist) {
|
||||
+ pos3 = pos2;
|
||||
+ dist3 = dist2;
|
||||
+ pos2 = position;
|
||||
+ dist2 = dist;
|
||||
+ }
|
||||
+ if (dist1 >= dist) {
|
||||
+ pos2 = pos1;
|
||||
+ dist2 = dist1;
|
||||
+ pos1 = position;
|
||||
+ dist1 = dist;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ this.c2me$dist1 = dist1;
|
||||
+ this.c2me$dist2 = dist2;
|
||||
+ this.c2me$dist3 = dist3;
|
||||
+ this.c2me$pos1 = pos1;
|
||||
+ this.c2me$pos2 = pos2;
|
||||
+ this.c2me$pos3 = pos3;
|
||||
+ }
|
||||
+
|
||||
+ private double c2me$calculateDensityModified(
|
||||
+ DensityFunction.FunctionContext pos, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2
|
||||
+ ) {
|
||||
+ int i = pos.blockY();
|
||||
+ BlockState blockState = fluidLevel.at(i);
|
||||
+ BlockState blockState2 = fluidLevel2.at(i);
|
||||
+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) {
|
||||
+ int j = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel);
|
||||
+ if (j == 0) {
|
||||
+ return 0.0;
|
||||
+ } else {
|
||||
+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel);
|
||||
+ final double q = aquiferExtracted$getQ(i, d, j);
|
||||
+
|
||||
+ return aquiferExtracted$postCalculateDensityModified(pos, q);
|
||||
+ }
|
||||
+ } else {
|
||||
+ return 2.0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private double aquiferExtracted$postCalculateDensity(DensityFunction.FunctionContext pos, MutableDouble mutableDouble, double q) {
|
||||
+ double r;
|
||||
+ if (!(q < -2.0) && !(q > 2.0)) {
|
||||
+ double s = mutableDouble.getValue();
|
||||
+ if (Double.isNaN(s)) {
|
||||
+ double t = this.barrierNoise.compute(pos);
|
||||
+ mutableDouble.setValue(t);
|
||||
+ r = t;
|
||||
+ } else {
|
||||
+ r = s;
|
||||
+ }
|
||||
+ } else {
|
||||
+ r = 0.0;
|
||||
+ }
|
||||
+
|
||||
+ return 2.0 * (r + q);
|
||||
+ }
|
||||
+
|
||||
+ private double aquiferExtracted$postCalculateDensityModified(DensityFunction.FunctionContext pos, double q) {
|
||||
+ double r;
|
||||
+ if (!(q < -2.0) && !(q > 2.0)) {
|
||||
+ double s = this.c2me$mutableDoubleThingy;
|
||||
+ if (Double.isNaN(s)) {
|
||||
+ double t = this.barrierNoise.compute(pos);
|
||||
+ this.c2me$mutableDoubleThingy = t;
|
||||
+ r = t;
|
||||
+ } else {
|
||||
+ r = s;
|
||||
+ }
|
||||
+ } else {
|
||||
+ r = 0.0;
|
||||
+ }
|
||||
+
|
||||
+ return 2.0 * (r + q);
|
||||
+ }
|
||||
+
|
||||
+ private static double aquiferExtracted$getQ(double i, double d, double j) {
|
||||
+ double e = i + 0.5 - d;
|
||||
+ double f = j / 2.0;
|
||||
+ double o = f - Math.abs(e);
|
||||
+ double q;
|
||||
+ if (e > 0.0) {
|
||||
+ if (o > 0.0) {
|
||||
+ q = o / 1.5;
|
||||
+ } else {
|
||||
+ q = o / 2.5;
|
||||
+ }
|
||||
+ } else {
|
||||
+ double p = 3.0 + o;
|
||||
+ if (p > 0.0) {
|
||||
+ q = p / 3.0;
|
||||
+ } else {
|
||||
+ q = p / 10.0;
|
||||
+ }
|
||||
+ }
|
||||
+ return q;
|
||||
+ }
|
||||
+ // DivineMC end - C2ME: Optimize Aquifer
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
index 86c15d2d90e63d21cb83622a7b29e11151a4f64a..2c0c0546046857056b8445f59828fdf9821ea001 100644
|
||||
--- a/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
+++ b/net/minecraft/world/level/levelgen/Beardifier.java
|
||||
@@ -29,6 +29,17 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
});
|
||||
private final ObjectListIterator<Beardifier.Rigid> pieceIterator;
|
||||
private final ObjectListIterator<JigsawJunction> junctionIterator;
|
||||
+ // DivineMC start - C2ME: Optimize Beardifier
|
||||
+ private Beardifier.Rigid[] c2me$pieceArray;
|
||||
+ private JigsawJunction[] c2me$junctionArray;
|
||||
+
|
||||
+ private void c2me$initArrays() {
|
||||
+ this.c2me$pieceArray = com.google.common.collect.Iterators.toArray(this.pieceIterator, Beardifier.Rigid.class);
|
||||
+ this.pieceIterator.back(Integer.MAX_VALUE);
|
||||
+ this.c2me$junctionArray = com.google.common.collect.Iterators.toArray(this.junctionIterator, JigsawJunction.class);
|
||||
+ this.junctionIterator.back(Integer.MAX_VALUE);
|
||||
+ }
|
||||
+ // DivineMC end - C2ME: Optimize Beardifier
|
||||
|
||||
public static Beardifier forStructuresInChunk(StructureManager structureManager, ChunkPos chunkPos) {
|
||||
int minBlockX = chunkPos.getMinBlockX();
|
||||
@@ -75,50 +86,44 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
|
||||
this.junctionIterator = junctionIterator;
|
||||
}
|
||||
|
||||
+ // DivineMC start - C2ME: Optimize Beardifier
|
||||
@Override
|
||||
public double compute(DensityFunction.FunctionContext context) {
|
||||
+ if (this.c2me$pieceArray == null || this.c2me$junctionArray == null) {
|
||||
+ this.c2me$initArrays();
|
||||
+ }
|
||||
int i = context.blockX();
|
||||
- int i1 = context.blockY();
|
||||
- int i2 = context.blockZ();
|
||||
+ int j = context.blockY();
|
||||
+ int k = context.blockZ();
|
||||
double d = 0.0;
|
||||
|
||||
- while (this.pieceIterator.hasNext()) {
|
||||
- Beardifier.Rigid rigid = this.pieceIterator.next();
|
||||
- BoundingBox boundingBox = rigid.box();
|
||||
- int groundLevelDelta = rigid.groundLevelDelta();
|
||||
- int max = Math.max(0, Math.max(boundingBox.minX() - i, i - boundingBox.maxX()));
|
||||
- int max1 = Math.max(0, Math.max(boundingBox.minZ() - i2, i2 - boundingBox.maxZ()));
|
||||
- int i3 = boundingBox.minY() + groundLevelDelta;
|
||||
- int i4 = i1 - i3;
|
||||
-
|
||||
- int i5 = switch (rigid.terrainAdjustment()) {
|
||||
- case NONE -> 0;
|
||||
- case BURY, BEARD_THIN -> i4;
|
||||
- case BEARD_BOX -> Math.max(0, Math.max(i3 - i1, i1 - boundingBox.maxY()));
|
||||
- case ENCAPSULATE -> Math.max(0, Math.max(boundingBox.minY() - i1, i1 - boundingBox.maxY()));
|
||||
- };
|
||||
+ for (Beardifier.Rigid piece : this.c2me$pieceArray) {
|
||||
+ BoundingBox blockBox = piece.box();
|
||||
+ int l = piece.groundLevelDelta();
|
||||
+ int m = Math.max(0, Math.max(blockBox.minX() - i, i - blockBox.maxX()));
|
||||
+ int n = Math.max(0, Math.max(blockBox.minZ() - k, k - blockBox.maxZ()));
|
||||
+ int o = blockBox.minY() + l;
|
||||
+ int p = j - o;
|
||||
|
||||
- d += switch (rigid.terrainAdjustment()) {
|
||||
+ d += switch (piece.terrainAdjustment()) { // 2 switch statement merged
|
||||
case NONE -> 0.0;
|
||||
- case BURY -> getBuryContribution(max, i5 / 2.0, max1);
|
||||
- case BEARD_THIN, BEARD_BOX -> getBeardContribution(max, i5, max1, i4) * 0.8;
|
||||
- case ENCAPSULATE -> getBuryContribution(max / 2.0, i5 / 2.0, max1 / 2.0) * 0.8;
|
||||
+ case BURY -> getBuryContribution(m, (double)p / 2.0, n);
|
||||
+ case BEARD_THIN -> getBeardContribution(m, p, n, p) * 0.8;
|
||||
+ case BEARD_BOX -> getBeardContribution(m, Math.max(0, Math.max(o - j, j - blockBox.maxY())), n, p) * 0.8;
|
||||
+ case ENCAPSULATE -> getBuryContribution((double)m / 2.0, (double)Math.max(0, Math.max(blockBox.minY() - j, j - blockBox.maxY())) / 2.0, (double)n / 2.0) * 0.8;
|
||||
};
|
||||
}
|
||||
|
||||
- this.pieceIterator.back(Integer.MAX_VALUE);
|
||||
-
|
||||
- while (this.junctionIterator.hasNext()) {
|
||||
- JigsawJunction jigsawJunction = this.junctionIterator.next();
|
||||
- int i6 = i - jigsawJunction.getSourceX();
|
||||
- int groundLevelDelta = i1 - jigsawJunction.getSourceGroundY();
|
||||
- int max = i2 - jigsawJunction.getSourceZ();
|
||||
- d += getBeardContribution(i6, groundLevelDelta, max, groundLevelDelta) * 0.4;
|
||||
+ for (JigsawJunction jigsawJunction : this.c2me$junctionArray) {
|
||||
+ int r = i - jigsawJunction.getSourceX();
|
||||
+ int l = j - jigsawJunction.getSourceGroundY();
|
||||
+ int m = k - jigsawJunction.getSourceZ();
|
||||
+ d += getBeardContribution(r, l, m, l) * 0.4;
|
||||
}
|
||||
|
||||
- this.junctionIterator.back(Integer.MAX_VALUE);
|
||||
return d;
|
||||
}
|
||||
+ // DivineMC end - C2ME: Optimize Beardifier
|
||||
|
||||
@Override
|
||||
public double minValue() {
|
||||
diff --git a/net/minecraft/world/level/levelgen/LegacyRandomSource.java b/net/minecraft/world/level/levelgen/LegacyRandomSource.java
|
||||
index c67168517774a0ad9ca43422a79ef14a8ea0c2e8..026dfbbb6c3fd5cd274dcbf721e5cf3af889e3d9 100644
|
||||
--- a/net/minecraft/world/level/levelgen/LegacyRandomSource.java
|
||||
+++ b/net/minecraft/world/level/levelgen/LegacyRandomSource.java
|
||||
@@ -53,13 +53,7 @@ public class LegacyRandomSource implements BitRandomSource {
|
||||
return this.gaussianSource.nextGaussian();
|
||||
}
|
||||
|
||||
- public static class LegacyPositionalRandomFactory implements PositionalRandomFactory {
|
||||
- private final long seed;
|
||||
-
|
||||
- public LegacyPositionalRandomFactory(long seed) {
|
||||
- this.seed = seed;
|
||||
- }
|
||||
-
|
||||
+ public record LegacyPositionalRandomFactory(long seed) implements PositionalRandomFactory { // DivineMC - make record
|
||||
@Override
|
||||
public RandomSource at(int x, int y, int z) {
|
||||
long seed = Mth.getSeed(x, y, z);
|
||||
diff --git a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
|
||||
index 9d3a9ca1e13cd80f468f1352bbb74345f03903dd..d97b9b43686bda0a95fc02f6ca31b2d07d603a32 100644
|
||||
--- a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
|
||||
+++ b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
|
||||
@@ -106,15 +106,7 @@ public class XoroshiroRandomSource implements RandomSource {
|
||||
return this.randomNumberGenerator.nextLong() >>> 64 - bits;
|
||||
}
|
||||
|
||||
- public static class XoroshiroPositionalRandomFactory implements PositionalRandomFactory {
|
||||
- private final long seedLo;
|
||||
- private final long seedHi;
|
||||
-
|
||||
- public XoroshiroPositionalRandomFactory(long seedLo, long seedHi) {
|
||||
- this.seedLo = seedLo;
|
||||
- this.seedHi = seedHi;
|
||||
- }
|
||||
-
|
||||
+ public record XoroshiroPositionalRandomFactory(long seedLo, long seedHi) implements PositionalRandomFactory { // DivineMC - make record
|
||||
@Override
|
||||
public RandomSource at(int x, int y, int z) {
|
||||
long seed = Mth.getSeed(x, y, z);
|
||||
@@ -1,49 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 10 Jul 2025 04:30:21 +0300
|
||||
Subject: [PATCH] Copper Bulb 1gt delay
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/CopperBulbBlock.java b/net/minecraft/world/level/block/CopperBulbBlock.java
|
||||
index 25caeb117d9a49fa00f46ec895a35dee8242aacd..3a2b751b150e7930817fd07d50a3baeecb44f7d1 100644
|
||||
--- a/net/minecraft/world/level/block/CopperBulbBlock.java
|
||||
+++ b/net/minecraft/world/level/block/CopperBulbBlock.java
|
||||
@@ -32,16 +32,36 @@ public class CopperBulbBlock extends Block {
|
||||
@Override
|
||||
protected void onPlace(BlockState state, Level level, BlockPos pos, BlockState oldState, boolean movedByPiston) {
|
||||
if (oldState.getBlock() != state.getBlock() && level instanceof ServerLevel serverLevel) {
|
||||
- this.checkAndFlip(state, serverLevel, pos);
|
||||
+ // DivineMC start - Copper Bulb 1gt delay
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt) {
|
||||
+ this.checkAndFlip(state, serverLevel, pos);
|
||||
+ } else {
|
||||
+ level.scheduleTick(pos, this, 1);
|
||||
+ }
|
||||
+ // DivineMC end - Copper Bulb 1gt delay
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void neighborChanged(BlockState state, Level level, BlockPos pos, Block neighborBlock, @Nullable Orientation orientation, boolean movedByPiston) {
|
||||
if (level instanceof ServerLevel serverLevel) {
|
||||
- this.checkAndFlip(state, serverLevel, pos);
|
||||
+ // DivineMC start - Copper Bulb 1gt delay
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt) {
|
||||
+ this.checkAndFlip(state, serverLevel, pos);
|
||||
+ } else {
|
||||
+ level.scheduleTick(pos, this, 1);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ // DivineMC start - Copper Bulb 1gt delay
|
||||
+ @Override
|
||||
+ public void tick(BlockState state, ServerLevel level, BlockPos pos, net.minecraft.util.RandomSource random) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt) {
|
||||
+ checkAndFlip(state, level, pos);
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Copper Bulb 1gt delay
|
||||
|
||||
public void checkAndFlip(BlockState state, ServerLevel level, BlockPos pos) {
|
||||
boolean hasNeighborSignal = level.hasNeighborSignal(pos);
|
||||
@@ -1,28 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 10 Jul 2025 04:31:46 +0300
|
||||
Subject: [PATCH] Crafter 1gt delay
|
||||
|
||||
|
||||
diff --git a/net/minecraft/world/level/block/CrafterBlock.java b/net/minecraft/world/level/block/CrafterBlock.java
|
||||
index 38b03c7b02bdfc579e5e126c12de3d878e26d188..c3e68a63f6f7d669dca8a08625a04bd7c8ef0327 100644
|
||||
--- a/net/minecraft/world/level/block/CrafterBlock.java
|
||||
+++ b/net/minecraft/world/level/block/CrafterBlock.java
|
||||
@@ -75,7 +75,7 @@ public class CrafterBlock extends BaseEntityBlock {
|
||||
boolean triggeredValue = state.getValue(TRIGGERED);
|
||||
BlockEntity blockEntity = level.getBlockEntity(pos);
|
||||
if (hasNeighborSignal && !triggeredValue) {
|
||||
- level.scheduleTick(pos, this, 4);
|
||||
+ level.scheduleTick(pos, this, !org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt ? 4 : 1); // DivineMC - Crafter 1gt delay
|
||||
level.setBlock(pos, state.setValue(TRIGGERED, true), 2);
|
||||
this.setBlockEntityTriggered(blockEntity, true);
|
||||
} else if (!hasNeighborSignal && triggeredValue) {
|
||||
@@ -125,7 +125,7 @@ public class CrafterBlock extends BaseEntityBlock {
|
||||
@Override
|
||||
public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) {
|
||||
if (state.getValue(TRIGGERED)) {
|
||||
- level.scheduleTick(pos, this, 4);
|
||||
+ level.scheduleTick(pos, this, !org.bxteam.divinemc.config.DivineConfig.MiscCategory.copperBulb1gt ? 4 : 1); // DivineMC - Crafter 1gt delay
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 10 Jul 2025 04:51:08 +0300
|
||||
Subject: [PATCH] Raytrace Entity Tracker
|
||||
|
||||
Original project: https://github.com/tr7zw/EntityCulling
|
||||
Original license: Custom License
|
||||
|
||||
Original project: https://github.com/LogisticsCraft/OcclusionCulling
|
||||
Original license: MIT
|
||||
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index 7ca147cf9da67c399806056e5092841f7ca32321..a6bf257ca93e4b3819b65b4ef4ba71d9e2b40933 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1421,7 +1421,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
double d1 = vec3_dx * vec3_dx + vec3_dz * vec3_dz; // Paper
|
||||
double d2 = d * d;
|
||||
// Paper start - Configurable entity tracking range by Y
|
||||
- boolean flag = d1 <= d2;
|
||||
+ boolean flag = d1 <= d2 && !entity.isCulled(); // DivineMC - Raytrace Entity Tracker
|
||||
if (flag && level.paperConfig().entities.trackingRangeY.enabled) {
|
||||
double rangeY = level.paperConfig().entities.trackingRangeY.get(this.entity, -1);
|
||||
if (rangeY != -1) {
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index cb77b3ab59542bc4e8b50aecb23d98186206a0ad..fa48496222ea922204163d48988246c44e09851f 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -145,7 +145,7 @@ import net.minecraft.world.waypoints.WaypointTransmitter;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
-public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity { // Paper - rewrite chunk system // Paper - optimise entity tracker
|
||||
+public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess, ScoreHolder, DataComponentGetter, ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity, ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity, dev.tr7zw.entityculling.versionless.access.Cullable { // Paper - rewrite chunk system // Paper - optimise entity tracker // DivineMC - Raytrace Entity Tracker
|
||||
public static javax.script.ScriptEngine scriptEngine = new javax.script.ScriptEngineManager().getEngineByName("rhino"); // Purpur - Configurable entity base attributes
|
||||
// CraftBukkit start
|
||||
private static final int CURRENT_LEVEL = 2;
|
||||
@@ -5495,4 +5495,47 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return false;
|
||||
}
|
||||
// Purpur end - Ridables
|
||||
+
|
||||
+ // DivineMC start - Raytrace Entity Tracker
|
||||
+ private long lasttime = 0;
|
||||
+ private boolean culled = false;
|
||||
+ private boolean outOfCamera = false;
|
||||
+
|
||||
+ @Override
|
||||
+ public void setTimeout() {
|
||||
+ this.lasttime = System.currentTimeMillis() + 1000;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isForcedVisible() {
|
||||
+ return this.lasttime > System.currentTimeMillis();
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setCulled(boolean value) {
|
||||
+ this.culled = value;
|
||||
+ if (!value) {
|
||||
+ setTimeout();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isCulled() {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) return false;
|
||||
+
|
||||
+ return this.culled;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void setOutOfCamera(boolean value) {
|
||||
+ this.outOfCamera = value;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public boolean isOutOfCamera() {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) return false;
|
||||
+
|
||||
+ return this.outOfCamera;
|
||||
+ }
|
||||
+ // DivineMC end - Raytrace Entity Tracker
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/EntityType.java b/net/minecraft/world/entity/EntityType.java
|
||||
index 0159627e2c9a540d062073faf9018f5215e10866..26f6941dfbe0453ed5b091e408d8422901f4ca32 100644
|
||||
--- a/net/minecraft/world/entity/EntityType.java
|
||||
+++ b/net/minecraft/world/entity/EntityType.java
|
||||
@@ -1093,6 +1093,7 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
|
||||
public EntityDimensions dimensions;
|
||||
private final float spawnDimensionsScale;
|
||||
private final FeatureFlagSet requiredFeatures;
|
||||
+ public boolean skipRaytracingCheck = false; // DivineMC - Raytrace Entity Tracker
|
||||
|
||||
private static <T extends Entity> EntityType<T> register(ResourceKey<EntityType<?>> key, EntityType.Builder<T> builder) {
|
||||
return Registry.register(BuiltInRegistries.ENTITY_TYPE, key, builder.build(key));
|
||||
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
|
||||
index 05634e09200fa613b69aafe9b2505dbc9b5c54eb..80ce59b79896ff415cf3a93eb6ea3272f42c3d02 100644
|
||||
--- a/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/net/minecraft/world/entity/player/Player.java
|
||||
@@ -122,7 +122,6 @@ import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.scores.PlayerTeam;
|
||||
import net.minecraft.world.scores.Scoreboard;
|
||||
-import net.minecraft.world.scores.Team;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public abstract class Player extends LivingEntity {
|
||||
@@ -222,6 +221,25 @@ public abstract class Player extends LivingEntity {
|
||||
public int burpDelay = 0; // Purpur - Burp delay
|
||||
public boolean canPortalInstant = false; // Purpur - Add portal permission bypass
|
||||
public int sixRowEnderchestSlotCount = -1; // Purpur - Barrels and enderchests 6 rows
|
||||
+ // DivineMC start - Raytrace Entity Tracker
|
||||
+ public dev.tr7zw.entityculling.CullTask cullTask;
|
||||
+ {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) {
|
||||
+ this.cullTask = null;
|
||||
+ } else {
|
||||
+ final com.logisticscraft.occlusionculling.OcclusionCullingInstance culling = new com.logisticscraft.occlusionculling.OcclusionCullingInstance(
|
||||
+ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retTracingDistance,
|
||||
+ new dev.tr7zw.entityculling.DefaultChunkDataProvider(this.level())
|
||||
+ );
|
||||
+
|
||||
+ this.cullTask = new dev.tr7zw.entityculling.CullTask(
|
||||
+ culling, this,
|
||||
+ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retHitboxLimit,
|
||||
+ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retCheckIntervalMs
|
||||
+ );
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Raytrace Entity Tracker
|
||||
|
||||
// CraftBukkit start
|
||||
public boolean fauxSleeping;
|
||||
@@ -310,6 +328,25 @@ public abstract class Player extends LivingEntity {
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
+ // DivineMC start - Raytrace Entity Tracker
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.MiscCategory.retEnabled) {
|
||||
+ if (this.cullTask != null) this.cullTask.signalStop();
|
||||
+ this.cullTask = null;
|
||||
+ } else {
|
||||
+ final com.logisticscraft.occlusionculling.OcclusionCullingInstance culling = new com.logisticscraft.occlusionculling.OcclusionCullingInstance(
|
||||
+ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retTracingDistance,
|
||||
+ new dev.tr7zw.entityculling.DefaultChunkDataProvider(this.level())
|
||||
+ );
|
||||
+
|
||||
+ this.cullTask = new dev.tr7zw.entityculling.CullTask(
|
||||
+ culling, this,
|
||||
+ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retHitboxLimit,
|
||||
+ org.bxteam.divinemc.config.DivineConfig.MiscCategory.retCheckIntervalMs
|
||||
+ );
|
||||
+ }
|
||||
+ if (this.cullTask != null) this.cullTask.setup();
|
||||
+ if (this.cullTask != null) this.cullTask.requestCullSignal();
|
||||
+ // DivineMC end - Raytrace Entity Tracker
|
||||
// Purpur start - Burp delay
|
||||
if (this.burpDelay > 0 && --this.burpDelay == 0) {
|
||||
this.level().playSound(null, getX(), getY(), getZ(), SoundEvents.PLAYER_BURP, SoundSource.PLAYERS, 1.0F, this.level().random.nextFloat() * 0.1F + 0.9F);
|
||||
@@ -1466,6 +1503,7 @@ public abstract class Player extends LivingEntity {
|
||||
if (this.containerMenu != null && this.hasContainerOpen()) {
|
||||
this.doCloseContainer();
|
||||
}
|
||||
+ if (this.cullTask != null) this.cullTask.signalStop(); // DivineMC - Raytrace Entity Tracker
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,86 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 11 Jun 2025 20:15:37 +0300
|
||||
Subject: [PATCH] Async Join Thread
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
index 443aebb71b2a55ee9dcd2dd4bf9a30fbb8da9e49..6cec77e483d51771c602bbdb537c62c893043c08 100644
|
||||
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
|
||||
@@ -53,7 +53,6 @@ import org.bukkit.event.player.PlayerPreLoginEvent;
|
||||
public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener {
|
||||
private static final AtomicInteger UNIQUE_THREAD_ID = new AtomicInteger(0);
|
||||
static final Logger LOGGER = LogUtils.getLogger();
|
||||
- private static final java.util.concurrent.ExecutorService authenticatorPool = java.util.concurrent.Executors.newCachedThreadPool(new com.google.common.util.concurrent.ThreadFactoryBuilder().setNameFormat("User Authenticator #%d").setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(LOGGER)).build()); // Paper - Cache authenticator threads
|
||||
private static final int MAX_TICKS_BEFORE_LOGIN = 600;
|
||||
private final byte[] challenge;
|
||||
final MinecraftServer server;
|
||||
@@ -182,22 +181,25 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
return;
|
||||
}
|
||||
// Paper end - Add Velocity IP Forwarding Support
|
||||
- // CraftBukkit start
|
||||
- // Paper start - Cache authenticator threads
|
||||
- authenticatorPool.execute(() -> {
|
||||
+ // DivineMC start - Async Join Thread
|
||||
+ org.bxteam.divinemc.async.AsyncJoinHandler.runAsync(() -> {
|
||||
try {
|
||||
GameProfile gameprofile = ServerLoginPacketListenerImpl.this.createOfflineProfile(ServerLoginPacketListenerImpl.this.requestedUsername); // Spigot
|
||||
|
||||
gameprofile = ServerLoginPacketListenerImpl.this.callPlayerPreLoginEvents(gameprofile); // Paper - Add more fields to AsyncPlayerPreLoginEvent
|
||||
ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId());
|
||||
- ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||
+ return gameprofile;
|
||||
} catch (Exception ex) {
|
||||
ServerLoginPacketListenerImpl.this.disconnect("Failed to verify username!");
|
||||
ServerLoginPacketListenerImpl.this.server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + ServerLoginPacketListenerImpl.this.requestedUsername, ex);
|
||||
+ return null;
|
||||
+ }
|
||||
+ }, (gameprofile) -> {
|
||||
+ if (gameprofile != null) {
|
||||
+ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||
}
|
||||
});
|
||||
- // Paper end - Cache authenticator threads
|
||||
- // CraftBukkit end
|
||||
+ // DivineMC end - Async Join Thread
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,7 +257,8 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
}
|
||||
|
||||
// Paper start - Cache authenticator threads
|
||||
- authenticatorPool.execute(new Runnable() {
|
||||
+ // DivineMC start - Async Join Thread
|
||||
+ org.bxteam.divinemc.async.AsyncJoinHandler.runAsync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String string1 = Objects.requireNonNull(ServerLoginPacketListenerImpl.this.requestedUsername, "Player name not initialized");
|
||||
@@ -406,16 +409,23 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
|
||||
//TODO Update handling for lazy sessions, might not even have to do anything?
|
||||
|
||||
// Proceed with login
|
||||
- authenticatorPool.execute(() -> {
|
||||
+ // DivineMC start - Async Join Thread
|
||||
+ org.bxteam.divinemc.async.AsyncJoinHandler.runAsync(() -> {
|
||||
try {
|
||||
final GameProfile gameprofile = this.callPlayerPreLoginEvents(this.authenticatedProfile);
|
||||
ServerLoginPacketListenerImpl.LOGGER.info("UUID of player {} is {}", gameprofile.getName(), gameprofile.getId());
|
||||
- ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||
+ return gameprofile;
|
||||
} catch (Exception ex) {
|
||||
disconnect("Failed to verify username!");
|
||||
server.server.getLogger().log(java.util.logging.Level.WARNING, "Exception verifying " + this.authenticatedProfile.getName(), ex);
|
||||
+ return null;
|
||||
+ }
|
||||
+ }, (gameprofile) -> {
|
||||
+ if (gameprofile != null) {
|
||||
+ ServerLoginPacketListenerImpl.this.startClientVerification(gameprofile);
|
||||
}
|
||||
});
|
||||
+ // DivineMC end - Async Join Thread
|
||||
return;
|
||||
}
|
||||
// Paper end - Add Velocity IP Forwarding Support
|
||||
@@ -1,125 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 10 Jul 2025 22:11:47 +0300
|
||||
Subject: [PATCH] Leaves: Protocol Core
|
||||
|
||||
Original project: https://github.com/LeavesMC/Leaves
|
||||
Original license: GPLv3
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
|
||||
index fb263fa1f30a7dfcb7ec2656abfb38e5fe88eac9..c3be4c2fd4a544967322a45d3b8c0fe78a0684a5 100644
|
||||
--- a/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
|
||||
+++ b/net/minecraft/network/protocol/common/custom/CustomPacketPayload.java
|
||||
@@ -40,13 +40,22 @@ public interface CustomPacketPayload {
|
||||
|
||||
@Override
|
||||
public void encode(B buffer, CustomPacketPayload value) {
|
||||
+ // DivineMC start - Leaves Protocol Core
|
||||
+ if (value instanceof org.leavesmc.leaves.protocol.core.LeavesCustomPayload payload) {
|
||||
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.encode(buffer, payload);
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Leaves Protocol Core
|
||||
this.writeCap(buffer, value.type(), value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CustomPacketPayload decode(B buffer) {
|
||||
ResourceLocation resourceLocation = buffer.readResourceLocation();
|
||||
- return (CustomPacketPayload)this.findCodec(resourceLocation).decode(buffer);
|
||||
+ // DivineMC start - Leaves Protocol Core
|
||||
+ var payload = org.leavesmc.leaves.protocol.core.LeavesProtocolManager.decode(resourceLocation, buffer);
|
||||
+ return java.util.Objects.requireNonNullElseGet(payload, () -> this.findCodec(resourceLocation).decode(buffer));
|
||||
+ // DivineMC end - Leaves Protocol Core
|
||||
}
|
||||
};
|
||||
}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 7f5f7d82ac8748758964c24f6c9377dda1dabb14..5969e9d929c709500670b086485f68b26a8475ae 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -1789,6 +1789,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
GameTestTicker.SINGLETON.tick();
|
||||
}
|
||||
|
||||
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleTick(tickCount); // DivineMC - Leaves Protocol Core
|
||||
+
|
||||
for (int i = 0; i < this.tickables.size(); i++) {
|
||||
this.tickables.get(i).run();
|
||||
}
|
||||
diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
index e5d6e5ec12168936d6d50b2f38a3cb58150b0af1..2b2cbe361e7d5dd9c8923c73831a9c5a6ec4a6ae 100644
|
||||
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
|
||||
@@ -61,6 +61,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
public @Nullable String playerBrand;
|
||||
public final java.util.Set<String> pluginMessagerChannels;
|
||||
// Paper end - retain certain values
|
||||
+ public final GameProfile profile; // DivineMC - Leaves Protocol Core
|
||||
|
||||
public ServerCommonPacketListenerImpl(MinecraftServer server, Connection connection, CommonListenerCookie cookie) {
|
||||
this.server = server;
|
||||
@@ -74,6 +75,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
this.pluginMessagerChannels = cookie.channels();
|
||||
this.keepAlive = cookie.keepAlive();
|
||||
// Paper end
|
||||
+ this.profile = cookie.gameProfile(); // DivineMC - Leaves Protocol Core
|
||||
}
|
||||
|
||||
// Paper start - configuration phase API
|
||||
@@ -165,6 +167,18 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
|
||||
@Override
|
||||
public void handleCustomPayload(ServerboundCustomPayloadPacket packet) {
|
||||
+ // DivineMC start - Leaves Protocol Core
|
||||
+ if (packet.payload() instanceof org.leavesmc.leaves.protocol.core.LeavesCustomPayload leavesPayload) {
|
||||
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePayload(org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this), leavesPayload);
|
||||
+ return;
|
||||
+ }
|
||||
+ if (packet.payload() instanceof net.minecraft.network.protocol.common.custom.DiscardedPayload(net.minecraft.resources.ResourceLocation id, byte[] data)) {
|
||||
+ if (org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleBytebuf(org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this), id, io.netty.buffer.Unpooled.wrappedBuffer(data))) {
|
||||
+ return;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Leaves Protocol Core
|
||||
+
|
||||
// Paper start
|
||||
if (!(packet.payload() instanceof final net.minecraft.network.protocol.common.custom.DiscardedPayload discardedPayload)) {
|
||||
return;
|
||||
@@ -230,6 +244,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
|
||||
final String channel = new String(data, from, length, java.nio.charset.StandardCharsets.US_ASCII);
|
||||
if (register) {
|
||||
bridge.addChannel(channel);
|
||||
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleMinecraftRegister(channel, org.leavesmc.leaves.protocol.core.ProtocolUtils.createSelector(this)); // DivineMC - Leaves Protocol Core
|
||||
} else {
|
||||
bridge.removeChannel(channel);
|
||||
}
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index e4513af9b89222cec9f9573a053504ec87fc30b8..0888ba7853f07909e9915d35f706d39a1c6cf307 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -343,6 +343,8 @@ public abstract class PlayerList {
|
||||
return;
|
||||
}
|
||||
|
||||
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // DivineMC - Leaves Protocol Core
|
||||
+
|
||||
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
|
||||
|
||||
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
|
||||
@@ -516,6 +518,7 @@ public abstract class PlayerList {
|
||||
return this.remove(player, net.kyori.adventure.text.Component.translatable("multiplayer.player.left", net.kyori.adventure.text.format.NamedTextColor.YELLOW, io.papermc.paper.configuration.GlobalConfiguration.get().messages.useDisplayNameInQuitMessage ? player.getBukkitEntity().displayName() : io.papermc.paper.adventure.PaperAdventure.asAdventure(player.getDisplayName())));
|
||||
}
|
||||
public @Nullable net.kyori.adventure.text.Component remove(ServerPlayer player, net.kyori.adventure.text.Component leaveMessage) {
|
||||
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerLeave(player); // DivineMC - Leaves Protocol Core
|
||||
// Paper end - Fix kick event leave message not being sent
|
||||
org.purpurmc.purpur.task.BossBarTask.removeFromAll(player.getBukkitEntity()); // Purpur - Implement TPSBar
|
||||
ServerLevel serverLevel = player.level();
|
||||
@@ -1459,6 +1462,7 @@ public abstract class PlayerList {
|
||||
serverPlayer.connection.send(clientboundUpdateRecipesPacket);
|
||||
serverPlayer.getRecipeBook().sendInitialRecipeBook(serverPlayer);
|
||||
}
|
||||
+ org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handleDataPackReload(); // DivineMC - Leaves Protocol Core
|
||||
}
|
||||
|
||||
public boolean isAllowCommandsForAllPlayers() {
|
||||
@@ -1,60 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Fri, 11 Jul 2025 20:39:54 +0300
|
||||
Subject: [PATCH] Paper PR: Optimise non-flush packet sending
|
||||
|
||||
Original project: https://github.com/PaperMC/Paper
|
||||
Original license: GPLv3
|
||||
Paper pull request: https://github.com/PaperMC/Paper/pull/10172
|
||||
|
||||
Places like entity tracking make heavy use of packet sending,
|
||||
and internally netty will use some very expensive thread wakeup
|
||||
calls when scheduling.
|
||||
|
||||
Thanks to various hacks in ProtocolLib as well as other
|
||||
plugins, we cannot simply use a queue of packets to group
|
||||
send on execute. We have to call execute for each packet.
|
||||
|
||||
Tux's suggestion here is exactly what was needed - tag
|
||||
the Runnable indicating it should not make a wakeup call.
|
||||
|
||||
Big thanks to Tux for making this possible as I had given
|
||||
up on this optimisation before he came along.
|
||||
|
||||
Locally this patch drops the entity tracker tick by a full 1.5x.
|
||||
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index 3f60d1b0ac91cfd3418e791222cd7267774b367a..882a912ba3f23ee8239c24068704d9ec9a7f7c40 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -150,6 +150,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
// Paper start - Optimize network
|
||||
public boolean isPending = true;
|
||||
public boolean queueImmunity;
|
||||
+ private io.netty.channel.SingleThreadEventLoop eventLoop; // Paper - Optimise non-flush packet sending
|
||||
// Paper end - Optimize network
|
||||
|
||||
public Connection(PacketFlow receiving) {
|
||||
@@ -160,6 +161,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
public void channelActive(ChannelHandlerContext context) throws Exception {
|
||||
super.channelActive(context);
|
||||
this.channel = context.channel();
|
||||
+ this.eventLoop = (io.netty.channel.SingleThreadEventLoop) this.channel.eventLoop(); // Paper - Optimise non-flush packet sending
|
||||
this.address = this.channel.remoteAddress();
|
||||
this.preparing = false; // Spigot
|
||||
if (this.delayedDisconnect != null) {
|
||||
@@ -474,7 +476,13 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
if (this.channel.eventLoop().inEventLoop()) {
|
||||
this.doSendPacket(packet, channelFutureListener, flag);
|
||||
} else {
|
||||
- this.channel.eventLoop().execute(() -> this.doSendPacket(packet, channelFutureListener, flag));
|
||||
+ // Paper start - Optimise non-flush packet sending
|
||||
+ if (!flag && org.bxteam.divinemc.config.DivineConfig.NetworkCategory.optimizeNonFlushPacketSending) {
|
||||
+ this.eventLoop.lazyExecute(() -> this.doSendPacket(packet, channelFutureListener, flag));
|
||||
+ } else {
|
||||
+ this.channel.eventLoop().execute(() -> this.doSendPacket(packet, channelFutureListener, flag));
|
||||
+ }
|
||||
+ // Paper end - Optimise non-flush packet sending
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,347 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Fri, 11 Jul 2025 21:47:45 +0300
|
||||
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
|
||||
index a814512fcfb85312474ae2c2c21443843bf57831..215d4444fbd9821811fbd4724de088dbb589f179 100644
|
||||
--- a/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 {
|
||||
|
||||
public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ);
|
||||
|
||||
- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ);
|
||||
+ public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - Buffered Linear region format
|
||||
|
||||
- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException;
|
||||
+ public org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - Buffered Linear region format
|
||||
|
||||
public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(
|
||||
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
|
||||
index f5ed467c0880e4bcdf1b9ae773a5aac21c4381c3..64c157252f2288b507025ea96bfe4f76c635f1d9 100644
|
||||
--- a/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 {
|
||||
this.regionDataController.finishWrite(this.chunkX, this.chunkZ, writeData);
|
||||
// Paper start - flush regionfiles on save
|
||||
if (this.world.paperConfig().chunks.flushRegionsOnSave) {
|
||||
- final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ);
|
||||
+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - Buffered Linear region format
|
||||
if (regionFile != null) {
|
||||
regionFile.flush();
|
||||
} // else: evicted from cache, which should have called flush
|
||||
@@ -1470,7 +1470,7 @@ public final class MoonriseRegionFileIO {
|
||||
|
||||
public static interface IORunnable {
|
||||
|
||||
- public void run(final RegionFile regionFile) throws IOException;
|
||||
+ public void run(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Buffered Linear region format
|
||||
|
||||
}
|
||||
}
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
|
||||
index 51c126735ace8fdde89ad97b5cab62f244212db0..23f6ed26b531ea570fdf2ae48c1e2710e0ed22ed 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
|
||||
@@ -3,10 +3,10 @@ package ca.spottedleaf.moonrise.patches.chunk_system.storage;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFile;
|
||||
import java.io.IOException;
|
||||
|
||||
-public interface ChunkSystemChunkBuffer {
|
||||
+public interface ChunkSystemChunkBuffer {
|
||||
public boolean moonrise$getWriteOnClose();
|
||||
|
||||
public void moonrise$setWriteOnClose(final boolean value);
|
||||
|
||||
- public void moonrise$write(final RegionFile regionFile) throws IOException;
|
||||
+ public void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException; // DivineMC - Buffered Linear region format
|
||||
}
|
||||
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
||||
index 5969e9d929c709500670b086485f68b26a8475ae..1c6749f3492195955c907c1e9812786b0936580a 100644
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -942,10 +942,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
||||
// CraftBukkit end
|
||||
if (flush) {
|
||||
for (ServerLevel serverLevel2 : this.getAllLevels()) {
|
||||
- LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", serverLevel2.getChunkSource().chunkMap.getStorageName());
|
||||
+ LOGGER.info("ThreadedChunkStorage ({}): All chunks are saved", serverLevel2.getChunkSource().chunkMap.getStorageName()); // DivineMC - Buffered Linear region format
|
||||
}
|
||||
|
||||
- LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved");
|
||||
+ LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // DivineMC - Buffered Linear region format
|
||||
}
|
||||
|
||||
return flag;
|
||||
diff --git a/net/minecraft/util/worldupdate/WorldUpgrader.java b/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
index 79d57ca8a7870a02e95562d89cbd4341d8282660..1156772217b139d54266f470b18d4a98dc960a79 100644
|
||||
--- a/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
+++ b/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
@@ -75,7 +75,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
volatile int skipped;
|
||||
final Reference2FloatMap<ResourceKey<Level>> progressMap = Reference2FloatMaps.synchronize(new Reference2FloatOpenHashMap<>());
|
||||
volatile Component status = Component.translatable("optimizeWorld.stage.counting");
|
||||
- static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
|
||||
+ static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\\\"+ net.minecraft.world.level.chunk.storage.RegionFileStorage.getExtensionName() +"$"); // DivineMC - Buffered Linear region format
|
||||
final DimensionDataStorage overworldDataStorage;
|
||||
|
||||
public WorldUpgrader(
|
||||
@@ -272,7 +272,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
}
|
||||
|
||||
private static List<WorldUpgrader.FileToUpgrade> getAllChunkPositions(RegionStorageInfo regionStorageInfo, Path path) {
|
||||
- File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(".mca"));
|
||||
+ File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(net.minecraft.world.level.chunk.storage.RegionFileStorage.getExtensionName())); // DivineMC - Buffered Linear region format
|
||||
if (files == null) {
|
||||
return List.of();
|
||||
} else {
|
||||
@@ -285,7 +285,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
int i1 = Integer.parseInt(matcher.group(2)) << 5;
|
||||
List<ChunkPos> list1 = Lists.newArrayList();
|
||||
|
||||
- try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) {
|
||||
+ try (org.bxteam.divinemc.region.IRegionFile regionFile = net.minecraft.world.level.chunk.storage.RegionFileStorage.createNew(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Buffered Linear region format
|
||||
for (int i2 = 0; i2 < 32; i2++) {
|
||||
for (int i3 = 0; i3 < 32; i3++) {
|
||||
ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1);
|
||||
@@ -333,7 +333,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
|
||||
protected abstract boolean tryProcessOnePosition(T chunkStorage, ChunkPos chunkPos, ResourceKey<Level> dimension);
|
||||
|
||||
- private void onFileFinished(RegionFile regionFile) {
|
||||
+ private void onFileFinished(org.bxteam.divinemc.region.IRegionFile regionFile) { // DivineMC - Buffered Linear region format
|
||||
if (WorldUpgrader.this.recreateRegionFiles) {
|
||||
if (this.previousWriteFuture != null) {
|
||||
this.previousWriteFuture.join();
|
||||
@@ -438,7 +438,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
- record FileToUpgrade(RegionFile file, List<ChunkPos> chunksToUpgrade) {
|
||||
+ record FileToUpgrade(org.bxteam.divinemc.region.IRegionFile file, List<ChunkPos> chunksToUpgrade) { // DivineMC - Buffered Linear region format
|
||||
}
|
||||
|
||||
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
|
||||
index ae0a893498d0bfe90c14508f15b431d4885e06ff..00656cf8634e06f7ce1067ef7ba44edfb4519be3 100644
|
||||
--- a/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;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
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, org.bxteam.divinemc.region.IRegionFile { // Paper - rewrite chunk system // DivineMC - Buffered Linear region format
|
||||
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
|
||||
private static final int SECTOR_BYTES = 4096;
|
||||
@@ -912,7 +912,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche
|
||||
}
|
||||
|
||||
@Override
|
||||
- public final void moonrise$write(final RegionFile regionFile) throws IOException {
|
||||
+ public final void moonrise$write(final org.bxteam.divinemc.region.IRegionFile regionFile) throws IOException { // DivineMC - Buffered Linear region format
|
||||
regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count));
|
||||
}
|
||||
// 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
|
||||
index 8d1174f25e0e90d0533970f4ddd8448442024936..ee797d6b3cd898cba1abd3422cb54b17eb4a639f 100644
|
||||
--- a/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
|
||||
private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper
|
||||
public static final String ANVIL_EXTENSION = ".mca";
|
||||
private static final int MAX_CACHE_SIZE = 256;
|
||||
- public final Long2ObjectLinkedOpenHashMap<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
+ public final Long2ObjectLinkedOpenHashMap<org.bxteam.divinemc.region.IRegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - Buffered Linear region format
|
||||
private final RegionStorageInfo info;
|
||||
private final Path folder;
|
||||
private final boolean sync;
|
||||
@@ -58,9 +58,29 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
private static final int MAX_NON_EXISTING_CACHE = 1024 * 4;
|
||||
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) {
|
||||
- return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca";
|
||||
+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + getExtensionName(); // DivineMC - Buffered Linear region format
|
||||
}
|
||||
|
||||
+ // DivineMC start - Buffered Linear region format
|
||||
+ public static org.bxteam.divinemc.region.IRegionFile createNew(RegionStorageInfo info, Path filePath, Path folder, boolean sync) throws IOException{
|
||||
+ final org.bxteam.divinemc.region.EnumRegionFileExtension regionFormat = org.bxteam.divinemc.config.DivineConfig.MiscCategory.regionFileType;
|
||||
+ final String fullFileName = filePath.getFileName().toString();
|
||||
+ final String[] fullNameSplit = fullFileName.split("\\.");
|
||||
+ final String extensionName = fullNameSplit[fullNameSplit.length - 1];
|
||||
+
|
||||
+ if (!regionFormat.getArgument().equalsIgnoreCase(extensionName)) {
|
||||
+ net.minecraft.server.MinecraftServer.setFatalException(new RuntimeException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument()));
|
||||
+ throw new IOException("Invalid region file format: " + extensionName + " expected " + regionFormat.getArgument());
|
||||
+ }
|
||||
+
|
||||
+ return regionFormat.getCreator().create(new org.bxteam.divinemc.region.RegionFileInfo(info, filePath, folder, sync));
|
||||
+ }
|
||||
+
|
||||
+ public static String getExtensionName() {
|
||||
+ return "." + org.bxteam.divinemc.config.DivineConfig.MiscCategory.regionFileType.getArgument();
|
||||
+ }
|
||||
+ // DivineMC end - Buffered Linear region format
|
||||
+
|
||||
private boolean doesRegionFilePossiblyExist(final long position) {
|
||||
synchronized (this.nonExistingRegionFiles) {
|
||||
if (this.nonExistingRegionFiles.contains(position)) {
|
||||
@@ -93,15 +113,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
|
||||
@Override
|
||||
- public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) {
|
||||
+ public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - Buffered Linear region format
|
||||
return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT));
|
||||
}
|
||||
|
||||
@Override
|
||||
- public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException {
|
||||
+ public synchronized final org.bxteam.divinemc.region.IRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - Buffered Linear region format
|
||||
final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT);
|
||||
|
||||
- RegionFile ret = this.regionCache.getAndMoveToFirst(key);
|
||||
+ org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Buffered Linear region format
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
@@ -125,7 +145,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
FileUtil.createDirectoriesSafe(this.folder);
|
||||
|
||||
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
|
||||
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // DivineMC - Buffered Linear region format
|
||||
|
||||
this.regionCache.putAndMoveToFirst(key, ret);
|
||||
|
||||
@@ -144,7 +164,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
|
||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||
- final RegionFile regionFile = this.getRegionFile(pos);
|
||||
+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Buffered Linear region format
|
||||
|
||||
// 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)
|
||||
@@ -178,7 +198,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
) throws IOException {
|
||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||
if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) {
|
||||
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
|
||||
+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Buffered Linear region format
|
||||
if (regionFile != null) {
|
||||
regionFile.clear(pos);
|
||||
} // else: didn't exist
|
||||
@@ -193,7 +213,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.ReadData moonrise$readData(
|
||||
final int chunkX, final int chunkZ
|
||||
) throws IOException {
|
||||
- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ);
|
||||
+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - Buffered Linear region format
|
||||
|
||||
final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ));
|
||||
|
||||
@@ -238,7 +258,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||
final ChunkPos headerChunkPos = SerializableChunkData.getChunkCoordinate(ret);
|
||||
- final RegionFile regionFile = this.getRegionFile(pos);
|
||||
+ final org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(pos); // DivineMC - Buffered Linear region format
|
||||
|
||||
if (regionFile.getRecalculateCount() != readData.recalculateCount()) {
|
||||
return null;
|
||||
@@ -262,7 +282,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
// Paper start - rewrite chunk system
|
||||
- public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException {
|
||||
+ public org.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - Buffered Linear region format
|
||||
return this.getRegionFile(chunkcoordintpair, false);
|
||||
}
|
||||
// Paper end - rewrite chunk system
|
||||
@@ -274,7 +294,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
|
||||
}
|
||||
|
||||
- @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.bxteam.divinemc.region.IRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - Buffered Linear region format
|
||||
// Paper start - rewrite chunk system
|
||||
if (existingOnly) {
|
||||
return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z);
|
||||
@@ -282,7 +302,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
synchronized (this) {
|
||||
final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT);
|
||||
|
||||
- RegionFile ret = this.regionCache.getAndMoveToFirst(key);
|
||||
+ org.bxteam.divinemc.region.IRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - Buffered Linear region format
|
||||
if (ret != null) {
|
||||
return ret;
|
||||
}
|
||||
@@ -297,7 +317,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
FileUtil.createDirectoriesSafe(this.folder);
|
||||
|
||||
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
|
||||
+ ret = this.createNew(this.info, regionPath, this.folder, this.sync); // DivineMC - Buffered Linear region format
|
||||
|
||||
this.regionCache.putAndMoveToFirst(key, ret);
|
||||
|
||||
@@ -311,7 +331,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO DIVINEMC - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); // DivineMC - Rebrand
|
||||
}
|
||||
|
||||
- private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException {
|
||||
+ private static CompoundTag readOversizedChunk(org.bxteam.divinemc.region.IRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // DivineMC - Buffered Linear region format
|
||||
synchronized (regionfile) {
|
||||
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
|
||||
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
|
||||
@@ -346,7 +366,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
@Nullable
|
||||
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
|
||||
- RegionFile regionFile = this.getRegionFile(chunkPos, true);
|
||||
+ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Buffered Linear region format
|
||||
if (regionFile == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -385,7 +405,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
|
||||
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
|
||||
- RegionFile regionFile = this.getRegionFile(chunkPos, true);
|
||||
+ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - Buffered Linear region format
|
||||
if (regionFile == null) {
|
||||
return;
|
||||
}
|
||||
@@ -399,7 +419,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
}
|
||||
|
||||
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
|
||||
+ org.bxteam.divinemc.region.IRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - Buffered Linear region format
|
||||
// Paper start - rewrite chunk system
|
||||
if (regionFile == null) {
|
||||
// if the RegionFile doesn't exist, no point in deleting from it
|
||||
@@ -429,7 +449,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// Paper start - rewrite chunk system
|
||||
synchronized (this) {
|
||||
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
|
||||
- for (final RegionFile regionFile : this.regionCache.values()) {
|
||||
+ for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Buffered Linear region format
|
||||
try {
|
||||
regionFile.close();
|
||||
} catch (final IOException ex) {
|
||||
@@ -445,7 +465,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
|
||||
// Paper start - rewrite chunk system
|
||||
synchronized (this) {
|
||||
final ExceptionCollector<IOException> exceptionCollector = new ExceptionCollector<>();
|
||||
- for (final RegionFile regionFile : this.regionCache.values()) {
|
||||
+ for (final org.bxteam.divinemc.region.IRegionFile regionFile : this.regionCache.values()) { // DivineMC - Buffered Linear region format
|
||||
try {
|
||||
regionFile.flush();
|
||||
} catch (final IOException ex) {
|
||||
@@ -1,174 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 13 Jul 2025 20:03:51 +0300
|
||||
Subject: [PATCH] Cleanup dead code from Paper
|
||||
|
||||
|
||||
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
||||
index 882a912ba3f23ee8239c24068704d9ec9a7f7c40..8a3e7aff7892140bd6caac2e7f8a29075d50459d 100644
|
||||
--- a/net/minecraft/network/Connection.java
|
||||
+++ b/net/minecraft/network/Connection.java
|
||||
@@ -610,13 +610,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
||||
if (!(this.packetListener instanceof net.minecraft.server.network.ServerLoginPacketListenerImpl loginPacketListener)
|
||||
|| loginPacketListener.state != net.minecraft.server.network.ServerLoginPacketListenerImpl.State.VERIFYING
|
||||
|| Connection.joinAttemptsThisTick++ < MAX_PER_TICK) {
|
||||
- // Paper start - detailed watchdog information
|
||||
- net.minecraft.network.protocol.PacketUtils.packetProcessing.push(this.packetListener);
|
||||
- try {
|
||||
- tickablePacketListener.tick();
|
||||
- } finally {
|
||||
- net.minecraft.network.protocol.PacketUtils.packetProcessing.pop();
|
||||
- } // Paper end - detailed watchdog information
|
||||
+ tickablePacketListener.tick();
|
||||
} // Paper end - Buffer joins to world
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/network/protocol/PacketUtils.java b/net/minecraft/network/protocol/PacketUtils.java
|
||||
index aa4dd7517e8be167aef1eaf7aa907e3ce7cc0e62..e3d3b062e273fee4a9d3ba3cadc212787096dc54 100644
|
||||
--- a/net/minecraft/network/protocol/PacketUtils.java
|
||||
+++ b/net/minecraft/network/protocol/PacketUtils.java
|
||||
@@ -21,8 +21,6 @@ public class PacketUtils {
|
||||
public static <T extends PacketListener> void ensureRunningOnSameThread(Packet<T> packet, T processor, BlockableEventLoop<?> executor) throws RunningOnDifferentThreadException {
|
||||
if (!executor.isSameThread()) {
|
||||
executor.executeIfPossible(() -> {
|
||||
- packetProcessing.push(processor); // Paper - detailed watchdog information
|
||||
- try { // Paper - detailed watchdog information
|
||||
if (processor instanceof net.minecraft.server.network.ServerCommonPacketListenerImpl serverCommonPacketListener && serverCommonPacketListener.processedDisconnect) return; // Paper - Don't handle sync packets for kicked players
|
||||
if (processor.shouldHandleMessage(packet)) {
|
||||
try {
|
||||
@@ -41,12 +39,6 @@ public class PacketUtils {
|
||||
} else {
|
||||
LOGGER.debug("Ignoring packet due to disconnection: {}", packet);
|
||||
}
|
||||
- // Paper start - detailed watchdog information
|
||||
- } finally {
|
||||
- totalMainThreadPacketsProcessed.getAndIncrement();
|
||||
- packetProcessing.pop();
|
||||
- }
|
||||
- // Paper end - detailed watchdog information
|
||||
});
|
||||
throw RunningOnDifferentThreadException.RUNNING_ON_DIFFERENT_THREAD;
|
||||
}
|
||||
@@ -73,22 +65,4 @@ public class PacketUtils {
|
||||
|
||||
packetListener.fillCrashReport(crashReport);
|
||||
}
|
||||
-
|
||||
- // Paper start - detailed watchdog information
|
||||
- public static final java.util.concurrent.ConcurrentLinkedDeque<PacketListener> packetProcessing = new java.util.concurrent.ConcurrentLinkedDeque<>();
|
||||
- static final java.util.concurrent.atomic.AtomicLong totalMainThreadPacketsProcessed = new java.util.concurrent.atomic.AtomicLong();
|
||||
-
|
||||
- public static long getTotalProcessedPackets() {
|
||||
- return totalMainThreadPacketsProcessed.get();
|
||||
- }
|
||||
-
|
||||
- public static java.util.List<PacketListener> getCurrentPacketProcessors() {
|
||||
- java.util.List<PacketListener> listeners = new java.util.ArrayList<>(4);
|
||||
- for (PacketListener listener : packetProcessing) {
|
||||
- listeners.add(listener);
|
||||
- }
|
||||
-
|
||||
- return listeners;
|
||||
- }
|
||||
- // Paper end - detailed watchdog information
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 0ad18866c323308ad9b87322932e03a283f740b1..386fdc23b35675a7db66d16bf2a8a6dd5b44059a 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -1349,13 +1349,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Paper end - log detailed entity tick information
|
||||
|
||||
public void tickNonPassenger(Entity entity) {
|
||||
- // Paper start - log detailed entity tick information
|
||||
ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot tick an entity off-main");
|
||||
- try {
|
||||
- if (currentlyTickingEntity.get() == null) {
|
||||
- currentlyTickingEntity.lazySet(entity);
|
||||
- }
|
||||
- // Paper end - log detailed entity tick information
|
||||
entity.setOldPosAndRot();
|
||||
entity.tickCount++;
|
||||
entity.totalEntityAge++; // Paper - age-like counter for all entities
|
||||
@@ -1368,13 +1362,6 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
for (Entity entity1 : entity.getPassengers()) {
|
||||
this.tickPassenger(entity, entity1, isActive); // Paper - EAR 2
|
||||
}
|
||||
- // Paper start - log detailed entity tick information
|
||||
- } finally {
|
||||
- if (currentlyTickingEntity.get() == entity) {
|
||||
- currentlyTickingEntity.lazySet(null);
|
||||
- }
|
||||
- }
|
||||
- // Paper end - log detailed entity tick information
|
||||
}
|
||||
|
||||
private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2
|
||||
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
||||
index fa48496222ea922204163d48988246c44e09851f..2c7c5dab268625e1328f57ac3ec2a735a82fea42 100644
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -1111,29 +1111,10 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
return this.onGround;
|
||||
}
|
||||
|
||||
- // Paper start - detailed watchdog information
|
||||
- public final Object posLock = new Object(); // Paper - log detailed entity tick information
|
||||
-
|
||||
- @Nullable
|
||||
- private Vec3 moveVector;
|
||||
- private double moveStartX;
|
||||
- private double moveStartY;
|
||||
- private double moveStartZ;
|
||||
- // Paper end - detailed watchdog information
|
||||
-
|
||||
public void move(MoverType type, Vec3 movement) {
|
||||
if (!this.boundingBoxChanged && movement.equals(Vec3.ZERO)) return; // DivineMC - VMP: skip entity move if movement is zero
|
||||
final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity
|
||||
- // Paper start - detailed watchdog information
|
||||
ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||
- synchronized (this.posLock) {
|
||||
- this.moveStartX = this.getX();
|
||||
- this.moveStartY = this.getY();
|
||||
- this.moveStartZ = this.getZ();
|
||||
- this.moveVector = movement;
|
||||
- }
|
||||
- try {
|
||||
- // Paper end - detailed watchdog information
|
||||
if (this.noPhysics) {
|
||||
this.setPos(this.getX() + movement.x, this.getY() + movement.y, this.getZ() + movement.z);
|
||||
} else {
|
||||
@@ -1248,13 +1229,6 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
this.setDeltaMovement(this.getDeltaMovement().multiply(blockSpeedFactor, 1.0, blockSpeedFactor));
|
||||
}
|
||||
}
|
||||
- // Paper start - detailed watchdog information
|
||||
- } finally {
|
||||
- synchronized (this.posLock) { // Paper
|
||||
- this.moveVector = null;
|
||||
- } // Paper
|
||||
- }
|
||||
- // Paper end - detailed watchdog information
|
||||
}
|
||||
|
||||
private void applyMovementEmissionAndPlaySound(Entity.MovementEmission movementEmission, Vec3 movement, BlockPos pos, BlockState state) {
|
||||
@@ -4969,9 +4943,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
|
||||
public void setDeltaMovement(Vec3 deltaMovement) {
|
||||
- synchronized (this.posLock) { // Paper - detailed watchdog information
|
||||
this.deltaMovement = deltaMovement;
|
||||
- } // Paper - detailed watchdog information
|
||||
}
|
||||
|
||||
public void addDeltaMovement(Vec3 addend) {
|
||||
@@ -5069,9 +5041,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
|
||||
}
|
||||
// Paper end - Block invalid positions and bounding box
|
||||
if (this.position.x != x || this.position.y != y || this.position.z != z) {
|
||||
- synchronized (this.posLock) { // Paper - detailed watchdog information
|
||||
this.position = new Vec3(x, y, z);
|
||||
- } // Paper - detailed watchdog information
|
||||
int floor = Mth.floor(x);
|
||||
int floor1 = Mth.floor(y);
|
||||
int floor2 = Mth.floor(z);
|
||||
@@ -1,54 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 17 Jul 2025 20:53:13 +0300
|
||||
Subject: [PATCH] C2ME: The End Biome Cache
|
||||
|
||||
This patch is based on the following mixins:
|
||||
* "com/ishland/c2me/opts/worldgen/vanilla/mixin/the_end_biome_cache/MixinTheEndBiomeSource.java"
|
||||
By: ishland <ishlandmc@yeah.net>
|
||||
As part of: C2ME (https://github.com/RelativityMC/C2ME-fabric)
|
||||
Licensed under: MIT (https://opensource.org/licenses/MIT)
|
||||
|
||||
diff --git a/net/minecraft/world/level/biome/TheEndBiomeSource.java b/net/minecraft/world/level/biome/TheEndBiomeSource.java
|
||||
index cf3172be76fa4c7987ed569138439ff42f92fa7f..0545a0dd25917d75b511d507dc19a5ca7d45b9d9 100644
|
||||
--- a/net/minecraft/world/level/biome/TheEndBiomeSource.java
|
||||
+++ b/net/minecraft/world/level/biome/TheEndBiomeSource.java
|
||||
@@ -55,8 +55,37 @@ public class TheEndBiomeSource extends BiomeSource {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
+ // DivineMC start - C2ME: The End Biome Cache
|
||||
+ private final ThreadLocal<it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap<Holder<Biome>>> cache = ThreadLocal.withInitial(it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap::new);
|
||||
+ private final int cacheCapacity = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.endBiomeCacheCapacity;
|
||||
+
|
||||
@Override
|
||||
- public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
|
||||
+ public Holder<Biome> getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler multiNoiseSampler) {
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.endBiomeCacheEnabled) {
|
||||
+ return getVanillaNoiseBiome(biomeX, biomeY, biomeZ, multiNoiseSampler);
|
||||
+ }
|
||||
+
|
||||
+ final long key = net.minecraft.world.level.ChunkPos.asLong(biomeX, biomeZ);
|
||||
+ final it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap<Holder<Biome>> cacheThreadLocal = cache.get();
|
||||
+ final Holder<Biome> biome = cacheThreadLocal.get(key);
|
||||
+
|
||||
+ if (biome != null) {
|
||||
+ return biome;
|
||||
+ } else {
|
||||
+ final Holder<Biome> gennedBiome = getVanillaNoiseBiome(biomeX, biomeY, biomeZ, multiNoiseSampler);
|
||||
+ cacheThreadLocal.put(key, gennedBiome);
|
||||
+ if (cacheThreadLocal.size() > cacheCapacity) {
|
||||
+ for (int i = 0; i < cacheCapacity / 16; i ++) {
|
||||
+ cacheThreadLocal.removeFirst();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return gennedBiome;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - C2ME: The End Biome Cache
|
||||
+
|
||||
+ private Holder<Biome> getVanillaNoiseBiome(int x, int y, int z, Climate.Sampler sampler) { // DivineMC - C2ME: The End Biome Cache
|
||||
int blockPosX = QuartPos.toBlock(x);
|
||||
int blockPosY = QuartPos.toBlock(y);
|
||||
int blockPosZ = QuartPos.toBlock(z);
|
||||
@@ -1,34 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Fri, 18 Jul 2025 13:54:17 +0300
|
||||
Subject: [PATCH] Euclidean distance squared option
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
index fef167837e05d6e80246d4fccd037cc1c9500f97..1ef70cc1ca0a47ddae8655e88fa6b74fa7f81dc6 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
|
||||
@@ -387,10 +387,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 - Euclidean distance squared option
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.useEuclideanDistanceSquared) {
|
||||
+ 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 - Euclidean distance squared option
|
||||
};
|
||||
private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
|
||||
private final LongHeapPriorityQueue tickingQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);
|
||||
@@ -1,144 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 20 Jul 2025 00:09:31 +0300
|
||||
Subject: [PATCH] Do not send spectator change packet
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerPlayerGameMode.java b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
index 02c02314a4a6a7a6da427f0d064dbc61ce92301d..56efd53d22f6d7338ef7d7cc36d612d410018c89 100644
|
||||
--- a/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayerGameMode.java
|
||||
@@ -75,10 +75,7 @@ public class ServerPlayerGameMode {
|
||||
// CraftBukkit end
|
||||
this.setGameModeForPlayer(gameModeForPlayer, this.gameModeForPlayer); // Paper - Fix MC-259571
|
||||
this.player.onUpdateAbilities();
|
||||
- this.level
|
||||
- .getServer()
|
||||
- .getPlayerList()
|
||||
- .broadcastAll(new ClientboundPlayerInfoUpdatePacket(ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player), this.player); // CraftBukkit
|
||||
+ this.sendGameModeUpdatePacket(gameModeForPlayer); // DivineMC - Do not send spectator change packet
|
||||
this.level.updateSleepingPlayerList();
|
||||
if (gameModeForPlayer == GameType.CREATIVE) {
|
||||
this.player.resetCurrentImpulseContext();
|
||||
@@ -571,4 +568,17 @@ public class ServerPlayerGameMode {
|
||||
return false;
|
||||
}
|
||||
// Purpur end - Shift right click to use exp for mending
|
||||
+
|
||||
+ // DivineMC start - Do not send spectator change packet
|
||||
+ private void sendGameModeUpdatePacket(GameType newGameMode) {
|
||||
+ ClientboundPlayerInfoUpdatePacket packet = new ClientboundPlayerInfoUpdatePacket(
|
||||
+ ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE, this.player);
|
||||
+
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket || newGameMode != GameType.SPECTATOR) {
|
||||
+ this.level.getServer().getPlayerList().broadcastAll(packet, this.player);
|
||||
+ } else {
|
||||
+ this.player.connection.send(packet);
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - Do not send spectator change packet
|
||||
}
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 0888ba7853f07909e9915d35f706d39a1c6cf307..48a02a25c4fa6f3bacefaccd122694156da1a331 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -356,6 +356,8 @@ public abstract class PlayerList {
|
||||
// CraftBukkit start - sendAll above replaced with this loop
|
||||
ClientboundPlayerInfoUpdatePacket packet = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(List.of(player)); // Paper - Add Listing API for Player
|
||||
|
||||
+ ClientboundPlayerInfoUpdatePacket modifiedPacket = this.createSpectatorFilteredPacket(packet); // DivineMC - Do not send spectator change packet
|
||||
+
|
||||
final List<ServerPlayer> onlinePlayers = Lists.newArrayListWithExpectedSize(this.players.size() - 1); // Paper - Use single player info update packet on join
|
||||
for (int i = 0; i < this.players.size(); ++i) {
|
||||
ServerPlayer entityplayer1 = (ServerPlayer) this.players.get(i);
|
||||
@@ -364,7 +366,7 @@ public abstract class PlayerList {
|
||||
// Paper start - Add Listing API for Player
|
||||
if (entityplayer1.getBukkitEntity().isListed(bukkitPlayer)) {
|
||||
// Paper end - Add Listing API for Player
|
||||
- entityplayer1.connection.send(packet);
|
||||
+ this.sendPlayerInfoPacket(entityplayer1, player, packet, modifiedPacket); // DivineMC - Do not send spectator change packet
|
||||
// Paper start - Add Listing API for Player
|
||||
} else {
|
||||
entityplayer1.connection.send(ClientboundPlayerInfoUpdatePacket.createSinglePlayerInitializing(player, false));
|
||||
@@ -380,7 +382,10 @@ public abstract class PlayerList {
|
||||
}
|
||||
// Paper start - Use single player info update packet on join
|
||||
if (!onlinePlayers.isEmpty()) {
|
||||
- player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, player)); // Paper - Add Listing API for Player
|
||||
+ // DivineMC start - Do not send spectator change packet
|
||||
+ ClientboundPlayerInfoUpdatePacket updatePacket = this.createFilteredPlayerListPacket(onlinePlayers, player);
|
||||
+ player.connection.send(updatePacket); // Paper - Add Listing API for Player
|
||||
+ // DivineMC end - Do not send spectator change packet
|
||||
}
|
||||
// Paper end - Use single player info update packet on join
|
||||
player.sentListPacket = true;
|
||||
@@ -1468,4 +1473,69 @@ public abstract class PlayerList {
|
||||
public boolean isAllowCommandsForAllPlayers() {
|
||||
return this.allowCommandsForAllPlayers;
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Do not send spectator change packet
|
||||
+ @Nullable
|
||||
+ private ClientboundPlayerInfoUpdatePacket createSpectatorFilteredPacket(ClientboundPlayerInfoUpdatePacket originalPacket) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ClientboundPlayerInfoUpdatePacket.Entry entry = originalPacket.entries().getFirst();
|
||||
+ if (entry.gameMode() != net.minecraft.world.level.GameType.SPECTATOR) {
|
||||
+ return null;
|
||||
+ }
|
||||
+
|
||||
+ ClientboundPlayerInfoUpdatePacket.Entry filteredEntry = new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
+ entry.profileId(),
|
||||
+ entry.profile(),
|
||||
+ entry.listed(),
|
||||
+ entry.latency(),
|
||||
+ net.minecraft.world.level.GameType.SURVIVAL,
|
||||
+ entry.displayName(),
|
||||
+ entry.showHat(),
|
||||
+ entry.listOrder(),
|
||||
+ entry.chatSession());
|
||||
+
|
||||
+ return new ClientboundPlayerInfoUpdatePacket(originalPacket.actions(), List.of(filteredEntry));
|
||||
+ }
|
||||
+
|
||||
+ private void sendPlayerInfoPacket(ServerPlayer receiver, ServerPlayer joiningPlayer,
|
||||
+ ClientboundPlayerInfoUpdatePacket originalPacket,
|
||||
+ @Nullable ClientboundPlayerInfoUpdatePacket filteredPacket) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket ||
|
||||
+ receiver == joiningPlayer ||
|
||||
+ filteredPacket == null) {
|
||||
+ receiver.connection.send(originalPacket);
|
||||
+ } else {
|
||||
+ receiver.connection.send(filteredPacket);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private ClientboundPlayerInfoUpdatePacket createFilteredPlayerListPacket(List<ServerPlayer> onlinePlayers, ServerPlayer joiningPlayer) {
|
||||
+ ClientboundPlayerInfoUpdatePacket updatePacket = ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(onlinePlayers, joiningPlayer);
|
||||
+
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.NetworkCategory.sendSpectatorChangePacket) {
|
||||
+ return updatePacket;
|
||||
+ }
|
||||
+
|
||||
+ List<ClientboundPlayerInfoUpdatePacket.Entry> newEntries = new java.util.ArrayList<>();
|
||||
+ for (ClientboundPlayerInfoUpdatePacket.Entry entry : updatePacket.entries()) {
|
||||
+ ClientboundPlayerInfoUpdatePacket.Entry newEntry = new ClientboundPlayerInfoUpdatePacket.Entry(
|
||||
+ entry.profileId(),
|
||||
+ entry.profile(),
|
||||
+ entry.listed(),
|
||||
+ entry.latency(),
|
||||
+ entry.gameMode() == net.minecraft.world.level.GameType.SPECTATOR ?
|
||||
+ net.minecraft.world.level.GameType.SURVIVAL : entry.gameMode(),
|
||||
+ entry.displayName(),
|
||||
+ entry.showHat(),
|
||||
+ entry.listOrder(),
|
||||
+ entry.chatSession());
|
||||
+ newEntries.add(newEntry);
|
||||
+ }
|
||||
+
|
||||
+ return new ClientboundPlayerInfoUpdatePacket(updatePacket.actions(), newEntries);
|
||||
+ }
|
||||
+ // DivineMC end - Do not send spectator change packet
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 20 Jul 2025 16:09:38 +0300
|
||||
Subject: [PATCH] Paper PR: Fire ServerListPingEvent for secondary motd send
|
||||
|
||||
Original license: GPLv3
|
||||
Original project: https://github.com/PaperMC/Paper
|
||||
Paper pull request: https://github.com/PaperMC/Paper/pull/8074
|
||||
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index 48a02a25c4fa6f3bacefaccd122694156da1a331..a0d45f72e7c35883996214a2c5420d6a996a58aa 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -304,10 +304,15 @@ public abstract class PlayerList {
|
||||
mutableComponent.withStyle(ChatFormatting.YELLOW);
|
||||
Component joinMessage = mutableComponent; // Paper - Adventure
|
||||
serverGamePacketListenerImpl.teleport(player.getX(), player.getY(), player.getZ(), player.getYRot(), player.getXRot());
|
||||
- ServerStatus status = this.server.getStatus();
|
||||
- if (status != null && !cookie.transferred()) {
|
||||
- player.sendServerStatus(status);
|
||||
+ // DivineMC start - Paper PR: Fire ServerListPingEvent for secondary motd send
|
||||
+ if (!cookie.transferred()) {
|
||||
+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(() -> {
|
||||
+ if (player.hasDisconnected()) return;
|
||||
+ net.minecraft.network.protocol.status.ServerStatus status = com.destroystokyo.paper.network.StandardPaperServerListPingEventImpl.getEventResponse(this.server, player.connection.connection);
|
||||
+ if (status != null) player.sendServerStatus(status);
|
||||
+ });
|
||||
}
|
||||
+ // DivineMC end - Paper PR: Fire ServerListPingEvent for secondary motd send
|
||||
|
||||
// player.connection.send(ClientboundPlayerInfoUpdatePacket.createPlayerInitializing(this.players)); // CraftBukkit - replaced with loop below
|
||||
this.players.add(player);
|
||||
@@ -1,45 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 4 Aug 2025 02:38:45 +0300
|
||||
Subject: [PATCH] Configurable player spawn tracking range
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
|
||||
index 6d1fe8028739145b11fce98ad62b2f8044299548..9f086ded18d1fc8850877c6be113d88074427526 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_tick_iteration/ChunkTickConstants.java
|
||||
@@ -2,7 +2,7 @@ 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.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange / 16.0); // DivineMC - Configurable player spawn tracking range
|
||||
// the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter
|
||||
// note: vanilla does not subtract 0.5 but the result is (luckily!) the same
|
||||
public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5);
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index a6bf257ca93e4b3819b65b4ef4ba71d9e2b40933..de7800b46f7e8c68f24de8476032f2179edc4797 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -822,10 +822,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
||||
final int len = players.size();
|
||||
|
||||
- Objects.checkFromIndexSize(0, len, raw.length);
|
||||
- for (int i = 0; i < len; ++i) {
|
||||
+ for (int i = 0; i < raw.length; ++i) { // DivineMC - Configurable player spawn tracking range
|
||||
final ServerPlayer player = raw[i];
|
||||
- if (this.playerIsCloseEnoughForSpawning(player, chunkPos, 16384.0D)) { // Spigot
|
||||
+ if (player == null) continue; // DivineMC - Configurable player spawn tracking range
|
||||
+ if (this.playerIsCloseEnoughForSpawning(player, chunkPos, (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.playerNearChunkDetectionRange^2))) { // Spigot // DivineMC - Configurable player spawn tracking range
|
||||
if (ret == null) {
|
||||
ret = new ArrayList<>(len - i);
|
||||
ret.add(player);
|
||||
@@ -1220,6 +1220,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
|
||||
for (int i = 0; i < playersLength; ++i) { // DivineMC - Multithreaded tracker
|
||||
final ServerPlayer player = playersRaw[i];
|
||||
+ if (player == null) continue; // DivineMC - Configurable player spawn tracking range
|
||||
this.updatePlayer(player);
|
||||
}
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 24 Jul 2025 14:07:47 +0300
|
||||
Subject: [PATCH] Optimize collections
|
||||
|
||||
|
||||
diff --git a/net/minecraft/core/NonNullList.java b/net/minecraft/core/NonNullList.java
|
||||
index 8c0d8f4e8f8c4cbf0a0b771c1bd99e54877b4944..b88a8663bb4ebd8bf2c541402ded6fd6e9a97589 100644
|
||||
--- a/net/minecraft/core/NonNullList.java
|
||||
+++ b/net/minecraft/core/NonNullList.java
|
||||
@@ -14,23 +14,23 @@ public class NonNullList<E> extends AbstractList<E> {
|
||||
private final E defaultValue;
|
||||
|
||||
public static <E> NonNullList<E> create() {
|
||||
- return new NonNullList<>(Lists.newArrayList(), null);
|
||||
+ return new NonNullList<>(new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(), null); // DivineMC - Optimize collections
|
||||
}
|
||||
|
||||
public static <E> NonNullList<E> createWithCapacity(int initialCapacity) {
|
||||
- return new NonNullList<>(Lists.newArrayListWithCapacity(initialCapacity), null);
|
||||
+ return new NonNullList<>(new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(initialCapacity), null); // DivineMC - Optimize collections
|
||||
}
|
||||
|
||||
public static <E> NonNullList<E> withSize(int size, E defaultValue) {
|
||||
Validate.notNull(defaultValue);
|
||||
Object[] objects = new Object[size];
|
||||
Arrays.fill(objects, defaultValue);
|
||||
- return new NonNullList<>(Arrays.asList((E[])objects), defaultValue);
|
||||
+ return new NonNullList<>(new it.unimi.dsi.fastutil.objects.ObjectArrayList<>((E[])objects), defaultValue); // DivineMC - Optimize collections
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
public static <E> NonNullList<E> of(E defaultValue, E... elements) {
|
||||
- return new NonNullList<>(Arrays.asList(elements), defaultValue);
|
||||
+ return new NonNullList<>(new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(elements), defaultValue); // DivineMC - Optimize collections
|
||||
}
|
||||
|
||||
protected NonNullList(List<E> list, @Nullable E defaultValue) {
|
||||
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||
index de7800b46f7e8c68f24de8476032f2179edc4797..3ca2f56cb31d41e88eb2a3e59c3749fbdef7c85e 100644
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -132,8 +132,10 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||
public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public
|
||||
private final String storageName;
|
||||
private final PlayerMap playerMap = new PlayerMap();
|
||||
- public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new Int2ObjectOpenHashMap<>();
|
||||
- private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap();
|
||||
+ // DivineMC start - Optimize collections
|
||||
+ public final Int2ObjectMap<ChunkMap.TrackedEntity> entityMap = new org.bxteam.divinemc.util.map.Int2ObjectConcurrentHashMap<>();
|
||||
+ private final Long2ByteMap chunkTypeCache = it.unimi.dsi.fastutil.longs.Long2ByteMaps.synchronize(new Long2ByteOpenHashMap());
|
||||
+ // DivineMC end - Optimize collections
|
||||
// Paper - rewrite chunk system
|
||||
public int serverViewDistance;
|
||||
public final WorldGenContext worldGenContext; // Paper - public
|
||||
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
|
||||
index 66ba223dacefb3531c46b144c4499b2b2285eafe..0b7f9af0c4e43115878769043ebd06a09ccdf059 100644
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -253,7 +253,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
|
||||
@Override
|
||||
public final <T extends Entity> List<T> getEntitiesOfClass(final Class<T> entityClass, final AABB boundingBox, final Predicate<? super T> predicate) {
|
||||
- final List<T> ret = new java.util.ArrayList<>();
|
||||
+ final List<T> ret = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // DivineMC - Optimize collections
|
||||
|
||||
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entityClass, null, boundingBox, ret, predicate);
|
||||
|
||||
@@ -262,7 +262,7 @@ public abstract class Level implements LevelAccessor, UUIDLookup<Entity>, AutoCl
|
||||
|
||||
@Override
|
||||
public final List<Entity> moonrise$getHardCollidingEntities(final Entity entity, final AABB box, final Predicate<? super Entity> predicate) {
|
||||
- final List<Entity> ret = new java.util.ArrayList<>();
|
||||
+ final List<Entity> ret = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // DivineMC - Optimize collections
|
||||
|
||||
((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)this).moonrise$getEntityLookup().getHardCollidingEntities(entity, box, ret, predicate);
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/ProtoChunk.java b/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
index aa085d8a78a3fb40a214e4b152ab04d9a409f76f..5ed1a8b6ac025d03fdeb408a6eaa00320087f690 100644
|
||||
--- a/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/ProtoChunk.java
|
||||
@@ -46,7 +46,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 - Optimize collections
|
||||
@Nullable
|
||||
private CarvingMask carvingMask;
|
||||
@Nullable
|
||||
@@ -1,221 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Thu, 24 Jul 2025 14:07:47 +0300
|
||||
Subject: [PATCH] Optimize level ticking
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 386fdc23b35675a7db66d16bf2a8a6dd5b44059a..4934ce03ac533d9c60674632cdac6621e62f6b44 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -908,9 +908,10 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
// Paper start - optimise random ticking
|
||||
private final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom simpleRandom = new ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed());
|
||||
|
||||
+ // DivineMC start - Optimize level ticking
|
||||
private void optimiseRandomTick(final LevelChunk chunk, final int tickSpeed) {
|
||||
final LevelChunkSection[] sections = chunk.getSections();
|
||||
- final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection((ServerLevel)(Object)this);
|
||||
+ final int minSection = ca.spottedleaf.moonrise.common.util.WorldUtil.getMinSection(this); // DivineMC - Optimize level ticking
|
||||
final ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom simpleRandom = this.simpleRandom;
|
||||
final boolean doubleTickFluids = !ca.spottedleaf.moonrise.common.PlatformHooks.get().configFixMC224294();
|
||||
|
||||
@@ -919,42 +920,38 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
final int offsetZ = cpos.z << 4;
|
||||
|
||||
for (int sectionIndex = 0, sectionsLen = sections.length; sectionIndex < sectionsLen; sectionIndex++) {
|
||||
- final int offsetY = (sectionIndex + minSection) << 4;
|
||||
final LevelChunkSection section = sections[sectionIndex];
|
||||
+ if (!section.isRandomlyTickingBlocks()) continue;
|
||||
+ final int offsetY = (sectionIndex + minSection) << 4;
|
||||
final net.minecraft.world.level.chunk.PalettedContainer<net.minecraft.world.level.block.state.BlockState> states = section.states;
|
||||
- if (!section.isRandomlyTickingBlocks()) {
|
||||
- continue;
|
||||
- }
|
||||
|
||||
- final ca.spottedleaf.moonrise.common.list.ShortList tickList = ((ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection)section).moonrise$getTickingBlockList();
|
||||
+ final ca.spottedleaf.moonrise.common.list.ShortList tickList = section.moonrise$getTickingBlockList();
|
||||
|
||||
for (int i = 0; i < tickSpeed; ++i) {
|
||||
- final int tickingBlocks = tickList.size();
|
||||
final int index = simpleRandom.nextInt() & ((16 * 16 * 16) - 1);
|
||||
|
||||
- if (index >= tickingBlocks) {
|
||||
+ if (index >= tickList.size()) {
|
||||
// most of the time we fall here
|
||||
continue;
|
||||
}
|
||||
|
||||
- final int location = (int)tickList.getRaw(index) & 0xFFFF;
|
||||
+ final int location = tickList.getRaw(index);
|
||||
final BlockState state = states.get(location);
|
||||
|
||||
// do not use a mutable pos, as some random tick implementations store the input without calling immutable()!
|
||||
- final BlockPos pos = new BlockPos((location & 15) | offsetX, ((location >>> (4 + 4)) & 15) | offsetY, ((location >>> 4) & 15) | offsetZ);
|
||||
+ final BlockPos pos = new BlockPos((location & 15) | offsetX, (location >>> (4 + 4)) | offsetY, ((location >>> 4) & 15) | offsetZ);
|
||||
|
||||
- state.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
|
||||
+ state.randomTick(this, pos, simpleRandom);
|
||||
if (doubleTickFluids) {
|
||||
final FluidState fluidState = state.getFluidState();
|
||||
if (fluidState.isRandomlyTicking()) {
|
||||
- fluidState.randomTick((ServerLevel)(Object)this, pos, simpleRandom);
|
||||
+ fluidState.randomTick(this, pos, simpleRandom);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-
|
||||
- return;
|
||||
}
|
||||
+ // DivineMC end - Optimize level ticking
|
||||
// Paper end - optimise random ticking
|
||||
|
||||
public void tickChunk(LevelChunk chunk, int randomTickSpeed) {
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 306590a29f8b6db6c0c68814f3fa28f3f26e448b..3dcdafe18085fc8fff9eb5bb50392ba13a27b066 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -75,7 +75,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
return "<null>";
|
||||
}
|
||||
};
|
||||
- private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel = Maps.newHashMap();
|
||||
+ private final Map<BlockPos, LevelChunk.RebindableTickingBlockEntityWrapper> tickersInLevel = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // DivineMC - Optimize level ticking
|
||||
public boolean loaded;
|
||||
public final ServerLevel level; // CraftBukkit - type
|
||||
@Nullable
|
||||
diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java
|
||||
index 66d0a6390febe929ef774b0a7813329015bc8cc2..c17549c4f8a877852c4b86453b1db7b17aab4665 100644
|
||||
--- a/net/minecraft/world/ticks/LevelChunkTicks.java
|
||||
+++ b/net/minecraft/world/ticks/LevelChunkTicks.java
|
||||
@@ -14,10 +14,10 @@ import javax.annotation.Nullable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickContainerAccess<T>, ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks { // Paper - rewrite chunk system
|
||||
- private final Queue<ScheduledTick<T>> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER);
|
||||
+ private final Queue<ScheduledTick<T>> tickQueue = new java.util.concurrent.PriorityBlockingQueue<>(11, ScheduledTick.DRAIN_ORDER); // DivineMC - Optimize level ticking
|
||||
@Nullable
|
||||
private List<SavedTick<T>> pendingTicks;
|
||||
- private final Set<ScheduledTick<?>> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
|
||||
+ private final Set<ScheduledTick<?>> ticksPerPosition = it.unimi.dsi.fastutil.objects.ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH)); // DivineMC - Optimize level ticking
|
||||
@Nullable
|
||||
private BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> onTickAdded;
|
||||
|
||||
@@ -67,10 +67,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 - Optimize collections
|
||||
+ 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) {
|
||||
+ net.minecraft.server.MinecraftServer.LOGGER.error("Encountered caught exception when polling chunk ticks, blocking and returning null.", e);
|
||||
+ return null;
|
||||
}
|
||||
+ // DivineMC end - Optimize collections
|
||||
|
||||
return scheduledTick;
|
||||
}
|
||||
@@ -83,6 +91,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
|
||||
}
|
||||
|
||||
private void scheduleUnchecked(ScheduledTick<T> tick) {
|
||||
+ if (tick == null) return; // DivineMC - Optimize level ticking
|
||||
this.tickQueue.add(tick);
|
||||
if (this.onTickAdded != null) {
|
||||
this.onTickAdded.accept(this, tick);
|
||||
@@ -124,6 +133,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
|
||||
}
|
||||
|
||||
for (ScheduledTick<T> scheduledTick : this.tickQueue) {
|
||||
+ if (scheduledTick == null) continue; // DivineMC - Optimize level ticking
|
||||
list.add(scheduledTick.toSavedTick(gametime));
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/world/ticks/LevelTicks.java b/net/minecraft/world/ticks/LevelTicks.java
|
||||
index c7f9485191dc797de78e6524c5c2c737581ed838..14f2d0088cd9e6d4a2eb084439bab18bd365c41f 100644
|
||||
--- a/net/minecraft/world/ticks/LevelTicks.java
|
||||
+++ b/net/minecraft/world/ticks/LevelTicks.java
|
||||
@@ -30,17 +30,20 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
|
||||
private static final Comparator<LevelChunkTicks<?>> CONTAINER_DRAIN_ORDER = (levelChunkTicks, levelChunkTicks1) -> ScheduledTick.INTRA_TICK_DRAIN_ORDER
|
||||
.compare(levelChunkTicks.peek(), levelChunkTicks1.peek());
|
||||
private final LongPredicate tickCheck;
|
||||
- private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = new Long2ObjectOpenHashMap<>();
|
||||
- private final Long2LongMap nextTickForContainer = Util.make(new Long2LongOpenHashMap(), map -> map.defaultReturnValue(Long.MAX_VALUE));
|
||||
- private final Queue<LevelChunkTicks<T>> containersToTick = new PriorityQueue<>(CONTAINER_DRAIN_ORDER);
|
||||
- private final Queue<ScheduledTick<T>> toRunThisTick = new ArrayDeque<>();
|
||||
+ // DivineMC start - Optimize collections
|
||||
+ private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = it.unimi.dsi.fastutil.longs.Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>());
|
||||
+ private final java.util.Map<Long, Long> nextTickForContainer = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
+ private final Queue<LevelChunkTicks<T>> containersToTick = new java.util.concurrent.PriorityBlockingQueue<>(11, CONTAINER_DRAIN_ORDER);
|
||||
+ private final Queue<ScheduledTick<T>> toRunThisTick = new java.util.concurrent.ConcurrentLinkedQueue<>();
|
||||
+ // DivineMC end - Optimize collections
|
||||
private final List<ScheduledTick<T>> alreadyRunThisTick = new ArrayList<>();
|
||||
- private final Set<ScheduledTick<?>> toRunThisTickSet = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
|
||||
+ private final Set<ScheduledTick<?>> toRunThisTickSet = com.google.common.collect.Sets.newConcurrentHashSet(); // DivineMC - Optimize level ticking
|
||||
private final BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> chunkScheduleUpdater = (levelChunkTicks, scheduledTick) -> {
|
||||
if (scheduledTick.equals(levelChunkTicks.peek())) {
|
||||
this.updateContainerScheduling(scheduledTick);
|
||||
}
|
||||
};
|
||||
+ private final java.util.concurrent.atomic.AtomicInteger toRunThisTickCount = new java.util.concurrent.atomic.AtomicInteger(0); // DivineMC - Optimize level ticking
|
||||
|
||||
public LevelTicks(LongPredicate tickCheck) {
|
||||
this.tickCheck = tickCheck;
|
||||
@@ -90,12 +93,14 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
|
||||
}
|
||||
|
||||
private void sortContainersToTick(long gameTime) {
|
||||
- ObjectIterator<Entry> objectIterator = Long2LongMaps.fastIterator(this.nextTickForContainer);
|
||||
+ java.util.Iterator<java.util.Map.Entry<Long, Long>> objectIterator = this.nextTickForContainer.entrySet().iterator(); // DivineMC - Optimize level ticking
|
||||
|
||||
while (objectIterator.hasNext()) {
|
||||
- Entry entry = objectIterator.next();
|
||||
- long longKey = entry.getLongKey();
|
||||
- long longValue = entry.getLongValue();
|
||||
+ // DivineMC start - Optimize collections
|
||||
+ java.util.Map.Entry<Long, Long> entry = objectIterator.next();
|
||||
+ long longKey = entry.getKey();
|
||||
+ long longValue = entry.getValue();
|
||||
+ // DivineMC end - Optimize collections
|
||||
if (longValue <= gameTime) {
|
||||
LevelChunkTicks<T> levelChunkTicks = this.allContainers.get(longKey);
|
||||
if (levelChunkTicks == null) {
|
||||
@@ -162,16 +167,19 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
|
||||
}
|
||||
|
||||
private void scheduleForThisTick(ScheduledTick<T> tick) {
|
||||
+ if (tick == null) return; // DivineMC - Optimize level ticking
|
||||
this.toRunThisTick.add(tick);
|
||||
+ this.toRunThisTickCount.incrementAndGet(); // DivineMC - Optimize level ticking
|
||||
}
|
||||
|
||||
private boolean canScheduleMoreTicks(int maxAllowedTicks) {
|
||||
- return this.toRunThisTick.size() < maxAllowedTicks;
|
||||
+ return this.toRunThisTickCount.get() < maxAllowedTicks; // DivineMC - Optimize level ticking
|
||||
}
|
||||
|
||||
private void runCollectedTicks(BiConsumer<BlockPos, T> ticker) {
|
||||
while (!this.toRunThisTick.isEmpty()) {
|
||||
ScheduledTick<T> scheduledTick = this.toRunThisTick.poll();
|
||||
+ this.toRunThisTickCount.decrementAndGet(); // DivineMC - Optimize level ticking
|
||||
if (!this.toRunThisTickSet.isEmpty()) {
|
||||
this.toRunThisTickSet.remove(scheduledTick);
|
||||
}
|
||||
@@ -182,7 +190,7 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
|
||||
}
|
||||
|
||||
private void cleanupAfterTick() {
|
||||
- this.toRunThisTick.clear();
|
||||
+ this.toRunThisTickCount.set(0); // DivineMC - Optimize level ticking
|
||||
this.containersToTick.clear();
|
||||
this.alreadyRunThisTick.clear();
|
||||
this.toRunThisTickSet.clear();
|
||||
@@ -1,529 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 11 Aug 2025 02:42:19 +0300
|
||||
Subject: [PATCH] Optimize Moonrise
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
index 93272808d94e81d31af728ebe85df9a2bc7aedab..b47be4b838f4c7f6c3fb62e4e18105c6b4972016 100644
|
||||
--- a/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
+++ b/ca/spottedleaf/moonrise/common/misc/NearbyPlayers.java
|
||||
@@ -59,7 +59,7 @@ 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 it.unimi.dsi.fastutil.objects.Reference2ReferenceMap<ServerPlayer, TrackedPlayer[]> players = it.unimi.dsi.fastutil.objects.Reference2ReferenceMaps.synchronize(new Reference2ReferenceOpenHashMap<>()); // DivineMC - Optimize collections
|
||||
// DivineMC start - Multithreaded Tracker
|
||||
private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<TrackedChunk> byChunk;
|
||||
{
|
||||
@@ -70,10 +70,10 @@ public final class NearbyPlayers {
|
||||
}
|
||||
}
|
||||
// DivineMC end - Multithreaded Tracker
|
||||
- private final Long2ReferenceOpenHashMap<ReferenceList<ServerPlayer>>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES];
|
||||
+ private final it.unimi.dsi.fastutil.longs.Long2ReferenceMap<ReferenceList<ServerPlayer>>[] directByChunk = new it.unimi.dsi.fastutil.longs.Long2ReferenceMap[TOTAL_MAP_TYPES]; // DivineMC - Optimize collections
|
||||
{
|
||||
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 - Optimize collections
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
index 2d24d03bbdb5ee0d862cbfff2219f58afffafe12..b4c55b8fee8dbab278e096580702a05282da2d51 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/EntityLookup.java
|
||||
@@ -93,8 +93,14 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
- final Visibility visibility = EntityLookup.getEntityStatus(entity);
|
||||
- return visibility.isAccessible() ? entity : null;
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ final FullChunkStatus entityStatus = ((ChunkSystemEntity) entity).moonrise$getChunkStatus();
|
||||
+ return switch (entityStatus) {
|
||||
+ case INACCESSIBLE -> null;
|
||||
+ case FULL, BLOCK_TICKING, ENTITY_TICKING -> entity;
|
||||
+ case null -> null;
|
||||
+ };
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -398,7 +404,14 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
return Visibility.TICKING;
|
||||
}
|
||||
final FullChunkStatus entityStatus = ((ChunkSystemEntity)entity).moonrise$getChunkStatus();
|
||||
- return Visibility.fromFullChunkStatus(entityStatus == null ? FullChunkStatus.INACCESSIBLE : entityStatus);
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ return switch (entityStatus) {
|
||||
+ case INACCESSIBLE -> Visibility.HIDDEN;
|
||||
+ case FULL, BLOCK_TICKING -> Visibility.TRACKED;
|
||||
+ case ENTITY_TICKING -> Visibility.TICKING;
|
||||
+ case null -> Visibility.HIDDEN;
|
||||
+ };
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
}
|
||||
|
||||
protected boolean addEntity(final Entity entity, final boolean fromDisk, final boolean event) {
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
index 57fec1f9a210d2ecb74ff7b05cec790ae77f9178..4d0e904d7d7659b24a883893cef167f3e80dfa36 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
|
||||
@@ -73,37 +73,51 @@ public final class ChunkHolderManager {
|
||||
private static final long NO_TIMEOUT_MARKER = Long.MIN_VALUE;
|
||||
public final ReentrantAreaLock ticketLockArea;
|
||||
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
|
||||
+ private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F);
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
final ChunkUnloadQueue unloadQueue;
|
||||
|
||||
- private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(16384, 0.25f);
|
||||
+ private final ConcurrentLong2ReferenceChainedHashTable<NewChunkHolder> chunkHolders = ConcurrentLong2ReferenceChainedHashTable.createWithCapacity(20, 0.9F); // DivineMC - Optimize Moonrise
|
||||
private final ServerLevel world;
|
||||
private final ChunkTaskScheduler taskScheduler;
|
||||
private long currentTick;
|
||||
|
||||
- private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
|
||||
- private final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>();
|
||||
- private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
|
||||
- if (c1 == c2) {
|
||||
- return 0;
|
||||
- }
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ public static class LevelHolderData {
|
||||
+ private final java.util.concurrent.ConcurrentLinkedDeque<NewChunkHolder> pendingFullLoadUpdate = new java.util.concurrent.ConcurrentLinkedDeque<>();
|
||||
+ private final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>();
|
||||
+ 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");
|
||||
+ }
|
||||
+
|
||||
+ return Long.compare(coord1, coord2);
|
||||
+ });
|
||||
+ }
|
||||
|
||||
- if (coord1 == coord2) {
|
||||
- throw new IllegalStateException("Duplicate chunkholder in auto save queue");
|
||||
+ public LevelHolderData getData() {
|
||||
+ if (this.world == null) {
|
||||
+ throw new RuntimeException("World was null!");
|
||||
}
|
||||
|
||||
- return Long.compare(coord1, coord2);
|
||||
- });
|
||||
+ return world.chunkHolderData;
|
||||
+ }
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
|
||||
private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> ticketCounters = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
|
||||
@@ -226,26 +240,29 @@ public final class ChunkHolderManager {
|
||||
this.taskScheduler.setShutdown(true);
|
||||
}
|
||||
|
||||
- void ensureInAutosave(final NewChunkHolder holder) {
|
||||
- if (!this.autoSaveQueue.contains(holder)) {
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ 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) {
|
||||
@@ -259,10 +276,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 - Optimize Moonrise
|
||||
|
||||
public void saveAllChunks(final boolean flush, final boolean shutdown, final boolean logProgress) {
|
||||
final List<NewChunkHolder> holders = this.getChunkHolders();
|
||||
@@ -461,8 +479,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 - Optimize Moonrise
|
||||
+ final long coord = iterator.next(); // DivineMC - Optimize Moonrise
|
||||
sections.computeIfAbsent(
|
||||
CoordinateUtils.getChunkKey(
|
||||
CoordinateUtils.getChunkX(coord) >> sectionShift,
|
||||
@@ -559,7 +577,7 @@ public final class ChunkHolderManager {
|
||||
chunkZ >> sectionShift
|
||||
);
|
||||
|
||||
- this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (final long keyInMap) -> {
|
||||
+ this.sectionToChunkToExpireCount.computeIfAbsent(sectionKey, (keyInMap) -> { // DivineMC - Optimize Moonrise
|
||||
return new Long2IntOpenHashMap();
|
||||
}).addTo(chunkKey, 1);
|
||||
}
|
||||
@@ -603,8 +621,8 @@ 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) -> {
|
||||
- return (SortedArraySet)SortedArraySet.create(4);
|
||||
+ final SortedArraySet<Ticket> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (keyInMap) -> { // DivineMC - Optimize Moonrise
|
||||
+ return SortedArraySet.create(4); // DivineMC - Optimize Moonrise
|
||||
});
|
||||
|
||||
final int levelBefore = getTicketLevelAt(ticketsAtChunk);
|
||||
@@ -784,8 +802,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 - Optimize Moonrise
|
||||
+ final long coord = iterator.next(); // DivineMC - Optimize Moonrise
|
||||
sections.computeIfAbsent(
|
||||
CoordinateUtils.getChunkKey(
|
||||
CoordinateUtils.getChunkX(coord) >> sectionShift,
|
||||
@@ -836,8 +854,8 @@ public final class ChunkHolderManager {
|
||||
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
||||
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
||||
|
||||
- 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 - Optimize Moonrise
|
||||
+ final long sectionKey = iterator.next(); // DivineMC - Optimize Moonrise
|
||||
|
||||
if (!this.sectionToChunkToExpireCount.containsKey(sectionKey)) {
|
||||
// removed concurrently
|
||||
@@ -1145,18 +1163,18 @@ public final class ChunkHolderManager {
|
||||
if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableParallelWorldTicking && !TickThread.isTickThreadFor(world) || !TickThread.isTickThread()) { // DivineMC - Parallel world ticking
|
||||
// These will be handled on the next ServerChunkCache$MainThreadExecutor#pollTask, as it runs the distance manager update
|
||||
// which will invoke processTicketUpdates
|
||||
- this.offThreadPendingFullLoadUpdate.addAll(changedFullStatus);
|
||||
+ this.getData().offThreadPendingFullLoadUpdate.addAll(changedFullStatus); // DivineMC - Optimize Moonrise
|
||||
} else {
|
||||
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Optimize Moonrise
|
||||
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 - Optimize Moonrise
|
||||
holder.onUnload();
|
||||
- this.autoSaveQueue.remove(holder);
|
||||
+ this.getData().autoSaveQueue.remove(holder); // DivineMC - Optimize Moonrise
|
||||
PlatformHooks.get().onChunkHolderDelete(this.world, holder.vanillaChunkHolder);
|
||||
this.chunkHolders.remove(CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ));
|
||||
}
|
||||
@@ -1320,6 +1338,27 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ 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 - Optimize Moonrise
|
||||
+
|
||||
public enum TicketOperationType {
|
||||
ADD, REMOVE, ADD_IF_REMOVED, ADD_AND_REMOVE
|
||||
}
|
||||
@@ -1479,8 +1518,10 @@ public final class ChunkHolderManager {
|
||||
|
||||
// only call on tick thread
|
||||
private void processOffThreadFullUpdates() {
|
||||
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||
- final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = this.offThreadPendingFullLoadUpdate;
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ final java.util.concurrent.ConcurrentLinkedDeque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate;
|
||||
+ final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = this.getData().offThreadPendingFullLoadUpdate;
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
|
||||
NewChunkHolder toUpdate;
|
||||
while ((toUpdate = offThreadPendingFullLoadUpdate.poll()) != null) {
|
||||
@@ -1492,7 +1533,7 @@ public final class ChunkHolderManager {
|
||||
private boolean processPendingFullUpdate() {
|
||||
this.processOffThreadFullUpdates();
|
||||
|
||||
- final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||
+ final java.util.Deque<NewChunkHolder> pendingFullLoadUpdate = this.getData().pendingFullLoadUpdate; // DivineMC - Optimize Moonrise
|
||||
|
||||
boolean ret = false;
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
|
||||
index 2cc0e7c72d2b2e562452138f2b41fd1dcaf0570a..affa0dac8633ce3a43c9609888ed96d0aabdab5e 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/NewChunkHolder.java
|
||||
@@ -646,12 +646,20 @@ public final class NewChunkHolder {
|
||||
}
|
||||
|
||||
public final ChunkHolder vanillaChunkHolder;
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ private final long cachedLongPos;
|
||||
+
|
||||
+ public long getCachedLongPos() {
|
||||
+ return cachedLongPos;
|
||||
+ }
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
|
||||
public NewChunkHolder(final ServerLevel world, final int chunkX, final int chunkZ, final ChunkTaskScheduler scheduler) {
|
||||
this.world = world;
|
||||
this.chunkX = chunkX;
|
||||
this.chunkZ = chunkZ;
|
||||
this.scheduler = scheduler;
|
||||
+ this.cachedLongPos = ((long)chunkZ << 32) | (chunkX & 0xFFFFFFFFL); // DivineMC - Optimize Moonrise
|
||||
this.vanillaChunkHolder = new ChunkHolder(
|
||||
new ChunkPos(chunkX, chunkZ), ChunkHolderManager.MAX_TICKET_LEVEL, world,
|
||||
world.getLightEngine(), null, world.getChunkSource().chunkMap
|
||||
@@ -792,9 +800,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 - Optimize Moonrise
|
||||
+ private volatile UnloadTask chunkDataUnload;
|
||||
+ private volatile UnloadTask entityDataUnload;
|
||||
+ private volatile UnloadTask poiDataUnload;
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
|
||||
public static final record UnloadTask(CallbackCompletable<CompoundTag> completable, PrioritisedExecutor.PrioritisedTask task,
|
||||
LazyRunnable toRun) {}
|
||||
@@ -879,7 +889,11 @@ public final class NewChunkHolder {
|
||||
MoonriseRegionFileIO.scheduleSave(this.world, this.chunkX, this.chunkZ, data, type);
|
||||
}
|
||||
|
||||
- this.getUnloadTask(type).completable().complete(data);
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ UnloadTask task = this.getUnloadTask(type);
|
||||
+ if (task == null) return;
|
||||
+ task.completable().complete(data);
|
||||
+ // DivineMC end - Optimize Moonrise
|
||||
final ReentrantAreaLock.Node schedulingLock = this.scheduler.schedulingLockArea.lock(this.chunkX, this.chunkZ);
|
||||
try {
|
||||
// can only write to these fields while holding the schedule lock
|
||||
@@ -1192,6 +1206,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 - Optimize Moonrise
|
||||
if (loaded) {
|
||||
if (holder.setNeighbourFullLoaded(-dx, -dz)) {
|
||||
changedFullStatus.add(holder);
|
||||
@@ -1216,6 +1231,19 @@ public final class NewChunkHolder {
|
||||
|
||||
private void updateCurrentState(final FullChunkStatus to) {
|
||||
this.currentFullChunkStatus = to;
|
||||
+ // DivineMC start - Optimize Moonrise
|
||||
+ 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 - Optimize Moonrise
|
||||
}
|
||||
|
||||
// only to be called on the main thread, no locks need to be held
|
||||
@@ -1350,7 +1378,7 @@ public final class NewChunkHolder {
|
||||
return this.requestedGenStatus;
|
||||
}
|
||||
|
||||
- private final Reference2ObjectOpenHashMap<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = new Reference2ObjectOpenHashMap<>();
|
||||
+ private final Reference2ObjectMap<ChunkStatus, List<Consumer<ChunkAccess>>> statusWaiters = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>()); // DivineMC - Optimize Moonrise
|
||||
|
||||
void addStatusConsumer(final ChunkStatus status, final Consumer<ChunkAccess> consumer) {
|
||||
this.statusWaiters.computeIfAbsent(status, (final ChunkStatus keyInMap) -> {
|
||||
@@ -1396,7 +1424,7 @@ public final class NewChunkHolder {
|
||||
}, Priority.HIGHEST);
|
||||
}
|
||||
|
||||
- private final Reference2ObjectOpenHashMap<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = new Reference2ObjectOpenHashMap<>();
|
||||
+ private final Reference2ObjectMap<FullChunkStatus, List<Consumer<LevelChunk>>> fullStatusWaiters = it.unimi.dsi.fastutil.objects.Reference2ObjectMaps.synchronize(new Reference2ObjectOpenHashMap<>()); // DivineMC - Optimize Moonrise
|
||||
|
||||
void addFullStatusConsumer(final FullChunkStatus status, final Consumer<LevelChunk> consumer) {
|
||||
this.fullStatusWaiters.computeIfAbsent(status, (final FullChunkStatus keyInMap) -> {
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java b/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
|
||||
index 93fd23027c00cef76562098306737272fda1350a..10c9aecb99bc3055104f50266542e249dc842ee7 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/util/ParallelSearchRadiusIteration.java
|
||||
@@ -23,6 +23,7 @@ public final class ParallelSearchRadiusIteration {
|
||||
}
|
||||
|
||||
public static long[] getSearchIteration(final int radius) {
|
||||
+ if (radius >= SEARCH_RADIUS_ITERATION_LIST.length) return SEARCH_RADIUS_ITERATION_LIST[SEARCH_RADIUS_ITERATION_LIST.length - 1]; // DivineMC - Optimize Moonrise
|
||||
return SEARCH_RADIUS_ITERATION_LIST[radius];
|
||||
}
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java b/ca/spottedleaf/moonrise/patches/starlight/light/SWMRNibbleArray.java
|
||||
index 4ca68a903e67606fc4ef0bfa9862a73797121c8b..1ac37db68341672481cd4bbdf7bab90572c35453 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 - Optimize Moonrise
|
||||
if (!this.isDirty()) {
|
||||
return false;
|
||||
}
|
||||
diff --git a/net/minecraft/server/level/DistanceManager.java b/net/minecraft/server/level/DistanceManager.java
|
||||
index 50bc5b940812432bc472e5b272582efb8bbfc7a7..0bece4ed69b332174cbe37f82df1f7da9276d591 100644
|
||||
--- a/net/minecraft/server/level/DistanceManager.java
|
||||
+++ b/net/minecraft/server/level/DistanceManager.java
|
||||
@@ -127,15 +127,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 - Optimize Moonrise
|
||||
// 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 - Optimize Moonrise
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 45bf13dc23b886ea2d660c38c74becf0e3754963..b05fb5946564264771f998cff418513916eb6adb 100644
|
||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||
@@ -672,8 +672,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 - Optimize Moonrise
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index 4934ce03ac533d9c60674632cdac6621e62f6b44..b50afea7c2e4c61a3df196e74afd8f82b30aca8a 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -179,6 +179,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 - Optimize Moonrise
|
||||
private int lastSpawnChunkRadius;
|
||||
final EntityTickList entityTickList = new EntityTickList(this); // DivineMC - Parallel world ticking
|
||||
private final ServerWaypointManager waypointManager;
|
||||
@@ -691,6 +692,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 - Optimize Moonrise
|
||||
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"),
|
||||
@@ -846,8 +848,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 - Optimize Moonrise
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
|
||||
@@ -2584,16 +2585,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
|
||||
public 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 - Optimize Moonrise
|
||||
// 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 - Optimize Moonrise
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 27 Aug 2025 22:48:22 +0300
|
||||
Subject: [PATCH] lithium: combined_heightmap_update
|
||||
|
||||
This patch is based on the following mixins:
|
||||
* "net/caffeinemc/mods/lithium/mixin/world/combined_heightmap_update/LevelChunkMixin"
|
||||
By: 2No2Name <2No2Name@web.de>
|
||||
As part of: Lithium (https://github.com/CaffeineMC/lithium)
|
||||
Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
index 3dcdafe18085fc8fff9eb5bb50392ba13a27b066..9cd2a05683d879f56b6e62dfd49ac30341deeb06 100644
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -380,10 +380,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
|
||||
return null;
|
||||
} else {
|
||||
Block block = state.getBlock();
|
||||
- this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING).update(i, y, i2, state);
|
||||
- this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES).update(i, y, i2, state);
|
||||
- this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR).update(i, y, i2, state);
|
||||
- this.heightmaps.get(Heightmap.Types.WORLD_SURFACE).update(i, y, i2, state);
|
||||
+ // DivineMC start - lithium: combined_heightmap_update
|
||||
+ Heightmap heightmap0 = this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING);
|
||||
+ Heightmap heightmap1 = this.heightmaps.get(Heightmap.Types.MOTION_BLOCKING_NO_LEAVES);
|
||||
+ Heightmap heightmap2 = this.heightmaps.get(Heightmap.Types.OCEAN_FLOOR);
|
||||
+ Heightmap heightmap3 = this.heightmaps.get(Heightmap.Types.WORLD_SURFACE);
|
||||
+ net.caffeinemc.mods.lithium.common.world.chunk.heightmap.CombinedHeightmapUpdate.updateHeightmaps(heightmap0, heightmap1, heightmap2, heightmap3, this, i, y, i2, state);
|
||||
+ // DivineMC end - lithium: combined_heightmap_update
|
||||
boolean hasOnlyAir1 = section.hasOnlyAir();
|
||||
if (hasOnlyAir != hasOnlyAir1) {
|
||||
this.level.getChunkSource().getLightEngine().updateSectionStatus(pos, hasOnlyAir1);
|
||||
diff --git a/net/minecraft/world/level/levelgen/Heightmap.java b/net/minecraft/world/level/levelgen/Heightmap.java
|
||||
index 5fc80f67cd76bb557e2f629d91b5c6538b660d28..28681630564fa4c4527280537e334c9e62c274a7 100644
|
||||
--- a/net/minecraft/world/level/levelgen/Heightmap.java
|
||||
+++ b/net/minecraft/world/level/levelgen/Heightmap.java
|
||||
@@ -123,6 +123,12 @@ public class Heightmap {
|
||||
this.data.set(getIndex(x, z), value - this.chunk.getMinY());
|
||||
}
|
||||
|
||||
+ // DivineMC start - lithium: combined_heightmap_update
|
||||
+ public final Predicate<BlockState> isOpaque() {
|
||||
+ return this.isOpaque;
|
||||
+ }
|
||||
+ // DivineMC end - lithium: combined_heightmap_update
|
||||
+
|
||||
public void setRawData(ChunkAccess chunk, Heightmap.Types type, long[] data) {
|
||||
long[] raw = this.data.getRaw();
|
||||
if (raw.length == data.length) {
|
||||
@@ -1,180 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 8 Sep 2025 00:53:55 +0300
|
||||
Subject: [PATCH] Entity Status Lock
|
||||
|
||||
|
||||
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..5b3e8951c619cc2af023d13c2067b8d3df9e76e3 100644
|
||||
--- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java
|
||||
@@ -225,8 +225,10 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
}
|
||||
|
||||
+ private final java.util.concurrent.locks.ReentrantLock statusLock = new java.util.concurrent.locks.ReentrantLock(); // DivineMC - Entity Status Lock
|
||||
private boolean preventStatusUpdates;
|
||||
public boolean startPreventingStatusUpdates() {
|
||||
+ this.statusLock.lock(); // DivineMC - Entity Status Lock
|
||||
final boolean ret = this.preventStatusUpdates;
|
||||
this.preventStatusUpdates = true;
|
||||
return ret;
|
||||
@@ -238,85 +240,107 @@ public final class ChunkEntitySlices {
|
||||
|
||||
public void stopPreventingStatusUpdates(final boolean prev) {
|
||||
this.preventStatusUpdates = prev;
|
||||
+ this.statusLock.unlock(); // DivineMC - Entity Status Lock
|
||||
}
|
||||
|
||||
public void updateStatus(final FullChunkStatus status, final EntityLookup lookup) {
|
||||
- this.status = status;
|
||||
+ // DivineMC start - Entity Status Lock
|
||||
+ this.statusLock.lock();
|
||||
+ try {
|
||||
+ this.status = status;
|
||||
|
||||
- final Entity[] entities = this.entities.getRawData();
|
||||
+ final Entity[] entities = this.entities.getRawData();
|
||||
|
||||
- for (int i = 0, size = this.entities.size(); i < size; ++i) {
|
||||
- final Entity entity = entities[i];
|
||||
+ for (int i = 0, size = this.entities.size(); i < size; ++i) {
|
||||
+ final Entity entity = entities[i];
|
||||
|
||||
- final Visibility oldVisibility = EntityLookup.getEntityStatus(entity);
|
||||
- ((ChunkSystemEntity)entity).moonrise$setChunkStatus(status);
|
||||
- final Visibility newVisibility = EntityLookup.getEntityStatus(entity);
|
||||
+ final Visibility oldVisibility = EntityLookup.getEntityStatus(entity);
|
||||
+ ((ChunkSystemEntity) entity).moonrise$setChunkStatus(status);
|
||||
+ final Visibility newVisibility = EntityLookup.getEntityStatus(entity);
|
||||
|
||||
- lookup.entityStatusChange(entity, this, oldVisibility, newVisibility, false, false, false);
|
||||
+ lookup.entityStatusChange(entity, this, oldVisibility, newVisibility, false, false, false);
|
||||
+ }
|
||||
+ } finally {
|
||||
+ this.statusLock.unlock();
|
||||
}
|
||||
+ // DivineMC end - Entity Status Lock
|
||||
}
|
||||
|
||||
public boolean addEntity(final Entity entity, final int chunkSection) {
|
||||
- if (!this.entities.add(entity)) {
|
||||
- return false;
|
||||
- }
|
||||
- ((ChunkSystemEntity)entity).moonrise$setChunkStatus(this.status);
|
||||
- ((ChunkSystemEntity)entity).moonrise$setChunkData(this.chunkData);
|
||||
- final int sectionIndex = chunkSection - this.minSection;
|
||||
+ // DivineMC start - Entity Status Lock
|
||||
+ this.statusLock.lock();
|
||||
+ try {
|
||||
+ if (!this.entities.add(entity)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ ((ChunkSystemEntity) entity).moonrise$setChunkStatus(this.status);
|
||||
+ ((ChunkSystemEntity) entity).moonrise$setChunkData(this.chunkData);
|
||||
+ final int sectionIndex = chunkSection - this.minSection;
|
||||
|
||||
- this.allEntities.addEntity(entity, sectionIndex);
|
||||
+ this.allEntities.addEntity(entity, sectionIndex);
|
||||
|
||||
- if (((ChunkSystemEntity)entity).moonrise$isHardColliding()) {
|
||||
- this.hardCollidingEntities.addEntity(entity, sectionIndex);
|
||||
- }
|
||||
+ if (((ChunkSystemEntity) entity).moonrise$isHardColliding()) {
|
||||
+ this.hardCollidingEntities.addEntity(entity, sectionIndex);
|
||||
+ }
|
||||
|
||||
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
|
||||
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
|
||||
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
|
||||
+ for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
|
||||
+ this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext(); ) {
|
||||
+ final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
|
||||
|
||||
- if (entry.getKey().isInstance(entity)) {
|
||||
- entry.getValue().addEntity(entity, sectionIndex);
|
||||
+ if (entry.getKey().isInstance(entity)) {
|
||||
+ entry.getValue().addEntity(entity, sectionIndex);
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
|
||||
- EntityCollectionBySection byType = this.entitiesByType.get(entity.getType());
|
||||
- if (byType != null) {
|
||||
- byType.addEntity(entity, sectionIndex);
|
||||
- } else {
|
||||
- this.entitiesByType.put(entity.getType(), byType = new EntityCollectionBySection(this));
|
||||
- byType.addEntity(entity, sectionIndex);
|
||||
- }
|
||||
+ EntityCollectionBySection byType = this.entitiesByType.get(entity.getType());
|
||||
+ if (byType != null) {
|
||||
+ byType.addEntity(entity, sectionIndex);
|
||||
+ } else {
|
||||
+ this.entitiesByType.put(entity.getType(), byType = new EntityCollectionBySection(this));
|
||||
+ byType.addEntity(entity, sectionIndex);
|
||||
+ }
|
||||
|
||||
- return true;
|
||||
+ return true;
|
||||
+ } finally {
|
||||
+ this.statusLock.unlock();
|
||||
+ }
|
||||
+ // DivineMC end - Entity Status Lock
|
||||
}
|
||||
|
||||
public boolean removeEntity(final Entity entity, final int chunkSection) {
|
||||
- if (!this.entities.remove(entity)) {
|
||||
- return false;
|
||||
- }
|
||||
- ((ChunkSystemEntity)entity).moonrise$setChunkStatus(null);
|
||||
- ((ChunkSystemEntity)entity).moonrise$setChunkData(null);
|
||||
- final int sectionIndex = chunkSection - this.minSection;
|
||||
+ // DivineMC start - Entity Status Lock
|
||||
+ this.statusLock.lock();
|
||||
+ try {
|
||||
+ if (!this.entities.remove(entity)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+ ((ChunkSystemEntity) entity).moonrise$setChunkStatus(null);
|
||||
+ ((ChunkSystemEntity) entity).moonrise$setChunkData(null);
|
||||
+ final int sectionIndex = chunkSection - this.minSection;
|
||||
|
||||
- this.allEntities.removeEntity(entity, sectionIndex);
|
||||
+ this.allEntities.removeEntity(entity, sectionIndex);
|
||||
|
||||
- if (((ChunkSystemEntity)entity).moonrise$isHardColliding()) {
|
||||
- this.hardCollidingEntities.removeEntity(entity, sectionIndex);
|
||||
- }
|
||||
+ if (((ChunkSystemEntity) entity).moonrise$isHardColliding()) {
|
||||
+ this.hardCollidingEntities.removeEntity(entity, sectionIndex);
|
||||
+ }
|
||||
|
||||
- for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
|
||||
- this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
|
||||
- final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
|
||||
+ for (final Iterator<Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection>> iterator =
|
||||
+ this.entitiesByClass.reference2ObjectEntrySet().fastIterator(); iterator.hasNext(); ) {
|
||||
+ final Reference2ObjectMap.Entry<Class<? extends Entity>, EntityCollectionBySection> entry = iterator.next();
|
||||
|
||||
- if (entry.getKey().isInstance(entity)) {
|
||||
- entry.getValue().removeEntity(entity, sectionIndex);
|
||||
+ if (entry.getKey().isInstance(entity)) {
|
||||
+ entry.getValue().removeEntity(entity, sectionIndex);
|
||||
+ }
|
||||
}
|
||||
- }
|
||||
|
||||
- final EntityCollectionBySection byType = this.entitiesByType.get(entity.getType());
|
||||
- byType.removeEntity(entity, sectionIndex);
|
||||
+ final EntityCollectionBySection byType = this.entitiesByType.get(entity.getType());
|
||||
+ byType.removeEntity(entity, sectionIndex);
|
||||
|
||||
- return true;
|
||||
+ return true;
|
||||
+ } finally {
|
||||
+ this.statusLock.unlock();
|
||||
+ }
|
||||
+ // DivineMC end - Entity Status Lock
|
||||
}
|
||||
|
||||
public void getHardCollidingEntities(final Entity except, final AABB box, final List<Entity> into, final Predicate<? super Entity> predicate) {
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,250 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 1 Oct 2025 01:49:00 +0300
|
||||
Subject: [PATCH] lithium: equipment_tracking
|
||||
|
||||
This patch is based on the following mixins:
|
||||
* "net/caffeinemc/mods/lithium/mixin/util/item_component_and_count_tracking/PatchedDataComponentMapMixin.java"
|
||||
* "net/caffeinemc/mods/lithium/mixin/util/item_component_and_count_tracking/ItemStackMixin.java"
|
||||
* "net/caffeinemc/mods/lithium/mixin/entity/equipment_tracking/enchantment_ticking/LivingEntityMixin.java"
|
||||
* "net/caffeinemc/mods/lithium/mixin/entity/equipment_tracking/equipment_changes/LivingEntityMixin.java"
|
||||
* "net/caffeinemc/mods/lithium/mixin/entity/equipment_tracking/EntityEquipmentMixin.java"
|
||||
* "net/caffeinemc/mods/lithium/common/util/change_tracking/ChangePublisher.java"
|
||||
* "net/caffeinemc/mods/lithium/common/util/change_tracking/ChangeSubscriber.java"
|
||||
By: 2No2Name <2No2Name@web.de>
|
||||
As part of: Lithium (https://github.com/CaffeineMC/lithium)
|
||||
Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
|
||||
|
||||
diff --git a/net/minecraft/world/entity/EntityEquipment.java b/net/minecraft/world/entity/EntityEquipment.java
|
||||
index 90814ad07a2686c5a274860395f5aca29cc3bf13..21119ff49d6d59aff48ce9fbf76a51fa296cd1c1 100644
|
||||
--- a/net/minecraft/world/entity/EntityEquipment.java
|
||||
+++ b/net/minecraft/world/entity/EntityEquipment.java
|
||||
@@ -7,7 +7,7 @@ import java.util.Objects;
|
||||
import java.util.Map.Entry;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
-public class EntityEquipment {
|
||||
+public class EntityEquipment implements net.caffeinemc.mods.lithium.common.util.change_tracking.ChangeSubscriber.CountChangeSubscriber<net.minecraft.world.item.ItemStack> { // DivineMC - lithium: equipment_tracking
|
||||
public static final Codec<EntityEquipment> CODEC = Codec.unboundedMap(EquipmentSlot.CODEC, ItemStack.CODEC).xmap(map -> {
|
||||
EnumMap<EquipmentSlot, ItemStack> map1 = new EnumMap<>(EquipmentSlot.class);
|
||||
map1.putAll((Map<? extends EquipmentSlot, ? extends ItemStack>)map);
|
||||
@@ -18,6 +18,11 @@ public class EntityEquipment {
|
||||
return map;
|
||||
});
|
||||
private final EnumMap<EquipmentSlot, ItemStack> items;
|
||||
+ // DivineMC start - lithium: equipment_tracking
|
||||
+ boolean shouldTickEnchantments = false;
|
||||
+ ItemStack recheckEnchantmentForStack = null;
|
||||
+ boolean hasUnsentEquipmentChanges = true;
|
||||
+ // DivineMC end - lithium: equipment_tracking
|
||||
|
||||
private EntityEquipment(EnumMap<EquipmentSlot, ItemStack> items) {
|
||||
this.items = items;
|
||||
@@ -29,7 +34,13 @@ public class EntityEquipment {
|
||||
|
||||
public ItemStack set(EquipmentSlot slot, ItemStack stack) {
|
||||
stack.getItem().verifyComponentsAfterLoad(stack);
|
||||
- return Objects.requireNonNullElse(this.items.put(slot, stack), ItemStack.EMPTY);
|
||||
+ // DivineMC start - lithium: equipment_tracking
|
||||
+ ItemStack oldStack = Objects.requireNonNullElse(this.items.put(slot, stack), ItemStack.EMPTY);
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
|
||||
+ this.onEquipmentReplaced(oldStack, stack);
|
||||
+ }
|
||||
+ return oldStack;
|
||||
+ // DivineMC end - lithium: equipment_tracking
|
||||
}
|
||||
|
||||
public ItemStack get(EquipmentSlot slot) {
|
||||
@@ -56,8 +67,23 @@ public class EntityEquipment {
|
||||
}
|
||||
|
||||
public void setAll(EntityEquipment equipment) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.onClear(); // DivineMC - lithium: equipment_tracking
|
||||
this.items.clear();
|
||||
this.items.putAll(equipment.items);
|
||||
+ // DivineMC start - lithium: equipment_tracking
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
|
||||
+ for (net.minecraft.world.item.ItemStack newStack : this.items.values()) {
|
||||
+ if (!newStack.isEmpty()) {
|
||||
+ if (!this.shouldTickEnchantments) {
|
||||
+ this.shouldTickEnchantments = stackHasTickableEnchantment(newStack);
|
||||
+ }
|
||||
+ if (!newStack.isEmpty()) {
|
||||
+ newStack.lithium$subscribe(this, 0);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - lithium: equipment_tracking
|
||||
}
|
||||
|
||||
public void dropAll(LivingEntity entity) {
|
||||
@@ -70,6 +96,7 @@ public class EntityEquipment {
|
||||
|
||||
public void clear() {
|
||||
this.items.replaceAll((equipmentSlot, itemStack) -> ItemStack.EMPTY);
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.onClear(); // DivineMC - lithium: equipment_tracking
|
||||
}
|
||||
|
||||
// Paper start - EntityDeathEvent
|
||||
@@ -78,4 +105,98 @@ public class EntityEquipment {
|
||||
return this.items.containsKey(slot);
|
||||
}
|
||||
// Paper end - EntityDeathEvent
|
||||
+
|
||||
+ // DivineMC start - lithium: equipment_tracking
|
||||
+ public boolean lithium$shouldTickEnchantments() {
|
||||
+ this.processScheduledEnchantmentCheck(null);
|
||||
+ return this.shouldTickEnchantments;
|
||||
+ }
|
||||
+
|
||||
+ public boolean lithium$hasUnsentEquipmentChanges() {
|
||||
+ return this.hasUnsentEquipmentChanges;
|
||||
+ }
|
||||
+
|
||||
+ public void lithium$onEquipmentChangesSent() {
|
||||
+ this.hasUnsentEquipmentChanges = false;
|
||||
+ }
|
||||
+
|
||||
+ private void onClear() {
|
||||
+ this.shouldTickEnchantments = false;
|
||||
+ this.recheckEnchantmentForStack = null;
|
||||
+ this.hasUnsentEquipmentChanges = true;
|
||||
+
|
||||
+ for (ItemStack oldStack : this.items.values()) {
|
||||
+ if (!oldStack.isEmpty()) {
|
||||
+ oldStack.lithium$unsubscribeWithData(this, 0);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void onEquipmentReplaced(ItemStack oldStack, ItemStack newStack) {
|
||||
+ if (!this.shouldTickEnchantments) {
|
||||
+ if (this.recheckEnchantmentForStack == oldStack) {
|
||||
+ this.recheckEnchantmentForStack = null;
|
||||
+ }
|
||||
+ this.shouldTickEnchantments = stackHasTickableEnchantment(newStack);
|
||||
+ }
|
||||
+
|
||||
+ this.hasUnsentEquipmentChanges = true;
|
||||
+
|
||||
+ if (!oldStack.isEmpty()) {
|
||||
+ oldStack.lithium$unsubscribeWithData(this, 0);
|
||||
+ }
|
||||
+ if (!newStack.isEmpty()) {
|
||||
+ newStack.lithium$subscribe(this, 0);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private static boolean stackHasTickableEnchantment(ItemStack stack) {
|
||||
+ if (!stack.isEmpty()) {
|
||||
+ net.minecraft.world.item.enchantment.ItemEnchantments enchantments = stack.get(net.minecraft.core.component.DataComponents.ENCHANTMENTS);
|
||||
+ if (enchantments != null && !enchantments.isEmpty()) {
|
||||
+ for (net.minecraft.core.Holder<net.minecraft.world.item.enchantment.Enchantment> enchantmentEntry : enchantments.keySet()) {
|
||||
+ if (!enchantmentEntry.value().getEffects(net.minecraft.world.item.enchantment.EnchantmentEffectComponents.TICK).isEmpty()) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void lithium$notify(@org.jetbrains.annotations.Nullable ItemStack publisher, int zero) {
|
||||
+ this.hasUnsentEquipmentChanges = true;
|
||||
+
|
||||
+ if (!this.shouldTickEnchantments) {
|
||||
+ this.processScheduledEnchantmentCheck(publisher);
|
||||
+ this.scheduleEnchantmentCheck(publisher);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private void scheduleEnchantmentCheck(@org.jetbrains.annotations.Nullable ItemStack toCheck) {
|
||||
+ this.recheckEnchantmentForStack = toCheck;
|
||||
+ }
|
||||
+
|
||||
+ private void processScheduledEnchantmentCheck(@org.jetbrains.annotations.Nullable ItemStack ignoredStack) {
|
||||
+ if (this.recheckEnchantmentForStack != null && this.recheckEnchantmentForStack != ignoredStack) {
|
||||
+ this.shouldTickEnchantments = stackHasTickableEnchantment(this.recheckEnchantmentForStack);
|
||||
+ this.recheckEnchantmentForStack = null;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void lithium$notifyCount(ItemStack publisher, int zero, int newCount) {
|
||||
+ if (newCount == 0) {
|
||||
+ publisher.lithium$unsubscribeWithData(this, zero);
|
||||
+ }
|
||||
+
|
||||
+ this.onEquipmentReplaced(publisher, ItemStack.EMPTY);
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void lithium$forceUnsubscribe(ItemStack publisher, int zero) {
|
||||
+ throw new UnsupportedOperationException();
|
||||
+ }
|
||||
+ // DivineMC end - lithium: equipment_tracking
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
||||
index e903e60c8914899d9be14cce9fdef9cc33ee71d5..1e27701cf4de424ee9685bd061afc9706996e8da 100644
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -433,9 +433,17 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
this.getSleepingPos().ifPresent(this::setPosToBed);
|
||||
}
|
||||
|
||||
- if (this.level() instanceof ServerLevel serverLevel) {
|
||||
- EnchantmentHelper.tickEffects(serverLevel, this);
|
||||
+ // DivineMC start - lithium: equipment_tracking
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
|
||||
+ if ((this instanceof Player || this.equipment.lithium$shouldTickEnchantments()) && this.level() instanceof ServerLevel serverLevel) {
|
||||
+ EnchantmentHelper.tickEffects(serverLevel, this);
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (this.level() instanceof ServerLevel serverLevel) {
|
||||
+ EnchantmentHelper.tickEffects(serverLevel, this);
|
||||
+ }
|
||||
}
|
||||
+ // DivineMC end - lithium: equipment_tracking
|
||||
|
||||
super.baseTick();
|
||||
if (this.fireImmune() || this.level().isClientSide) {
|
||||
@@ -3413,6 +3421,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
public void detectEquipmentUpdates() {
|
||||
Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges();
|
||||
if (map != null) {
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking && !(this instanceof net.minecraft.world.entity.player.Player)) this.equipment.lithium$onEquipmentChangesSent(); // DivineMC - lithium: equipment_tracking
|
||||
this.handleHandSwap(map);
|
||||
if (!map.isEmpty()) {
|
||||
this.handleEquipmentChanges(map);
|
||||
@@ -3422,6 +3431,14 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
||||
|
||||
@Nullable
|
||||
private Map<EquipmentSlot, ItemStack> collectEquipmentChanges() {
|
||||
+ // DivineMC start - lithium: equipment_tracking
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) {
|
||||
+ final boolean isArmorStandUpdateNoTick = this instanceof net.minecraft.world.entity.decoration.ArmorStand stand && !stand.canTick && stand.noTickEquipmentDirty;
|
||||
+ if (!isArmorStandUpdateNoTick && !this.equipment.lithium$hasUnsentEquipmentChanges()) {
|
||||
+ return null;
|
||||
+ }
|
||||
+ }
|
||||
+ // DivineMC end - lithium: equipment_tracking
|
||||
Map<EquipmentSlot, ItemStack> map = null;
|
||||
// Paper start - EntityEquipmentChangedEvent
|
||||
record EquipmentChangeImpl(org.bukkit.inventory.ItemStack oldItem, org.bukkit.inventory.ItemStack newItem) implements io.papermc.paper.event.entity.EntityEquipmentChangedEvent.EquipmentChange {
|
||||
diff --git a/net/minecraft/world/entity/decoration/ArmorStand.java b/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
index 83fdd22eeb141079e05018ebf5cef70e7eb78726..81f6d57e6bd225998f4c44a78b4aab2166fde1f0 100644
|
||||
--- a/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
+++ b/net/minecraft/world/entity/decoration/ArmorStand.java
|
||||
@@ -528,8 +528,9 @@ public class ArmorStand extends LivingEntity {
|
||||
maxUpStep = level().purpurConfig.armorstandStepHeight; // Purpur - Add option to set armorstand step height
|
||||
if (!this.canTick) {
|
||||
if (this.noTickEquipmentDirty) {
|
||||
- this.noTickEquipmentDirty = false;
|
||||
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.noTickEquipmentDirty = false; // DivineMC - lithium: equipment_tracking
|
||||
this.detectEquipmentUpdates();
|
||||
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.equipmentTracking) this.noTickEquipmentDirty = false; // DivineMC - lithium: equipment_tracking
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -1,62 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: dan28000 <84990628+dan28000@users.noreply.github.com>
|
||||
Date: Mon, 6 Oct 2025 14:17:59 +0200
|
||||
Subject: [PATCH] Configurable-Files-Locations
|
||||
|
||||
|
||||
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
||||
index a0d45f72e7c35883996214a2c5420d6a996a58aa..2c6aa5bac80e6383f935e368eb1aa69ca4b46d70 100644
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -101,10 +101,12 @@ import net.minecraft.world.scores.Team;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
public abstract class PlayerList {
|
||||
- public static final File USERBANLIST_FILE = new File("banned-players.json");
|
||||
- public static final File IPBANLIST_FILE = new File("banned-ips.json");
|
||||
- public static final File OPLIST_FILE = new File("ops.json");
|
||||
- public static final File WHITELIST_FILE = new File("whitelist.json");
|
||||
+ // DivineMC - make configurable location of files start
|
||||
+ public static File USERBANLIST_FILE = new File("banned-players.json");
|
||||
+ public static File IPBANLIST_FILE = new File("banned-ips.json");
|
||||
+ public static File OPLIST_FILE = new File("ops.json");
|
||||
+ public static File WHITELIST_FILE = new File("whitelist.json");
|
||||
+ // DivineMC - make configurable location of files end
|
||||
public static final Component CHAT_FILTERED_FULL = Component.translatable("chat.filtered_full");
|
||||
public static final Component DUPLICATE_LOGIN_DISCONNECT_MESSAGE = Component.translatable("multiplayer.disconnect.duplicate_login");
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
@@ -113,10 +115,12 @@ public abstract class PlayerList {
|
||||
private final MinecraftServer server;
|
||||
public final List<ServerPlayer> players = new java.util.concurrent.CopyOnWriteArrayList(); // CraftBukkit - ArrayList -> CopyOnWriteArrayList: Iterator safety
|
||||
private final Map<UUID, ServerPlayer> playersByUUID = Maps.newHashMap();
|
||||
- private final UserBanList bans = new UserBanList(USERBANLIST_FILE);
|
||||
- private final IpBanList ipBans = new IpBanList(IPBANLIST_FILE);
|
||||
- private final ServerOpList ops = new ServerOpList(OPLIST_FILE);
|
||||
- private final UserWhiteList whitelist = new UserWhiteList(WHITELIST_FILE);
|
||||
+ // DivineMC - make configurable location of files start
|
||||
+ private final UserBanList bans;
|
||||
+ private final IpBanList ipBans;
|
||||
+ private final ServerOpList ops;
|
||||
+ private final UserWhiteList whitelist;
|
||||
+ // DivineMC - make configurable location of files end
|
||||
// CraftBukkit start
|
||||
// private final Map<UUID, ServerStatsCounter> stats = Maps.newHashMap();
|
||||
// private final Map<UUID, PlayerAdvancements> advancements = Maps.newHashMap();
|
||||
@@ -144,6 +148,17 @@ public abstract class PlayerList {
|
||||
this.registries = registries;
|
||||
this.maxPlayers = maxPlayers;
|
||||
this.playerIo = playerIo;
|
||||
+ // DivineMC - make configurable location of files start
|
||||
+ USERBANLIST_FILE = (File) server.options.valueOf("banned-players");
|
||||
+ IPBANLIST_FILE = (File) server.options.valueOf("banned-ips");
|
||||
+ OPLIST_FILE = (File) server.options.valueOf("ops");
|
||||
+ WHITELIST_FILE = (File) server.options.valueOf("whitelist");
|
||||
+
|
||||
+ bans = new UserBanList(USERBANLIST_FILE);
|
||||
+ ipBans = new IpBanList(IPBANLIST_FILE);
|
||||
+ ops = new ServerOpList(OPLIST_FILE);
|
||||
+ whitelist = new UserWhiteList(WHITELIST_FILE);
|
||||
+ // DivineMC - make configurable location of files end
|
||||
}
|
||||
|
||||
abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/core/BlockPos.java
|
||||
+++ b/net/minecraft/core/BlockPos.java
|
||||
@@ -347,7 +_,18 @@
|
||||
@@ -348,7 +_,18 @@
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/server/MinecraftServer.java
|
||||
+++ b/net/minecraft/server/MinecraftServer.java
|
||||
@@ -989,6 +_,13 @@
|
||||
@@ -973,6 +_,13 @@
|
||||
if (this.hasStopped) return;
|
||||
this.hasStopped = true;
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
||||
shutdownThread = Thread.currentThread(); // Paper - Improved watchdog support
|
||||
org.spigotmc.WatchdogThread.doStop(); // Paper - Improved watchdog support
|
||||
@@ -1080,6 +_,7 @@
|
||||
@@ -1065,6 +_,7 @@
|
||||
// Paper end - rewrite chunk system
|
||||
// Paper start - Improved watchdog support - move final shutdown items here
|
||||
Util.shutdownExecutors();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
||||
@@ -195,6 +_,26 @@
|
||||
@@ -287,6 +_,26 @@
|
||||
org.purpurmc.purpur.PurpurConfig.registerCommands();
|
||||
// Purpur end - Purpur config files
|
||||
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
||||
|
||||
+
|
||||
+ // DivineMC start - Pufferfish: SIMD Support
|
||||
+ try {
|
||||
+ gg.pufferfish.pufferfish.simd.SIMDDetection.isEnabled = gg.pufferfish.pufferfish.simd.SIMDDetection.canEnable(LOGGER);
|
||||
@@ -23,11 +24,10 @@
|
||||
+ LOGGER.warn("Debug: Java: {}, test run: {}", System.getProperty("java.version"), gg.pufferfish.pufferfish.simd.SIMDDetection.testRun);
|
||||
+ }
|
||||
+ // DivineMC end - Pufferfish: SIMD Support
|
||||
+
|
||||
this.setPvpAllowed(properties.pvp);
|
||||
this.setFlightAllowed(properties.allowFlight);
|
||||
this.setMotd(properties.motd);
|
||||
@@ -275,7 +_,7 @@
|
||||
|
||||
// this.worldData.setGameType(properties.gameMode.get()); // CraftBukkit - moved to world loading
|
||||
LOGGER.info("Default game type: {}", properties.gameMode.get());
|
||||
@@ -363,7 +_,7 @@
|
||||
String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord";
|
||||
String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/";
|
||||
// Paper end - Add Velocity IP Forwarding Support
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/server/level/ChunkMap.java
|
||||
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||
@@ -1302,7 +_,7 @@
|
||||
@@ -1345,7 +_,7 @@
|
||||
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
|
||||
// CraftBukkit start - respect vanish API
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/server/level/ServerPlayer.java
|
||||
+++ b/net/minecraft/server/level/ServerPlayer.java
|
||||
@@ -2237,6 +_,7 @@
|
||||
@@ -2353,6 +_,7 @@
|
||||
this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId()));
|
||||
if (gameMode == GameType.SPECTATOR) {
|
||||
this.removeEntitiesOnShoulder();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
@@ -313,6 +_,7 @@
|
||||
@@ -315,6 +_,7 @@
|
||||
private static final int MAX_SIGN_LINE_LENGTH = Integer.getInteger("Paper.maxSignLength", 80); // Paper - Limit client sign length
|
||||
private final io.papermc.paper.event.packet.ClientTickEndEvent tickEndEvent; // Paper - add client tick end event
|
||||
public final io.papermc.paper.connection.PaperPlayerGameConnection playerGameConnection; // Paper
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie cookie) {
|
||||
super(server, connection, cookie);
|
||||
@@ -324,6 +_,7 @@
|
||||
@@ -326,6 +_,7 @@
|
||||
this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat
|
||||
this.tickEndEvent = new io.papermc.paper.event.packet.ClientTickEndEvent(player.getBukkitEntity()); // Paper - add client tick end event
|
||||
this.playerGameConnection = new io.papermc.paper.connection.PaperPlayerGameConnection(this); // Paper
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
--- a/net/minecraft/server/players/PlayerList.java
|
||||
+++ b/net/minecraft/server/players/PlayerList.java
|
||||
@@ -1141,6 +_,7 @@
|
||||
@@ -1070,6 +_,7 @@
|
||||
player.connection.send(new ClientboundInitializeBorderPacket(worldBorder));
|
||||
player.connection.send(new ClientboundSetTimePacket(level.getGameTime(), level.getDayTime(), level.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)));
|
||||
player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getSharedSpawnPos(), level.getSharedSpawnAngle()));
|
||||
player.connection.send(new ClientboundSetDefaultSpawnPositionPacket(level.getRespawnData()));
|
||||
+ org.leavesmc.leaves.protocol.XaeroMapProtocol.onSendWorldInfo(player); // DivineMC - Leaves: Xaero's Map Protocol
|
||||
if (level.isRaining()) {
|
||||
// CraftBukkit start - handle player weather
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/entity/Entity.java
|
||||
+++ b/net/minecraft/world/entity/Entity.java
|
||||
@@ -374,6 +_,7 @@
|
||||
@@ -376,6 +_,7 @@
|
||||
public boolean isTemporarilyActive;
|
||||
public long activatedImmunityTick = Integer.MIN_VALUE;
|
||||
public @Nullable Boolean immuneToFire = null; // Purpur - Fire immune API
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
public void inactiveTick() {
|
||||
}
|
||||
@@ -1125,6 +_,7 @@
|
||||
@@ -1131,6 +_,7 @@
|
||||
// Paper end - detailed watchdog information
|
||||
|
||||
public void move(MoverType type, Vec3 movement) {
|
||||
@@ -16,7 +16,7 @@
|
||||
final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity
|
||||
// Paper start - detailed watchdog information
|
||||
ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main");
|
||||
@@ -2576,6 +_,7 @@
|
||||
@@ -2633,6 +_,7 @@
|
||||
}
|
||||
|
||||
this.addAdditionalSaveData(output, includeAll); // CraftBukkit - pass on includeAll
|
||||
@@ -24,7 +24,7 @@
|
||||
if (this.isVehicle()) {
|
||||
ValueOutput.ValueOutputList valueOutputList = output.childrenList("Passengers");
|
||||
|
||||
@@ -2684,6 +_,7 @@
|
||||
@@ -2741,6 +_,7 @@
|
||||
this.tags.clear();
|
||||
input.read("Tags", TAG_LIST_CODEC).ifPresent(this.tags::addAll);
|
||||
this.readAdditionalSaveData(input);
|
||||
@@ -32,7 +32,7 @@
|
||||
if (this.repositionEntityAfterLoad()) {
|
||||
this.reapplyPosition();
|
||||
}
|
||||
@@ -4219,6 +_,7 @@
|
||||
@@ -4298,6 +_,7 @@
|
||||
}
|
||||
|
||||
public boolean canTeleport(Level fromLevel, Level toLevel) {
|
||||
@@ -40,7 +40,7 @@
|
||||
if (!this.isAlive() || !this.valid) return false; // Paper - Fix item duplication and teleport issues
|
||||
if (fromLevel.dimension() == Level.END && toLevel.dimension() == Level.OVERWORLD) {
|
||||
for (Entity entity : this.getPassengers()) {
|
||||
@@ -4448,6 +_,7 @@
|
||||
@@ -4527,6 +_,7 @@
|
||||
}
|
||||
|
||||
public final void setBoundingBox(AABB bb) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/entity/LivingEntity.java
|
||||
+++ b/net/minecraft/world/entity/LivingEntity.java
|
||||
@@ -1425,7 +_,7 @@
|
||||
@@ -1431,7 +_,7 @@
|
||||
player.setRealHealth(health);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
return;
|
||||
}
|
||||
// CraftBukkit end
|
||||
@@ -2762,6 +_,7 @@
|
||||
@@ -2793,6 +_,7 @@
|
||||
}
|
||||
|
||||
protected void updateSwingTime() {
|
||||
@@ -17,11 +17,11 @@
|
||||
int currentSwingDuration = this.getCurrentSwingDuration();
|
||||
if (this.swinging) {
|
||||
this.swingTime++;
|
||||
@@ -3278,7 +_,13 @@
|
||||
@@ -3309,7 +_,13 @@
|
||||
}
|
||||
|
||||
protected float getFlyingSpeed() {
|
||||
- return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : 0.02F;
|
||||
- return this.getControllingPassenger() instanceof Player ? this.getSpeed() * 0.1F : 0.02F;
|
||||
+ // DivineMC start - Fix MC-172801
|
||||
+ float flyingSpeed = 0.02F;
|
||||
+ if (this.getAttributes().hasAttribute(Attributes.FLYING_SPEED)) {
|
||||
@@ -32,10 +32,10 @@
|
||||
}
|
||||
|
||||
public float getSpeed() {
|
||||
@@ -3727,6 +_,7 @@
|
||||
@@ -3758,6 +_,7 @@
|
||||
protected void updateFallFlying() {
|
||||
this.checkFallDistanceAccumulation();
|
||||
if (!this.level().isClientSide) {
|
||||
if (!this.level().isClientSide()) {
|
||||
+ if (!this.isFallFlying() && this.fallFlyTicks == 0) return; // DivineMC - lithium: entity.fast_elytra_check
|
||||
if (!this.canGlide()) {
|
||||
if (this.getSharedFlag(7) != false && !CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) // CraftBukkit
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/entity/Mob.java
|
||||
+++ b/net/minecraft/world/entity/Mob.java
|
||||
@@ -329,6 +_,8 @@
|
||||
@@ -339,6 +_,8 @@
|
||||
this.playAmbientSound();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/entity/monster/ZombieVillager.java
|
||||
+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
|
||||
@@ -292,6 +_,12 @@
|
||||
@@ -301,6 +_,12 @@
|
||||
if (!this.isSilent()) {
|
||||
level.levelEvent(null, 1027, this.blockPosition(), 0);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
--- a/net/minecraft/world/entity/player/Player.java
|
||||
+++ b/net/minecraft/world/entity/player/Player.java
|
||||
@@ -1817,6 +_,11 @@
|
||||
@@ -1669,6 +_,7 @@
|
||||
}
|
||||
|
||||
public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) {
|
||||
+ // DivineMC start - Fix MC-31819
|
||||
+ if (this.level().getDifficulty() == Difficulty.PEACEFUL) {
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Fix MC-31819
|
||||
+ if (this.level().getDifficulty() == Difficulty.PEACEFUL) return; // DivineMC - Fix MC-31819
|
||||
// CraftBukkit end
|
||||
if (!this.abilities.invulnerable) {
|
||||
if (!this.level().isClientSide) {
|
||||
if (!this.level().isClientSide()) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/entity/raid/Raid.java
|
||||
+++ b/net/minecraft/world/entity/raid/Raid.java
|
||||
@@ -511,7 +_,7 @@
|
||||
@@ -533,7 +_,7 @@
|
||||
double d1 = vec3.z + 13.0 / squareRoot * (vec31.z - vec3.z);
|
||||
if (squareRoot <= 64.0 || players.contains(serverPlayer)) {
|
||||
serverPlayer.connection
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/GameRules.java
|
||||
+++ b/net/minecraft/world/level/GameRules.java
|
||||
@@ -288,7 +_,7 @@
|
||||
@@ -301,7 +_,7 @@
|
||||
}
|
||||
|
||||
private GameRules(Map<GameRules.Key<?>, GameRules.Value<?>> rules, FeatureFlagSet enabledFeatures) {
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
--- a/net/minecraft/world/level/Level.java
|
||||
+++ b/net/minecraft/world/level/Level.java
|
||||
@@ -106,7 +_,7 @@
|
||||
public static final int TICKS_PER_DAY = 24000;
|
||||
public static final int MAX_ENTITY_SPAWN_Y = 20000000;
|
||||
public static final int MIN_ENTITY_SPAWN_Y = -20000000;
|
||||
@@ -111,7 +_,7 @@
|
||||
.add(new ExplosionParticleInfo(ParticleTypes.POOF, 0.5F, 1.0F))
|
||||
.add(new ExplosionParticleInfo(ParticleTypes.SMOKE, 1.0F, 1.0F))
|
||||
.build();
|
||||
- public final List<TickingBlockEntity> blockEntityTickers = Lists.newArrayList();
|
||||
+ public final org.bxteam.divinemc.util.BlockEntityTickersList blockEntityTickers = new org.bxteam.divinemc.util.BlockEntityTickersList(); // Paper - public // DivineMC - optimize block entity removals - Fix MC-117075
|
||||
protected final NeighborUpdater neighborUpdater;
|
||||
+ public final org.bxteam.divinemc.util.BlockEntityTickersList blockEntityTickers = new org.bxteam.divinemc.util.BlockEntityTickersList(); // DivineMC - optimize block entity removals - Fix MC-117075
|
||||
protected final CollectingNeighborUpdater neighborUpdater;
|
||||
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
|
||||
private boolean tickingBlockEntities;
|
||||
@@ -1501,13 +_,11 @@
|
||||
@@ -1452,13 +_,11 @@
|
||||
boolean runsNormally = this.tickRateManager().runsNormally();
|
||||
|
||||
int tickedEntities = 0; // Paper - rewrite chunk system
|
||||
@@ -24,7 +24,7 @@
|
||||
} else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) {
|
||||
tickingBlockEntity.tick();
|
||||
// Paper start - rewrite chunk system
|
||||
@@ -1517,7 +_,7 @@
|
||||
@@ -1468,7 +_,7 @@
|
||||
// Paper end - rewrite chunk system
|
||||
}
|
||||
}
|
||||
@@ -32,4 +32,4 @@
|
||||
+ this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removals - Fix MC-117075
|
||||
|
||||
this.tickingBlockEntities = false;
|
||||
profilerFiller.pop();
|
||||
this.spigotConfig.currentPrimedTnt = 0; // Spigot
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/BlockEntity.java
|
||||
@@ -386,7 +_,7 @@
|
||||
@@ -392,7 +_,7 @@
|
||||
|
||||
// CraftBukkit start - add method
|
||||
public org.bukkit.inventory.InventoryHolder getOwner() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
|
||||
@@ -423,6 +_,11 @@
|
||||
@@ -424,6 +_,11 @@
|
||||
} else {
|
||||
Direction opposite = blockEntity.facing.getOpposite();
|
||||
if (isFullContainer(attachedContainer, opposite)) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
--- a/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
|
||||
@@ -272,11 +_,18 @@
|
||||
@@ -279,11 +_,18 @@
|
||||
public BlockState getBlockStateFinal(final int x, final int y, final int z) {
|
||||
// Copied and modified from below
|
||||
final int sectionIndex = this.getSectionIndex(y);
|
||||
|
||||
@@ -5,7 +5,7 @@ Subject: [PATCH] Rebrand
|
||||
|
||||
|
||||
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
index dc49ba7b833b0d2edc8959ebe8cbecdad720bf06..5736b550ad3f1e7dd9fd1a1f985be2974278e7a9 100644
|
||||
index 6194d6d8952864c71cc4017a639b818e4ecccea9..46e62dead64e18691122a6dfaa1df77acbd46b27 100644
|
||||
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
|
||||
@@ -593,7 +593,7 @@ public class Metrics {
|
||||
@@ -141,7 +141,7 @@ index d543b1b107ab8d3eeb1fc3c1cadf489928d2786e..e77078e54efdfe931202ecf8c8550840
|
||||
}
|
||||
}
|
||||
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||
index b678ca41f7fb1f4aa10c012fb2b432f5e65b2a91..b0b05383838f2ebb42791a1fca8d3ce0d361e477 100644
|
||||
index 1b0ee48e28aaa68ddb1f28c23d3c5f5f40505c98..4d3518795a238d87ca4f3df0bee074ab5bcc2734 100644
|
||||
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
|
||||
@@ -23,15 +23,18 @@ public record ServerBuildInfoImpl(
|
||||
@@ -197,7 +197,7 @@ index 62e2d5704c348955bc8284dc2d54c933b7bcdd06..341f13e57896f03058ea3ec68e69b7cb
|
||||
public void executeAsync(final Runnable runnable) {
|
||||
MCUtil.scheduleAsyncTask(this.catching(runnable, "asynchronous"));
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
index 2e7c3d4befeb6256ce81ecaa9ed4e8fbcb21651e..a839dbbb72f48b8f8736d9f4693c528686570732 100644
|
||||
index 554fc2c53b5028c8f89a0ae69a75e075ba4f4435..a3e4065916f2aa2971f4e19f0702c7a052af2090 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
|
||||
@@ -491,7 +491,7 @@ public class CraftScheduler implements BukkitScheduler {
|
||||
@@ -223,7 +223,7 @@ index e34ceaa77c7e538c8d6bc341c4c6f450488ce426..4aef151bd162c4c99a3eaec1854b5463
|
||||
|
||||
if (stream != null) {
|
||||
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
index 39493810336442e74c0fc99fdeb5e073a8f4e95e..dffff76bf6df39dd26892edc2b4988fafab282e7 100644
|
||||
index bf0cda94d87e46149a21505fc67ddb9ad9af0838..0e5b10153821fda6056791e1c216d05a9ac8e5bc 100644
|
||||
--- a/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
+++ b/src/main/java/org/spigotmc/WatchdogThread.java
|
||||
@@ -75,14 +75,14 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
|
||||
@@ -279,311 +279,326 @@ diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
|
||||
index 518591dd83289e041a16e2c2e7d7e7640d4b2e1b..f54753531b3bf2e8b5377f342465e727c7da98f2 100644
|
||||
GIT binary patch
|
||||
literal 6677
|
||||
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
|
||||
DA-Nv<
|
||||
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
|
||||
Mr>mdKI;Vst03o>^`Tzg`
|
||||
|
||||
literal 9260
|
||||
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
|
||||
HqBZh=dic2S
|
||||
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
|
||||
|
||||
|
||||
@@ -5,18 +5,18 @@ Subject: [PATCH] Configuration
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 043d8c902c07769b72233e286e94271b135875f2..3ce12d384561fc36ad957c4a298eb9701ed8c977 100644
|
||||
index 0d2ba00b359ebc4f487a1029730518e741fc5f9f..916cca90459831c12b988ca10a0f53cb1befc058 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1063,6 +1063,7 @@ public final class CraftServer implements Server {
|
||||
@@ -1008,6 +1008,7 @@ public final class CraftServer implements Server {
|
||||
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
|
||||
this.console.paperConfigurations.reloadConfigs(this.console);
|
||||
org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur - Purpur config files
|
||||
+ org.bxteam.divinemc.config.DivineConfig.init((File) console.options.valueOf("divinemc-settings")); // DivineMC - Configuration
|
||||
for (ServerLevel world : this.console.getAllLevels()) {
|
||||
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
|
||||
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
@@ -1079,6 +1080,13 @@ public final class CraftServer implements Server {
|
||||
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && world.getGameRules().getBoolean(GameRules.RULE_SPAWN_MONSTERS)); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
|
||||
@@ -1024,6 +1025,13 @@ public final class CraftServer implements Server {
|
||||
}
|
||||
world.spigotConfig.init(); // Spigot
|
||||
world.purpurConfig.init(); // Purpur - Purpur config files
|
||||
@@ -31,7 +31,7 @@ index 043d8c902c07769b72233e286e94271b135875f2..3ce12d384561fc36ad957c4a298eb970
|
||||
|
||||
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
index 3a4239d6f5768f7e2b6025477670dd2eb9f8cbc4..0838fcfaa950300f7a394295509be86cab824f99 100644
|
||||
index 7e99752be20868606ab31b9db831c9940f970c9b..4cf0a09594e72193a452215c50ed1cce309d5cc7 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java
|
||||
@@ -172,6 +172,14 @@ public class Main {
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Mon, 27 Jan 2025 18:42:29 +0300
|
||||
Subject: [PATCH] Delete timings
|
||||
|
||||
|
||||
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 e989053b703fddfbffc3e4ed9381594aaaa0df41..d7398b1ecf2660c29fb7d106b48fe02d3736603e 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
|
||||
@@ -1,6 +1,5 @@
|
||||
package io.papermc.paper.plugin.manager;
|
||||
|
||||
-import co.aikar.timings.TimedEventExecutor;
|
||||
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
|
||||
import com.destroystokyo.paper.exception.ServerEventException;
|
||||
import com.google.common.collect.Sets;
|
||||
@@ -96,7 +95,6 @@ class PaperEventManager {
|
||||
throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled");
|
||||
}
|
||||
|
||||
- executor = new TimedEventExecutor(executor, plugin, null, event);
|
||||
this.getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled));
|
||||
}
|
||||
|
||||
@@ -183,7 +181,7 @@ class PaperEventManager {
|
||||
}
|
||||
}
|
||||
|
||||
- EventExecutor executor = new TimedEventExecutor(EventExecutor.create(method, eventClass), plugin, method, eventClass);
|
||||
+ EventExecutor executor = EventExecutor.create(method, eventClass); // DivineMC - Delete timings
|
||||
eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
|
||||
}
|
||||
return ret;
|
||||
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java
|
||||
index 097500a59336db1bbfffcd1aa4cff7a8586e46ec..69341cb3b11409e41b9ff756b11d9bd1b9e6da10 100644
|
||||
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java
|
||||
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java
|
||||
@@ -232,7 +232,7 @@ public class PaperPluginManagerImpl implements PluginManager, DependencyContext
|
||||
|
||||
@Override
|
||||
public boolean useTimings() {
|
||||
- return co.aikar.timings.Timings.isTimingsEnabled();
|
||||
+ return false; // DivineMC - Delete timings
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,22 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Wed, 2 Jul 2025 19:14:51 +0300
|
||||
Subject: [PATCH] Delete ReloadCommand
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
index 3ce12d384561fc36ad957c4a298eb9701ed8c977..4ae2ede15d7b69ce3ba7a920ecb7c2c84952de0f 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
|
||||
@@ -1023,11 +1023,6 @@ public final class CraftServer implements Server {
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
- // Paper start - lifecycle events
|
||||
- if (io.papermc.paper.plugin.lifecycle.event.LifecycleEventRunner.INSTANCE.blocksPluginReloading()) {
|
||||
- throw new IllegalStateException(org.bukkit.command.defaults.ReloadCommand.RELOADING_DISABLED_MESSAGE);
|
||||
- }
|
||||
- // Paper end - lifecycle events
|
||||
org.spigotmc.WatchdogThread.hasStarted = false; // Paper - Disable watchdog early timeout on reload
|
||||
this.reloadCount++;
|
||||
this.configuration = YamlConfiguration.loadConfiguration(this.getConfigFile());
|
||||
@@ -1,29 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 23 Mar 2025 16:39:45 +0300
|
||||
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
|
||||
index b4ee0f809c1524c74eca74ee6bc471a3051d92a6..7725870545b4c87dc5e7536d04c710999ea6932b 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
|
||||
@@ -2125,4 +2125,18 @@ public class CraftEventFactory {
|
||||
|
||||
return disconnectReason;
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
+ public static io.papermc.paper.event.player.PlayerFillBottleEvent callPlayerFillBottleEvent(net.minecraft.world.entity.player.Player player, InteractionHand hand, ItemStack glassBottle, ItemStack resultItem) {
|
||||
+ final io.papermc.paper.event.player.PlayerFillBottleEvent event = new io.papermc.paper.event.player.PlayerFillBottleEvent(((org.bukkit.entity.Player) player.getBukkitEntity()), org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand), CraftItemStack.asBukkitCopy(glassBottle), CraftItemStack.asCraftMirror(resultItem));
|
||||
+ event.callEvent();
|
||||
+ return event;
|
||||
+ }
|
||||
+
|
||||
+ public static io.papermc.paper.event.block.BlockFillBottleEvent callBlockFillBottleEvent(LevelAccessor level, BlockPos blockPos, ItemStack glassBottle, ItemStack resultItem) {
|
||||
+ final io.papermc.paper.event.block.BlockFillBottleEvent event = new io.papermc.paper.event.block.BlockFillBottleEvent(CraftBlock.at(level, blockPos), CraftItemStack.asBukkitCopy(glassBottle), CraftItemStack.asCraftMirror(resultItem));
|
||||
+ event.callEvent();
|
||||
+ return event;
|
||||
+ }
|
||||
+ // DivineMC end - Paper PR: Add FillBottleEvents for player and dispenser
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
Date: Sun, 23 Mar 2025 16:53:16 +0300
|
||||
Subject: [PATCH] Paper PR: Player standing on position API
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index 476eefebace887064b728f08af40c746b6f70787..93d03f99db85fc0415bc4d83ce019927bc9b33ce 100644
|
||||
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
@@ -1353,6 +1353,20 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
|
||||
return this.entity.get(io.papermc.paper.datacomponent.PaperDataComponentType.bukkitToMinecraft(type)) != null;
|
||||
}
|
||||
|
||||
+ // Paper start - Player standing on position API
|
||||
+ @Override
|
||||
+ public org.bukkit.block.Block getMovementAffectingBlock() {
|
||||
+ return CraftBlock.at(this.getHandle().level(), this.getHandle().getBlockPosBelowThatAffectsMyMovement());
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public org.bukkit.block.Block getSupportingBlock() {
|
||||
+ return this.getHandle().mainSupportingBlockPos
|
||||
+ .map((pos) -> CraftBlock.at(this.getHandle().level(), pos))
|
||||
+ .orElse(null);
|
||||
+ }
|
||||
+ // Paper end - Player standing on position API
|
||||
+
|
||||
// Purpur start - Ridables
|
||||
@Override
|
||||
public org.bukkit.entity.Player getRider() {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user