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

apply rest of patches

This commit is contained in:
NONPLAYT
2025-04-24 19:47:15 +03:00
parent 9f8678ca4d
commit e379851085
48 changed files with 928 additions and 937 deletions

View File

@@ -53,7 +53,7 @@ index a43e5190c0f9ae14ccecccd5b58dc0e17f18b0a1..06ffba13f211851e8f6d630a72b41474
private boolean canMerge(ExperienceOrb orb) {
- return orb != this && canMerge(orb, this.getId(), this.value);
+ return org.bxteam.divinemc.DivineConfig.clumpOrbs ? orb.isAlive() && !this.is(orb) : orb != this && ExperienceOrb.canMerge(orb, this.getId(), this.value); // DivineMC - Clump experience orbs
+ return org.bxteam.divinemc.DivineConfig.clumpOrbs ? orb.isAlive() && !this.is(orb) : orb != this && canMerge(orb, this.getId(), this.value); // DivineMC - Clump experience orbs
}
private static boolean canMerge(ExperienceOrb orb, int amount, int other) {

View File

@@ -1,75 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 11 Jan 2025 22:22:01 +0300
Subject: [PATCH] Rebrand
diff --git a/net/minecraft/CrashReport.java b/net/minecraft/CrashReport.java
index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1feacca106 100644
--- a/net/minecraft/CrashReport.java
+++ b/net/minecraft/CrashReport.java
@@ -30,7 +30,7 @@ public class CrashReport {
private boolean trackingStackTrace = true;
private StackTraceElement[] uncategorizedStackTrace = new StackTraceElement[0];
private final SystemReport systemReport = new SystemReport();
- private List<String> extraInfo = List.of("", "DO NOT REPORT THIS TO PAPER! REPORT TO PURPUR INSTEAD!", ""); // Purpur - Rebrand
+ private List<String> extraInfo = List.of("", "DO NOT REPORT THIS TO PAPER! REPORT TO DIVINEMC INSTEAD!", ""); // DivineMC - Rebrand
public CrashReport(String title, Throwable exception) {
io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 781030cb2e0316151c20351f04347c8db63f43e1..6bb8afb3b0e92c374474c92fa44dc7b80af0bd73 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1182,6 +1182,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
protected void runServer() {
try {
+ org.bxteam.divinemc.spark.ThreadDumperRegistry.REGISTRY.add(Thread.currentThread().getName()); // DivineMC
if (!this.initServer()) {
throw new IllegalStateException("Failed to initialize server");
}
diff --git a/net/minecraft/server/gui/MinecraftServerGui.java b/net/minecraft/server/gui/MinecraftServerGui.java
index 614c7d9f673c926562acc8fa3b3788623900db41..33456c7c106abbddf743e1203a6e8122cf10b797 100644
--- a/net/minecraft/server/gui/MinecraftServerGui.java
+++ b/net/minecraft/server/gui/MinecraftServerGui.java
@@ -51,7 +51,7 @@ public class MinecraftServerGui extends JComponent {
} catch (Exception var3) {
}
- final JFrame jFrame = new JFrame("Purpur Minecraft server"); // Purpur - Improve GUI
+ final JFrame jFrame = new JFrame("DivineMC Minecraft server"); // Purpur - Improve GUI // DivineMC - Rebrand
final MinecraftServerGui minecraftServerGui = new MinecraftServerGui(server);
jFrame.setDefaultCloseOperation(2);
jFrame.add(minecraftServerGui);
@@ -59,7 +59,7 @@ public class MinecraftServerGui extends JComponent {
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
// Paper start - Improve ServerGUI
- jFrame.setName("Purpur Minecraft server"); // Purpur - Improve GUI
+ jFrame.setName("DivineMC Minecraft server"); // Purpur - Improve GUI // DivineMC - Rebrand
try {
jFrame.setIconImage(javax.imageio.ImageIO.read(java.util.Objects.requireNonNull(MinecraftServerGui.class.getClassLoader().getResourceAsStream("logo.png"))));
} catch (java.io.IOException ignore) {
@@ -69,7 +69,7 @@ public class MinecraftServerGui extends JComponent {
@Override
public void windowClosing(WindowEvent event) {
if (!minecraftServerGui.isClosing.getAndSet(true)) {
- jFrame.setTitle("Purpur Minecraft server - shutting down!"); // Purpur - Improve GUI
+ jFrame.setTitle("DivineMC Minecraft server - shutting down!"); // Purpur - Improve GUI // DivineMC - Rebrand
server.halt(true);
minecraftServerGui.runFinalizers();
}
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 80ed0e4b8c867d031413b4140e52af1342fdcb54..6ebd1300c2561116b83cb2472ac7939ead36d576 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -283,7 +283,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
// Paper start
private static void printOversizedLog(String msg, Path file, int x, int z) {
- 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 PURPUR - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); // Purpur - Rebrand
+ 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 {

View File

@@ -1,53 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Mon, 27 Jan 2025 20:22:52 +0300
Subject: [PATCH] Configuration
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 1d9bf122c4c32c486a33d846c95afcab12560fd7..61eeec6a0d789e5e44abdeb5826d7ee2307301ba 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -218,6 +218,15 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
}
org.purpurmc.purpur.PurpurConfig.registerCommands();
// Purpur end - Configurable void damage height and damage
+ // DivineMC start - Configuration
+ try {
+ org.bxteam.divinemc.DivineConfig.init((java.io.File) options.valueOf("divinemc-settings"));
+ } catch (Exception e) {
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e);
+ return false;
+ }
+ org.bxteam.divinemc.command.DivineCommands.registerCommands(this);
+ // DivineMC end - Configuration
// Paper start - initialize global and world-defaults configuration
this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess());
this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess());
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 0fe8f4601eedfa68c38ebadc7847ba7a07ff6fb6..b4c2602ecf6b943ab022866231f74b850269af8f 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -171,6 +171,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files
+ public final org.bxteam.divinemc.DivineWorldConfig divineConfig; // DivineMC - Configuration
public static BlockPos lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
@@ -898,6 +899,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(), env); // Purpur - Purpur config files
+ // DivineMC start - Configuration
+ try {
+ this.divineConfig = new org.bxteam.divinemc.DivineWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), env);
+ } catch (java.io.IOException e) {
+ net.minecraft.server.MinecraftServer.LOGGER.error("Failed to load DivineMC configuration for world '{}'", ((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), e);
+ throw new RuntimeException(e);
+ }
+ // DivineMC end - Configuration
this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur - Add adjustable breeding cooldown to config
this.generator = gen;
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);

View File

@@ -1,433 +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 a65affc41a4fc299bc2281f0f53f2e075633899d..7284c984f9309d4a862fe6f89df993c9a6a9efa6 100644
--- a/net/minecraft/server/commands/SeedCommand.java
+++ b/net/minecraft/server/commands/SeedCommand.java
@@ -12,6 +12,17 @@ public class SeedCommand {
long seed = context.getSource().getLevel().getSeed();
Component component = ComponentUtils.copyOnClickText(String.valueOf(seed));
context.getSource().sendSuccess(() -> Component.translatable("commands.seed.success", component), false);
+
+ // DivineMC start - Implement Secure Seed
+ if (org.bxteam.divinemc.DivineConfig.enableSecureSeed) {
+ su.plo.matter.Globals.setupGlobals(context.getSource().getLevel());
+ String seedStr = su.plo.matter.Globals.seedToString(su.plo.matter.Globals.worldSeed);
+ Component featureSeedComponent = ComponentUtils.copyOnClickText(seedStr);
+
+ context.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 5748658abf0b90812005ae9d426df92daf5532f0..8b4b91be368b4195326eeb1c714d713a95f28d76 100644
--- a/net/minecraft/server/dedicated/DedicatedServerProperties.java
+++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java
@@ -114,7 +114,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.DivineConfig.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 8055b8552b40160732953b15876dda7983890d06..ab30af9cd58ff7310e05be87b08f42bacf69e11e 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -618,6 +618,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 3980e0dfb08a357384ea33670fb282a26a598f6e..9afd448ede87c9192dc576f66e08676a68b34d98 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -632,6 +632,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 240a54b210e23d5b79e6bcaf3806aa454668135d..66dffb8a2c6725ea2502b498044b854f043f3c73 100644
--- a/net/minecraft/world/entity/monster/Slime.java
+++ b/net/minecraft/world/entity/monster/Slime.java
@@ -423,8 +423,13 @@ public class Slime extends Mob implements Enemy {
return false;
}
- 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; // Spigot // Paper
+ ChunkPos chunkPos = new ChunkPos(pos);
+ // DivineMC start - Implement Secure Seed
+ boolean isSlimeChunk = org.bxteam.divinemc.DivineConfig.enableSecureSeed
+ ? level.getChunk(chunkPos.x, chunkPos.z).isSlimeChunk()
+ : WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel) level).getSeed(), level.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper
+ boolean flag = level.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || isSlimeChunk;
+ // 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 6d565b52552534ce9cacfc35ad1bf4adcb69eac3..80a0f5524e91e55d716e93c29e199d9816b0072a 100644
--- a/net/minecraft/world/level/chunk/ChunkAccess.java
+++ b/net/minecraft/world/level/chunk/ChunkAccess.java
@@ -82,6 +82,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);
@@ -191,6 +195,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
public abstract BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving);
diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java
index 6ed51cf42b5864194d671b5b56f5b9bdf0291dc0..7e0b602e9fd9e3b3f60014ab179b3a82e3bf5c2a 100644
--- a/net/minecraft/world/level/chunk/ChunkGenerator.java
+++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
@@ -343,7 +343,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.DivineConfig.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 -> {
@@ -556,8 +560,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.DivineConfig.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..a3093ef1b47544f2eb02d366040526697dafc8db 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.DivineConfig.enableSecureSeed
+ ? new su.plo.matter.WorldgenCryptoRandom(0, 0, su.plo.matter.Globals.Salt.STRONGHOLDS, 0)
+ : RandomSource.create();
+
+ if (!org.bxteam.divinemc.DivineConfig.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..630f6c409db349819fc5fd19a3d78fadb4cfb6d6 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.DivineConfig.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 38475f6975533909924c8d54f438cf43cdfe31a3..6759df026a29810021ddb37f3ddb62382b83a94e 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.DivineConfig.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..7c35949c9a2f102e9da246fd5bf81d9e14eb36ca 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.DivineConfig.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..f01d96895ab348971fb31b614026fb3d106e9a3e 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.DivineConfig.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 670335a7bbfbc9da64c389977498c22dfcd03251..7174a9767cbc94544be81c74d6468f3f73386edc 100644
--- a/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
+++ b/net/minecraft/world/level/levelgen/structure/placement/StructurePlacement.java
@@ -118,8 +118,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.DivineConfig.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, salt, regionX, regionZ);
+ }
+ // 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 eb85edaa3b7fab4f11545b0fa8bfea882dedb67d..63143ceec98f7a84ec4064d05e8f88c11200172f 100644
--- a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
+++ b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
@@ -64,7 +64,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.DivineConfig.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()

View File

@@ -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] 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 67cbf9f5760fae5db6f31e64095cd1b6be6ade8e..7ad36864d700f3012a3791bf3814465e5e9deffa 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.DivineConfig.asyncPathfinding) {
+ Path possiblePath = findPathToPois(mob, set);
+
+ org.bxteam.divinemc.entity.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..3f676309af0d5529413fa047a7f3cac99260b9ad 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.DivineConfig.asyncPathfinding && !flag && this.tryComputePath(owner, walkTarget, level.getGameTime())) { // DivineMC - async path processing
this.lastTargetPos = walkTarget.getTarget().currentBlockPosition();
return true;
+ } else if (org.bxteam.divinemc.DivineConfig.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.DivineConfig.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.DivineConfig.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.DivineConfig.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..1e9383442d0a0adf4bf621fc35108b35b1375bc7 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.DivineConfig.asyncPathfinding) {
+ Path possiblePath = AcquirePoi.findPathToPois(mob, set);
+
+ org.bxteam.divinemc.entity.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 d8f532c5e68ff4dff933556c4f981e9474c044e6..37f3d3888ea2a862d006cf2b201f9715bcb8ce1e 100644
--- a/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
+++ b/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
@@ -56,7 +56,7 @@ public abstract class DoorInteractGoal extends Goal {
} else {
GroundPathNavigation groundPathNavigation = (GroundPathNavigation)this.mob.getNavigation();
Path path = groundPathNavigation.getPath();
- if (path != null && !path.isDone()) {
+ if (path != null && path.isProcessed() && !path.isDone()) { // DivineMC - async path processing
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 66a02fe7594522ef391d67e09856bf3f70fe597d..0cd0d1059ac3612ba34f1a47a5023a8d07ee612f 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.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.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.DivineConfig.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 71ea68b56b3069bdf8e47931156b6ef49ea8ce5d..0e680d3954d5847125484c2a93d9cd8e133ad8c3 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.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.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.DivineConfig.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 045cfafb3afe8271d60852ae3c7cdcb039b44d4f..f544bf28ac6531061da08c726684687416b9426c 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.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.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.DivineConfig.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 6c8fb611943aee8cabc471c63166f9b44ef14826..02814be0e1ac9b743a4c6b5b75015a5e87fc2aa6 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.entity.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.DivineConfig.asyncPathfinding) {
+ // assign early a target position. most calls will only have 1 position
+ if (!targets.isEmpty()) this.targetPos = targets.iterator().next();
+
+ org.bxteam.divinemc.entity.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 2979846853898d78a2df19df2287da16dbe4ae71..504911c14aad5c53aeea2c71bda3978f022601dd 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.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.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.DivineConfig.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..9494dd144ff1115c9f0862614ef618035ee2565f 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.DivineConfig.asyncPathfinding) {
+ Path possiblePath = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
+ org.bxteam.divinemc.entity.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 d5727999eb67ff30dbf47865d59452483338e170..ddbee0f0f42fae0a26321bb324d22f5e7520ae72 100644
--- a/net/minecraft/world/entity/animal/Bee.java
+++ b/net/minecraft/world/entity/animal/Bee.java
@@ -936,7 +936,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();
@@ -990,7 +990,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 4aabb98e0b37b652ad4d334b99c48a818c2859b4..dfcba5c2c8a489ebe74c2d5c1fa980c401806757 100644
--- a/net/minecraft/world/entity/animal/frog/Frog.java
+++ b/net/minecraft/world/entity/animal/frog/Frog.java
@@ -473,6 +473,17 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
super(mob, level);
}
+ // DivineMC start - async path processing
+ private static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.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);
@@ -481,6 +492,11 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
@Override
protected PathFinder createPathFinder(int maxVisitedNodes) {
this.nodeEvaluator = new Frog.FrogNodeEvaluator(true);
+ // DivineMC start - async path processing
+ if (org.bxteam.divinemc.DivineConfig.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 6c73245b8d04f194e72165aa0000ca79a95db59d..2686df57d9d48db1438278d0d053bdbd3c65c0a7 100644
--- a/net/minecraft/world/entity/monster/Drowned.java
+++ b/net/minecraft/world/entity/monster/Drowned.java
@@ -313,7 +313,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 241526239bdbd5d9276f85e7fca46a7051f46a25..2329973f735e1ae7fbb76798dc113f4261c906b7 100644
--- a/net/minecraft/world/entity/monster/Strider.java
+++ b/net/minecraft/world/entity/monster/Strider.java
@@ -579,9 +579,25 @@ public class Strider extends Animal implements ItemSteerable, Saddleable {
super(strider, level);
}
+ // DivineMC start - async path processing
+ private static final org.bxteam.divinemc.entity.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.entity.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.DivineConfig.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 e4b8a74fae6d058a9a75a12d2ff08c7984442538..59a12809e5c7f5ee85ca1f587f6b77383a1ff062 100644
--- a/net/minecraft/world/entity/monster/warden/Warden.java
+++ b/net/minecraft/world/entity/monster/warden/Warden.java
@@ -597,6 +597,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.DivineConfig.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..965c1d2dd1acd542936fad8034c2de1746193355 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.entity.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.entity.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.DivineConfig.asyncPathfinding)
+ this.openSet.clear(); // it's always cleared in processPath
+ NodeEvaluator nodeEvaluator = this.nodeEvaluatorGenerator == null
+ ? this.nodeEvaluator
+ : org.bxteam.divinemc.entity.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.entity.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.entity.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator);
+ return this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier);
+ }
+
+ return new org.bxteam.divinemc.entity.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.entity.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];

View File

@@ -1,294 +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] Multithreaded Tracker
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index dd2509996bfd08e8c3f9f2be042229eac6d7692d..8ef5a1aaac9c27873ce746eb281f77bb318a3c69 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -342,7 +342,11 @@ public final class RegionizedPlayerChunkLoader {
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.DivineConfig.multithreadedEnabled && !org.bxteam.divinemc.DivineConfig.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/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index d3d9926d504fa6b3384be5ae06b2843ebb7f807c..965899a98223b15bd770378c202873cbf15b714d 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -951,6 +951,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.DivineConfig.multithreadedEnabled) {
+ final ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel level = this.level;
+ org.bxteam.divinemc.entity.tracking.MultithreadedTracker.tick(level);
+ return;
+ }
+ // DivineMC end - Multithreaded tracker
// Paper start - optimise entity tracker
if (true) {
this.newTrackerTick();
@@ -1073,7 +1080,11 @@ 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 final Set<ServerPlayerConnection> seenBy = org.bxteam.divinemc.DivineConfig.multithreadedEnabled
+ ? com.google.common.collect.Sets.newConcurrentHashSet()
+ : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
+ // DivineMC end - Multithreaded tracker
// Paper start - optimise entity tracker
private long lastChunkUpdate = -1L;
@@ -1100,21 +1111,55 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.lastTrackedChunk = chunk;
final ServerPlayer[] playersRaw = players.getRawDataUnchecked();
+ final int playersLen = players.size(); // Ensure length won't change in the future tasks
+
+ // DivineMC start - Multithreaded tracker
+ if (org.bxteam.divinemc.DivineConfig.multithreadedEnabled && org.bxteam.divinemc.DivineConfig.multithreadedCompatModeEnabled) {
+ 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);
+ }
- for (int i = 0, len = players.size(); i < len; ++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
+ for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
+ final ServerPlayer player = conn.getPlayer();
+ if (!players.contains(player)) {
+ this.removePlayer(player);
+ }
+ }
+ }
+ };
+
+ // 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) {
+ org.bxteam.divinemc.entity.tracking.MultithreadedTracker.getTrackerExecutor().execute(updatePlayerTasks);
+ } else {
+ updatePlayerTasks.run();
+ }
+ } else {
+ for (int i = 0, len = players.size(); i < len; ++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
- for (final ServerPlayerConnection conn : new java.util.ArrayList<>(this.seenBy)) {
- final ServerPlayer player = conn.getPlayer();
- if (!players.contains(player)) {
- this.removePlayer(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)) {
+ final ServerPlayer player = conn.getPlayer();
+ if (!players.contains(player)) {
+ this.removePlayer(player);
+ }
}
}
}
+ // DivineMC end - Multithreaded tracker
}
@Override
@@ -1176,7 +1221,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public void broadcast(Packet<?> packet) {
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) { // DivineMC - Multithreaded tracker
serverPlayerConnection.send(packet);
}
}
@@ -1189,21 +1234,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public void broadcastRemoved() {
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) { // DivineMC - Multithreaded tracker
this.serverEntity.removePairing(serverPlayerConnection.getPlayer());
}
}
public void removePlayer(ServerPlayer player) {
- org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
if (this.seenBy.remove(player.connection)) {
this.serverEntity.removePairing(player);
}
}
public void updatePlayer(ServerPlayer player) {
- org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot
if (player != this.entity) {
+ if (org.bxteam.divinemc.DivineConfig.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();
diff --git a/net/minecraft/server/level/ServerBossEvent.java b/net/minecraft/server/level/ServerBossEvent.java
index f106373ef3ac4a8685c2939c9e8361688a285913..3b4dff8867e91884b5720ca8a9cb64af655f8475 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.DivineConfig.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 0fb253aa55a24b56b17f524b3261c5b75c7d7e59..b6053158f5d9b6ad325ea075ab7c60f9966ba496 100644
--- a/net/minecraft/server/level/ServerEntity.java
+++ b/net/minecraft/server/level/ServerEntity.java
@@ -110,8 +110,16 @@ public class ServerEntity {
.forEach(
removedPassenger -> {
if (removedPassenger instanceof ServerPlayer serverPlayer1) {
- serverPlayer1.connection
- .teleport(serverPlayer1.getX(), serverPlayer1.getY(), serverPlayer1.getZ(), serverPlayer1.getYRot(), serverPlayer1.getXRot());
+ // DivineMC start - Multithreaded tracker
+ if (org.bxteam.divinemc.DivineConfig.multithreadedEnabled && Thread.currentThread() instanceof org.bxteam.divinemc.entity.tracking.MultithreadedTracker.MultithreadedTrackerThread) {
+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(() -> serverPlayer1.connection
+ .teleport(serverPlayer1.getX(), serverPlayer1.getY(), serverPlayer1.getZ(), serverPlayer1.getYRot(), serverPlayer1.getXRot())
+ );
+ } else {
+ serverPlayer1.connection
+ .teleport(serverPlayer1.getX(), serverPlayer1.getY(), serverPlayer1.getZ(), serverPlayer1.getYRot(), serverPlayer1.getXRot());
+ }
+ // DivineMC end - Multithreaded tracker
}
}
);
@@ -410,12 +418,13 @@ public class ServerEntity {
if (this.entity instanceof LivingEntity) {
Set<AttributeInstance> attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync();
if (!attributesToSync.isEmpty()) {
+ final Set<AttributeInstance> copy = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(attributesToSync); // DivineMC - Multithreaded tracker
// CraftBukkit start - Send scaled max health
if (this.entity instanceof ServerPlayer serverPlayer) {
- serverPlayer.getBukkitEntity().injectScaledMaxHealth(attributesToSync, false);
+ serverPlayer.getBukkitEntity().injectScaledMaxHealth(copy, false); // DivineMC - Multithreaded tracker
}
// CraftBukkit end
- this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync));
+ this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy)); // DivineMC - Multithreaded tracker
}
attributesToSync.clear();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index c229d69ce3d007e4cb57e559611b3fca7a03562f..ba5ca5213fafd60b2257409f334a7c6b28fe918a 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -2497,7 +2497,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public LevelEntityGetter<Entity> getEntities() {
- org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
+ //org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // DivineMC - Multithreaded tracker
return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system
}
@@ -2724,7 +2724,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
map.carriedByPlayers.remove(player);
- if (map.carriedBy.removeIf(holdingPlayer -> holdingPlayer.player == player)) {
+ if (map.carriedBy.removeIf(holdingPlayer -> holdingPlayer != null && holdingPlayer.player == player)) { // DivineMC - Multithreaded tracker
map.decorations.remove(player.getName().getString());
}
}
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 56a22d19a82a937c08cb4527b0f67f219a6bb8a0..f8c76bb2c9fa625e191036dc58ef3dfb1d4ee930 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1822,7 +1822,7 @@ public class ServerGamePacketListenerImpl
}
public void internalTeleport(PositionMoveRotation posMoveRotation, Set<Relative> relatives) {
- org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper
+ //org.spigotmc.AsyncCatcher.catchOp("teleport"); // DivineMC - Multithreaded tracker
// 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/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
index 8013594bb4844e7a8abf28123958e7f632d39341..72593629324ccd4d70b8ed86a90fb69785d57f5f 100644
--- a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
+++ b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
@@ -24,8 +24,11 @@ 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 boolean multiThreadedTrackingEnabled = org.bxteam.divinemc.DivineConfig.multithreadedEnabled;
+ private final Map<ResourceLocation, AttributeModifier> modifierById = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new Object2ObjectArrayMap<>();
+ private final Map<ResourceLocation, AttributeModifier> permanentModifiers = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new Object2ObjectArrayMap<>();
+ // DivineMC end - Multithreaded tracker
private double baseValue;
private boolean dirty = true;
private double cachedValue;
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
index a25d74592e89e3d6339479c6dc2b6f45d1932cfc..621b183211b8148bb8db256d2119c82f8a2c626b 100644
--- a/net/minecraft/world/entity/ai/attributes/AttributeMap.java
+++ b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
@@ -19,9 +19,12 @@ import org.slf4j.Logger;
public class AttributeMap {
private static final Logger LOGGER = LogUtils.getLogger();
- 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 boolean multiThreadedTrackingEnabled = org.bxteam.divinemc.DivineConfig.multithreadedEnabled;
+ private final Map<Holder<Attribute>, AttributeInstance> attributes = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
+ private final Set<AttributeInstance> attributesToSync = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
+ private final Set<AttributeInstance> attributesToUpdate = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
+ // DivineMC end - Multithreaded tracker
private final AttributeSupplier supplier;
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index 681dec447486138088fe5f705ef4fadab531139f..3d6aad86519be3e1449d3288369a41aebb924c90 100644
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -279,6 +279,7 @@ public class MapItemSavedData extends SavedData {
for (int i = 0; i < this.carriedBy.size(); i++) {
MapItemSavedData.HoldingPlayer holdingPlayer1 = this.carriedBy.get(i);
+ if (holdingPlayer1 == null) continue; // DivineMC - Multithreaded tracker
Player player1 = holdingPlayer1.player;
String string = player1.getName().getString();
if (!player1.isRemoved() && (player1.getInventory().contains(predicate) || mapStack.isFramed())) {

View File

@@ -1,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 13bcd8653d766cd0b754a22e9aab261fbc62b0a5..0bc2d17e9bad62f62ab171feb2a92b87e1c3ba6a 100644
--- a/net/minecraft/server/commands/LocateCommand.java
+++ b/net/minecraft/server/commands/LocateCommand.java
@@ -103,44 +103,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(
@@ -195,7 +228,7 @@ public class LocateCommand {
.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, 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;
}

View File

@@ -1,650 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Fri, 31 Jan 2025 21:50:46 +0300
Subject: [PATCH] Misc Optimizations
diff --git a/com/mojang/brigadier/tree/CommandNode.java b/com/mojang/brigadier/tree/CommandNode.java
index 2ae5b80338282ac73c74765fc0729af2d54f6d6c..00a63a6a5983e6a25f2a9014a2f9eefeda468cdf 100644
--- a/com/mojang/brigadier/tree/CommandNode.java
+++ b/com/mojang/brigadier/tree/CommandNode.java
@@ -24,7 +24,7 @@ import java.util.concurrent.CompletableFuture;
import java.util.function.Predicate;
public abstract class CommandNode<S> implements Comparable<CommandNode<S>> {
- private final Map<String, CommandNode<S>> children = new LinkedHashMap<>();
+ private final Map<String, CommandNode<S>> children = Collections.synchronizedMap(new LinkedHashMap<>()); // DivineMC - Misc Optimizations
private final Map<String, LiteralCommandNode<S>> literals = new LinkedHashMap<>();
private final Map<String, ArgumentCommandNode<S, ?>> arguments = new LinkedHashMap<>();
public Predicate<S> requirement; // Paper - public-f
diff --git a/com/mojang/math/OctahedralGroup.java b/com/mojang/math/OctahedralGroup.java
index 11902e7427761746ee098fea3276a34fef0096ba..3ba23fa243f7af712a41316066ca554f1c23b495 100644
--- a/com/mojang/math/OctahedralGroup.java
+++ b/com/mojang/math/OctahedralGroup.java
@@ -112,6 +112,7 @@ public enum OctahedralGroup implements StringRepresentable {
this.transformation = new Matrix3f().scaling(invertX ? -1.0F : 1.0F, invertY ? -1.0F : 1.0F, invertZ ? -1.0F : 1.0F);
this.transformation.mul(permutation.transformation());
this.initializeRotationDirections(); // Paper - Avoid Lazy Initialization for Enum Fields
+ this.rotate(Direction.UP); // DivineMC - Math Optimizations
}
private BooleanList packInversions() {
diff --git a/com/mojang/math/Transformation.java b/com/mojang/math/Transformation.java
index aa755b8b7f8bc5910322e0c5b520f603da06a85a..e781dea43279aa77cc40a7afd2281c32cc8347a9 100644
--- a/com/mojang/math/Transformation.java
+++ b/com/mojang/math/Transformation.java
@@ -51,6 +51,7 @@ public final class Transformation {
} else {
this.matrix = matrix;
}
+ ensureDecomposed(); // DivineMC - Math Optimizations
}
public Transformation(@Nullable Vector3f translation, @Nullable Quaternionf leftRotation, @Nullable Vector3f scale, @Nullable Quaternionf rightRotation) {
@@ -60,6 +61,7 @@ public final class Transformation {
this.scale = scale != null ? scale : new Vector3f(1.0F, 1.0F, 1.0F);
this.rightRotation = rightRotation != null ? rightRotation : new Quaternionf();
this.decomposed = true;
+ ensureDecomposed(); // DivineMC - Math Optimizations
}
public static Transformation identity() {
diff --git a/net/minecraft/core/MappedRegistry.java b/net/minecraft/core/MappedRegistry.java
index 5f752603aa5611ce9d3dd44cc5b70c27ac46a86e..332122c0b700fb743f91f3fed16aade41dceec28 100644
--- a/net/minecraft/core/MappedRegistry.java
+++ b/net/minecraft/core/MappedRegistry.java
@@ -34,10 +34,12 @@ public class MappedRegistry<T> implements WritableRegistry<T> {
private final ResourceKey<? extends Registry<T>> key;
private final ObjectList<Holder.Reference<T>> byId = new ObjectArrayList<>(256);
private final Reference2IntMap<T> toId = Util.make(new Reference2IntOpenHashMap<>(2048), map -> map.defaultReturnValue(-1)); // Paper - Perf: Use bigger expected size to reduce collisions
- private final Map<ResourceLocation, Holder.Reference<T>> byLocation = new HashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions
- private final Map<ResourceKey<T>, Holder.Reference<T>> byKey = new HashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions
- private final Map<T, Holder.Reference<T>> byValue = new IdentityHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions
- private final Map<ResourceKey<T>, RegistrationInfo> registrationInfos = new IdentityHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions
+ // DivineMC start - Some optimizations
+ private final Map<ResourceLocation, Holder.Reference<T>> byLocation = new java.util.concurrent.ConcurrentHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions
+ private final Map<ResourceKey<T>, Holder.Reference<T>> byKey = new java.util.concurrent.ConcurrentHashMap<>(2048); // Paper - Perf: Use bigger expected size to reduce collisions
+ private final Map<T, Holder.Reference<T>> byValue = Collections.synchronizedMap(new IdentityHashMap<>(2048)); // Paper - Perf: Use bigger expected size to reduce collisions
+ private final Map<ResourceKey<T>, RegistrationInfo> registrationInfos = Collections.synchronizedMap(new IdentityHashMap<>(2048)); // Paper - Perf: Use bigger expected size to reduce collisions
+ // DivineMC end - Some optimizations
private Lifecycle registryLifecycle;
private final Map<TagKey<T>, HolderSet.Named<T>> frozenTags = new IdentityHashMap<>();
MappedRegistry.TagSet<T> allTags = MappedRegistry.TagSet.unbound();
diff --git a/net/minecraft/server/level/ChunkTrackingView.java b/net/minecraft/server/level/ChunkTrackingView.java
index bee90335677f7d8b01589ce5cfd81a40fd422886..a5e488d14fd2016ee188b114d0e681562b5b09cc 100644
--- a/net/minecraft/server/level/ChunkTrackingView.java
+++ b/net/minecraft/server/level/ChunkTrackingView.java
@@ -73,12 +73,12 @@ public interface ChunkTrackingView {
}
static boolean isWithinDistance(int centerX, int centerZ, int viewDistance, int x, int z, boolean includeOuterChunksAdjacentToViewBorder) {
- int i = includeOuterChunksAdjacentToViewBorder ? 2 : 1;
- long l = Math.max(0, Math.abs(x - centerX) - i);
- long l1 = Math.max(0, Math.abs(z - centerZ) - i);
- long l2 = l * l + l1 * l1;
- int i1 = viewDistance * viewDistance;
- return l2 < i1;
+ // DivineMC start - Some optimizations
+ int actualViewDistance = viewDistance + (includeOuterChunksAdjacentToViewBorder ? 1 : 0);
+ int xDistance = Math.abs(centerX - x);
+ int zDistance = Math.abs(centerZ - z);
+ return xDistance <= actualViewDistance && zDistance <= actualViewDistance;
+ // DivineMC end - Some optimizations
}
public record Positioned(ChunkPos center, int viewDistance) implements ChunkTrackingView {
diff --git a/net/minecraft/util/ClassInstanceMultiMap.java b/net/minecraft/util/ClassInstanceMultiMap.java
index 2a708ae0d5bb209650b525e3c56051f8b5655074..4c7670224f0c90c1d0d833ff0b3d908846133b4a 100644
--- a/net/minecraft/util/ClassInstanceMultiMap.java
+++ b/net/minecraft/util/ClassInstanceMultiMap.java
@@ -14,9 +14,9 @@ import java.util.Map.Entry;
import net.minecraft.Util;
public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
- private final Map<Class<?>, List<T>> byClass = Maps.newHashMap();
+ private final Map<Class<?>, List<T>> byClass = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // DivineMC - Misc Optimizations
private final Class<T> baseClass;
- private final List<T> allInstances = Lists.newArrayList();
+ private final List<T> allInstances = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(); // DivineMC - Misc Optimizations
public ClassInstanceMultiMap(Class<T> baseClass) {
this.baseClass = baseClass;
@@ -56,13 +56,27 @@ public class ClassInstanceMultiMap<T> extends AbstractCollection<T> {
}
public <S> Collection<S> find(Class<S> type) {
+ // DivineMC start - Some optimizations
+ List<T> cached = this.byClass.get(type);
+ if (cached != null) return (Collection<S>) cached;
+
if (!this.baseClass.isAssignableFrom(type)) {
throw new IllegalArgumentException("Don't know how to search for " + type);
} else {
- List<? extends T> list = this.byClass
- .computeIfAbsent(type, clazz -> this.allInstances.stream().filter(clazz::isInstance).collect(Util.toMutableList()));
- return (Collection<S>)Collections.unmodifiableCollection(list);
+ List<? extends T> list = this.byClass.computeIfAbsent(type,
+ typeClass -> {
+ it.unimi.dsi.fastutil.objects.ObjectArrayList<T> ts = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(this.allInstances.size());
+ for (Object _allElement : ((it.unimi.dsi.fastutil.objects.ObjectArrayList<T>) this.allInstances).elements()) {
+ if (typeClass.isInstance(_allElement)) {
+ ts.add((T) _allElement);
+ }
+ }
+ return ts;
+ }
+ );
+ return (Collection<S>) list;
}
+ // DivineMC end - Some optimizations
}
@Override
diff --git a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
index f28fbf81a417a678726d3f77b3999054676d522e..7ff32b1f93b31fafd13f4e0857d14d85ef1f28c7 100644
--- a/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
+++ b/net/minecraft/util/CrudeIncrementalIntIdentityHashBiMap.java
@@ -52,23 +52,23 @@ public class CrudeIncrementalIntIdentityHashBiMap<K> implements IdMap<K>, ca.spo
@Nullable
@Override
- public K byId(int value) {
+ public synchronized K byId(int value) { // DivineMC - Misc Optimizations
return value >= 0 && value < this.byId.length ? this.byId[value] : null;
}
- private int getValue(int key) {
+ private synchronized int getValue(int key) { // DivineMC - Misc Optimizations
return key == -1 ? -1 : this.values[key];
}
- public boolean contains(K value) {
+ public synchronized boolean contains(K value) { // DivineMC - Misc Optimizations
return this.getId(value) != -1;
}
- public boolean contains(int value) {
+ public synchronized boolean contains(int value) { // DivineMC - Misc Optimizations
return this.byId(value) != null;
}
- public int add(K object) {
+ public synchronized int add(K object) { // DivineMC - Misc Optimizations
int i = this.nextId();
this.addMapping(object, i);
return i;
@@ -106,7 +106,7 @@ public class CrudeIncrementalIntIdentityHashBiMap<K> implements IdMap<K>, ca.spo
// Paper end - optimise palette reads
}
- public void addMapping(K object, int intKey) {
+ public synchronized void addMapping(K object, int intKey) { // DivineMC - Misc Optimizations
int max = Math.max(intKey, this.size + 1);
if (max >= this.keys.length * 0.8F) {
int i = this.keys.length << 1;
@@ -173,11 +173,11 @@ public class CrudeIncrementalIntIdentityHashBiMap<K> implements IdMap<K>, ca.spo
}
@Override
- public Iterator<K> iterator() {
+ public synchronized Iterator<K> iterator() { // DivineMC - Misc Optimizations
return Iterators.filter(Iterators.forArray(this.byId), Predicates.notNull());
}
- public void clear() {
+ public synchronized void clear() { // DivineMC - Misc Optimizations
Arrays.fill(this.keys, null);
Arrays.fill(this.byId, null);
this.nextId = 0;
diff --git a/net/minecraft/util/CubicSpline.java b/net/minecraft/util/CubicSpline.java
index f36f8f2d49d4eba5c80eb243883749d6f831eb8a..5abd899c88683cb79bb8f02e43c4bfbe8563f496 100644
--- a/net/minecraft/util/CubicSpline.java
+++ b/net/minecraft/util/CubicSpline.java
@@ -254,31 +254,47 @@ public interface CubicSpline<C, I extends ToFloatFunction<C>> extends ToFloatFun
@Override
public float apply(C object) {
- float f = this.coordinate.apply(object);
- int i = findIntervalStart(this.locations, f);
- int i1 = this.locations.length - 1;
- if (i < 0) {
- return linearExtend(f, this.locations, this.values.get(0).apply(object), this.derivatives, 0);
- } else if (i == i1) {
- return linearExtend(f, this.locations, this.values.get(i1).apply(object), this.derivatives, i1);
+ // DivineMC start - Some optimizations
+ float point = this.coordinate.apply(object);
+ int rangeForLocation = findIntervalStart(this.locations, point);
+ int last = this.locations.length - 1;
+ if (rangeForLocation < 0) {
+ return linearExtend(point, this.locations, this.values.get(0).apply(object), this.derivatives, 0);
+ } else if (rangeForLocation == last) {
+ return linearExtend(point, this.locations, this.values.get(last).apply(object), this.derivatives, last);
} else {
- float f1 = this.locations[i];
- float f2 = this.locations[i + 1];
- float f3 = (f - f1) / (f2 - f1);
- ToFloatFunction<C> toFloatFunction = (ToFloatFunction<C>)this.values.get(i);
- ToFloatFunction<C> toFloatFunction1 = (ToFloatFunction<C>)this.values.get(i + 1);
- float f4 = this.derivatives[i];
- float f5 = this.derivatives[i + 1];
- float f6 = toFloatFunction.apply(object);
- float f7 = toFloatFunction1.apply(object);
- float f8 = f4 * (f2 - f1) - (f7 - f6);
- float f9 = -f5 * (f2 - f1) + (f7 - f6);
- return Mth.lerp(f3, f6, f7) + f3 * (1.0F - f3) * Mth.lerp(f3, f8, f9);
+ float loc0 = this.locations[rangeForLocation];
+ float loc1 = this.locations[rangeForLocation + 1];
+ float locDist = loc1 - loc0;
+ float k = (point - loc0) / locDist;
+ float n = this.values.get(rangeForLocation).apply(object);
+ float o = this.values.get(rangeForLocation + 1).apply(object);
+ float onDist = o - n;
+ float p = this.derivatives[rangeForLocation] * locDist - onDist;
+ float q = -this.derivatives[rangeForLocation + 1] * locDist + onDist;
+ return Mth.lerp(k, n, o) + k * (1.0F - k) * Mth.lerp(k, p, q);
}
+ // DivineMC end - Some optimizations
}
private static int findIntervalStart(float[] locations, float start) {
- return Mth.binarySearch(0, locations.length, i -> start < locations[i]) - 1;
+ // DivineMC start - Some optimizations
+ int min = 0;
+ int i = locations.length;
+
+ while (i > 0) {
+ int j = i / 2;
+ int k = min + j;
+ if (start < locations[k]) {
+ i = j;
+ } else {
+ min = k + 1;
+ i -= j + 1;
+ }
+ }
+
+ return min - 1;
+ // DivineMC end - Some optimizations
}
@VisibleForTesting
@@ -313,5 +329,27 @@ public interface CubicSpline<C, I extends ToFloatFunction<C>> extends ToFloatFun
this.derivatives
);
}
+
+ // DivineMC start - Some optimizations
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Multipoint<?, ?> that = (Multipoint<?, ?>) o;
+ return java.util.Objects.equals(coordinate, that.coordinate()) && java.util.Arrays.equals(locations, that.locations()) && java.util.Objects.equals(values, that.values()) && java.util.Arrays.equals(derivatives, that.derivatives());
+ }
+
+ @Override
+ public int hashCode() {
+ int result = 1;
+
+ result = 31 * result + java.util.Objects.hashCode(coordinate);
+ result = 31 * result + java.util.Arrays.hashCode(locations);
+ result = 31 * result + java.util.Objects.hashCode(values);
+ result = 31 * result + java.util.Arrays.hashCode(derivatives);
+
+ return result;
+ }
+ // DivineMC end - Some optimizations
}
}
diff --git a/net/minecraft/util/Mth.java b/net/minecraft/util/Mth.java
index ab3a221c115992d0f4ea921aa92cf0976b815ff4..076a931341da486162f289a5f19d3d6736df7768 100644
--- a/net/minecraft/util/Mth.java
+++ b/net/minecraft/util/Mth.java
@@ -46,11 +46,11 @@ public class Mth {
private static final double[] COS_TAB = new double[257];
public static float sin(float value) {
- return SIN[(int)(value * 10430.378F) & 65535];
+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.sin(value); // DivineMC - Math Optimizations
}
public static float cos(float value) {
- return SIN[(int)(value * 10430.378F + 16384.0F) & 65535];
+ return net.caffeinemc.mods.lithium.common.util.math.CompactSineLUT.cos(value); // DivineMC - Math Optimizations
}
public static float sqrt(float value) {
@@ -58,18 +58,15 @@ public class Mth {
}
public static int floor(float value) {
- int i = (int)value;
- return value < i ? i - 1 : i;
+ return (int) Math.floor(value); // DivineMC - Math Optimizations
}
public static int floor(double value) {
- int i = (int)value;
- return value < i ? i - 1 : i;
+ return (int) Math.floor(value); // DivineMC - Math Optimizations
}
public static long lfloor(double value) {
- long l = (long)value;
- return value < l ? l - 1L : l;
+ return (long) Math.floor(value); // DivineMC - Math Optimizations
}
public static float abs(float value) {
@@ -81,13 +78,11 @@ public class Mth {
}
public static int ceil(float value) {
- int i = (int)value;
- return value > i ? i + 1 : i;
+ return (int) Math.ceil(value); // DivineMC - Math Optimizations
}
public static int ceil(double value) {
- int i = (int)value;
- return value > i ? i + 1 : i;
+ return (int) Math.ceil(value); // DivineMC - Math Optimizations
}
public static int clamp(int value, int min, int max) {
@@ -123,15 +118,7 @@ public class Mth {
}
public static double absMax(double x, double y) {
- if (x < 0.0) {
- x = -x;
- }
-
- if (y < 0.0) {
- y = -y;
- }
-
- return Math.max(x, y);
+ return Math.max(Math.abs(x), Math.abs(y)); // DivineMC - Math Optimizations
}
public static int floorDiv(int dividend, int divisor) {
@@ -162,14 +149,26 @@ public class Mth {
return Math.floorMod(x, y);
}
- public static float positiveModulo(float numerator, float denominator) {
+ public static float positiveModuloForAnyDenominator(float numerator, float denominator) { // DivineMC - Math Optimizations
return (numerator % denominator + denominator) % denominator;
}
- public static double positiveModulo(double numerator, double denominator) {
+ public static double positiveModuloForAnyDenominator(double numerator, double denominator) { // DivineMC - Math Optimizations
return (numerator % denominator + denominator) % denominator;
}
+ // DivineMC start - Math Optimizations
+ public static float positiveModuloForPositiveIntegerDenominator(float numerator, float denominator) {
+ var modulo = numerator % denominator;
+ return modulo < 0 ? modulo + denominator : modulo;
+ }
+
+ public static double positiveModuloForPositiveIntegerDenominator(double numerator, double denominator) {
+ var modulo = numerator % denominator;
+ return modulo < 0 ? modulo + denominator : modulo;
+ }
+ // DivineMC end - Math Optimizations
+
public static boolean isMultipleOf(int number, int multiple) {
return number % multiple == 0;
}
diff --git a/net/minecraft/util/RandomSource.java b/net/minecraft/util/RandomSource.java
index 98a54bc4de251014342cda6d0951b7fea79ce553..663edee4dfa660e3d3a04c728fd764258867916d 100644
--- a/net/minecraft/util/RandomSource.java
+++ b/net/minecraft/util/RandomSource.java
@@ -12,7 +12,7 @@ public interface RandomSource {
double GAUSSIAN_SPREAD_FACTOR = 2.297;
static RandomSource create() {
- return create(RandomSupport.generateUniqueSeed());
+ return createThreadSafe(); // DivineMC - Misc Optimizations
}
@Deprecated
@@ -21,7 +21,7 @@ public interface RandomSource {
}
static RandomSource create(long seed) {
- return new LegacyRandomSource(seed);
+ return new ThreadSafeLegacyRandomSource(seed); // DivineMC - Misc Optimizations
}
static RandomSource createNewThreadLocalInstance() {
diff --git a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java
index 15de39fa82c7aea18298509fe9587d027c30cc15..eb534ed5a7478fc632db096328e3582f4ec410b8 100644
--- a/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java
+++ b/net/minecraft/util/debugchart/DebugSampleSubscriptionTracker.java
@@ -15,7 +15,7 @@ public class DebugSampleSubscriptionTracker {
public static final int STOP_SENDING_AFTER_MS = 10000;
private final PlayerList playerList;
private final EnumMap<RemoteDebugSampleType, Map<ServerPlayer, DebugSampleSubscriptionTracker.SubscriptionStartedAt>> subscriptions;
- private final Queue<DebugSampleSubscriptionTracker.SubscriptionRequest> subscriptionRequestQueue = new LinkedList<>();
+ private final java.util.List<SubscriptionRequest> subscriptionRequestQueue = java.util.Collections.synchronizedList(new LinkedList<>()); // DivineMC - Misc Optimizations
public DebugSampleSubscriptionTracker(PlayerList playerList) {
this.playerList = playerList;
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 258cb45f1f959b75c1bcdb130811af2f8fddf07d..9c0e539f09bddac018f93d212e3cdbc446f3c672 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -143,7 +143,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
// Paper start - Share random for entities to make them more random
- public static RandomSource SHARED_RANDOM = new RandomRandomSource();
+ public static RandomSource SHARED_RANDOM = new net.minecraft.world.level.levelgen.ThreadSafeLegacyRandomSource(net.minecraft.world.level.levelgen.RandomSupport.generateUniqueSeed()); // DivineMC - Misc Optimizations
// Paper start - replace random
private static final class RandomRandomSource extends ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom {
public RandomRandomSource() {
diff --git a/net/minecraft/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
index 66f3565b978f2ed91cb2bc3a816f1701c0873c73..b4e19cc65701d5ef94e1cc0a7473225c222725c3 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -832,7 +832,7 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) {
this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause
} else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) {
- Entity nearestPlayer = this.level().findNearbyPlayer(this, -1.0, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API
+ Entity nearestPlayer = this.divinemc$findNearbyPlayer(this.level(), this, -1.0); // Paper - Affects Spawning API // DivineMC - faster player lookup
if (nearestPlayer != null) {
// Paper start - Configurable despawn distances
final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory());
@@ -861,6 +861,19 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Leashab
}
}
+ // DivineMC start - faster player lookup
+ private Player divinemc$findNearbyPlayer(Level instance, Entity entity, double maxDistance) {
+ final Player closestPlayer = instance.getNearestPlayer(entity, this.getType().getCategory().getDespawnDistance());
+ if (closestPlayer != null) {
+ return closestPlayer;
+ } else {
+ final List<? extends Player> players = this.level().players();
+ if (players.isEmpty()) return null;
+ return players.get(0);
+ }
+ }
+ // DivineMC end - faster player lookup
+
@Override
protected final void serverAiStep() {
this.noActionTime++;
diff --git a/net/minecraft/world/level/GameRules.java b/net/minecraft/world/level/GameRules.java
index 5ded2f808a9fcb26856567de6bc56e206f948a84..02d64a5ea756b2c91a71b7a0fc0f21219983616a 100644
--- a/net/minecraft/world/level/GameRules.java
+++ b/net/minecraft/world/level/GameRules.java
@@ -249,7 +249,7 @@ public class GameRules {
}
private GameRules(Map<GameRules.Key<?>, GameRules.Value<?>> rules, FeatureFlagSet enabledFeatures) {
- this.rules = rules;
+ this.rules = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(rules); // DivineMC - lithium: collections.gamerules
this.enabledFeatures = enabledFeatures;
// Paper start - Perf: Use array for gamerule storage
diff --git a/net/minecraft/world/level/LocalMobCapCalculator.java b/net/minecraft/world/level/LocalMobCapCalculator.java
index 9641219c190261dea0db5f95f040a705ba0a3ff9..a3fccdeb2c076e12b611683da55d45e00a166417 100644
--- a/net/minecraft/world/level/LocalMobCapCalculator.java
+++ b/net/minecraft/world/level/LocalMobCapCalculator.java
@@ -13,16 +13,24 @@ import net.minecraft.world.entity.MobCategory;
public class LocalMobCapCalculator {
private final Long2ObjectMap<List<ServerPlayer>> playersNearChunk = new Long2ObjectOpenHashMap<>();
- private final Map<ServerPlayer, LocalMobCapCalculator.MobCounts> playerMobCounts = Maps.newHashMap();
+ private final Map<ServerPlayer, LocalMobCapCalculator.MobCounts> playerMobCounts = Maps.newConcurrentMap(); // DivineMC - Misc Optimizations
private final ChunkMap chunkMap;
public LocalMobCapCalculator(ChunkMap chunkMap) {
this.chunkMap = chunkMap;
}
- private List<ServerPlayer> getPlayersNear(ChunkPos pos) {
- return this.playersNearChunk.computeIfAbsent(pos.toLong(), key -> this.chunkMap.getPlayersCloseForSpawning(pos));
+ // DivineMC start - Some optimizations
+ private synchronized @org.jetbrains.annotations.NotNull List<ServerPlayer> getPlayersNear(ChunkPos pos) {
+ List<ServerPlayer> retVal = this.playersNearChunk.get(pos.toLong());
+ if (retVal == null) {
+ List<ServerPlayer> newVal = this.chunkMap.getPlayersCloseForSpawning(pos);
+ this.playersNearChunk.put(pos.toLong(), newVal);
+ return newVal;
+ }
+ return retVal;
}
+ // DivineMC end - Some optimizations
public void addMob(ChunkPos pos, MobCategory category) {
for (ServerPlayer serverPlayer : this.getPlayersNear(pos)) {
@@ -42,14 +50,14 @@ public class LocalMobCapCalculator {
}
static class MobCounts {
- private final Object2IntMap<MobCategory> counts = new Object2IntOpenHashMap<>(MobCategory.values().length);
+ private final int[] spawnGroupDensities = new int[MobCategory.values().length]; // DivineMC - Misc Optimizations
public void add(MobCategory category) {
- this.counts.computeInt(category, (key, value) -> value == null ? 1 : value + 1);
+ this.spawnGroupDensities[category.ordinal()] ++; // DivineMC - Misc Optimizations
}
public boolean canSpawn(MobCategory category) {
- return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk();
+ return this.spawnGroupDensities[category.ordinal()] < category.getMaxInstancesPerChunk(); // DivineMC - Misc Optimizations
}
}
}
diff --git a/net/minecraft/world/level/levelgen/blending/Blender.java b/net/minecraft/world/level/levelgen/blending/Blender.java
index 01e5b29d6e9a5c53c0e23b61ed0c1d7be1a0fe08..d80df05e40f3941ade5ed320e12f8dcf47e6b247 100644
--- a/net/minecraft/world/level/levelgen/blending/Blender.java
+++ b/net/minecraft/world/level/levelgen/blending/Blender.java
@@ -144,7 +144,7 @@ public class Blender {
private static double heightToOffset(double height) {
double d = 1.0;
double d1 = height + 0.5;
- double d2 = Mth.positiveModulo(d1, 8.0);
+ double d2 = Mth.positiveModuloForPositiveIntegerDenominator(d1, 8.0); // DivineMC - Math optimizations
return 1.0 * (32.0 * (d1 - 128.0) - 3.0 * (d1 - 120.0) * d2 + 3.0 * d2 * d2) / (128.0 * (32.0 - 3.0 * d2));
}
diff --git a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
index 681dec447486138088fe5f705ef4fadab531139f..12ea268eaec629fde20d55460e618fde3a3e006d 100644
--- a/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
+++ b/net/minecraft/world/level/saveddata/maps/MapItemSavedData.java
@@ -198,6 +198,7 @@ public class MapItemSavedData extends SavedData {
}
}
+ mapItemSavedData.setDirty(false); // DivineMC - Misc Optimizations
return mapItemSavedData;
}
diff --git a/net/minecraft/world/level/storage/DimensionDataStorage.java b/net/minecraft/world/level/storage/DimensionDataStorage.java
index d9a3b5a2e6495b7e22c114506c2bd1e406f58f8f..a6e03345afd6d8a38e06a43c59103209618baa14 100644
--- a/net/minecraft/world/level/storage/DimensionDataStorage.java
+++ b/net/minecraft/world/level/storage/DimensionDataStorage.java
@@ -34,7 +34,7 @@ import org.slf4j.Logger;
public class DimensionDataStorage implements AutoCloseable {
private static final Logger LOGGER = LogUtils.getLogger();
- public final Map<String, Optional<SavedData>> cache = new HashMap<>();
+ public final Map<String, Optional<SavedData>> cache = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Concurrent HashMap
private final DataFixer fixerUpper;
private final HolderLookup.Provider registries;
private final Path dataFolder;
diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java
index c9c6e4e460ad8435f12761704bb9b0284d6aa708..54807bb4b4189ceaded1f78a1a9ab85ce40ab2b1 100644
--- a/net/minecraft/world/phys/AABB.java
+++ b/net/minecraft/world/phys/AABB.java
@@ -189,13 +189,15 @@ public class AABB {
}
public AABB intersect(AABB other) {
- double max = Math.max(this.minX, other.minX);
- double max1 = Math.max(this.minY, other.minY);
- double max2 = Math.max(this.minZ, other.minZ);
- double min = Math.min(this.maxX, other.maxX);
- double min1 = Math.min(this.maxY, other.maxY);
- double min2 = Math.min(this.maxZ, other.maxZ);
- return new AABB(max, max1, max2, min, min1, min2);
+ // DivineMC start - Math Optimizations
+ return new AABB(
+ this.minX > other.minX ? this.minX : other.minX,
+ this.minY > other.minY ? this.minY : other.minY,
+ this.minZ > other.minZ ? this.minZ : other.minZ,
+ this.maxX < other.maxX ? this.maxX : other.maxX,
+ this.maxY < other.maxY ? this.maxY : other.maxY,
+ this.maxZ < other.maxZ ? this.maxZ : other.maxZ
+ );
}
public AABB minmax(AABB other) {
@@ -227,16 +229,37 @@ public class AABB {
}
public boolean intersects(AABB other) {
- return this.intersects(other.minX, other.minY, other.minZ, other.maxX, other.maxY, other.maxZ);
+ // DivineMC start - Math Optimizations
+ return this.minX < other.maxX &&
+ this.maxX > other.minX &&
+ this.minY < other.maxY &&
+ this.maxY > other.minY &&
+ this.minZ < other.maxZ &&
+ this.maxZ > other.minZ;
+ // DivineMC end - Math Optimizations
}
public boolean intersects(double x1, double y1, double z1, double x2, double y2, double z2) {
- return this.minX < x2 && this.maxX > x1 && this.minY < y2 && this.maxY > y1 && this.minZ < z2 && this.maxZ > z1;
+ // DivineMC start - Math Optimizations
+ return this.minX < x2 &&
+ this.maxX > x1 &&
+ this.minY < y2 &&
+ this.maxY > y1 &&
+ this.minZ < z2 &&
+ this.maxZ > z1;
+ // DivineMC end - Math Optimizations
}
public boolean intersects(Vec3 min, Vec3 max) {
return this.intersects(
- Math.min(min.x, max.x), Math.min(min.y, max.y), Math.min(min.z, max.z), Math.max(min.x, max.x), Math.max(min.y, max.y), Math.max(min.z, max.z)
+ // DivineMC start - Math Optimizations
+ min.x < max.x ? min.x : max.x,
+ min.y < max.y ? min.y : max.y,
+ min.z < max.z ? min.z : max.z,
+ min.x > max.x ? min.x : max.x,
+ min.y > max.y ? min.y : max.y,
+ min.z > max.z ? min.z : max.z
+ // DivineMC end - Math Optimizations
);
}

View File

@@ -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 47a7ce88bf4d26408545dcc061aa763311af0dc9..13877d2bd4289652a9627780839b8d879a66d753 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())) {
+ 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 44bc0823e163bb7edee27889201ec76e93e095cf..974e1e5dcb2613c5aaedd3f2f66483c9dcd6cd23 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())) {
+ 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())) {
+ 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;
@@ -341,33 +375,46 @@ public abstract class FlowingFluid extends Fluid {
protected void beforeDestroyingBlock(LevelAccessor level, BlockPos pos, BlockState state, BlockPos source) { beforeDestroyingBlock(level, pos, state); } // Paper - Add BlockBreakBlockEvent
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 85629a43f5469a89dd6078d879f475e8212438ec..35b5a33c79c883f28c99c992695b188524593b55 100644
--- a/net/minecraft/world/level/material/LavaFluid.java
+++ b/net/minecraft/world/level/material/LavaFluid.java
@@ -224,6 +224,7 @@ public abstract class LavaFluid extends FlowingFluid {
// CraftBukkit end
}
+ level.setBlock(pos, Blocks.STONE.defaultBlockState(), 3); // DivineMC - Optimize Fluids
this.fizz(level, pos);
return;
}

View File

@@ -1,422 +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 entity stupid brain
diff --git a/net/minecraft/world/entity/AgeableMob.java b/net/minecraft/world/entity/AgeableMob.java
index 179f4e4b9b1eb57f78bbb2f9fa34b11ea79b7a88..143a4ca51a57934bf545e031b10525dedbe9c3bd 100644
--- a/net/minecraft/world/entity/AgeableMob.java
+++ b/net/minecraft/world/entity/AgeableMob.java
@@ -121,6 +121,16 @@ public abstract class AgeableMob extends PathfinderMob {
public void onSyncedDataUpdated(EntityDataAccessor<?> key) {
if (DATA_BABY_ID.equals(key)) {
this.refreshDimensions();
+ // DivineMC start - Optimize entity stupid brain
+ 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 entity stupid brain
}
super.onSyncedDataUpdated(key);
diff --git a/net/minecraft/world/entity/ai/Brain.java b/net/minecraft/world/entity/ai/Brain.java
index 8f7efe6b2c191f615dfc8394baec44dc0761ff51..406eb049cb22d0736d8b003a2f547cc25c6f68b6 100644
--- a/net/minecraft/world/entity/ai/Brain.java
+++ b/net/minecraft/world/entity/ai/Brain.java
@@ -45,16 +45,73 @@ 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();
- private final Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> availableBehaviorsByPriority = Maps.newTreeMap();
+ private Map<MemoryModuleType<?>, Optional<? extends ExpirableValue<?>>> memories = Maps.newConcurrentMap(); // DivineMC - concurrent map
+ public Map<SensorType<? extends Sensor<? super E>>, Sensor<? super E>> sensors = Maps.newLinkedHashMap(); // DivineMC - linked hash map
+ private final Map<Integer, Map<Activity, Set<BehaviorControl<? super E>>>> availableBehaviorsByPriority = Maps.newTreeMap(); // DivineMC - tree map
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 - hash map
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 entity stupid brain
+ 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 entity stupid brain
public static <E extends LivingEntity> Brain.Provider<E> provider(
Collection<? extends MemoryModuleType<?>> memoryTypes, Collection<? extends SensorType<? extends Sensor<? super E>>> sensorTypes
@@ -146,6 +203,12 @@ public class Brain<E extends LivingEntity> {
for (Brain.MemoryValue<?> memoryValue : memoryValues) {
memoryValue.setMemoryInternal(this);
}
+ // DivineMC start - Optimize entity stupid brain
+ 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 entity stupid brain
}
public <T> DataResult<T> serializeStart(DynamicOps<T> ops) {
@@ -165,6 +228,7 @@ public class Brain<E extends LivingEntity> {
}
public <U> void eraseMemory(MemoryModuleType<U> type) {
+ if (!this.memories.containsKey(type)) return; // DivineMC - skip if memory does not contain key
this.setMemory(type, Optional.empty());
}
@@ -180,16 +244,33 @@ public class Brain<E extends LivingEntity> {
this.setMemoryInternal(memoryType, memory.map(ExpirableValue::of));
}
+ // DivineMC start - Optimize entity stupid brain
<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 entity stupid brain
+
public <U> Optional<U> getMemory(MemoryModuleType<U> type) {
Optional<? extends ExpirableValue<?>> optional = this.memories.get(type);
if (optional == null) {
@@ -251,19 +332,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 entity stupid brain
}
public void useDefaultActivity() {
@@ -294,6 +363,7 @@ public class Brain<E extends LivingEntity> {
this.activeActivities.clear();
this.activeActivities.addAll(this.coreActivities);
this.activeActivities.add(activity);
+ this.onPossibleActivitiesChanged(); // DivineMC - Optimize entity stupid brain
}
}
@@ -374,11 +444,13 @@ public class Brain<E extends LivingEntity> {
.computeIfAbsent(activity, activity1 -> Sets.newLinkedHashSet())
.add((BehaviorControl<? super E>)pair.getSecond());
}
+ this.onTasksChanged(); // DivineMC - Optimize entity stupid brain
}
@VisibleForTesting
public void removeAllBehaviors() {
this.availableBehaviorsByPriority.clear();
+ this.onTasksChanged(); // DivineMC - Optimize entity stupid brain
}
public boolean isActive(Activity activity) {
@@ -395,6 +467,7 @@ public class Brain<E extends LivingEntity> {
}
}
+ brain.memoryModCount = this.memoryModCount + 1; // DivineMC - Optimize entity stupid brain
return brain;
}
@@ -429,31 +502,38 @@ public class Brain<E extends LivingEntity> {
for (BehaviorControl<? super E> behaviorControl : this.getRunningBehaviors()) {
behaviorControl.doStop(level, owner, gameTime);
+ // DivineMC start - Optimize entity stupid brain
+ if (this.runningTasks != null) {
+ this.runningTasks.setVisible(behaviorControl, false);
+ }
+ // DivineMC end - Optimize entity stupid brain
}
}
+ // DivineMC start - Optimize entity stupid brain
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 entity stupid brain
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 entity stupid brain
+ if (this.runningTasks != null && behaviorControl.getStatus() != Behavior.Status.RUNNING) {
+ this.runningTasks.setVisible(behaviorControl, false);
+ }
+ // DivineMC end - Optimize entity stupid brain
}
}
diff --git a/net/minecraft/world/entity/ai/behavior/Behavior.java b/net/minecraft/world/entity/ai/behavior/Behavior.java
index 5b0cadd2544fb2a627822e645ff32fec2e9cfda9..253b9ad671cf0932bb17d468f8b91a15a86ff77a 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 entity stupid brain
+ private long cachedMemoryModCount = -1;
+ private boolean cachedHasRequiredMemoryState;
+ // DivineMC end - Optimize entity stupid brain
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 entity stupid brain - 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 entity stupid brain
+ 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 entity stupid brain
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 ec90ea4e66c6c38d7ad41805a16c63e006e44be4..0204fe68c97d152a7c3201620b6709a8bebefdf6 100644
--- a/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
+++ b/net/minecraft/world/entity/ai/behavior/LongJumpToRandomPos.java
@@ -120,6 +120,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 entity stupid brain
+ 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 entity stupid brain
this.jumpCandidates = BlockPos.betweenClosedStream(
x - this.maxLongJumpWidth,
y - this.maxLongJumpHeight,
@@ -175,11 +181,27 @@ public class LongJumpToRandomPos<E extends Mob> extends Behavior<E> {
}
}
+ // DivineMC start - Optimize entity stupid brain
protected Optional<LongJumpToRandomPos.PossibleJump> getJumpCandidate(ServerLevel level) {
- Optional<LongJumpToRandomPos.PossibleJump> randomItem = WeightedRandom.getRandomItem(level.random, this.jumpCandidates);
- 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);
+ }
+ }
+
+ 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);
+ }
}
+ // DivineMC end - Optimize entity stupid brain
private boolean isAcceptableLandingPosition(ServerLevel level, E entity, BlockPos pos) {
BlockPos blockPos = entity.blockPosition();
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 9b8f5d9926d68fd8b9f1f976e0be0975158cafc3..e21f024d0ed7f936ff17df16bd9666fffbf44a75 100644
--- a/net/minecraft/world/entity/animal/goat/Goat.java
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
@@ -96,6 +96,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 entity stupid brain
+ 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 entity stupid brain
}
public ItemStack createHorn() {

View File

@@ -1,192 +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:57:01 +0300
Subject: [PATCH] Optimize explosions
diff --git a/net/minecraft/world/level/ServerExplosion.java b/net/minecraft/world/level/ServerExplosion.java
index 6bddf42504039f2be5eb9a5a35a0835e0e3239fe..ea6da35e6c38a0b8b67d0b7a1426445eadfb540c 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -375,6 +375,11 @@ public class ServerExplosion implements Explosion {
}
private List<BlockPos> calculateExplodedPositions() {
+ // DivineMC start - Optimize explosions
+ if (org.bxteam.divinemc.DivineConfig.enableFasterTntOptimization && !level.isClientSide && !(getIndirectSourceEntity() instanceof net.minecraft.world.entity.monster.breeze.Breeze)) {
+ return doExplosionA(this);
+ }
+ // DivineMC end - Optimize explosions
// Paper start - collision optimisations
final ObjectArrayList<BlockPos> ret = new ObjectArrayList<>();
@@ -473,6 +478,157 @@ public class ServerExplosion implements Explosion {
// Paper end - collision optimisations
}
+ // DivineMC start - Optimize explosions
+ private static final it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap<org.apache.commons.lang3.tuple.Pair<net.minecraft.world.phys.Vec3, net.minecraft.world.phys.AABB>> densityCache = new it.unimi.dsi.fastutil.objects.Object2DoubleOpenHashMap<>();
+ private static final it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<net.minecraft.core.BlockPos, net.minecraft.world.level.block.state.BlockState> stateCache = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>();
+ private static final it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<net.minecraft.core.BlockPos, net.minecraft.world.level.material.FluidState> fluidCache = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>();
+ private static final BlockPos.MutableBlockPos posMutable = new BlockPos.MutableBlockPos(0, 0, 0);
+ private static final it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<net.minecraft.core.BlockPos> affectedBlockPositionsSet = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>();
+ private static boolean firstRay;
+ private static boolean rayCalcDone;
+
+ public static @org.jetbrains.annotations.NotNull List<BlockPos> doExplosionA(ServerExplosion e) {
+ List<BlockPos> toBlow;
+
+ if (!org.bxteam.divinemc.DivineConfig.explosionNoBlockDamage && e.damageSource != null) {
+ rayCalcDone = false;
+ firstRay = true;
+ getAffectedPositionsOnPlaneY(e, 0, 0, 15, 0, 15); // bottom
+ getAffectedPositionsOnPlaneY(e, 15, 0, 15, 0, 15); // top
+ getAffectedPositionsOnPlaneX(e, 0, 1, 14, 0, 15); // west
+ getAffectedPositionsOnPlaneX(e, 15, 1, 14, 0, 15); // east
+ getAffectedPositionsOnPlaneZ(e, 0, 1, 14, 1, 14); // north
+ getAffectedPositionsOnPlaneZ(e, 15, 1, 14, 1, 14); // south
+ stateCache.clear();
+ fluidCache.clear();
+
+ toBlow = new ArrayList<>(affectedBlockPositionsSet);
+ affectedBlockPositionsSet.clear();
+ } else {
+ toBlow = java.util.Collections.emptyList();
+ }
+ densityCache.clear();
+
+ return toBlow;
+ }
+
+ private static void getAffectedPositionsOnPlaneX(Explosion e, int x, int yStart, int yEnd, int zStart, int zEnd) {
+ if (!rayCalcDone) {
+ final double xRel = (double) x / 15.0D * 2.0D - 1.0D;
+
+ for (int z = zStart; z <= zEnd; ++z) {
+ double zRel = (double) z / 15.0D * 2.0D - 1.0D;
+
+ for (int y = yStart; y <= yEnd; ++y) {
+ double yRel = (double) y / 15.0D * 2.0D - 1.0D;
+
+ if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private static void getAffectedPositionsOnPlaneY(Explosion e, int y, int xStart, int xEnd, int zStart, int zEnd) {
+ if (!rayCalcDone) {
+ final double yRel = (double) y / 15.0D * 2.0D - 1.0D;
+
+ for (int z = zStart; z <= zEnd; ++z) {
+ double zRel = (double) z / 15.0D * 2.0D - 1.0D;
+
+ for (int x = xStart; x <= xEnd; ++x) {
+ double xRel = (double) x / 15.0D * 2.0D - 1.0D;
+
+ if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private static void getAffectedPositionsOnPlaneZ(Explosion e, int z, int xStart, int xEnd, int yStart, int yEnd) {
+ if (!rayCalcDone) {
+ final double zRel = (double) z / 15.0D * 2.0D - 1.0D;
+
+ for (int x = xStart; x <= xEnd; ++x) {
+ double xRel = (double) x / 15.0D * 2.0D - 1.0D;
+
+ for (int y = yStart; y <= yEnd; ++y) {
+ double yRel = (double) y / 15.0D * 2.0D - 1.0D;
+
+ if (checkAffectedPosition((ServerExplosion) e, xRel, yRel, zRel)) {
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private static boolean checkAffectedPosition(ServerExplosion e, double xRel, double yRel, double zRel) {
+ double len = Math.sqrt(xRel * xRel + yRel * yRel + zRel * zRel);
+ double xInc = (xRel / len) * 0.3;
+ double yInc = (yRel / len) * 0.3;
+ double zInc = (zRel / len) * 0.3;
+ float rand = e.level().random.nextFloat();
+ float sizeRand = (org.bxteam.divinemc.DivineConfig.tntRandomRange >= 0 ? (float) org.bxteam.divinemc.DivineConfig.tntRandomRange : rand);
+ float size = e.radius() * (0.7F + sizeRand * 0.6F);
+ Vec3 vec3 = e.center();
+ double posX = vec3.x;
+ double posY = vec3.y;
+ double posZ = vec3.z;
+
+ for (float f1 = 0.3F; size > 0.0F; size -= 0.22500001F) {
+ posMutable.set(posX, posY, posZ);
+
+ // Don't query already cached positions again from the world
+ BlockState state = stateCache.get(posMutable);
+ FluidState fluid = fluidCache.get(posMutable);
+ BlockPos posImmutable = null;
+
+ if (state == null) {
+ posImmutable = posMutable.immutable();
+ state = e.level().getBlockState(posImmutable);
+ stateCache.put(posImmutable, state);
+ fluid = e.level().getFluidState(posImmutable);
+ fluidCache.put(posImmutable, fluid);
+ }
+
+ if (!state.isAir()) {
+ float resistance = Math.max(state.getBlock().getExplosionResistance(), fluid.getExplosionResistance());
+
+ if (e.source != null) {
+ resistance = e.source.getBlockExplosionResistance(e, e.level(), posMutable, state, fluid, resistance);
+ }
+
+ size -= (resistance + 0.3F) * 0.3F;
+ }
+
+ if (size > 0.0F) {
+ if ((e.source == null || e.source.shouldBlockExplode(e, e.level(), posMutable, state, size)))
+ affectedBlockPositionsSet.add(posImmutable != null ? posImmutable : posMutable.immutable());
+ } else if (firstRay) {
+ rayCalcDone = true;
+ return true;
+ }
+
+ firstRay = false;
+
+ posX += xInc;
+ posY += yInc;
+ posZ += zInc;
+ }
+
+ return false;
+ }
+
+ private Optional<Float> noBlockCalcsWithNoBLockDamage(final ExplosionDamageCalculator instance, final Explosion explosion, final BlockGetter blockGetter, final BlockPos blockPos, final BlockState blockState, final FluidState fluidState) {
+ if (org.bxteam.divinemc.DivineConfig.explosionNoBlockDamage) return Optional.of(Blocks.BEDROCK.getExplosionResistance());
+ return instance.getBlockExplosionResistance(explosion, blockGetter, blockPos, blockState, fluidState);
+ }
+ // DivineMC end - Optimize explosions
+
private void hurtEntities() {
float f = this.radius * 2.0F;
int floor = Mth.floor(this.center.x - f - 1.0);
@@ -565,6 +721,11 @@ public class ServerExplosion implements Explosion {
}
private void interactWithBlocks(List<BlockPos> blocks) {
+ // DivineMC start - Optimize explosions
+ if (org.bxteam.divinemc.DivineConfig.explosionNoBlockDamage) {
+ blocks.clear();
+ }
+ // DivineMC end - Optimize explosions
List<ServerExplosion.StackCollector> list = new ArrayList<>();
Util.shuffle(blocks, this.level.random);

View File

@@ -1,70 +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 f8c76bb2c9fa625e191036dc58ef3dfb1d4ee930..5b8031a45b1f4f6d0e86c2a839d173a6e3f4f697 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -574,7 +574,7 @@ public class ServerGamePacketListenerImpl
return;
}
// Paper end - Prevent moving into unloaded chunks
- if (d7 - d6 > Math.max(100.0, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && !this.isSingleplayerOwner()) {
+ if (!org.bxteam.divinemc.DivineConfig.alwaysAllowWeirdMovement && (d7 - d6 > Math.max(100.0, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && !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
@@ -604,7 +604,7 @@ public class ServerGamePacketListenerImpl
d5 = d2 - rootVehicle.getZ();
d7 = d3 * d3 + d4 * d4 + d5 * d5;
boolean flag2 = false;
- if (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot
+ if (!org.bxteam.divinemc.DivineConfig.alwaysAllowWeirdMovement && (d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold)) { // Spigot // DivineMC - stop weird movement
flag2 = 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));
}
@@ -1453,18 +1453,22 @@ 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,
- toX, toY, toZ, toYaw, toPitch, true);
- if (!event.isAllowed()) {
- if (event.getLogWarning()) {
- LOGGER.warn("{} moved too quickly! {},{},{}", this.player.getName().getString(), d3, d4, d5);
+ // DivineMC start - Stop teleporting players when they move too quickly
+ if (!org.bxteam.divinemc.DivineConfig.alwaysAllowWeirdMovement && !(org.bxteam.divinemc.DivineConfig.ignoreMovedTooQuicklyWhenLagging && player.serverLevel().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(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot());
+ return;
}
- this.teleport(this.player.getX(), this.player.getY(), this.player.getZ(), this.player.getYRot(), this.player.getXRot());
- return;
+ // Paper end - Add fail move event
}
- // Paper end - Add fail move event
+ // DivineMC end - Stop teleporting players when they move too quickly
}
}
}
@@ -1525,6 +1529,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.DivineConfig.alwaysAllowWeirdMovement // DivineMC - Stop teleporting players when they move too quickly
&& d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold // Spigot
&& !this.player.isSleeping()
&& !this.player.gameMode.isCreative()

View File

@@ -1,331 +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 5a726da8535aa939f043829a3c60fdd9d4ed154a..0aebdd1cb0e1b63ff9a867bdcda7cbdc3c194b56 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 static final long SERVER_INIT = System.nanoTime(); // Paper - Lag compensation
protected boolean upnp = false; // Purpur - UPnP Port Forwarding
public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - Parallel world ticking
+ public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
@@ -1558,6 +1559,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 a70007d324e2169d1b2a1a11046500196b8b5660..53b606c34f65b80a676ddd26d64028dbdebecb43 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -218,6 +218,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
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 org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag Compensation
public LevelChunk getChunkIfLoaded(int x, int z) {
return this.chunkSource.getChunkAtIfLoadedImmediately(x, z); // Paper - Use getChunkIfLoadedImmediately
@@ -774,6 +775,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
}
+ this.tpsCalculator.doTick(); // DivineMC - Lag compensation
+
this.updateSkyBrightness();
if (runsNormally) {
this.tickTime();
@@ -853,11 +856,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.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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 04a1c17a34b495b71eb1b0ccd597cef83480464d..edb128a3f454e7b3009ca360509decd7a618de5d 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -555,6 +555,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
}
+ lagCompensation(); // DivineMC - Lag Compensation
this.tickEffects();
this.animStepO = this.animStep;
this.yBodyRotO = this.yBodyRot;
@@ -563,6 +564,17 @@ public abstract class LivingEntity extends Entity implements Attackable {
this.xRotO = this.getXRot();
}
+ // DivineMC start - Lag Compensation
+ private void lagCompensation() {
+ if (!org.bxteam.divinemc.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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 be357d9e3c5327ceec12c31830551a564c8cea1b..f77da420bc88df6ec304086fc1eba0690fe278b1 100644
--- a/net/minecraft/world/entity/PortalProcessor.java
+++ b/net/minecraft/world/entity/PortalProcessor.java
@@ -26,10 +26,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.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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 771b169fa360411bb313ae04c7dd55836875c611..e64ed6a23efbe89b8d3dd1e5a2a69ba4b7743369 100644
--- a/net/minecraft/world/entity/item/ItemEntity.java
+++ b/net/minecraft/world/entity/item/ItemEntity.java
@@ -153,8 +153,25 @@ public class ItemEntity extends Entity implements TraceableEntity {
}
// Paper end - EAR 2
+ // DivineMC start - Lag compensation
+ private void lagCompensation() {
+ if (!org.bxteam.divinemc.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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 6821d39a24ef610ea8b04f6dbeca2cdc0b8e7787..a4d76e4aafb98b1bbc0e5a80d65cf0f9a3a53fd5 100644
--- a/net/minecraft/world/item/Item.java
+++ b/net/minecraft/world/item/Item.java
@@ -258,9 +258,21 @@ public class Item implements FeatureElement, ItemLike {
return consumable != null ? consumable.animation() : ItemUseAnimation.NONE;
}
+ // DivineMC start - Lag compensation
+ private int lagCompensation(int original, net.minecraft.server.level.ServerLevel level) {
+ if (!org.bxteam.divinemc.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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);
- return consumable != null ? consumable.consumeTicks() : 0;
+ int original = consumable != null ? consumable.consumeTicks() : 0;
+ if (entity.level() instanceof net.minecraft.server.level.ServerLevel serverLevel) {
+ return lagCompensation(original, serverLevel);
+ }
+
+ return original;
}
public boolean releaseUsing(ItemStack stack, Level level, LivingEntity entity, int timeLeft) {
diff --git a/net/minecraft/world/level/GameRules.java b/net/minecraft/world/level/GameRules.java
index 02d64a5ea756b2c91a71b7a0fc0f21219983616a..d515ba4e775e1199e1cbf4f79978d318eaa6b336 100644
--- a/net/minecraft/world/level/GameRules.java
+++ b/net/minecraft/world/level/GameRules.java
@@ -320,8 +320,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.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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 b631e35e965b1914cdeeddab8bd6bdbfd2465079..bb7dab597850fba8f0dff4461fc518e0a33b00c7 100644
--- a/net/minecraft/world/level/block/state/BlockBehaviour.java
+++ b/net/minecraft/world/level/block/state/BlockBehaviour.java
@@ -346,13 +346,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.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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 b245f594ff91e2d29c83f56b9ed5165f37387e7e..534384727e852dc8ea822f49f182af49eb3a40c1 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -907,6 +907,19 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
this.ticker = ticker;
}
+ // DivineMC start - Lag compensation
+ private <T extends BlockEntity> void lagCompensation(Runnable original) {
+ original.run();
+ if (!org.bxteam.divinemc.DivineConfig.lagCompensationEnabled) return;
+ if (!org.bxteam.divinemc.DivineConfig.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()) {
@@ -915,7 +928,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 35b5a33c79c883f28c99c992695b188524593b55..6845a1c3b6038700751312d8beb0f9a2844003a5 100644
--- a/net/minecraft/world/level/material/LavaFluid.java
+++ b/net/minecraft/world/level/material/LavaFluid.java
@@ -175,9 +175,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.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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 2e4fed7c27910b6c886f710f33b0841c2a175837..89f22ebcbaf21df3afb6a00f60d8e00777875aac 100644
--- a/net/minecraft/world/level/material/WaterFluid.java
+++ b/net/minecraft/world/level/material/WaterFluid.java
@@ -113,8 +113,16 @@ public abstract class WaterFluid extends FlowingFluid {
return 1;
}
+ // DivineMC start - Lag compensation
+ private int lagCompensation(ServerLevel level) {
+ if (!org.bxteam.divinemc.DivineConfig.lagCompensationEnabled || !org.bxteam.divinemc.DivineConfig.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;
}

View File

@@ -1,48 +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:14:09 +0300
Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
tasks to be run
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index df07a4a62bd518f3a13995a3ccc7970c714bad7b..851f943cddad03ae12e1ed85f64072682447a367 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
protected boolean upnp = false; // Purpur - UPnP Port Forwarding
public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - Parallel world ticking
public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
+ public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
@@ -1706,17 +1707,18 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
this.server.getScheduler().mainThreadHeartbeat(); // CraftBukkit
// Paper start - Folia scheduler API
((io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler) org.bukkit.Bukkit.getGlobalRegionScheduler()).tick();
- getAllLevels().forEach(level -> {
- for (final net.minecraft.world.entity.Entity entity : level.getEntities().getAll()) {
- if (entity.isRemoved()) {
- continue;
- }
- final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();
- if (bukkit != null) {
- bukkit.taskScheduler.executeTick();
- }
+ // DivineMC start - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
+ for (final net.minecraft.world.entity.Entity entity : entitiesWithScheduledTasks) {
+ if (entity.isRemoved()) {
+ continue;
}
- });
+
+ final org.bukkit.craftbukkit.entity.CraftEntity bukkit = entity.getBukkitEntityRaw();
+ if (bukkit != null) {
+ bukkit.taskScheduler.executeTick();
+ }
+ }
+ // DivineMC end - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
// Paper end - Folia scheduler API
io.papermc.paper.adventure.providers.ClickCallbackProviderImpl.CALLBACK_MANAGER.handleQueue(this.tickCount); // Paper
this.getFunctions().tick();

View File

@@ -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 c7d91a38fc3b5cf2487e09719a1f9bc39ca5d20e..875e9711c9dacaf73636c7c7ce1cf740a23f006f 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
}

View File

@@ -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 1d399532c67c213c95c06837b0c7855384f1a25c..cad1f8cb68ef9615587e651a3120f68a3c32add0 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 76481c0e77fc3a2e4be8eeb9de8d1e6de5507c64..8f0aa83cc81f36d70a39600a82d0212db70e02ec 100644
--- a/net/minecraft/world/entity/projectile/ThrownEgg.java
+++ b/net/minecraft/world/entity/projectile/ThrownEgg.java
@@ -52,7 +52,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

View File

@@ -1,34 +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:28:34 +0300
Subject: [PATCH] Block Log4Shell exploit
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index 5b8031a45b1f4f6d0e86c2a839d173a6e3f4f697..a3ec8c92dae7735bb0b1ececc9851c829c486a53 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2425,6 +2425,7 @@ public class ServerGamePacketListenerImpl
}
private void tryHandleChat(String message, Runnable handler, boolean sync) { // CraftBukkit
+ if (ServerGamePacketListenerImpl.isLog4ShellExploit(message)) return; // DivineMC - Block Log4Shell exploit
if (isChatMessageIllegal(message)) {
this.disconnectAsync(Component.translatable("multiplayer.disconnect.illegal_characters"), org.bukkit.event.player.PlayerKickEvent.Cause.ILLEGAL_CHARACTERS); // Paper - add proper async disconnect
} else if (this.player.isRemoved() || this.player.getChatVisibility() == ChatVisiblity.HIDDEN) { // CraftBukkit - dead men tell no tales
@@ -2453,6 +2454,15 @@ public class ServerGamePacketListenerImpl
}
}
+ // DivineMC start - Block Log4Shell exploit
+ public static boolean isLog4ShellExploit(String message) {
+ java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(".*\\$\\{[^}]*}.*");
+ java.util.regex.Matcher matcher = pattern.matcher(message);
+
+ return matcher.find();
+ }
+ // DivineMC end - Block Log4Shell exploit
+
public static boolean isChatMessageIllegal(String message) {
for (int i = 0; i < message.length(); i++) {
if (!StringUtil.isAllowedChatCharacter(message.charAt(i))) {

View File

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

View File

@@ -1,53 +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] Skip distanceToSqr call in ServerEntity#sendChanges if the
delta movement hasn't changed
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
index b6053158f5d9b6ad325ea075ab7c60f9966ba496..c7ad6bf5dd8cb8a27de3e3ed82c6eefaa36c5c08 100644
--- a/net/minecraft/server/level/ServerEntity.java
+++ b/net/minecraft/server/level/ServerEntity.java
@@ -203,23 +203,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) {

View File

@@ -1,19 +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:52:39 +0300
Subject: [PATCH] Optimize canSee checks
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index dccf4d4b1067e1b09e38cabeae82185929494b62..55da7420dc3dfff468529a0f101f864dbefe3c7c 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -1258,7 +1258,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z);
// Paper end - Configurable entity tracking range by Y
// CraftBukkit start - respect vanish API
- if (flag && !player.getBukkitEntity().canSee(this.entity.getBukkitEntity())) { // Paper - only consider hits
+ if (flag && !player.getBukkitEntity().canSeeChunkMapUpdatePlayer(this.entity.getBukkitEntity())) { // Paper - only consider hits // DivineMC - optimize canSee checks
flag = false;
}
// CraftBukkit end

View File

@@ -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 d1daa3443446f47e2215f0c7c5823da58e053bab..61b1440ee7909946cd2d7a4d8622f79c6f6ac76b 100644
--- a/net/minecraft/network/FriendlyByteBuf.java
+++ b/net/minecraft/network/FriendlyByteBuf.java
@@ -105,7 +105,28 @@ public class FriendlyByteBuf extends ByteBuf {
return this;
}
+ @SuppressWarnings({"unchecked", "rawtypes"}) // DivineMC - Implement NoChatReports
public <T> T readJsonWithCodec(Codec<T> codec) {
+ // DivineMC start - Implement NoChatReports
+ if (org.bxteam.divinemc.DivineConfig.noChatReportsEnabled) {
+ if (codec == net.minecraft.network.protocol.status.ServerStatus.CODEC) {
+ JsonElement jsonElement = GsonHelper.fromJson(GSON, this.readUtf(), JsonElement.class);
+ 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 = GsonHelper.fromJson(GSON, this.readUtf(), JsonElement.class);
DataResult<T> dataResult = codec.parse(JsonOps.INSTANCE, jsonElement);
return dataResult.getOrThrow(exception -> new DecoderException("Failed to decode json: " + exception));
@@ -117,6 +138,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.DivineConfig.noChatReportsEnabled) {
+ if (org.bxteam.divinemc.DivineConfig.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..61ecf4c6ae37b13ed42dff8d4165d32f3a5cc0c9 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.DivineConfig.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..3af0436ac2dff04cfaa1b3dda11a5417f2c0890c 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.DivineConfig.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..d94858facc06d57139e953796ee09dad17648dbb 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.DivineConfig.noChatReportsEnabled) {
+ var impl = (net.minecraft.server.network.ServerGamePacketListenerImpl) handler;
+
+ if (!impl.getPlayer().getServer().isSingleplayerOwner(impl.getPlayer().getGameProfile())) {
+ if (org.bxteam.divinemc.DivineConfig.noChatReportsDemandOnClient) {
+ impl.disconnect(net.minecraft.network.chat.Component.literal(org.bxteam.divinemc.DivineConfig.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 30bd254542d631676494f349ff3f44f52d54ab2f..6c728ae3b58bc1b8449d34c6c74091612b79f39e 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 9fcdff2be139296f4e14b54c33cc795efdff0c7f..64c3bbe540599e5195f0cc89635bff2c56d1a320 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -668,6 +668,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@Override
public boolean enforceSecureProfile() {
+ if (org.bxteam.divinemc.DivineConfig.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 801dd76a2c7f76fc6fdb7167cbf3ab1310be36c9..4fa55fac5dab26a505cba2c1876e9459a582da12 100644
--- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java
@@ -312,10 +312,64 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack
}
public void send(Packet<?> packet) {
+ // DivineMC start - Implement NoChatReports
+ if (org.bxteam.divinemc.DivineConfig.noChatReportsEnabled) {
+ Object self = this;
+ boolean cancel = false;
+
+ if (self instanceof ServerGamePacketListenerImpl listener) {
+ if (org.bxteam.divinemc.DivineConfig.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.DivineConfig.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 PacketSendListener listener) {
+ // DivineMC start - Implement NoChatReports
+ if (org.bxteam.divinemc.DivineConfig.noChatReportsEnabled) {
+ Object self = this;
+ boolean cancel = false;
+
+ if (self instanceof ServerGamePacketListenerImpl listenerImpl) {
+ if (org.bxteam.divinemc.DivineConfig.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.DivineConfig.noChatReportsConvertToGameMessage) {
+ if (packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket chat && listener != 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 3d8c1c5aa922ec0417388a1ff27d423cdb6d1351..6cbd57650f1f966955ee14039bca8ceb164599cd 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -274,7 +274,7 @@ public abstract class PlayerList {
!_boolean,
_boolean2,
player.createCommonSpawnInfo(serverLevel),
- this.server.enforceSecureProfile()
+ org.bxteam.divinemc.DivineConfig.noChatReportsEnabled || this.server.enforceSecureProfile() // DivineMC - Implement NoChatReports
)
);
player.getBukkitEntity().sendSupportedChannels(); // CraftBukkit
@@ -1333,6 +1333,7 @@ public abstract class PlayerList {
}
public boolean verifyChatTrusted(PlayerChatMessage message) { // Paper - private -> public
+ if (org.bxteam.divinemc.DivineConfig.noChatReportsEnabled) return true; // DivineMC - Implement NoChatReports
return message.hasSignature() && !message.hasExpiredServer(Instant.now());
}

View File

@@ -1,275 +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
diff --git a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
index 63143ceec98f7a84ec4064d05e8f88c11200172f..02f67af9c312f3d9213af1e410986165dcf618a4 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;
@@ -292,6 +294,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.DivineConfig.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.DivineConfig.enableStructureLayoutOptimizer || !org.bxteam.divinemc.DivineConfig.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.DivineConfig.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.DivineConfig.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.DivineConfig.enableStructureLayoutOptimizer) {
+ return original;
+ }
+ if (!org.bxteam.divinemc.DivineConfig.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,
@@ -349,9 +453,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));
@@ -362,10 +466,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) {
@@ -398,7 +506,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);
@@ -427,9 +535,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.DivineConfig.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 4a6da3648c513a6cce16cf71246937d2d0ad014d..6af4c9026e814dee1ed4c7593ad00b5f8af9b979 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.DivineConfig.enableStructureLayoutOptimizer) {
+ structureLayoutOptimizer$fasterJigsawListShuffling1(jigsaws, random);
+ structureLayoutOptimizer$fasterJigsawListShuffling2(jigsaws);
+ } else {
+ Util.shuffle(jigsaws, random);
+ sortBySelectionPriority(jigsaws);
+ }
+ // DivineMC end - Optimize Structure Generation
+
return jigsaws;
}
@@ -191,4 +199,12 @@ public class SinglePoolElement extends StructurePoolElement {
public String toString() {
return "Single[" + this.template + "]";
}
+
+ // 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) { }
+ // Quiil end - Optimize Structure Generation
}
diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
index a37eb2e29b4577ebc711e8ef7b47fbbc3bc66897..45d6fbeeaac577bb35adb69fd344b9486953ea03 100644
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
@@ -249,6 +249,12 @@ public class StructureTemplate {
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;
@@ -266,7 +272,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.DivineConfig.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
@@ -890,7 +900,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.DivineConfig.enableStructureLayoutOptimizer
+ ? new org.bxteam.divinemc.util.structure.PalettedStructureBlockInfoList(blocks)
+ : blocks;
+ // DivineMC end - Optimize Structure Generation
}
public List<StructureTemplate.JigsawBlockInfo> jigsaws() {

View File

@@ -1,38 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Wed, 5 Feb 2025 17:48:56 +0300
Subject: [PATCH] Verify Minecraft EULA earlier
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
index 1485186d4989874ef89c4e83830f26358a43759c..c4f9b67c92e4c7e8015f637fe633a9e8da276e5c 100644
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
@@ -123,7 +123,6 @@ public class Main {
dedicatedServerSettings.forceSave();
RegionFileVersion.configure(dedicatedServerSettings.getProperties().regionFileComression);
Path path2 = Paths.get("eula.txt");
- Eula eula = new Eula(path2);
// 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"));
@@ -146,19 +145,6 @@ public class Main {
return;
}
- // Spigot start
- boolean eulaAgreed = Boolean.getBoolean("com.mojang.eula.agree");
- if (eulaAgreed) {
- LOGGER.error("You have used the Spigot command line EULA agreement flag.");
- LOGGER.error("By using this setting you are indicating your agreement to Mojang's EULA (https://aka.ms/MinecraftEULA).");
- LOGGER.error("If you do not agree to the above EULA please stop your server and remove this flag immediately.");
- }
- if (!eula.hasAgreedToEULA() && !eulaAgreed) {
- // Spigot end
- LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
- return;
- }
-
// Paper start - Detect headless JRE
String awtException = io.papermc.paper.util.ServerEnvironment.awtDependencyCheck();
if (awtException != null) {

View File

@@ -1,18 +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:03:59 +0300
Subject: [PATCH] Configurable MC-67
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 3943789e241f6bb6bc165099b1fb585463cf3d86..07e8bda8eb200d5a7554e0319e1a00dc85454e1a 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -4017,6 +4017,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
public boolean canTeleport(Level fromLevel, Level toLevel) {
+ if (!fromLevel.divineConfig.allowEntityPortalWithPassenger && (this.isPassenger() || this.isVehicle())) return false; // DivineMC - Allow entity teleport with passenger
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()) {

View File

@@ -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 c7ae41b2cbc1eb85a6eb9c16813bd326fb8f49f0..e6764ee35f9d9d20a7693d50ea61b703867e3c79 100644
--- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
+++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java
@@ -364,4 +364,14 @@ public class FireworkRocketEntity extends Projectile implements ItemSupplier {
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 cad1f8cb68ef9615587e651a3120f68a3c32add0..18298f3ba544e07110ea8d5b15ae753f7e3de65a 100644
--- a/net/minecraft/world/entity/projectile/Snowball.java
+++ b/net/minecraft/world/entity/projectile/Snowball.java
@@ -100,4 +100,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
}

View File

@@ -1,84 +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
diff --git a/net/minecraft/core/Direction.java b/net/minecraft/core/Direction.java
index 216f97207dac88cc1dc3df59c6ee8a62c7614b4a..05c7de5729466786a0196fa5f91eccc3cfffc675 100644
--- a/net/minecraft/core/Direction.java
+++ b/net/minecraft/core/Direction.java
@@ -217,7 +217,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) {
@@ -350,7 +350,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 54807bb4b4189ceaded1f78a1a9ab85ce40ab2b1..977642da91cf3bace9182e36c10512c8a1830503 100644
--- a/net/minecraft/world/phys/AABB.java
+++ b/net/minecraft/world/phys/AABB.java
@@ -18,6 +18,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);
@@ -79,11 +88,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

View File

@@ -1,107 +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 80a7a85e1a03a1ca406259207e1ae3b909b3284f..aa2d99de3d23d262542bfb1592fe084f94230f85 100644
--- a/net/minecraft/Util.java
+++ b/net/minecraft/Util.java
@@ -97,7 +97,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.DivineConfig.virtualThreadsEnabled && org.bxteam.divinemc.DivineConfig.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 212d2bcfd34f7cb14e18a8af2cd296fc01d371f6..ec76e4f29ba96b31a24a5d195b852342a57e0bdb 100644
--- a/net/minecraft/commands/Commands.java
+++ b/net/minecraft/commands/Commands.java
@@ -474,7 +474,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.DivineConfig.virtualThreadsEnabled && org.bxteam.divinemc.DivineConfig.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 5a0c8791495aa522e511918ad0a24d9bbe6b5877..9d6fa3bced0ba5ab3443bdf4ce306598a8e4a31f 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2710,8 +2710,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.DivineConfig.virtualThreadsEnabled && org.bxteam.divinemc.DivineConfig.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 a3ec8c92dae7735bb0b1ececc9851c829c486a53..02b4275d170cc854a7482f0e963394aee21171dd 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -808,8 +808,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.DivineConfig.virtualThreadsEnabled && org.bxteam.divinemc.DivineConfig.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/ServerLoginPacketListenerImpl.java b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
index 45ea5fa0ef57724acce46008c53f7fa216cf78ee..f4a9d49247d2124b03273c38b14ddf9661184749 100644
--- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java
@@ -55,7 +55,11 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener,
// CraftBukkit end
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
+ // DivineMC start - Virtual Threads
+ private static final java.util.concurrent.ExecutorService authenticatorPool = org.bxteam.divinemc.DivineConfig.virtualThreadsEnabled && org.bxteam.divinemc.DivineConfig.virtualAuthenticatorScheduler
+ ? java.util.concurrent.Executors.newVirtualThreadPerTaskExecutor()
+ : 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
+ // DivineMC end - Virtual Threads
private static final int MAX_TICKS_BEFORE_LOGIN = 600;
private final byte[] challenge;
final MinecraftServer server;
diff --git a/net/minecraft/server/network/ServerTextFilter.java b/net/minecraft/server/network/ServerTextFilter.java
index 5d18f6c3173ed257bef15637a53adbff26ee9062..c843e073db2a0046bbd5b64e1a4f4e956ce88a70 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.DivineConfig.virtualThreadsEnabled && org.bxteam.divinemc.DivineConfig.virtualServerTextFilterPool
+ ? Executors.newVirtualThreadPerTaskExecutor()
+ : Executors.newFixedThreadPool(size, THREAD_FACTORY);
+ // DivineMC end - Virtual Threads
}
protected ServerTextFilter(

View File

@@ -1,87 +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 76b8d42ae530b59cdaba0583365a557da6b90ede..235772cc9a7c878235b97c8d84cacda3016f91ca 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -55,6 +55,8 @@ public final class RegionizedPlayerChunkLoader {
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;
+ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("RegionizedPlayerChunkLoader"); // DivineMC - Async Chunk Sending
+
public static final class ViewDistanceHolder {
private volatile ViewDistances viewDistances;
@@ -426,17 +428,61 @@ public final class RegionizedPlayerChunkLoader {
}
private void sendChunk(final int chunkX, final int chunkZ) {
- if (this.sentChunks.add(CoordinateUtils.getChunkKey(chunkX, chunkZ))) {
- ((ChunkSystemChunkHolder)((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
- .getChunkHolder(chunkX, chunkZ).vanillaChunkHolder).moonrise$addReceivedChunk(this.player);
+ // DivineMC start - Async Chunk Sending
+ final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
+
+ if (!this.sentChunks.add(chunkKey)) return;
- final LevelChunk chunk = ((ChunkSystemLevel)this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
+ final LevelChunk chunk = ((ChunkSystemLevel) this.world).moonrise$getFullChunkIfLoaded(chunkX, chunkZ);
+ if (chunk == null) {
+ this.sentChunks.remove(chunkKey);
+ return;
+ }
+ try {
+ ((ChunkSystemServerLevel) this.world).moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(chunkX, chunkZ).vanillaChunkHolder.moonrise$addReceivedChunk(this.player);
PlatformHooks.get().onChunkWatch(this.world, chunk, this.player);
- PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
+ } catch (IllegalStateException e) {
+ this.sentChunks.remove(chunkKey);
return;
}
- throw new IllegalStateException();
+
+ if (org.bxteam.divinemc.DivineConfig.asyncChunkSendingEnabled) {
+ net.minecraft.Util.backgroundExecutor().execute(() -> {
+ try {
+ // Modified from PlayerChunkSender#sendChunk
+ final net.minecraft.server.network.ServerGamePacketListenerImpl connection = this.player.connection;
+ final ServerLevel serverLevel = this.world;
+
+ final net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket packet = new net.minecraft.network.protocol.game.ClientboundLevelChunkWithLightPacket(
+ chunk, serverLevel.getLightEngine(), null, null,
+ serverLevel.chunkPacketBlockController.shouldModify(this.player, chunk)
+ );
+
+ serverLevel.getServer().execute(() -> {
+ if (this.removed || !this.sentChunks.contains(chunkKey)) return;
+
+ connection.send(packet);
+
+ if (io.papermc.paper.event.packet.PlayerChunkLoadEvent.getHandlerList().getRegisteredListeners().length > 0) {
+ new io.papermc.paper.event.packet.PlayerChunkLoadEvent(
+ new org.bukkit.craftbukkit.CraftChunk(chunk),
+ this.player.getBukkitEntity()
+ ).callEvent();
+ }
+
+ net.minecraft.network.protocol.game.DebugPackets.sendPoiPacketsForChunk(serverLevel, chunk.getPos());
+ });
+ } catch (Exception e) {
+ LOGGER.error("Failed to send chunk asynchronously!", e);
+
+ if (!this.removed) this.sentChunks.remove(chunkKey);
+ }
+ });
+ } else {
+ PlayerChunkSender.sendChunk(this.player.connection, this.world, chunk);
+ }
+ // DivineMC end - Async Chunk Sending
}
private void sendUnloadChunk(final int chunkX, final int chunkZ) {

View File

@@ -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 02b4275d170cc854a7482f0e963394aee21171dd..c3e8da14d4faf560d24f877ef9eeb4a5dcb2aa8d 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -819,7 +819,7 @@ public class ServerGamePacketListenerImpl
public void handleCustomCommandSuggestions(ServerboundCommandSuggestionPacket packet) {
// PacketUtils.ensureRunningOnSameThread(packet, this, this.player.serverLevel()); // 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.DivineConfig.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;
}
@@ -831,7 +831,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.DivineConfig.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;
}
@@ -891,6 +891,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.DivineConfig.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;
@@ -2624,6 +2625,7 @@ public class ServerGamePacketListenerImpl
// this.chatSpamThrottler.increment();
if (!this.chatSpamThrottler.isIncrementAndUnderThreshold()
// CraftBukkit end
+ && !org.bxteam.divinemc.DivineConfig.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
@@ -3402,7 +3404,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.DivineConfig.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;
}

View File

@@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Wed, 5 Mar 2025 18:08:25 +0300
Subject: [PATCH] Configurable MC-59471
Bring back MC-59471, MC-129055 on 1.21.2+, which fixed in 1.21.2 snapshots 24w33a and 24w36a
P.S: This setting is different from skip-tripwire-hook-placement-validation in Paper
diff --git a/net/minecraft/world/level/block/TripWireHookBlock.java b/net/minecraft/world/level/block/TripWireHookBlock.java
index 9aace993c6c18f1a50610e4766225485984b8167..0849e0b116845a16792855afdd16de7ec6838542 100644
--- a/net/minecraft/world/level/block/TripWireHookBlock.java
+++ b/net/minecraft/world/level/block/TripWireHookBlock.java
@@ -201,7 +201,6 @@ public class TripWireHookBlock extends Block {
if (!cancelledEmitterHook) { // Paper - Call BlockRedstoneEvent
emitState(level, pos, flag2, flag3, flag, flag1);
if (!attaching) {
- if (io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.skipTripwireHookPlacementValidation || level.getBlockState(pos).is(Blocks.TRIPWIRE_HOOK)) // Paper - Validate tripwire hook placement before update
level.setBlock(pos, blockState1.setValue(FACING, direction), 3);
if (shouldNotifyNeighbours) {
notifyNeighbors(block, level, pos, direction);
@@ -214,10 +213,17 @@ public class TripWireHookBlock extends Block {
BlockPos blockPos1 = pos.relative(direction, i2);
BlockState blockState2 = blockStates[i2];
if (blockState2 != null) {
- BlockState blockState3 = level.getBlockState(blockPos1);
- if (blockState3.is(Blocks.TRIPWIRE) || blockState3.is(Blocks.TRIPWIRE_HOOK)) {
- if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates || !blockState3.is(Blocks.TRIPWIRE)) level.setBlock(blockPos1, blockState2.trySetValue(ATTACHED, Boolean.valueOf(flag2)), 3); // Paper - prevent tripwire from updating
+ // DivineMC start - Configurable MC-59471
+ if (level.divineConfig.allowTripwireDupe) {
+ level.setBlock(blockPos1, blockState2.trySetValue(ATTACHED, flag2), 3);
+ level.getBlockState(blockPos1);
+ } else {
+ BlockState blockState3 = level.getBlockState(blockPos1);
+ if (blockState3.is(Blocks.TRIPWIRE) || blockState3.is(Blocks.TRIPWIRE_HOOK)) {
+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().blockUpdates.disableTripwireUpdates || !blockState3.is(Blocks.TRIPWIRE)) level.setBlock(blockPos1, blockState2.trySetValue(ATTACHED, Boolean.valueOf(flag2)), 3); // Paper - prevent tripwire from updating
+ }
}
+ // DivineMC end - Configurable MC-59471
}
}
}

View File

@@ -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 712d3d1669aecd38934957c81835e1f38289539a..810e61913aece5a8158f83b6dd56a7b6cb083c19 100644
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
@@ -275,6 +275,28 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
data.palette.read(buffer);
buffer.readLongArray(data.storage.getRaw());
this.data = data;
+ // DivineMC start - ModernFix: compact_bit_storage
+ if (org.bxteam.divinemc.DivineConfig.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 {

View File

@@ -1,72 +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 8c883ff13866d6416bd70cc61ab1e37dd1a5b33c..7bd3507837862b8afb8227a85a44c879692a9631 100644
--- a/net/minecraft/world/level/BaseCommandBlock.java
+++ b/net/minecraft/world/level/BaseCommandBlock.java
@@ -32,6 +32,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);
@@ -131,7 +135,35 @@ public abstract class BaseCommandBlock implements CommandSource {
this.successCount++;
}
});
- server.getCommands().dispatchServerCommand(commandSourceStack, this.command); // CraftBukkit
+ // DivineMC start - Command block parse results caching
+ if (org.bxteam.divinemc.DivineConfig.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 {
+ server.getCommands().dispatchServerCommand(commandSourceStack, this.command); // CraftBukkit
+ }
+ // 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");
@@ -151,6 +183,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;
}

View File

@@ -1,328 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 16 Mar 2025 21:16:55 +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..fdccc27c528b01b16a72e614ffd96523aa6f50d2 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 - Linear region file 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 - Linear region file 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 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..34682217252cb98a70511a8cb25f077ec9f872b8 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 - Linear region file 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 - Linear region file format
}
}
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
index 51c126735ace8fdde89ad97b5cab62f244212db0..8713d00d767c9225a0823d2fdbb0b479005738d7 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java
@@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer {
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 - Linear region file format
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 26a4a279122bb03a83dd4a34e780d6a4567ba3a8..51b79f614417f231951e9ba05b29ff0044e081e7 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -947,10 +947,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 - Linear region file format
}
- LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved");
+ LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // DivineMC - Linear region file format
}
return flag;
diff --git a/net/minecraft/util/worldupdate/WorldUpgrader.java b/net/minecraft/util/worldupdate/WorldUpgrader.java
index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..e99f3c3567f9e6fb5a328bf9b59d40c72522f922 100644
--- a/net/minecraft/util/worldupdate/WorldUpgrader.java
+++ b/net/minecraft/util/worldupdate/WorldUpgrader.java
@@ -72,7 +72,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]+)\\.(linear | mca)$"); // DivineMC - Linear region file format
final DimensionDataStorage overworldDataStorage;
public WorldUpgrader(
@@ -261,7 +261,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(".linear") || filename.endsWith(".mca")); // DivineMC - Linear region file format
if (files == null) {
return List.of();
} else {
@@ -274,7 +274,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 = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - Linear region file format
for (int i2 = 0; i2 < 32; i2++) {
for (int i3 = 0; i3 < 32; i3++) {
ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1);
@@ -322,7 +322,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 - Linear region file format
if (WorldUpgrader.this.recreateRegionFiles) {
if (this.previousWriteFuture != null) {
this.previousWriteFuture.join();
@@ -424,7 +424,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 - Linear region file 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 c72494e757a9dc50e053dbc873f7b30e83d5cb8c..2988084cf2d72557dd304dcb904d09441e79863d 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 - Linear region file 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;
@@ -904,7 +904,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 - Linear region file 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 16cd10ab8de69ca3d29c84cf93715645322fd72a..9fd987078625bee796b381108ae7dbfb1f14d256 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 - Linear region file format
private final RegionStorageInfo info;
private final Path folder;
private final boolean sync;
@@ -33,7 +33,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
@Nullable
public static ChunkPos getRegionFileCoordinates(Path file) {
String fileName = file.getFileName().toString();
- if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) {
+ if (!fileName.startsWith("r.") || !fileName.endsWith(".mca") || !fileName.endsWith(".linear")) { // DivineMC - Linear region file format
return null;
}
@@ -58,6 +58,12 @@ 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) {
+ // DivineMC start - Linear region file format
+ if (org.bxteam.divinemc.DivineConfig.regionFormatTypeName == org.bxteam.divinemc.region.RegionFileFormat.LINEAR) {
+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".linear";
+ }
+ // DivineMC end - Linear region file format
+
return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca";
}
@@ -93,15 +99,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 - Linear region file 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 - Linear region file 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 - Linear region file format
if (ret != null) {
return ret;
}
@@ -125,7 +131,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format
this.regionCache.putAndMoveToFirst(key, ret);
@@ -144,11 +150,11 @@ 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 - Linear region file 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)
- final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile)regionFile).moonrise$startWrite(compound, pos);
+ final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = regionFile.moonrise$startWrite(compound, pos); // DivineMC - Linear region file format
try { // Paper - implement RegionFileSizeException
try {
@@ -178,7 +184,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 - Linear region file format
if (regionFile != null) {
regionFile.clear(pos);
} // else: didn't exist
@@ -193,7 +199,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 - Linear region file format
final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ));
@@ -237,7 +243,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 - Linear region file format
return this.getRegionFile(chunkcoordintpair, false);
}
// Paper end - rewrite chunk system
@@ -249,7 +255,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 - Linear region file format
// Paper start - rewrite chunk system
if (existingOnly) {
return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z);
@@ -257,7 +263,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 - Linear region file format
if (ret != null) {
return ret;
}
@@ -272,7 +278,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
FileUtil.createDirectoriesSafe(this.folder);
- ret = new RegionFile(this.info, regionPath, this.folder, this.sync);
+ ret = org.bxteam.divinemc.region.RegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - Linear region file format
this.regionCache.putAndMoveToFirst(key, ret);
@@ -286,7 +292,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 - Linear region file format
synchronized (regionfile) {
try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) {
CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z);
@@ -321,7 +327,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 - Linear region file format
if (regionFile == null) {
return null;
}
@@ -360,7 +366,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 - Linear region file format
if (regionFile == null) {
return;
}
@@ -374,7 +380,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 - Linear region file format
// Paper start - rewrite chunk system
if (regionFile == null) {
// if the RegionFile doesn't exist, no point in deleting from it
@@ -404,7 +410,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 - Linear region file format
try {
regionFile.close();
} catch (final IOException ex) {
@@ -420,7 +426,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 - Linear region file format
try {
regionFile.flush();
} catch (final IOException ex) {

View File

@@ -1,203 +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] Async mob spawning
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 51b79f614417f231951e9ba05b29ff0044e081e7..dee93ae262a2a06e68dfe8ae1b7193172c436990 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -291,6 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public java.util.concurrent.Semaphore serverLevelTickingSemaphore = null; // DivineMC - Parallel world ticking
public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
public final Set<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
+ public org.bxteam.divinemc.util.AsyncProcessor mobSpawnExecutor = new org.bxteam.divinemc.util.AsyncProcessor("mob_spawning"); // DivineMC - Async mob spawning
public 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/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
index 7f982949304535376dabf42aab1848cabc8987cf..a2bb32b964d08079456d93d49f12b23f7c17a7db 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -183,6 +183,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
}
// Paper end - chunk tick iteration optimisations
+ // DivineMC start - Async mob spawning
+ public boolean firstRunSpawnCounts = true;
+ public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false);
+ // DivineMC end - Async mob spawning
public ServerChunkCache(
ServerLevel level,
@@ -581,6 +585,35 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
this.broadcastChangedChunks();
}
+
+ // DivineMC start - Async mob spawning
+ if (org.bxteam.divinemc.DivineConfig.enableAsyncSpawning) {
+ for (ServerPlayer player : this.level.players) {
+ for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) {
+ player.mobCounts[ii] = 0;
+
+ int newBackoff = player.mobBackoffCounts[ii] - 1;
+ if (newBackoff < 0) {
+ newBackoff = 0;
+ }
+ player.mobBackoffCounts[ii] = newBackoff;
+ }
+ }
+ if (firstRunSpawnCounts) {
+ firstRunSpawnCounts = false;
+ spawnCountsReady.set(true);
+ }
+ if (spawnCountsReady.getAndSet(false)) {
+ MinecraftServer.getServer().mobSpawnExecutor.submit(() -> {
+ int mapped = distanceManager.getNaturalSpawnChunkCount();
+ try {
+ lastSpawnState = NaturalSpawner.createState(mapped, new ArrayList<>(level.entityTickList.entities), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), true);
+ } finally { }
+ spawnCountsReady.set(true);
+ });
+ }
+ }
+ // DivineMC end - Async mob spawning
}
private void broadcastChangedChunks() {
@@ -621,27 +654,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 - Async 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.DivineConfig.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 - Async 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;
@@ -655,7 +692,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 - Async mob spawning
} else {
filteredSpawningCategories = List.of();
}
@@ -663,8 +700,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
for (LevelChunk levelChunk : chunks) {
ChunkPos pos = levelChunk.getPos();
levelChunk.incrementInhabitedTime(timeInhabited);
- if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot
- NaturalSpawner.spawnForChunk(this.level, levelChunk, spawnState, filteredSpawningCategories);
+ // DivineMC start - Async mob spawning
+ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && (!org.bxteam.divinemc.DivineConfig.enableAsyncSpawning || spawnCountsReady.get()) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot
+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState, filteredSpawningCategories);
+ // DivineMC end - Async mob spawning
}
if (true) { // Paper - rewrite chunk system
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
index d3f5242fc66529bf3137da4d505a6cf55e749e43..650dfce05bfc68d4c664471b430bd5c0f9629283 100644
--- a/net/minecraft/world/level/NaturalSpawner.java
+++ b/net/minecraft/world/level/NaturalSpawner.java
@@ -155,7 +155,18 @@ public final class NaturalSpawner {
return list;
}
+ private static int maxCapPerPlayer = -1; // DivineMC - Async mob spawning
+
public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List<MobCategory> categories) {
+ // DivineMC start - Async mob spawning
+ if (maxCapPerPlayer < 0) {
+ maxCapPerPlayer = 0;
+ for (final MobCategory value : MobCategory.values()) {
+ maxCapPerPlayer += value.getMaxInstancesPerChunk();
+ }
+ }
+ // DivineMC end - Async mob spawning
+
for (MobCategory mobCategory : categories) {
// Paper start - Optional per player mob spawns
final boolean canSpawn;
@@ -642,6 +653,13 @@ public final class NaturalSpawner {
}
boolean canSpawnForCategoryLocal(MobCategory category, ChunkPos chunkPos) {
+ // DivineMC start - Async mob spawning
+ if (this.localMobCapCalculator == null) {
+ LOGGER.warn("Local mob cap calculator was null! Report to DivineMC!");
+ return false;
+ }
+ // DivineMC end - Async mob spawning
+
return this.localMobCapCalculator.canSpawn(category, chunkPos);
}
}
diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java
index 018a04674897cfcec0e8de5cb2ab06243a994ae3..8c1de4654a3a29e75716a03efd476b8a3b7fe9e9 100644
--- a/net/minecraft/world/level/entity/EntityTickList.java
+++ b/net/minecraft/world/level/entity/EntityTickList.java
@@ -9,7 +9,7 @@ import javax.annotation.Nullable;
import net.minecraft.world.entity.Entity;
public class EntityTickList {
- public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
+ public final java.util.concurrent.ConcurrentLinkedQueue<Entity> entities = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - rewrite chunk system // DivineMC - Async mob spawning
// DivineMC start - Parallel world ticking
private final net.minecraft.server.level.ServerLevel serverLevel;
@@ -43,13 +43,13 @@ public class EntityTickList {
// Paper start - rewrite chunk system
// To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
// (by dfl iterator() is configured to not iterate over new entries)
- final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = this.entities.iterator();
+ final java.util.Iterator<Entity> iterator = this.entities.iterator(); // DivineMC - Async mob spawning
try {
while (iterator.hasNext()) {
entity.accept(iterator.next());
}
} finally {
- iterator.finishedIterating();
+ //iterator.finishedIterating(); // DivineMC - Async mob spawning
}
// Paper end - rewrite chunk system
}

View File

@@ -1,437 +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 ae0a3c3d9d6300293a6d0dff5cae49ebe7c11dab..3b08dad7a9fac7ac9acec0bfb85d4826452bdc99 100644
--- a/io/papermc/paper/entity/activation/ActivationRange.java
+++ b/io/papermc/paper/entity/activation/ActivationRange.java
@@ -161,6 +161,21 @@ public final class ActivationRange {
}
ActivationRange.activateEntity(entity);
+
+ // DivineMC start - Dynamic Activation of Brain
+ if (org.bxteam.divinemc.DivineConfig.dabEnabled && entity.getType().dabEnabled && (!org.bxteam.divinemc.DivineConfig.dabDontEnableIfInWater || entity.getType().is(net.minecraft.tags.EntityTypeTags.CAN_BREATHE_UNDER_WATER) || !entity.isInWaterOrBubble())) {
+ if (!entity.activatedPriorityReset) {
+ entity.activatedPriorityReset = true;
+ entity.activatedPriority = org.bxteam.divinemc.DivineConfig.dabMaximumActivationFrequency;
+ }
+ int squaredDistance = (int) player.distanceToSqr(entity);
+ entity.activatedPriority = squaredDistance > org.bxteam.divinemc.DivineConfig.dabStartDistanceSquared ?
+ Math.max(1, Math.min(squaredDistance >> org.bxteam.divinemc.DivineConfig.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 561066a2cf769e13ef3cea0881f7a2010ecbf2ec..5fe908ce51f95e1eab024dcd41ed108373f17fea 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -818,6 +818,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 04ae7636d14a40a427b5d9b746632b0c489efa21..f1cd66d7d96771bc4967e214f70c756fec30efe5 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -336,6 +336,8 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
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.DivineConfig.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 4186db5cb8d2cd29ebc230d704dd125ae0dfa358..79593dc0e42e4cf0aee5e7b8cac4aca186887d6f 100644
--- a/net/minecraft/world/entity/EntityType.java
+++ b/net/minecraft/world/entity/EntityType.java
@@ -1063,6 +1063,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 b4e19cc65701d5ef94e1cc0a7473225c222725c3..00daf8de01bf23f55ba8af12d3e3e551d981c61c 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -218,10 +218,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();
}
}
@@ -888,13 +888,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 b816b2de8eb327060ca6ea7c4afc17373fa77ff6..4eed0bd3670fdcb0a156c29e7db63233a47f539b 100644
--- a/net/minecraft/world/entity/ai/goal/GoalSelector.java
+++ b/net/minecraft/world/entity/ai/goal/GoalSelector.java
@@ -36,10 +36,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.DivineConfig.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 b2c9da89ae6044536f4996fdbd37e2cabf22ca12..fa9672e890f327dbdec57eadc258bbae8e98e91e 100644
--- a/net/minecraft/world/entity/animal/allay/Allay.java
+++ b/net/minecraft/world/entity/animal/allay/Allay.java
@@ -118,6 +118,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);
@@ -287,9 +288,13 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
@Override
protected void customServerAiStep(ServerLevel level) {
//if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 bbfe48fd278cda9926793d0d2de743558fefd622..3f7c48282577a2de20e78b69ddcbc08347318fd3 100644
--- a/net/minecraft/world/entity/animal/axolotl/Axolotl.java
+++ b/net/minecraft/world/entity/animal/axolotl/Axolotl.java
@@ -105,6 +105,7 @@ public class Axolotl extends Animal implements VariantHolder<Axolotl.Variant>, B
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);
@@ -347,12 +348,16 @@ public class Axolotl extends Animal implements VariantHolder<Axolotl.Variant>, B
@Override
protected void customServerAiStep(ServerLevel level) {
//if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 dfcba5c2c8a489ebe74c2d5c1fa980c401806757..1827dead0a0a1d8e9dfbcc44038c9dbfbefddd48 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 implements VariantHolder<Holder<FrogVariant>> {
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);
@@ -242,9 +243,13 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
@Override
protected void customServerAiStep(ServerLevel level) {
//if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 78d256f6a95acb367efd690bc368d2106a928b8f..b32fabed65f929cb8d2c8c93667f2e45b9bef0b8 100644
--- a/net/minecraft/world/entity/animal/frog/Tadpole.java
+++ b/net/minecraft/world/entity/animal/frog/Tadpole.java
@@ -62,6 +62,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);
@@ -133,9 +134,13 @@ public class Tadpole extends AbstractFish {
@Override
protected void customServerAiStep(ServerLevel level) {
//if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 e21f024d0ed7f936ff17df16bd9666fffbf44a75..1f46d9e9def33458001c4c30bf2e37486646d23f 100644
--- a/net/minecraft/world/entity/animal/goat/Goat.java
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
@@ -90,6 +90,7 @@ public class Goat extends Animal {
public static final EntityDataAccessor<Boolean> DATA_HAS_RIGHT_HORN = SynchedEntityData.defineId(Goat.class, EntityDataSerializers.BOOLEAN);
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);
@@ -230,9 +231,13 @@ public class Goat extends Animal {
@Override
protected void customServerAiStep(ServerLevel level) {
//if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 a5ee49e35b0825c03af058347ee189a7962e8027..4a02ff2dbea64cf6fb867872c08ad1b80fc5145b 100644
--- a/net/minecraft/world/entity/monster/hoglin/Hoglin.java
+++ b/net/minecraft/world/entity/monster/hoglin/Hoglin.java
@@ -84,6 +84,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);
@@ -203,17 +204,21 @@ public class Hoglin extends Animal implements Enemy, HoglinBase {
@Override
protected void customServerAiStep(ServerLevel level) {
//if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 b2e64c0d4c1943f8a50a03ba59318fc2e6b9e26a..a7f2c0aec77a8b196c9207b071ac904c30f34ee6 100644
--- a/net/minecraft/world/entity/monster/piglin/Piglin.java
+++ b/net/minecraft/world/entity/monster/piglin/Piglin.java
@@ -143,6 +143,7 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
public Set<Item> allowedBarterItems = new HashSet<>();
public Set<Item> interestItems = new HashSet<>();
// CraftBukkit end
+ private int behaviorTick; // DivineMC - Dynamic Activation of Brain
public Piglin(EntityType<? extends AbstractPiglin> entityType, Level level) {
super(entityType, level);
@@ -382,9 +383,13 @@ public class Piglin extends AbstractPiglin implements CrossbowAttackMob, Invento
@Override
protected void customServerAiStep(ServerLevel level) {
//if ((getRider() == null || !this.isControllable()) && this.behaviorTick++ % this.activatedPriority == 0) // Pufferfish // 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 59a12809e5c7f5ee85ca1f587f6b77383a1ff062..9777f5e99909790b49b05ea64fe12dedaaba6a0a 100644
--- a/net/minecraft/world/entity/monster/warden/Warden.java
+++ b/net/minecraft/world/entity/monster/warden/Warden.java
@@ -113,6 +113,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);
@@ -306,18 +307,22 @@ public class Warden extends Monster implements VibrationSystem {
@Override
protected void customServerAiStep(ServerLevel level) {
- 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 (this.behaviorTick++ % this.activatedPriority == 0) {
+ 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 fec90e482c8935dfca609bbf90e67f86a1586221..2ac8a11e9afc6f776eba3dbe852d7b680ed21705 100644
--- a/net/minecraft/world/entity/npc/Villager.java
+++ b/net/minecraft/world/entity/npc/Villager.java
@@ -179,6 +179,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);
@@ -397,7 +399,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
}
// Purpur end - Lobotomize stuck villagers
// Pufferfish start
- if (!inactive && (getRider() == null || !this.isControllable()) /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { // Purpur - Ridables
+ if (!inactive && this.behaviorTick++ % this.activatedPriority == 0 && (getRider() == null || !this.isControllable()) /*&& this.behaviorTick++ % this.activatedPriority == 0*/) { // 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

View File

@@ -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 2686df57d9d48db1438278d0d053bdbd3c65c0a7..44fa660cbe277c2b2dd5cce3e508b61848b2cccc 100644
--- a/net/minecraft/world/entity/monster/Drowned.java
+++ b/net/minecraft/world/entity/monster/Drowned.java
@@ -97,6 +97,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 a5bfc6f5caba1da8cfcb345524e05e8676672cb0..02ba60f5624c99c6360fa5f08aa2d518e34772ab 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 7af71c777dca26cd94b1807a2a77ea0d30e92976..5a86d217f9f8374c4ca8846fa22e721ad1f3f11b 100644
--- a/net/minecraft/world/entity/monster/Zombie.java
+++ b/net/minecraft/world/entity/monster/Zombie.java
@@ -123,6 +123,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
@@ -190,7 +191,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 2d5ddf98b79f97bdd15593a5989f978155375e99..a053f42a1ffa7285ddf18f3f92dea803f4fe9461 100644
--- a/net/minecraft/world/entity/monster/ZombieVillager.java
+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
@@ -99,6 +99,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 fddbbffafea275dad187b7908386cf4c05c86743..05256fefd6b015d84adadd877110440ac31a48b4 100644
--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java
+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java
@@ -85,6 +85,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
@@ -136,7 +137,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);
}

View File

@@ -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 b402f6a6ecb8047bbb791b212fba375f4c9e6af5..f381f3ecd27315e06ca6883006a8a4c3eb443c34 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 c8c8351f5645cf4041d26b0e02c072546ad329c6..75a695aaf0dd2f58e1fa5e1c532ae298c2a2abdb 100644
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -727,13 +727,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 fd49500f735e3482a0118316bd7a4340f41fe8be..4160c0649be830476b5bbea97557d9a505672abc 100644
--- a/net/minecraft/world/level/block/BeehiveBlock.java
+++ b/net/minecraft/world/level/block/BeehiveBlock.java
@@ -158,12 +158,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;

View File

@@ -1,50 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Wed, 26 Mar 2025 01:46:49 +0300
Subject: [PATCH] Leaf: Improve BlockEntity ticking isRemoved check
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 0337f4b9ca3c9c9a1e2a7cf19fcbad5e78b949dc..1820069a7c5833b0a13e034c232f06af234788e3 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -989,13 +989,26 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
public static class RebindableTickingBlockEntityWrapper implements TickingBlockEntity {
public TickingBlockEntity ticker;
+ private @Nullable BlockEntity blockEntityReference = null; // DivineMC - Improve BlockEntity ticking isRemoved check
RebindableTickingBlockEntityWrapper(TickingBlockEntity ticker) {
this.ticker = ticker;
+ // DivineMC start - Improve BlockEntity ticking isRemoved check
+ if (ticker instanceof BoundTickingBlockEntity<?> boundTicker) {
+ blockEntityReference = boundTicker.blockEntity;
+ }
+ // DivineMC end - Improve BlockEntity ticking isRemoved check
}
public void rebind(TickingBlockEntity ticker) {
this.ticker = ticker;
+ // DivineMC start - Improve BlockEntity ticking isRemoved check
+ if (ticker instanceof BoundTickingBlockEntity<?> boundTicker) {
+ blockEntityReference = boundTicker.blockEntity;
+ } else {
+ blockEntityReference = null;
+ }
+ // DivineMC end - Improve BlockEntity ticking isRemoved check
}
@Override
@@ -1005,6 +1018,12 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
@Override
public boolean isRemoved() {
+ // DivineMC start - Improve BlockEntity ticking isRemoved check
+ if (blockEntityReference != null) {
+ return blockEntityReference.isRemoved();
+ }
+ // DivineMC end - Improve BlockEntity ticking isRemoved check
+
return this.ticker.isRemoved();
}

View File

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

View File

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

View File

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