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

implement new patches

This commit is contained in:
NONPLAYT
2025-02-22 15:13:16 +03:00
parent b90c03f48d
commit a67dc0f576
184 changed files with 21942 additions and 1357 deletions

View File

@@ -1,10 +1,62 @@
# This file is auto generated, any changes may be overridden! # This file is auto generated, any changes may be overridden!
# See CONTRIBUTING.md on how to add access transformers. # See CONTRIBUTING.md on how to add access transformers.
public net.minecraft.world.entity.projectile.AbstractArrow startFalling()V private-f net.minecraft.world.level.levelgen.NoiseChunk$Cache2D function
public net.minecraft.world.level.block.state.pattern.BlockPattern matches(Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/Direction;Lnet/minecraft/core/Direction;Lcom/google/common/cache/LoadingCache;)Lnet/minecraft/world/level/block/state/pattern/BlockPattern$BlockPatternMatch; private-f net.minecraft.world.level.levelgen.NoiseChunk$CacheOnce function
public net.minecraft.world.level.chunk.storage.RegionFile getOversizedData(II)Lnet/minecraft/nbt/CompoundTag; private-f net.minecraft.world.level.levelgen.NoiseChunk$FlatCache noiseFiller
public net.minecraft.world.level.chunk.storage.RegionFile isOversized(II)Z private-f net.minecraft.world.level.levelgen.NoiseChunk$NoiseInterpolator noiseFiller
public net.minecraft.world.level.chunk.storage.RegionFile recalculateHeader()Z private-f net.minecraft.world.level.levelgen.RandomState router
public net.minecraft.world.level.chunk.storage.RegionFile setOversized(IIZ)V private-f net.minecraft.world.level.levelgen.RandomState sampler
public net.minecraft.world.level.chunk.storage.RegionFile write(Lnet/minecraft/world/level/ChunkPos;Ljava/nio/ByteBuffer;)V public net.minecraft.util.Mth SIN
public net.minecraft.world.entity.ai.Brain sensors
public net.minecraft.world.entity.ai.sensing.Sensor scanRate
public net.minecraft.world.entity.ai.sensing.Sensor timeToTick
public net.minecraft.world.level.ServerExplosion damageSource
public net.minecraft.world.level.ServerExplosion source
public net.minecraft.world.level.chunk.LevelChunkSection nonEmptyBlockCount
public net.minecraft.world.level.chunk.LevelChunkSection tickingBlockCount
public net.minecraft.world.level.chunk.LevelChunkSection tickingFluidCount
public net.minecraft.world.level.chunk.PalettedContainer palette
public net.minecraft.world.level.chunk.PalettedContainer strategy
public net.minecraft.world.level.levelgen.DensityFunctions$BlendAlpha
public net.minecraft.world.level.levelgen.DensityFunctions$BlendDensity
public net.minecraft.world.level.levelgen.DensityFunctions$BlendOffset
public net.minecraft.world.level.levelgen.DensityFunctions$Clamp
public net.minecraft.world.level.levelgen.DensityFunctions$Constant
public net.minecraft.world.level.levelgen.DensityFunctions$Mapped
public net.minecraft.world.level.levelgen.DensityFunctions$Mapped$Type
public net.minecraft.world.level.levelgen.DensityFunctions$Noise
public net.minecraft.world.level.levelgen.DensityFunctions$RangeChoice
public net.minecraft.world.level.levelgen.DensityFunctions$Shift
public net.minecraft.world.level.levelgen.DensityFunctions$ShiftA
public net.minecraft.world.level.levelgen.DensityFunctions$ShiftB
public net.minecraft.world.level.levelgen.DensityFunctions$ShiftedNoise
public net.minecraft.world.level.levelgen.DensityFunctions$TwoArgumentSimpleFunction
public net.minecraft.world.level.levelgen.DensityFunctions$WeirdScaledSampler
public net.minecraft.world.level.levelgen.DensityFunctions$WeirdScaledSampler$RarityValueMapper mapper
public net.minecraft.world.level.levelgen.DensityFunctions$YClampedGradient
public net.minecraft.world.level.levelgen.NoiseChunk$BlendAlpha
public net.minecraft.world.level.levelgen.NoiseChunk$BlendOffset
public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity
public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity getSpaghettiRarity3D(D)D
public net.minecraft.world.level.levelgen.NoiseRouterData$QuantizedSpaghettiRarity getSphaghettiRarity2D(D)D
public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedHi
public net.minecraft.world.level.levelgen.Xoroshiro128PlusPlus seedLo
public net.minecraft.world.level.levelgen.XoroshiroRandomSource randomNumberGenerator
public net.minecraft.world.level.levelgen.structure.pools.StructureTemplatePool rawTemplates
public net.minecraft.world.level.levelgen.synth.BlendedNoise mainNoise
public net.minecraft.world.level.levelgen.synth.BlendedNoise maxLimitNoise
public net.minecraft.world.level.levelgen.synth.BlendedNoise minLimitNoise
public net.minecraft.world.level.levelgen.synth.BlendedNoise smearScaleMultiplier
public net.minecraft.world.level.levelgen.synth.BlendedNoise xzFactor
public net.minecraft.world.level.levelgen.synth.BlendedNoise xzMultiplier
public net.minecraft.world.level.levelgen.synth.BlendedNoise xzScale
public net.minecraft.world.level.levelgen.synth.BlendedNoise yFactor
public net.minecraft.world.level.levelgen.synth.BlendedNoise yMultiplier
public net.minecraft.world.level.levelgen.synth.BlendedNoise yScale
public net.minecraft.world.level.levelgen.synth.ImprovedNoise p
public net.minecraft.world.level.levelgen.synth.PerlinNoise amplitudes
public net.minecraft.world.level.levelgen.synth.PerlinNoise lowestFreqInputFactor
public net.minecraft.world.level.levelgen.synth.PerlinNoise lowestFreqValueFactor
public net.minecraft.world.level.levelgen.synth.PerlinNoise noiseLevels
public net.minecraft.world.level.levelgen.synth.SimplexNoise p
public net.minecraft.world.level.pathfinder.SwimNodeEvaluator allowBreaching public net.minecraft.world.level.pathfinder.SwimNodeEvaluator allowBreaching

View File

@@ -43,13 +43,13 @@ subprojects {
extensions.configure<JavaPluginExtension> { extensions.configure<JavaPluginExtension> {
toolchain { toolchain {
languageVersion = JavaLanguageVersion.of(21) languageVersion = JavaLanguageVersion.of(22)
} }
} }
tasks.withType<JavaCompile> { tasks.withType<JavaCompile> {
options.encoding = Charsets.UTF_8.name() options.encoding = Charsets.UTF_8.name()
options.release = 21 options.release = 22
options.isFork = true options.isFork = true
} }
tasks.withType<Javadoc> { tasks.withType<Javadoc> {

View File

@@ -0,0 +1,38 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Fri, 21 Feb 2025 22:58:46 +0300
Subject: [PATCH] Rebrand
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfo.java b/src/main/java/io/papermc/paper/ServerBuildInfo.java
index fb1fe2651e53a9bf46b3632c638e13eea9dcda93..81e92d1053efd15c079e318a4ae087948bc07866 100644
--- a/src/main/java/io/papermc/paper/ServerBuildInfo.java
+++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java
@@ -25,6 +25,14 @@ public interface ServerBuildInfo {
*/
Key BRAND_PURPUR_ID = Key.key("purpurmc", "purpur");
// Purpur end
+
+ // DivineMC start - Rebrand
+ /**
+ * The brand id for DivineMC.
+ */
+ Key BRAND_DIVINEMC_ID = Key.key("bxteam", "divinemc");
+ // DivineMC end
+
/**
* Gets the {@code ServerBuildInfo}.
*
diff --git a/src/main/java/org/bukkit/command/defaults/VersionCommand.java b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
index c880d0010849ab733ad13bbd18fab3c864d0cf61..a76439e59eefa4b6dbd0e100d72c21055d0ca008 100644
--- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java
+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java
@@ -259,7 +259,7 @@ public class VersionCommand extends BukkitCommand {
// Purpur start
int distance = getVersionFetcher().distance();
final Component message = Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()),
- ChatColor.parseMM("<grey>Current Purpur Version: %s%s*", distance == 0 ? "<green>" : distance > 0 ? "<yellow>" : "<red>", Bukkit.getVersion()),
+ ChatColor.parseMM("<grey>Current DivineMC Version: %s%s*", distance == 0 ? "<green>" : distance > 0 ? "<yellow>" : "<red>", Bukkit.getVersion()), // DivineMC - Rebrand
// Purpur end
msg
);

View File

@@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Fri, 21 Feb 2025 23:00:22 +0300
Subject: [PATCH] Configuration
diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java
index 78637a4f9650c1dd7ccc94bbfeb1fac048aa7f69..225c13225837c2748843cece816e2ad70da4b056 100644
--- a/src/main/java/org/bukkit/Server.java
+++ b/src/main/java/org/bukkit/Server.java
@@ -2346,6 +2346,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
}
// Purpur end
+ // DivineMC start - Configuration
+ @NotNull
+ public org.bukkit.configuration.file.YamlConfiguration getDivineConfig() {
+ throw new UnsupportedOperationException("Not supported yet");
+ }
+ // DivineMC end - Configuration
+
/**
* Sends the component to the player
*

View File

@@ -2104,6 +2104,150 @@ index 632c4961515f5052551f841cfa840e60bba7a257..00000000000000000000000000000000
- super.stopTiming(); - super.stopTiming();
- } - }
-} -}
diff --git a/src/main/java/org/bukkit/command/Command.java b/src/main/java/org/bukkit/command/Command.java
index 71eb845a4d3b8b6ec3b816a0f20ec807e0f9a86d..a43419c23aa0f6fd809caf5a841cb138f350b7ba 100644
--- a/src/main/java/org/bukkit/command/Command.java
+++ b/src/main/java/org/bukkit/command/Command.java
@@ -33,16 +33,6 @@ public abstract class Command {
protected String usageMessage;
private String permission;
private net.kyori.adventure.text.Component permissionMessage; // Paper
- /**
- * @deprecated Timings will be removed in the future
- */
- @Deprecated(forRemoval = true)
- public co.aikar.timings.Timing timings; // Paper
- /**
- * @deprecated Timings will be removed in the future
- */
- @Deprecated(forRemoval = true)
- @NotNull public String getTimingName() {return getName();} // Paper
protected Command(@NotNull String name) {
this(name, "", "/" + name, new ArrayList<String>());
diff --git a/src/main/java/org/bukkit/command/FormattedCommandAlias.java b/src/main/java/org/bukkit/command/FormattedCommandAlias.java
index abe256e1e45ce28036da4aa1586715bc8a1a3414..9eab8024e0675865f17669847759a26d28f74f3a 100644
--- a/src/main/java/org/bukkit/command/FormattedCommandAlias.java
+++ b/src/main/java/org/bukkit/command/FormattedCommandAlias.java
@@ -12,7 +12,6 @@ public class FormattedCommandAlias extends Command {
public FormattedCommandAlias(@NotNull String alias, @NotNull String[] formatStrings) {
super(alias);
- timings = co.aikar.timings.TimingsManager.getCommandTiming("minecraft", this); // Spigot
this.formatStrings = formatStrings;
}
@@ -120,10 +119,6 @@ public class FormattedCommandAlias extends Command {
return formatString.trim(); // Paper - Causes an extra space at the end, breaks with brig commands
}
- @NotNull
- @Override // Paper
- public String getTimingName() {return "Command Forwarder - " + super.getTimingName();} // Paper
-
private static boolean inRange(int i, int j, int k) {
return i >= j && i <= k;
}
diff --git a/src/main/java/org/bukkit/command/SimpleCommandMap.java b/src/main/java/org/bukkit/command/SimpleCommandMap.java
index 685aa9d73f14a5e3a85b251b83fbe8134b0a244c..6878e8bff4900a6d9b41cb981a69821da7f51242 100644
--- a/src/main/java/org/bukkit/command/SimpleCommandMap.java
+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java
@@ -39,7 +39,6 @@ public class SimpleCommandMap implements CommandMap {
register("bukkit", new VersionCommand("version"));
register("bukkit", new ReloadCommand("reload"));
//register("bukkit", new PluginsCommand("plugins")); // Paper
- register("bukkit", new co.aikar.timings.TimingsCommand("timings")); // Paper
}
public void setFallbackCommands() {
@@ -71,7 +70,6 @@ public class SimpleCommandMap implements CommandMap {
*/
@Override
public boolean register(@NotNull String label, @NotNull String fallbackPrefix, @NotNull Command command) {
- command.timings = co.aikar.timings.TimingsManager.getCommandTiming(fallbackPrefix, command); // Paper
label = label.toLowerCase(Locale.ROOT).trim();
fallbackPrefix = fallbackPrefix.toLowerCase(Locale.ROOT).trim();
boolean registered = register(label, command, false, fallbackPrefix);
@@ -166,12 +164,6 @@ public class SimpleCommandMap implements CommandMap {
parsedArgs = event.getArgs();
// Purpur end - ExecuteCommandEvent
- // Paper start - Plugins do weird things to workaround normal registration
- if (target.timings == null) {
- target.timings = co.aikar.timings.TimingsManager.getCommandTiming(null, target);
- }
- // Paper end
-
try {
//try (co.aikar.timings.Timing ignored = target.timings.startTiming()) { // Paper - use try with resources // Purpur - Remove Timings
// Note: we don't return the result of target.execute as thats success / failure, we return handled (true) or not handled (false)
diff --git a/src/main/java/org/bukkit/plugin/SimplePluginManager.java b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
index 001465eedafa51ac027a4db51cba6223edfe1171..9cb0f09b821a4020d17771a5b64ddd53e7d78478 100644
--- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java
+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java
@@ -720,12 +720,7 @@ public final class SimplePluginManager implements PluginManager {
throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled");
}
- executor = new co.aikar.timings.TimedEventExecutor(executor, plugin, null, event); // Paper
- if (false) { // Spigot - RL handles useTimings check now // Paper
- getEventListeners(event).register(new TimedRegisteredListener(listener, executor, priority, plugin, ignoreCancelled));
- } else {
- getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled));
- }
+ getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled)); // DivineMC - Delete Timings
}
@NotNull
@@ -955,8 +950,7 @@ public final class SimplePluginManager implements PluginManager {
@Override
public boolean useTimings() {
- if (true) {return this.paperPluginManager.useTimings();} // Paper
- return co.aikar.timings.Timings.isTimingsEnabled(); // Spigot
+ return false; // DivineMC - Delete Timings
}
/**
@@ -966,7 +960,7 @@ public final class SimplePluginManager implements PluginManager {
*/
@Deprecated(forRemoval = true)
public void useTimings(boolean use) {
- co.aikar.timings.Timings.setTimingsEnabled(use); // Paper
+ // DivineMC - Delete Timings
}
// Paper start
diff --git a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
index 065f182fbfe4541d602f57d548f286ee3c2fab19..40350504b5f7a92d834e95bb2e4e4268195ec9e7 100644
--- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java
@@ -43,7 +43,6 @@ import org.bukkit.plugin.TimedRegisteredListener;
import org.bukkit.plugin.UnknownDependencyException;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
-import org.spigotmc.CustomTimingsHandler; // Spigot
import org.yaml.snakeyaml.error.YAMLException;
/**
@@ -294,7 +293,7 @@ public final class JavaPluginLoader implements PluginLoader {
}
}
- EventExecutor executor = new co.aikar.timings.TimedEventExecutor(new EventExecutor() { // Paper
+ EventExecutor executor = new EventExecutor() { // Paper // DivineMC - Delete Timings
@Override
public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { // Paper
try {
@@ -308,7 +307,7 @@ public final class JavaPluginLoader implements PluginLoader {
throw new EventException(t);
}
}
- }, plugin, method, eventClass); // Paper
+ }; // Paper // DivineMC - Delete Timings
if (false) { // Spigot - RL handles useTimings check now
eventSet.add(new TimedRegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
} else {
diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java diff --git a/src/main/java/org/spigotmc/CustomTimingsHandler.java b/src/main/java/org/spigotmc/CustomTimingsHandler.java
deleted file mode 100644 deleted file mode 100644
index b4249da3eb26eae26ec000cc4d56cd21ac2fc6d5..0000000000000000000000000000000000000000 index b4249da3eb26eae26ec000cc4d56cd21ac2fc6d5..0000000000000000000000000000000000000000

View File

@@ -57,17 +57,16 @@
implementation("ca.spottedleaf:concurrentutil:0.0.3") implementation("ca.spottedleaf:concurrentutil:0.0.3")
implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+ implementation("org.jline:jline-terminal-ffm:3.27.1") // use ffm on java 22+
implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21 implementation("org.jline:jline-terminal-jni:3.27.1") // fall back to jni on java 21
@@ -176,6 +_,9 @@ @@ -176,6 +_,8 @@
implementation("org.mozilla:rhino-engine:1.7.14") // Purpur implementation("org.mozilla:rhino-engine:1.7.14") // Purpur
implementation("dev.omega24:upnp4j:1.0") // Purpur implementation("dev.omega24:upnp4j:1.0") // Purpur
+ implementation("com.github.luben:zstd-jni:1.5.6-9") // DivineMC + implementation("net.objecthunter:exp4j:0.4.8") // DivineMC
+ implementation("org.lz4:lz4-java:1.8.0") // DivineMC
+ +
runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6") runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6")
runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18") runtimeOnly("org.apache.maven.resolver:maven-resolver-connector-basic:1.9.18")
runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18") runtimeOnly("org.apache.maven.resolver:maven-resolver-transport-http:1.9.18")
@@ -203,26 +_,35 @@ @@ -203,30 +_,41 @@
implementation("me.lucko:spark-paper:1.10.119-SNAPSHOT") implementation("me.lucko:spark-paper:1.10.119-SNAPSHOT")
} }
@@ -91,6 +90,7 @@
val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash" val implementationVersion = "$mcVersion-${build ?: "DEV"}-$gitHash"
val date = git.exec(providers, "show", "-s", "--format=%ci", gitHash).get().trim() val date = git.exec(providers, "show", "-s", "--format=%ci", gitHash).get().trim()
val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim() val gitBranch = git.exec(providers, "rev-parse", "--abbrev-ref", "HEAD").get().trim()
+ val experimental = rootProject.providers.gradleProperty("experimental").get()
attributes( attributes(
"Main-Class" to "org.bukkit.craftbukkit.Main", "Main-Class" to "org.bukkit.craftbukkit.Main",
- "Implementation-Title" to "Purpur", // Purpur - "Implementation-Title" to "Purpur", // Purpur
@@ -109,3 +109,8 @@
"Build-Number" to (build ?: ""), "Build-Number" to (build ?: ""),
"Build-Time" to buildTime.toString(), "Build-Time" to buildTime.toString(),
"Git-Branch" to gitBranch, "Git-Branch" to gitBranch,
"Git-Commit" to gitHash,
+ "Experimental" to experimental, // DivineMC - Experimental flag
)
for (tld in setOf("net", "com", "org")) {
attributes("$tld/bukkit", "Sealed" to true)

View File

@@ -17,6 +17,75 @@ index 394443d00e661715439be1e56dddc129947699a4..480ad57a6b7b74e6b83e9c6ceb69ea1f
public CrashReport(String title, Throwable exception) { public CrashReport(String title, Throwable exception) {
io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper io.papermc.paper.util.StacktraceDeobfuscator.INSTANCE.deobfuscateThrowable(exception); // Paper
diff --git a/net/minecraft/server/Main.java b/net/minecraft/server/Main.java
index 1485186d4989874ef89c4e83830f26358a43759c..680369af59fd2aa36bf1cf4e28b598854383abe3 100644
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
@@ -62,6 +62,14 @@ import org.slf4j.Logger;
public class Main {
private static final Logger LOGGER = LogUtils.getLogger();
+ // DivineMC start - Log experimental warning
+ static {
+ io.papermc.paper.ServerBuildInfo info = io.papermc.paper.ServerBuildInfo.buildInfo();
+ if (io.papermc.paper.ServerBuildInfoImpl.IS_EXPERIMENTAL) {
+ LOGGER.warn("Running an experimental version of {}, please proceed with caution.", info.brandName());
+ }
+ }
+ // DivineMC end - Log experimental warning
@SuppressForbidden(
reason = "System.out needed before bootstrap"
@@ -114,6 +122,18 @@ public class Main {
org.purpurmc.purpur.PurpurConfig.registerMinecraftDebugCommands = purpurConfiguration.getBoolean("settings.register-minecraft-debug-commands"); // Purpur - register minecraft debug commands
// Purpur end - Add toggle for enchant level clamping - load config files early
+ // DivineMC start - Server startup settings
+ org.bukkit.configuration.file.YamlConfiguration divinemcConfiguration = io.papermc.paper.configuration.PaperConfigurations.loadLegacyConfigFile((File) optionSet.valueOf("divinemc-settings"));
+ boolean divinemcNativeMathEnabled = divinemcConfiguration.getBoolean("settings.chunk-generation.native-acceleration-enabled", true);
+ if (divinemcNativeMathEnabled) {
+ try {
+ Class.forName("org.bxteam.divinemc.math.NativeLoader").getField("lookup").get(null);
+ } catch (Throwable e) {
+ e.printStackTrace();
+ }
+ }
+ // DivineMC end - Server startup settings
+
io.papermc.paper.plugin.PluginInitializerManager.load(optionSet); // Paper
Bootstrap.bootStrap();
Bootstrap.validate();
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 diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 80ed0e4b8c867d031413b4140e52af1342fdcb54..6ebd1300c2561116b83cb2472ac7939ead36d576 100644 index 80ed0e4b8c867d031413b4140e52af1342fdcb54..6ebd1300c2561116b83cb2472ac7939ead36d576 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java --- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java

View File

@@ -1,11 +1,11 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 12 Jan 2025 16:19:14 +0300 Date: Mon, 27 Jan 2025 20:22:52 +0300
Subject: [PATCH] DivineMC Configuration Subject: [PATCH] Configuration
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index db82329935145ec12fa47eef730613ee9c7666ee..0eecc41b02f205022a717691a18114d5c091bc3d 100644 index 4f90ebcd86fba38dec313143e36614e992c7dbc7..959d87f4cd1efe8cf591e98c7d32728067f7117c 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java --- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java +++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -243,6 +243,17 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @@ -243,6 +243,17 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
@@ -13,36 +13,36 @@ index db82329935145ec12fa47eef730613ee9c7666ee..0eecc41b02f205022a717691a18114d5
org.purpurmc.purpur.PurpurConfig.registerCommands(); org.purpurmc.purpur.PurpurConfig.registerCommands();
*/// Purpur end - Purpur config files // Purpur - Configurable void damage height and damage */// Purpur end - Purpur config files // Purpur - Configurable void damage height and damage
+ +
+ // DivineMC start - DivineMC configuration + // DivineMC start - Configuration
+ try { + try {
+ org.bxteam.divinemc.configuration.DivineConfig.init((java.io.File) options.valueOf("divinemc-settings")); + org.bxteam.divinemc.DivineConfig.init((java.io.File) options.valueOf("divinemc-settings"));
+ } catch (Exception e) { + } catch (Exception e) {
+ DedicatedServer.LOGGER.error("Unable to load server configuration", e); + DedicatedServer.LOGGER.error("Unable to load server configuration", e);
+ return false; + return false;
+ } + }
+ org.bxteam.divinemc.command.DivineCommands.registerCommands(this); // DivineMC - register commands + org.bxteam.divinemc.command.DivineCommands.registerCommands(this);
+ // DivineMC end - DivineMC configuration + // DivineMC end - Configuration
+ +
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
this.setPvpAllowed(properties.pvp); this.setPvpAllowed(properties.pvp);
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 66d1525eff7e23c49d0a2d4b217a58f88c2a3d6c..3ed76a5eabbe35f23d1809b669fc94dd63399764 100644 index 0fe8f4601eedfa68c38ebadc7847ba7a07ff6fb6..3856bbe579ef6df2f220c46bc69461cab026a131 100644
--- a/net/minecraft/world/level/Level.java --- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java +++ b/net/minecraft/world/level/Level.java
@@ -171,6 +171,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -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 io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray
public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files
+ public final org.bxteam.divinemc.configuration.DivineWorldConfig divinemcConfig; // DivineMC - DivineMC config files + public final org.bxteam.divinemc.DivineWorldConfig divineConfig; // DivineMC - Configuration
public static BlockPos lastPhysicsProblem; // Spigot public static BlockPos lastPhysicsProblem; // Spigot
private int tileTickPosition; private org.spigotmc.TickLimiter entityLimiter;
public final Map<ServerExplosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions private org.spigotmc.TickLimiter tileLimiter;
@@ -896,6 +897,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl @@ -898,6 +899,7 @@ 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.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.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 this.purpurConfig = new org.purpurmc.purpur.PurpurWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), env); // Purpur - Purpur config files
+ this.divinemcConfig = new org.bxteam.divinemc.configuration.DivineWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), env); // DivineMC - DivineMC configuration + this.divineConfig = new org.bxteam.divinemc.DivineWorldConfig(((net.minecraft.world.level.storage.PrimaryLevelData) levelData).getLevelName(), env); // DivineMC - Configuration
this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur - Add adjustable breeding cooldown to config this.playerBreedingCooldowns = this.getNewBreedingCooldownCache(); // Purpur - Add adjustable breeding cooldown to config
this.generator = gen; this.generator = gen;
this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env); this.world = new CraftWorld((ServerLevel) this, gen, biomeProvider, env);

View File

@@ -1,183 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 12 Jan 2025 00:14:45 +0300
Subject: [PATCH] Add missing purpur config options
diff --git a/net/minecraft/world/entity/animal/allay/Allay.java b/net/minecraft/world/entity/animal/allay/Allay.java
index 22e0fad86da2e7b932863ef30182355aa41424a1..d4eee24b5ab89f82e4e90f551d6651330d4508cb 100644
--- a/net/minecraft/world/entity/animal/allay/Allay.java
+++ b/net/minecraft/world/entity/animal/allay/Allay.java
@@ -181,6 +181,18 @@ public class Allay extends PathfinderMob implements InventoryCarrier, VibrationS
}
// Purpur end - Configurable entity base attributes
+ // DivineMC start - Add missing purpur config options
+ @Override
+ public boolean isSensitiveToWater() {
+ return level().purpurConfig.allayTakeDamageFromWater;
+ }
+
+ @Override
+ public boolean isAlwaysExperienceDropper() {
+ return level().purpurConfig.allayAlwaysDropExp;
+ }
+ // DivineMC end - Add missing purpur config options
+
@Override
protected Brain.Provider<Allay> brainProvider() {
return Brain.provider(MEMORY_TYPES, SENSOR_TYPES);
diff --git a/net/minecraft/world/entity/animal/camel/Camel.java b/net/minecraft/world/entity/animal/camel/Camel.java
index 1d7ae2a08968860636918e7c66b60139a9d761b4..126af60a694600d40e3ae6bd39e94e55dd9d0b6e 100644
--- a/net/minecraft/world/entity/animal/camel/Camel.java
+++ b/net/minecraft/world/entity/animal/camel/Camel.java
@@ -97,6 +97,18 @@ public class Camel extends AbstractHorse {
}
// Purpur end - Make entity breeding times configurable
+ // DivineMC start - Add missing purpur config options
+ @Override
+ public boolean isSensitiveToWater() {
+ return level().purpurConfig.camelTakeDamageFromWater;
+ }
+
+ @Override
+ public boolean isAlwaysExperienceDropper() {
+ return level().purpurConfig.camelAlwaysDropExp;
+ }
+ // DivineMC end - Add missing purpur config options
+
@Override
public void addAdditionalSaveData(CompoundTag compound) {
super.addAdditionalSaveData(compound);
diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
index c4ea9485294b7dec2582c638802f003ad70659b6..d286d4a45b6c8d5c684ad11500d2ad1a10a70c18 100644
--- a/net/minecraft/world/entity/animal/frog/Frog.java
+++ b/net/minecraft/world/entity/animal/frog/Frog.java
@@ -165,6 +165,23 @@ public class Frog extends Animal implements VariantHolder<Holder<FrogVariant>> {
}
// Purpur end - Ridables
+ // DivineMC start - Add missing purpur config options
+ @Override
+ public boolean isSensitiveToWater() {
+ return level().purpurConfig.frogTakeDamageFromWater;
+ }
+
+ @Override
+ public boolean isAlwaysExperienceDropper() {
+ return level().purpurConfig.frogAlwaysDropExp;
+ }
+
+ @Override
+ public void initAttributes() {
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(level().purpurConfig.frogMaxHealth);
+ }
+ // DivineMC end
+
// Purpur start - Make entity breeding times configurable
@Override
public int getPurpurBreedTime() {
diff --git a/net/minecraft/world/entity/animal/frog/Tadpole.java b/net/minecraft/world/entity/animal/frog/Tadpole.java
index e888e606b4b14fa6485de7426bc146b6005962af..a4383a7d41c91f9e478c7e221828ba92437af06c 100644
--- a/net/minecraft/world/entity/animal/frog/Tadpole.java
+++ b/net/minecraft/world/entity/animal/frog/Tadpole.java
@@ -107,6 +107,23 @@ public class Tadpole extends AbstractFish {
}
// Purpur end - Ridables
+ // DivineMC start - Add missing purpur config options
+ @Override
+ public boolean isSensitiveToWater() {
+ return level().purpurConfig.tadpoleTakeDamageFromWater;
+ }
+
+ @Override
+ public boolean isAlwaysExperienceDropper() {
+ return level().purpurConfig.tadpoleAlwaysDropExp;
+ }
+
+ @Override
+ public void initAttributes() {
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(level().purpurConfig.tadpoleMaxHealth);
+ }
+ // DivineMC end - Add missing purpur config options
+
@Override
protected PathNavigation createNavigation(Level level) {
return new WaterBoundPathNavigation(this, level);
diff --git a/net/minecraft/world/entity/animal/sniffer/Sniffer.java b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
index 11a5da22149a61ca48bbb0a8ed10b71e91a5cc98..ed1ffc1578e50fa6fedc6124fe016a1535c0e968 100644
--- a/net/minecraft/world/entity/animal/sniffer/Sniffer.java
+++ b/net/minecraft/world/entity/animal/sniffer/Sniffer.java
@@ -120,6 +120,18 @@ public class Sniffer extends Animal {
}
// Purpur end - Make entity breeding times configurable
+ // DivineMC start - Add missing purpur config options
+ @Override
+ public boolean isSensitiveToWater() {
+ return level().purpurConfig.snifferTakeDamageFromWater;
+ }
+
+ @Override
+ public boolean isAlwaysExperienceDropper() {
+ return level().purpurConfig.snifferAlwaysDropExp;
+ }
+ // DivineMC end
+
@Override
protected void defineSynchedData(SynchedEntityData.Builder builder) {
super.defineSynchedData(builder);
diff --git a/net/minecraft/world/entity/monster/warden/Warden.java b/net/minecraft/world/entity/monster/warden/Warden.java
index f968e5c99bdb23b268bc34ea1ba5d54ae9ad0ff9..f74c784906208034f51b31bd9aba45733c3ebebe 100644
--- a/net/minecraft/world/entity/monster/warden/Warden.java
+++ b/net/minecraft/world/entity/monster/warden/Warden.java
@@ -155,6 +155,23 @@ public class Warden extends Monster implements VibrationSystem {
}
// Purpur end - Ridables
+ // DivineMC start - Add missing purpur config options
+ @Override
+ public boolean isSensitiveToWater() {
+ return level().purpurConfig.wardenTakeDamageFromWater;
+ }
+
+ @Override
+ public boolean isAlwaysExperienceDropper() {
+ return level().purpurConfig.wardenAlwaysDropExp;
+ }
+
+ @Override
+ public void initAttributes() {
+ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(level().purpurConfig.wardenMaxHealth);
+ }
+ // DivineMC end
+
@Override
public Packet<ClientGamePacketListener> getAddEntityPacket(ServerEntity entity) {
return new ClientboundAddEntityPacket(this, entity, this.hasPose(Pose.EMERGING) ? 1 : 0);
diff --git a/net/minecraft/world/entity/vehicle/AbstractChestBoat.java b/net/minecraft/world/entity/vehicle/AbstractChestBoat.java
index b230955ae880d84fde40b4feffa5caf3c4449eb7..5b88c69427d5915ff547e4caf7b5656e96912e93 100644
--- a/net/minecraft/world/entity/vehicle/AbstractChestBoat.java
+++ b/net/minecraft/world/entity/vehicle/AbstractChestBoat.java
@@ -26,8 +26,8 @@ import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.storage.loot.LootTable;
public abstract class AbstractChestBoat extends AbstractBoat implements HasCustomInventoryScreen, ContainerEntity {
- private static final int CONTAINER_SIZE = 27;
- private NonNullList<ItemStack> itemStacks = NonNullList.withSize(27, ItemStack.EMPTY);
+ private static final int CONTAINER_SIZE = org.purpurmc.purpur.PurpurConfig.chestBoatRows * 9; // DivineMC - Add missing purpur config options
+ private NonNullList<ItemStack> itemStacks = NonNullList.withSize(org.purpurmc.purpur.PurpurConfig.chestBoatRows * 9, ItemStack.EMPTY); // DivineMC - Add missing purpur config options
@Nullable
private ResourceKey<LootTable> lootTable;
private long lootTableSeed;
@@ -118,7 +118,7 @@ public abstract class AbstractChestBoat extends AbstractBoat implements HasCusto
@Override
public int getContainerSize() {
- return 27;
+ return org.purpurmc.purpur.PurpurConfig.chestBoatRows * 9; // DivineMC - Add missing purpur config options
}
@Override

View File

@@ -0,0 +1,433 @@
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 6540b2d6a1062d883811ce240c49d30d1925b291..2678bf59d557f085c7265e2f3eb038647723d35e 100644
--- a/net/minecraft/server/level/ServerChunkCache.java
+++ b/net/minecraft/server/level/ServerChunkCache.java
@@ -652,6 +652,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 59d03ddc42d53e2b825abe0cf2ab24e85d586a19..dd113d67356177a8d98ea10a8b6d4a4d5159674c 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -634,6 +634,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

@@ -0,0 +1,810 @@
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..aadc05082a029ab41ab2512f5cd5b3d2a361e097 100644
--- a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
+++ b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java
@@ -94,21 +94,54 @@ 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) {
+ // await on path async
+ Path possiblePath = findPathToPois(mob, set);
+
+ // wait on the path to be processed
+ org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> {
+ // read canReach check
+ if (path == null || !path.canReach()) {
+ for (Pair<Holder<PoiType>, BlockPos> pair : set) {
+ map.computeIfAbsent(
+ pair.getSecond().asLong(),
+ m -> new JitteredLinearRetry(mob.level().random, time)
+ );
+ }
+ return;
+ }
+ BlockPos blockPos = path.getTarget();
+ poiManager.getType(blockPos).ifPresent(poiType -> {
+ poiManager.take(acquirablePois,
+ (holder, blockPos2) -> blockPos2.equals(blockPos),
+ blockPos,
+ 1
+ );
+ memoryAccessor.set(GlobalPos.of(level.dimension(), blockPos));
+ entityEventId.ifPresent(status -> level.broadcastEntityEvent(mob, status));
+ map.clear();
+ DebugPackets.sendPoiTicketCountPacket(level, blockPos);
+ });
});
} 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);
+ 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 AcquirePoi.JitteredLinearRetry(level.random, time));
+ }
}
}
+ // DivineMC end - Async path processing
return true;
}
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..5e4e4ab9b50fcddfd022dbab15620c9c0cb53645 100644
--- a/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java
+++ b/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java
@@ -60,17 +60,38 @@ 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);
+ // DivineMC start - async path processing
+ if (org.bxteam.divinemc.DivineConfig.asyncPathfinding) {
+ // await on path async
+ Path possiblePath = AcquirePoi.findPathToPois(mob, set);
+
+ // wait on the path to be processed
+ org.bxteam.divinemc.entity.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> {
+ if (path == null || !path.canReach() || mutableInt.getValue() < 5) { // read canReach check
+ map.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < mutableLong.getValue());
+ return;
+ }
+ BlockPos blockPos = path.getTarget();
+ Optional<Holder<PoiType>> optional2 = poiManager.getType(blockPos);
+ if (optional2.isPresent()) {
+ walkTarget.set(new WalkTarget(blockPos, speedModifier, 1));
+ DebugPackets.sendPoiTicketCountPacket(level, blockPos);
+ }
+ });
+ } else {
+ 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());
}
- } else if (mutableInt.getValue() < 5) {
- map.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < mutableLong.getValue());
}
+ // DivineMC end - async path processing
return true;
} else {
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 b44f2c49509d847817a78e9c4fb1499fb378054b..c0b61c38a82fd3de046b550a49d8cde6afa9d9af 100644
--- a/net/minecraft/world/entity/ai/navigation/PathNavigation.java
+++ b/net/minecraft/world/entity/ai/navigation/PathNavigation.java
@@ -169,6 +169,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 {
@@ -195,12 +199,30 @@ 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);
- profilerFiller.pop();
- 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 {
+ profilerFiller.pop();
+ if (path != null && path.getTarget() != null) {
+ this.targetPos = path.getTarget();
+ this.reachRange = accuracy;
+ this.resetStuckTimeout();
+ }
}
+ // DivineMC end - async path processing
return path;
}
@@ -251,8 +273,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;
@@ -275,6 +297,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()) {
@@ -304,6 +327,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();
@@ -460,7 +484,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..3a8b3c71f6fd0c0f57a3190dc8a0f808c6d1002b 100644
--- a/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java
@@ -57,17 +57,37 @@ 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);
+ // 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 -> {
+ // read canReach check
+ if ((path == null || !path.canReach()) && this.triedCount < 5) {
+ this.batchCache.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < this.lastUpdate);
+ return;
+ }
+ if (path == null) return;
+
+ BlockPos blockPos = path.getTarget();
+ Optional<Holder<PoiType>> optional = poiManager.getType(blockPos);
+ if (optional.isPresent()) {
+ entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, blockPos);
+ }
+ });
+ } else {
+ Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
+ 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);
}
- } 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 143a740ce2e7f9d384b71b4d64e8b8218f60cba7..3c657179644750846180ab1c45250a9e17dda396 100644
--- a/net/minecraft/world/entity/animal/frog/Frog.java
+++ b/net/minecraft/world/entity/animal/frog/Frog.java
@@ -480,6 +480,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);
@@ -488,6 +499,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 f968e5c99bdb23b268bc34ea1ba5d54ae9ad0ff9..7b185f07f099c2704ecd5c983a11f4085a4f13c2 100644
--- a/net/minecraft/world/entity/monster/warden/Warden.java
+++ b/net/minecraft/world/entity/monster/warden/Warden.java
@@ -602,6 +602,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 81de6c1bbef1cafd3036e736dd305fbedc8368c6..0796343f89c8424d0f7553c60dde952ab06b9f3a 100644
--- a/net/minecraft/world/level/pathfinder/PathFinder.java
+++ b/net/minecraft/world/level/pathfinder/PathFinder.java
@@ -25,11 +25,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;
@@ -37,26 +45,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
ProfilerFiller profilerFiller = Profiler.get();
profilerFiller.push("find_path");
profilerFiller.markForCharting(MetricCategory.PATH_FINDING);
@@ -95,7 +140,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

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

View File

@@ -0,0 +1,333 @@
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/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
index da2921268a9aa4545a12c155a33bed9fccb4f19c..e3427e7aecfc4e1fafb38316824aa1ee50c9901a 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -264,9 +264,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
final ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
- for (int i = 0, len = inRange.size(); i < len; i++) {
- ++(backingSet[i].mobCounts[index]);
+ // DivineMC start - Multithreaded tracker
+ if (org.bxteam.divinemc.DivineConfig.multithreadedEnabled) {
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ final ServerPlayer player = backingSet[i];
+ if (player == null) continue;
+ ++(player.mobCounts[index]);
+ }
+ } else {
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ ++(backingSet[i].mobCounts[index]);
+ }
}
+ // DivineMC end - Multithreaded tracker
}
// Paper start - per player mob count backoff
@@ -950,6 +960,19 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity)entity).moonrise$setTrackedEntity(null); // Paper - optimise entity tracker
}
+ // DivineMC start - Multithreaded tracker
+ private final java.util.concurrent.ConcurrentLinkedQueue<Runnable> trackerMainThreadTasks = new java.util.concurrent.ConcurrentLinkedQueue<>();
+ private boolean tracking = false;
+
+ public void runOnTrackerMainThread(final Runnable runnable) {
+ if (false && this.tracking) { // TODO: check here
+ this.trackerMainThreadTasks.add(runnable);
+ } else {
+ runnable.run();
+ }
+ }
+ // DivineMC end - Multithreaded tracker
+
// Paper start - optimise entity tracker
private void newTrackerTick() {
final ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup entityLookup = (ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup)((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel)this.level).moonrise$getEntityLookup();;
@@ -972,6 +995,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();
@@ -1094,7 +1124,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;
@@ -1121,21 +1155,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
@@ -1197,9 +1265,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public void broadcast(Packet<?> packet) {
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
+ // DivineMC start - Multithreaded tracker
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) {
serverPlayerConnection.send(packet);
}
+ // DivineMC end - Multithreaded tracker
}
public void broadcastAndSend(Packet<?> packet) {
@@ -1210,21 +1280,22 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
}
public void broadcastRemoved() {
- for (ServerPlayerConnection serverPlayerConnection : this.seenBy) {
+ // DivineMC start - Multithreaded tracker
+ for (ServerPlayerConnection serverPlayerConnection : this.seenBy.toArray(new ServerPlayerConnection[0])) {
this.serverEntity.removePairing(serverPlayerConnection.getPlayer());
}
+ // DivineMC end - Multithreaded tracker
}
public void removePlayer(ServerPlayer player) {
- org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot
if (this.seenBy.remove(player.connection)) {
this.serverEntity.removePairing(player);
}
}
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..3ee43ca5c49af83a067c7ffe74d3f2bc6e4a6c9e 100644
--- a/net/minecraft/server/level/ServerEntity.java
+++ b/net/minecraft/server/level/ServerEntity.java
@@ -110,8 +110,13 @@ 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
}
}
);
@@ -304,7 +309,11 @@ public class ServerEntity {
public void removePairing(ServerPlayer player) {
this.entity.stopSeenByPlayer(player);
- player.connection.send(new ClientboundRemoveEntitiesPacket(this.entity.getId()));
+ // DivineMC start - Multithreaded tracker - send in main thread
+ ((ServerLevel) this.entity.level()).chunkSource.chunkMap.runOnTrackerMainThread(() ->
+ player.connection.send(new ClientboundRemoveEntitiesPacket(this.entity.getId()))
+ );
+ // DivineMC end - Multithreaded tracker
}
public void addPairing(ServerPlayer player) {
@@ -404,18 +413,27 @@ public class ServerEntity {
List<SynchedEntityData.DataValue<?>> list = entityData.packDirty();
if (list != null) {
this.trackedDataValues = entityData.getNonDefaultValues();
- this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list));
+ // DivineMC start - Multithreaded tracker - send in main thread
+ ((ServerLevel) this.entity.level()).chunkSource.chunkMap.runOnTrackerMainThread(() ->
+ this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list))
+ );
+ // DivineMC end - Multithreaded tracker
}
if (this.entity instanceof LivingEntity) {
Set<AttributeInstance> attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync();
if (!attributesToSync.isEmpty()) {
- // CraftBukkit start - Send scaled max health
- if (this.entity instanceof ServerPlayer serverPlayer) {
- serverPlayer.getBukkitEntity().injectScaledMaxHealth(attributesToSync, false);
- }
- // CraftBukkit end
- this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync));
+ // DivineMC start - Multithreaded tracker
+ final Set<AttributeInstance> copy = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(attributesToSync);
+ ((ServerLevel) this.entity.level()).chunkSource.chunkMap.runOnTrackerMainThread(() -> {
+ // CraftBukkit start - Send scaled max health
+ if (this.entity instanceof ServerPlayer serverPlayer) {
+ serverPlayer.getBukkitEntity().injectScaledMaxHealth(copy, false);
+ }
+ // CraftBukkit end
+ this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy));
+ });
+ // DivineMC end - Multithreaded tracker
}
attributesToSync.clear();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index dd113d67356177a8d98ea10a8b6d4a4d5159674c..5d2483b2d59ae246b822d73b9996c2aa86623ab1 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -2514,7 +2514,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
}
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index b45b37fcdfe0d3877b368444f8f6a376d6373f59..cfd3698dc575669456136da9cbbb100fd557e5ac 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1813,7 +1813,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

View File

@@ -0,0 +1,129 @@
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

@@ -0,0 +1,988 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Wed, 29 Jan 2025 00:59:03 +0300
Subject: [PATCH] Parallel world ticking
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
index b5817aa8f537593f6d9fc6b612c82ccccb250ac7..0c99bffa769d53562a10d23c4a9b37dc59c7f478 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/scheduling/ChunkHolderManager.java
@@ -1031,7 +1031,7 @@ public final class ChunkHolderManager {
if (changedFullStatus.isEmpty()) {
return;
}
- if (!TickThread.isTickThread()) {
+ if (!TickThread.isTickThreadFor(world)) { // DivineMC - parallel world ticking
this.taskScheduler.scheduleChunkTask(() -> {
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
@@ -1057,7 +1057,7 @@ public final class ChunkHolderManager {
// note: never call while inside the chunk system, this will absolutely break everything
public void processUnloads() {
- TickThread.ensureTickThread("Cannot unload chunks off-main");
+ TickThread.ensureTickThread(world, "Cannot unload chunks off-main"); // DivineMC - parallel world ticking
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
throw new IllegalStateException("Cannot unload chunks recursively");
@@ -1339,7 +1339,7 @@ public final class ChunkHolderManager {
List<NewChunkHolder> changedFullStatus = null;
- final boolean isTickThread = TickThread.isTickThread();
+ final boolean isTickThread = TickThread.isTickThreadFor(world); // DivineMC - parallel world ticking
boolean ret = false;
final boolean canProcessFullUpdates = processFullUpdates & isTickThread;
diff --git a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
index 4a881636ba21fae9e50950bbba2b4321b71d35ab..d019e6cd603c918b576b950a3c678862b2248c93 100644
--- a/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/BoatDispenseItemBehavior.java
@@ -46,7 +46,7 @@ public class BoatDispenseItemBehavior extends DefaultDispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(d1, d2 + d4, d3));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
index bd5bbc7e55c6bea77991fe5a3c0c2580313d16c5..10ab4be4b8d7e488148bab395e344fca0d09fbb0 100644
--- a/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DefaultDispenseItemBehavior.java
@@ -78,7 +78,7 @@ public class DefaultDispenseItemBehavior implements DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack);
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(itemEntity.getDeltaMovement()));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
level.getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/core/dispenser/DispenseItemBehavior.java b/net/minecraft/core/dispenser/DispenseItemBehavior.java
index f576449e8bc6fd92963cbe3954b0c853a02def3c..c8c8351f5645cf4041d26b0e02c072546ad329c6 100644
--- a/net/minecraft/core/dispenser/DispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/DispenseItemBehavior.java
@@ -89,7 +89,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
@@ -147,7 +147,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
@@ -201,7 +201,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity());
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
world.getCraftServer().getPluginManager().callEvent(event);
}
@@ -251,7 +251,7 @@ public interface DispenseItemBehavior {
org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(world, blockSource.pos());
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleCopy);
org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), abstractChestedHorse.getBukkitLivingEntity());
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
world.getCraftServer().getPluginManager().callEvent(event);
}
@@ -329,7 +329,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(x, y, z));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
level.getCraftServer().getPluginManager().callEvent(event);
}
@@ -389,7 +389,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
levelAccessor.getMinecraftWorld().getCraftServer().getPluginManager().callEvent(event);
}
@@ -425,7 +425,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
@@ -482,7 +482,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
level.getCraftServer().getPluginManager().callEvent(event);
}
@@ -510,8 +510,10 @@ public interface DispenseItemBehavior {
// CraftBukkit start
level.captureTreeGeneration = false;
if (level.capturedBlockStates.size() > 0) {
- org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType;
- net.minecraft.world.level.block.SaplingBlock.treeType = null;
+ // DivineMC start - parallel world ticking
+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get();
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null);
+ // DivineMC end - parallel world ticking
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(blockPos, level.getWorld());
List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(level.capturedBlockStates.values());
level.capturedBlockStates.clear();
@@ -548,7 +550,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(singleItemStack);
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) blockPos.getX() + 0.5D, (double) blockPos.getY(), (double) blockPos.getZ() + 0.5D));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
level.getCraftServer().getPluginManager().callEvent(event);
}
@@ -591,7 +593,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
level.getCraftServer().getPluginManager().callEvent(event);
}
@@ -644,7 +646,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
level.getCraftServer().getPluginManager().callEvent(event);
}
@@ -702,7 +704,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - only single item in event
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), org.bukkit.craftbukkit.util.CraftVector.toBukkit(blockPos));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
@@ -783,7 +785,7 @@ public interface DispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), entitiesOfClass.get(0).getBukkitLivingEntity());
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
index b91b2f5ea6a1da0477541dc65fdfbfa57b9af475..e2b7ee10569812c94a5ff6d6e731941f24527c55 100644
--- a/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/EquipmentDispenseItemBehavior.java
@@ -39,7 +39,7 @@ public class EquipmentDispenseItemBehavior extends DefaultDispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
org.bukkit.event.block.BlockDispenseArmorEvent event = new org.bukkit.event.block.BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) livingEntity.getBukkitEntity());
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
world.getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
index 116395b6c00a0814922516707544a9ff26d68835..37f710bfa8a9388351d1d32f6f2eeac7c8bfd4bd 100644
--- a/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/MinecartDispenseItemBehavior.java
@@ -62,7 +62,7 @@ public class MinecartDispenseItemBehavior extends DefaultDispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1);
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(vec31.x, vec31.y, vec31.z));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
index 449d9b72ff4650961daa9d1bd25940f3914a6b12..097528f85e5c0393c8b20a68aede99b4b949cb24 100644
--- a/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ProjectileDispenseBehavior.java
@@ -32,7 +32,7 @@ public class ProjectileDispenseBehavior extends DefaultDispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack1);
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(block, craftItem.clone(), new org.bukkit.util.Vector((double) direction.getStepX(), (double) direction.getStepY(), (double) direction.getStepZ()));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
index 626e9feb6a6e7a2cbc7c63e30ba4fb6b923e85c7..6fad185f34c4614f16012ec008add241f188d462 100644
--- a/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
+++ b/net/minecraft/core/dispenser/ShearsDispenseItemBehavior.java
@@ -25,7 +25,7 @@ public class ShearsDispenseItemBehavior extends OptionalDispenseItemBehavior {
org.bukkit.block.Block bukkitBlock = org.bukkit.craftbukkit.block.CraftBlock.at(serverLevel, blockSource.pos());
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item); // Paper - ignore stack size on damageable items
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(0, 0, 0));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
serverLevel.getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
index 5ab2c8333178335515e619b87ae420f948c83bd1..9d2bc41befd0f73b6a0f097d45fbe771e13be86f 100644
--- a/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
+++ b/net/minecraft/core/dispenser/ShulkerBoxDispenseBehavior.java
@@ -27,7 +27,7 @@ public class ShulkerBoxDispenseBehavior extends OptionalDispenseItemBehavior {
org.bukkit.craftbukkit.inventory.CraftItemStack craftItem = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item.copyWithCount(1)); // Paper - single item in event
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), new org.bukkit.util.Vector(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
- if (!DispenserBlock.eventFired) {
+ if (!DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
blockSource.level().getCraftServer().getPluginManager().callEvent(event);
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 781030cb2e0316151c20351f04347c8db63f43e1..527547b98b70429830a3cf82fddba202e0ba8131 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -306,6 +306,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public boolean lagging = false; // Purpur - Lagging threshold
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 static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
@@ -1757,35 +1758,49 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
this.isIteratingOverLevels = true; // Paper - Throw exception on world create while being ticked
- for (ServerLevel serverLevel : this.getAllLevels()) {
- serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
- serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
- serverLevel.updateLagCompensationTick(); // Paper - lag compensation
- net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
- serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables
- profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
- /* Drop global time updates
- if (this.tickCount % 20 == 0) {
- profilerFiller.push("timeSync");
- this.synchronizeTime(serverLevel);
+ // DivineMC start - parallel world ticking
+ java.util.ArrayDeque<java.util.concurrent.Future<ServerLevel>> tasks = new java.util.ArrayDeque<>();
+ try {
+ for (ServerLevel serverLevel : this.getAllLevels()) {
+ serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
+ serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
+ serverLevel.updateLagCompensationTick(); // Paper - lag compensation
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
+ serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables
+ profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
+ profilerFiller.push("tick");
+
+ serverLevelTickingSemaphore.acquire();
+ tasks.add(
+ serverLevel.tickExecutor.submit(() -> {
+ try {
+ ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread currentThread = (ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread) Thread.currentThread();
+ currentThread.currentlyTickingServerLevel = serverLevel;
+
+ serverLevel.tick(hasTimeLeft);
+ } catch (Throwable throwable) {
+ CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
+
+ serverLevel.fillReportDetails(crashreport);
+ throw new ReportedException(crashreport);
+ } finally {
+ serverLevelTickingSemaphore.release();
+ }
+ }, serverLevel)
+ );
+
+ profilerFiller.pop();
profilerFiller.pop();
+ serverLevel.explosionDensityCache.clear(); // Paper - Optimize explosions
}
- // CraftBukkit end */
- profilerFiller.push("tick");
-
- try {
- serverLevel.tick(hasTimeLeft);
- } catch (Throwable var7) {
- CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
- serverLevel.fillReportDetails(crashReport);
- throw new ReportedException(crashReport);
+ while (!tasks.isEmpty()) {
+ tasks.pop().get();
}
-
- profilerFiller.pop();
- profilerFiller.pop();
- serverLevel.explosionDensityCache.clear(); // Paper - Optimize explosions
+ } catch (java.lang.InterruptedException | java.util.concurrent.ExecutionException e) {
+ throw new RuntimeException(e); // Propagate exception
}
+ // DivineMC end - parallel world ticking
this.isIteratingOverLevels = false; // Paper - Throw exception on world create while being ticked
profilerFiller.popPush("connection");
@@ -1876,6 +1891,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
Map<ResourceKey<Level>, ServerLevel> oldLevels = this.levels;
Map<ResourceKey<Level>, ServerLevel> newLevels = Maps.newLinkedHashMap(oldLevels);
newLevels.remove(level.dimension());
+ level.tickExecutor.shutdown(); // DivineMC - parallel world ticking
this.levels = Collections.unmodifiableMap(newLevels);
}
// CraftBukkit end
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
index 959d87f4cd1efe8cf591e98c7d32728067f7117c..697f690305db56ae5a05483aae37994d4e8f9f83 100644
--- a/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
@@ -234,6 +234,10 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
+ // DivineMC start - parallel world ticking
+ serverLevelTickingSemaphore = new java.util.concurrent.Semaphore(org.bxteam.divinemc.DivineConfig.parallelThreadCount);
+ DedicatedServer.LOGGER.info("Using " + serverLevelTickingSemaphore.availablePermits() + " permits for parallel world ticking");
+ // DivineMC end - parallel world ticking
/*// Purpur start - Purpur config files // Purpur - Configurable void damage height and damage
try {
org.purpurmc.purpur.PurpurConfig.init((java.io.File) options.valueOf("purpur-settings"));
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 5d2483b2d59ae246b822d73b9996c2aa86623ab1..92f3e5d929997a974c367ec3ce02cda4acdb5183 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -184,7 +184,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final MinecraftServer server;
public final net.minecraft.world.level.storage.PrimaryLevelData serverLevelData; // CraftBukkit - type
private int lastSpawnChunkRadius;
- final EntityTickList entityTickList = new EntityTickList();
+ final EntityTickList entityTickList = new EntityTickList(this); // DivineMC - parallel world ticking
// Paper - rewrite chunk system
private final GameEventDispatcher gameEventDispatcher;
public boolean noSave;
@@ -210,6 +210,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private double preciseTime; // Purpur - Configurable daylight cycle
private boolean forceTime; // Purpur - Configurable daylight cycle
private final RandomSequences randomSequences;
+ public java.util.concurrent.ExecutorService tickExecutor; // DivineMC - parallel world ticking
// CraftBukkit start
public final LevelStorageSource.LevelStorageAccess levelStorageAccess;
@@ -702,6 +703,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler);
// Paper end - rewrite chunk system
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
+ 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
}
@@ -1292,7 +1294,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
// Paper start - rewrite chunk system
if ((++this.tickedBlocksOrFluids & 7L) != 0L) {
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks();
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); // DivineMC - remove
}
// Paper end - rewrite chunk system
@@ -1305,7 +1307,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
// Paper start - rewrite chunk system
if ((++this.tickedBlocksOrFluids & 7L) != 0L) {
- ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks();
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer)this.server).moonrise$executeMidTickTasks(); // DivineMC - remove
}
// Paper end - rewrite chunk system
@@ -1565,6 +1567,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
private void addPlayer(ServerPlayer player) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot add player off-main"); // DivineMC - parallel world ticking (additional concurrency issues logs)
Entity entity = this.getEntities().get(player.getUUID());
if (entity != null) {
LOGGER.warn("Force-added player with duplicate UUID {}", player.getUUID());
@@ -1577,7 +1580,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// CraftBukkit start
private boolean addEntity(Entity entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
- org.spigotmc.AsyncCatcher.catchOp("entity add"); // Spigot
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this, "Cannot add entity off-main"); // DivineMC - parallel world ticking (additional concurrency issues logs)
entity.generation = false; // Paper - Don't fire sync event during generation; Reset flag if it was added during a ServerLevel generation process
// Paper start - extra debug info
if (entity.valid) {
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
index 515b2178e71a3723eace26c89032e45678145224..a33071d4b9b5ab75bcef93411e67d4f7c47d5c62 100644
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -428,6 +428,8 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
// Paper end - rewrite chunk system
+ public boolean hasTickedAtLeastOnceInNewWorld = false; // DivineMC - parallel world ticking
+
public ServerPlayer(MinecraftServer server, ServerLevel level, GameProfile gameProfile, ClientInformation clientInformation) {
super(level, level.getSharedSpawnPos(), level.getSharedSpawnAngle(), gameProfile);
this.textFilter = server.createTextFilterForPlayer(this);
@@ -803,6 +805,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
@Override
public void tick() {
+ hasTickedAtLeastOnceInNewWorld = true; // DivineMC - parallel world ticking
// CraftBukkit start
if (this.joining) {
this.joining = false;
@@ -1448,6 +1451,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
return this;
} else {
// CraftBukkit start
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot change dimension of a player off-main, from world " + serverLevel().getWorld().getName() + " to world " + level.getWorld().getName()); // DivineMC - parallel world ticking (additional concurrency issues logs)
/*
this.isChangingDimension = true;
LevelData levelData = level.getLevelData();
@@ -1815,6 +1819,12 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
return OptionalInt.empty();
} else {
// CraftBukkit start
+ // DivineMC start - parallel world ticking
+ if (!hasTickedAtLeastOnceInNewWorld) {
+ MinecraftServer.LOGGER.warn("Ignoring request to open container " + abstractContainerMenu + " because we haven't ticked in the current world yet!", new Throwable());
+ return OptionalInt.empty();
+ }
+ // DivineMC end - parallel world ticking
this.containerMenu = abstractContainerMenu; // Moved up
if (!this.isImmobile())
this.connection
@@ -1879,6 +1889,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
}
@Override
public void closeContainer(org.bukkit.event.inventory.InventoryCloseEvent.Reason reason) {
+ // DivineMC start - parallel world ticking (debugging)
+ if (org.bxteam.divinemc.DivineConfig.logContainerCreationStacktraces) {
+ MinecraftServer.LOGGER.warn("Closing " + this.getBukkitEntity().getName() + " inventory that was created at", this.containerMenu.containerCreationStacktrace);
+ }
+ // DivineMC end - parallel world ticking (debugging)
org.bukkit.craftbukkit.event.CraftEventFactory.handleInventoryCloseEvent(this, reason); // CraftBukkit
// Paper end - Inventory close reason
this.connection.send(new ClientboundContainerClosePacket(this.containerMenu.containerId));
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index cfd3698dc575669456136da9cbbb100fd557e5ac..aabce23007006fe2dca1e4ac7c0657d2a1cae30e 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -572,7 +572,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
@@ -602,7 +602,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));
}
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
index e8ff6e79ce7ba0ec8b2a90bcb81283f52106c535..6b23cf5122fe65b2ad253ed8536658441297e953 100644
--- a/net/minecraft/server/players/PlayerList.java
+++ b/net/minecraft/server/players/PlayerList.java
@@ -150,6 +150,7 @@ public abstract class PlayerList {
abstract public void loadAndSaveFiles(); // Paper - fix converting txt to json file; moved from DedicatedPlayerList constructor
public void placeNewPlayer(Connection connection, ServerPlayer player, CommonListenerCookie cookie) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot place new player off-main"); // DivineMC - parallel world ticking
player.isRealPlayer = true; // Paper
player.loginTime = System.currentTimeMillis(); // Paper - Replace OfflinePlayer#getLastPlayed
GameProfile gameProfile = player.getGameProfile();
@@ -716,6 +717,13 @@ public abstract class PlayerList {
return this.respawn(player, keepInventory, reason, eventReason, null);
}
public ServerPlayer respawn(ServerPlayer player, boolean keepInventory, Entity.RemovalReason reason, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason eventReason, org.bukkit.Location location) {
+ // DivineMC start - parallel world ticking (additional concurrency issues logs)
+ System.out.println("respawning player - current player container is " + player.containerMenu + " but their inventory is " + player.inventoryMenu);
+ if (location != null) // TODO: Is this really never null, or is IntelliJ IDEA tripping? Because I'm pretty sure that this can be null and there isn't any @NotNull annotations
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, from world " + player.serverLevel().getWorld().getName() + " to world " + location.getWorld().getName());
+ else
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureOnlyTickThread("Cannot respawn player off-main, respawning in world " + player.serverLevel().getWorld().getName());
+ // DivineMC end - parallel world ticking (additional concurrency issues logs)
player.stopRiding(); // CraftBukkit
this.players.remove(player);
this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot
@@ -726,6 +734,7 @@ public abstract class PlayerList {
ServerPlayer serverPlayer = player;
Level fromWorld = player.level();
player.wonGame = false;
+ serverPlayer.hasTickedAtLeastOnceInNewWorld = false; // DivineMC - parallel world ticking
// CraftBukkit end
serverPlayer.connection = player.connection;
serverPlayer.restoreFrom(player, keepInventory);
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
index 80f2d38449f1db1d9b6926e4552d3061cb88b4af..356a1bfc610214912f58c4126cdd5694ffecfcb8 100644
--- a/net/minecraft/world/entity/Entity.java
+++ b/net/minecraft/world/entity/Entity.java
@@ -850,7 +850,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
// CraftBukkit start
public void postTick() {
// No clean way to break out of ticking once the entity has been copied to a new world, so instead we move the portalling later in the tick cycle
- if (!(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities
+ if (false && !(this instanceof ServerPlayer) && this.isAlive()) { // Paper - don't attempt to teleport dead entities // DivineMC - parallel world ticking
this.handlePortal();
}
}
@@ -3870,6 +3870,7 @@ public abstract class Entity implements SyncedDataHolder, Nameable, EntityAccess
}
private Entity teleportCrossDimension(ServerLevel level, TeleportTransition teleportTransition) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(level, "Cannot teleport entity to another world off-main, from world " + this.level.getWorld().getName() + " to world " + level.getWorld().getName()); // DivineMC - parallel world ticking
List<Entity> passengers = this.getPassengers();
List<Entity> list = new ArrayList<>(passengers.size());
this.ejectPassengers();
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
index 3dcd8df0b395a8fed8bc0cbe0ff78f4ae0056fd3..228c63bf506548666ce87fae694e2270c97c6770 100644
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -93,7 +93,14 @@ public abstract class AbstractContainerMenu {
public void startOpen() {}
// CraftBukkit end
+ public Throwable containerCreationStacktrace; // DivineMC - parallel world ticking
+
protected AbstractContainerMenu(@Nullable MenuType<?> menuType, int containerId) {
+ // DivineMC start - parallel world ticking (debugging)
+ if (org.bxteam.divinemc.DivineConfig.logContainerCreationStacktraces) {
+ this.containerCreationStacktrace = new Throwable();
+ }
+ // DivineMC start - parallel world ticking (debugging)
this.menuType = menuType;
this.containerId = containerId;
}
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index 264b713e8b7c3d5f7d8e1facc90a60349f2cf414..f461b060e03edf4102290a424ab008b88d80bdc2 100644
--- a/net/minecraft/world/item/ItemStack.java
+++ b/net/minecraft/world/item/ItemStack.java
@@ -407,8 +407,8 @@ public final class ItemStack implements DataComponentHolder {
if (interactionResult.consumesAction() && serverLevel.captureTreeGeneration && !serverLevel.capturedBlockStates.isEmpty()) {
serverLevel.captureTreeGeneration = false;
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(clickedPos, serverLevel.getWorld());
- org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeType;
- net.minecraft.world.level.block.SaplingBlock.treeType = null;
+ org.bukkit.TreeType treeType = net.minecraft.world.level.block.SaplingBlock.treeTypeRT.get(); // DivineMC - parallel world ticking
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(null); // DivineMC - parallel world ticking
List<org.bukkit.craftbukkit.block.CraftBlockState> blocks = new java.util.ArrayList<>(serverLevel.capturedBlockStates.values());
serverLevel.capturedBlockStates.clear();
org.bukkit.event.world.StructureGrowEvent structureEvent = null;
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 3856bbe579ef6df2f220c46bc69461cab026a131..8f37c27bba829733fb8db5f35470092a76c83e98 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -172,6 +172,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 io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo((net.minecraft.world.level.block.RedStoneWireBlock) net.minecraft.world.level.block.Blocks.REDSTONE_WIRE); // DivineMC - parallel world ticking (moved to world)
public static BlockPos lastPhysicsProblem; // Spigot
private org.spigotmc.TickLimiter entityLimiter;
private org.spigotmc.TickLimiter tileLimiter;
@@ -1146,6 +1147,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@Override
public boolean setBlock(BlockPos pos, BlockState state, int flags, int recursionLeft) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, pos, "Updating block asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
// CraftBukkit start - tree generation
if (this.captureTreeGeneration) {
// Paper start - Protect Bedrock and End Portal/Frames from being destroyed
@@ -1530,7 +1532,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
tickingBlockEntity.tick();
// Paper start - rewrite chunk system
if ((++tickedEntities & 7) == 0) {
- ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
+ // ((ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
}
// Paper end - rewrite chunk system
}
@@ -1553,7 +1555,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DISCARD);
// Paper end - Prevent block entity and entity crashes
}
- this.moonrise$midTickTasks(); // Paper - rewrite chunk system
+ // this.moonrise$midTickTasks(); // Paper - rewrite chunk system
}
// Paper start - Option to prevent armor stands from doing entity lookups
@@ -1696,6 +1698,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@Nullable
public BlockEntity getBlockEntity(BlockPos pos, boolean validate) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThreadOrAsyncThread((ServerLevel) this, "Cannot read world asynchronously"); // DivineMC - parallel world ticking
// Paper start - Perf: Optimize capturedTileEntities lookup
net.minecraft.world.level.block.entity.BlockEntity blockEntity;
if (!this.capturedTileEntities.isEmpty() && (blockEntity = this.capturedTileEntities.get(pos)) != null) {
@@ -1713,6 +1716,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
public void setBlockEntity(BlockEntity blockEntity) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel) this, "Cannot modify world asynchronously"); // DivineMC - parallel world ticking
BlockPos blockPos = blockEntity.getBlockPos();
if (!this.isOutsideBuildHeight(blockPos)) {
// CraftBukkit start
@@ -1797,6 +1801,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@Override
public List<Entity> getEntities(@Nullable Entity entity, AABB boundingBox, Predicate<? super Entity> predicate) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread((ServerLevel)this, boundingBox, "Cannot getEntities asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
Profiler.get().incrementCounter("getEntities");
List<Entity> list = Lists.newArrayList();
@@ -2109,8 +2114,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
public abstract RecipeAccess recipeAccess();
public BlockPos getBlockRandomPos(int x, int y, int z, int yMask) {
- this.randValue = this.randValue * 3 + 1013904223;
- int i = this.randValue >> 2;
+ int i = this.random.nextInt() >> 2; // DivineMC - parallel world ticking
return new BlockPos(x + (i & 15), y + (i >> 16 & yMask), z + (i >> 8 & 15));
}
diff --git a/net/minecraft/world/level/block/DispenserBlock.java b/net/minecraft/world/level/block/DispenserBlock.java
index e0a4d41e5bcf144ea4c10d6f633c3a95ed2c5aec..274f36581e7040c67bf8649258660228a3e8cce0 100644
--- a/net/minecraft/world/level/block/DispenserBlock.java
+++ b/net/minecraft/world/level/block/DispenserBlock.java
@@ -50,7 +50,7 @@ public class DispenserBlock extends BaseEntityBlock {
private static final DefaultDispenseItemBehavior DEFAULT_BEHAVIOR = new DefaultDispenseItemBehavior();
public static final Map<Item, DispenseItemBehavior> DISPENSER_REGISTRY = new IdentityHashMap<>();
private static final int TRIGGER_DURATION = 4;
- public static boolean eventFired = false; // CraftBukkit
+ public static ThreadLocal<Boolean> eventFired = ThreadLocal.withInitial(() -> Boolean.FALSE); // DivineMC - parallel world ticking
@Override
public MapCodec<? extends DispenserBlock> codec() {
@@ -96,7 +96,7 @@ public class DispenserBlock extends BaseEntityBlock {
DispenseItemBehavior dispenseMethod = this.getDispenseMethod(level, item);
if (dispenseMethod != DispenseItemBehavior.NOOP) {
if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockPreDispenseEvent(level, pos, item, randomSlot)) return; // Paper - Add BlockPreDispenseEvent
- DispenserBlock.eventFired = false; // CraftBukkit - reset event status
+ DispenserBlock.eventFired.set(Boolean.FALSE); // CraftBukkit - reset event status // DivineMC - parallel world ticking
dispenserBlockEntity.setItem(randomSlot, dispenseMethod.dispense(blockSource, item));
}
}
diff --git a/net/minecraft/world/level/block/FungusBlock.java b/net/minecraft/world/level/block/FungusBlock.java
index 85f0eac75784565c658c5178c544f969db3d6f54..22c527a7b44a434b66a2217ed88eca79703b2036 100644
--- a/net/minecraft/world/level/block/FungusBlock.java
+++ b/net/minecraft/world/level/block/FungusBlock.java
@@ -76,9 +76,9 @@ public class FungusBlock extends BushBlock implements BonemealableBlock {
// CraftBukkit start
.map((value) -> {
if (this == Blocks.WARPED_FUNGUS) {
- SaplingBlock.treeType = org.bukkit.TreeType.WARPED_FUNGUS;
+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.WARPED_FUNGUS); // DivineMC - parallel world ticking
} else if (this == Blocks.CRIMSON_FUNGUS) {
- SaplingBlock.treeType = org.bukkit.TreeType.CRIMSON_FUNGUS;
+ SaplingBlock.treeTypeRT.set(org.bukkit.TreeType.CRIMSON_FUNGUS); // DivineMC - parallel world ticking
}
return value;
})
diff --git a/net/minecraft/world/level/block/MushroomBlock.java b/net/minecraft/world/level/block/MushroomBlock.java
index 904369f4d7db41026183f2de7c96c2f0f4dc204d..1a3f07834fd1483aa77f7733512908b62583edda 100644
--- a/net/minecraft/world/level/block/MushroomBlock.java
+++ b/net/minecraft/world/level/block/MushroomBlock.java
@@ -94,7 +94,7 @@ public class MushroomBlock extends BushBlock implements BonemealableBlock {
return false;
} else {
level.removeBlock(pos, false);
- SaplingBlock.treeType = (this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM; // CraftBukkit
+ SaplingBlock.treeTypeRT.set((this == Blocks.BROWN_MUSHROOM) ? org.bukkit.TreeType.BROWN_MUSHROOM : org.bukkit.TreeType.RED_MUSHROOM); // CraftBukkit // DivineMC - parallel world ticking
if (optional.get().value().place(level, level.getChunkSource().getGenerator(), random, pos)) {
return true;
} else {
diff --git a/net/minecraft/world/level/block/RedStoneWireBlock.java b/net/minecraft/world/level/block/RedStoneWireBlock.java
index 12c9d60314c99fb65e640d255a2d0c6b7790ad4d..0f56ea9dd444148b134a3d97f0b7c4563df73e39 100644
--- a/net/minecraft/world/level/block/RedStoneWireBlock.java
+++ b/net/minecraft/world/level/block/RedStoneWireBlock.java
@@ -292,7 +292,7 @@ public class RedStoneWireBlock extends Block {
// Paper start - Optimize redstone (Eigencraft)
// The bulk of the new functionality is found in RedstoneWireTurbo.java
- io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this);
+ // io.papermc.paper.redstone.RedstoneWireTurbo turbo = new io.papermc.paper.redstone.RedstoneWireTurbo(this);
/*
* Modified version of pre-existing updateSurroundingRedstone, which is called from
@@ -308,7 +308,7 @@ public class RedStoneWireBlock extends Block {
if (orientation != null) {
source = pos.relative(orientation.getFront().getOpposite());
}
- turbo.updateSurroundingRedstone(worldIn, pos, state, source);
+ worldIn.turbo.updateSurroundingRedstone(worldIn, pos, state, source); // DivineMC - parallel world ticking
return;
}
updatePowerStrength(worldIn, pos, state, orientation, blockAdded);
@@ -336,7 +336,7 @@ public class RedStoneWireBlock extends Block {
// [Space Walker] suppress shape updates and emit those manually to
// bypass the new neighbor update stack.
if (level.setBlock(pos, state, Block.UPDATE_KNOWN_SHAPE | Block.UPDATE_CLIENTS)) {
- turbo.updateNeighborShapes(level, pos, state);
+ level.turbo.updateNeighborShapes(level, pos, state); // DivineMC - parallel world ticking
}
}
}
diff --git a/net/minecraft/world/level/block/SaplingBlock.java b/net/minecraft/world/level/block/SaplingBlock.java
index e014f052e9b0f5ca6b28044e2389782b7d0e0cb8..d10f8909fcfa930c726f2620e3ffc912baa40be7 100644
--- a/net/minecraft/world/level/block/SaplingBlock.java
+++ b/net/minecraft/world/level/block/SaplingBlock.java
@@ -26,7 +26,7 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock {
protected static final float AABB_OFFSET = 6.0F;
protected static final VoxelShape SHAPE = Block.box(2.0, 0.0, 2.0, 14.0, 12.0, 14.0);
protected final TreeGrower treeGrower;
- public static org.bukkit.TreeType treeType; // CraftBukkit
+ public static final ThreadLocal<org.bukkit.TreeType> treeTypeRT = new ThreadLocal<>(); // CraftBukkit // DivineMC - parallel world ticking (from Folia)
@Override
public MapCodec<? extends SaplingBlock> codec() {
@@ -63,8 +63,10 @@ public class SaplingBlock extends BushBlock implements BonemealableBlock {
this.treeGrower.growTree(level, level.getChunkSource().getGenerator(), pos, state, random);
level.captureTreeGeneration = false;
if (!level.capturedBlockStates.isEmpty()) {
- org.bukkit.TreeType treeType = SaplingBlock.treeType;
- SaplingBlock.treeType = null;
+ // DivineMC start - parallel world ticking
+ org.bukkit.TreeType treeType = SaplingBlock.treeTypeRT.get();
+ SaplingBlock.treeTypeRT.set(null);
+ // DivineMC end - parallel world ticking
org.bukkit.Location location = org.bukkit.craftbukkit.util.CraftLocation.toBukkit(pos, level.getWorld());
java.util.List<org.bukkit.block.BlockState> blocks = new java.util.ArrayList<>(level.capturedBlockStates.values());
level.capturedBlockStates.clear();
diff --git a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
index 26db603ed681a6c302596627d4dd5bf8a9bafc4e..3b56375f705a0d65901f702e53e1fc609eeaf1a6 100644
--- a/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/BaseContainerBlockEntity.java
@@ -77,6 +77,12 @@ public abstract class BaseContainerBlockEntity extends BlockEntity implements Co
return canUnlock(player, code, displayName, null);
}
public static boolean canUnlock(Player player, LockCode code, Component displayName, @Nullable BlockEntity blockEntity) {
+ // DivineMC start - parallel world ticking
+ if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != serverPlayer.serverLevel()) {
+ net.minecraft.server.MinecraftServer.LOGGER.warn("Player " + serverPlayer.getScoreboardName() + " (" + serverPlayer.getStringUUID() + ") attempted to open a BlockEntity @ " + blockEntity.getLevel().getWorld().getName() + " " + blockEntity.getBlockPos().getX() + ", " + blockEntity.getBlockPos().getY() + ", " + blockEntity.getBlockPos().getZ() + " while they were in a different world " + serverPlayer.level().getWorld().getName() + " than the block themselves!");
+ return false;
+ }
+ // DivineMC end - parallel world ticking
if (player instanceof net.minecraft.server.level.ServerPlayer serverPlayer && blockEntity != null && blockEntity.getLevel() != null && blockEntity.getLevel().getBlockEntity(blockEntity.getBlockPos()) == blockEntity) {
final org.bukkit.block.Block block = org.bukkit.craftbukkit.block.CraftBlock.at(blockEntity.getLevel(), blockEntity.getBlockPos());
net.kyori.adventure.text.Component lockedMessage = net.kyori.adventure.text.Component.translatable("container.isLocked", io.papermc.paper.adventure.PaperAdventure.asAdventure(displayName));
diff --git a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
index 1638eccef431fb68775af624110f1968f0c6dabd..8f3eb265adcacf6d4f71db9a298ba8a7ce99c941 100644
--- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java
@@ -43,9 +43,9 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi
// Paper end - Fix NPE in SculkBloomEvent world access
public static void serverTick(Level level, BlockPos pos, BlockState state, SculkCatalystBlockEntity sculkCatalyst) {
- org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = sculkCatalyst.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverrideRT.set(pos); // DivineMC - parallel world ticking // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
sculkCatalyst.catalystListener.getSculkSpreader().updateCursors(level, pos, level.getRandom(), true);
- org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = null; // CraftBukkit
+ org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverrideRT.set(null); // DivineMC - parallel world ticking // CraftBukkit
}
@Override
diff --git a/net/minecraft/world/level/block/grower/TreeGrower.java b/net/minecraft/world/level/block/grower/TreeGrower.java
index cf7311c507de09a8f89934e430b2201e8bdffe51..30bd72ad2f66616a89b78fb0677109b8341eb132 100644
--- a/net/minecraft/world/level/block/grower/TreeGrower.java
+++ b/net/minecraft/world/level/block/grower/TreeGrower.java
@@ -204,55 +204,59 @@ public final class TreeGrower {
// CraftBukkit start
private void setTreeType(Holder<ConfiguredFeature<?, ?>> holder) {
ResourceKey<ConfiguredFeature<?, ?>> treeFeature = holder.unwrapKey().get();
+ // DivineMC start - parallel world ticking
+ org.bukkit.TreeType treeType;
if (treeFeature == TreeFeatures.OAK || treeFeature == TreeFeatures.OAK_BEES_005) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TREE;
+ treeType = org.bukkit.TreeType.TREE;
} else if (treeFeature == TreeFeatures.HUGE_RED_MUSHROOM) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.RED_MUSHROOM;
+ treeType = org.bukkit.TreeType.RED_MUSHROOM;
} else if (treeFeature == TreeFeatures.HUGE_BROWN_MUSHROOM) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BROWN_MUSHROOM;
+ treeType = org.bukkit.TreeType.BROWN_MUSHROOM;
} else if (treeFeature == TreeFeatures.JUNGLE_TREE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.COCOA_TREE;
+ treeType = org.bukkit.TreeType.COCOA_TREE;
} else if (treeFeature == TreeFeatures.JUNGLE_TREE_NO_VINE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.SMALL_JUNGLE;
+ treeType = org.bukkit.TreeType.SMALL_JUNGLE;
} else if (treeFeature == TreeFeatures.PINE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_REDWOOD;
+ treeType = org.bukkit.TreeType.TALL_REDWOOD;
} else if (treeFeature == TreeFeatures.SPRUCE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.REDWOOD;
+ treeType = org.bukkit.TreeType.REDWOOD;
} else if (treeFeature == TreeFeatures.ACACIA) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.ACACIA;
+ treeType = org.bukkit.TreeType.ACACIA;
} else if (treeFeature == TreeFeatures.BIRCH || treeFeature == TreeFeatures.BIRCH_BEES_005) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BIRCH;
+ treeType = org.bukkit.TreeType.BIRCH;
} else if (treeFeature == TreeFeatures.SUPER_BIRCH_BEES_0002) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_BIRCH;
+ treeType = org.bukkit.TreeType.TALL_BIRCH;
} else if (treeFeature == TreeFeatures.SWAMP_OAK) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.SWAMP;
+ treeType = org.bukkit.TreeType.SWAMP;
} else if (treeFeature == TreeFeatures.FANCY_OAK || treeFeature == TreeFeatures.FANCY_OAK_BEES_005) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.BIG_TREE;
+ treeType = org.bukkit.TreeType.BIG_TREE;
} else if (treeFeature == TreeFeatures.JUNGLE_BUSH) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE_BUSH;
+ treeType = org.bukkit.TreeType.JUNGLE_BUSH;
} else if (treeFeature == TreeFeatures.DARK_OAK) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.DARK_OAK;
+ treeType = org.bukkit.TreeType.DARK_OAK;
} else if (treeFeature == TreeFeatures.MEGA_SPRUCE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_REDWOOD;
+ treeType = org.bukkit.TreeType.MEGA_REDWOOD;
} else if (treeFeature == TreeFeatures.MEGA_PINE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MEGA_PINE;
+ treeType = org.bukkit.TreeType.MEGA_PINE;
} else if (treeFeature == TreeFeatures.MEGA_JUNGLE_TREE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.JUNGLE;
+ treeType = org.bukkit.TreeType.JUNGLE;
} else if (treeFeature == TreeFeatures.AZALEA_TREE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.AZALEA;
+ treeType = org.bukkit.TreeType.AZALEA;
} else if (treeFeature == TreeFeatures.MANGROVE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.MANGROVE;
+ treeType = org.bukkit.TreeType.MANGROVE;
} else if (treeFeature == TreeFeatures.TALL_MANGROVE) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.TALL_MANGROVE;
+ treeType = org.bukkit.TreeType.TALL_MANGROVE;
} else if (treeFeature == TreeFeatures.CHERRY || treeFeature == TreeFeatures.CHERRY_BEES_005) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.CHERRY;
+ treeType = org.bukkit.TreeType.CHERRY;
} else if (treeFeature == TreeFeatures.PALE_OAK || treeFeature == TreeFeatures.PALE_OAK_BONEMEAL) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.PALE_OAK;
+ treeType = org.bukkit.TreeType.PALE_OAK;
} else if (treeFeature == TreeFeatures.PALE_OAK_CREAKING) {
- net.minecraft.world.level.block.SaplingBlock.treeType = org.bukkit.TreeType.PALE_OAK_CREAKING;
+ treeType = org.bukkit.TreeType.PALE_OAK_CREAKING;
} else {
throw new IllegalArgumentException("Unknown tree generator " + treeFeature);
}
+ net.minecraft.world.level.block.SaplingBlock.treeTypeRT.set(treeType);
+ // DivineMC end - parallel world ticking
}
// CraftBukkit end
}
diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java
index 5652ed5fb03a4a1a94c348109cb499196f909712..6167f72d1e374a7093f9880ab50e27eda603a680 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -367,6 +367,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
@Nullable
public BlockState setBlockState(BlockPos pos, BlockState state, boolean isMoving, boolean doPlace) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.level, pos, "Updating block asynchronously"); // DivineMC - parallel world ticking
// CraftBukkit end
int y = pos.getY();
LevelChunkSection section = this.getSection(this.getSectionIndex(y));
diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java
index 423779a2b690f387a4f0bd07b97b50e0baefda76..f43f318577efff0c920029d467a54608614f410c 100644
--- a/net/minecraft/world/level/entity/EntityTickList.java
+++ b/net/minecraft/world/level/entity/EntityTickList.java
@@ -11,16 +11,27 @@ import net.minecraft.world.entity.Entity;
public class EntityTickList {
private final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
+ // DivineMC start - parallel world ticking
+ // Used to track async entity additions/removals/loops
+ private final net.minecraft.server.level.ServerLevel serverLevel;
+
+ public EntityTickList(net.minecraft.server.level.ServerLevel serverLevel) {
+ this.serverLevel = serverLevel;
+ }
+ // DivineMC end - parallel world ticking
+
private void ensureActiveIsNotIterated() {
// Paper - rewrite chunk system
}
public void add(Entity entity) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(entity, "Asynchronous entity ticklist addition"); // Paper // DivineMC - parallel world ticking
this.ensureActiveIsNotIterated();
this.entities.add(entity); // Paper - rewrite chunk system
}
public void remove(Entity entity) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(entity, "Asynchronous entity ticklist removal"); // Paper // DivineMC - parallel world ticking
this.ensureActiveIsNotIterated();
this.entities.remove(entity); // Paper - rewrite chunk system
}
@@ -30,6 +41,7 @@ public class EntityTickList {
}
public void forEach(Consumer<Entity> entity) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverLevel, "Asynchronous entity ticklist iteration"); // DivineMC - parallel world ticking
// 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)
diff --git a/net/minecraft/world/level/saveddata/maps/MapIndex.java b/net/minecraft/world/level/saveddata/maps/MapIndex.java
index ffe604f8397a002800e6ecc2f878d0f6f1c98703..8f6436d2e87e7e11d98dcf20f4a62a4b3c7f6d92 100644
--- a/net/minecraft/world/level/saveddata/maps/MapIndex.java
+++ b/net/minecraft/world/level/saveddata/maps/MapIndex.java
@@ -34,17 +34,24 @@ public class MapIndex extends SavedData {
@Override
public CompoundTag save(CompoundTag tag, HolderLookup.Provider registries) {
- for (Entry<String> entry : this.usedAuxIds.object2IntEntrySet()) {
- tag.putInt(entry.getKey(), entry.getIntValue());
+ // DivineMC start - make map data thread-safe
+ synchronized (this.usedAuxIds) {
+ for (Entry<String> entry : this.usedAuxIds.object2IntEntrySet()) {
+ tag.putInt(entry.getKey(), entry.getIntValue());
+ }
}
-
+ // DivineMC end - make map data thread-safe
return tag;
}
public MapId getFreeAuxValueForMap() {
- int i = this.usedAuxIds.getInt("map") + 1;
- this.usedAuxIds.put("map", i);
- this.setDirty();
- return new MapId(i);
+ // DivineMC start - make map data thread-safe
+ synchronized (this.usedAuxIds) {
+ int i = this.usedAuxIds.getInt("map") + 1;
+ this.usedAuxIds.put("map", i);
+ this.setDirty();
+ return new MapId(i);
+ }
+ // DivineMC end - make map data thread-safe
}
}

View File

@@ -0,0 +1,401 @@
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] C2ME: opts_native_math
diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java
index 73962e79a0f3d892e3155443a1b84508b0f4042e..1d7c8c2196afb8515802734ad756abec1d5ceaf2 100644
--- a/net/minecraft/world/level/biome/BiomeManager.java
+++ b/net/minecraft/world/level/biome/BiomeManager.java
@@ -29,39 +29,64 @@ public class BiomeManager {
}
public Holder<Biome> getBiome(BlockPos pos) {
- int i = pos.getX() - 2;
- int i1 = pos.getY() - 2;
- int i2 = pos.getZ() - 2;
- int i3 = i >> 2;
- int i4 = i1 >> 2;
- int i5 = i2 >> 2;
- double d = (i & 3) / 4.0;
- double d1 = (i1 & 3) / 4.0;
- double d2 = (i2 & 3) / 4.0;
- int i6 = 0;
- double d3 = Double.POSITIVE_INFINITY;
+ // DivineMC start - C2ME: opts_native_math
+ if (org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ int mask = org.bxteam.divinemc.math.Bindings.c2me_natives_biome_access_sample(this.biomeZoomSeed, pos.getX(), pos.getY(), pos.getZ());
- for (int i7 = 0; i7 < 8; i7++) {
- boolean flag = (i7 & 4) == 0;
- boolean flag1 = (i7 & 2) == 0;
- boolean flag2 = (i7 & 1) == 0;
- int i8 = flag ? i3 : i3 + 1;
- int i9 = flag1 ? i4 : i4 + 1;
- int i10 = flag2 ? i5 : i5 + 1;
- double d4 = flag ? d : d - 1.0;
- double d5 = flag1 ? d1 : d1 - 1.0;
- double d6 = flag2 ? d2 : d2 - 1.0;
- double fiddledDistance = getFiddledDistance(this.biomeZoomSeed, i8, i9, i10, d4, d5, d6);
- if (d3 > fiddledDistance) {
- i6 = i7;
- d3 = fiddledDistance;
+ return this.noiseBiomeSource.getNoiseBiome(
+ ((pos.getX() - 2) >> 2) + ((mask & 4) != 0 ? 1 : 0),
+ ((pos.getY() - 2) >> 2) + ((mask & 2) != 0 ? 1 : 0),
+ ((pos.getZ() - 2) >> 2) + ((mask & 1) != 0 ? 1 : 0)
+ );
+ } else {
+ final int var0 = pos.getX() - 2;
+ final int var1 = pos.getY() - 2;
+ final int var2 = pos.getZ() - 2;
+ final int var3 = var0 >> 2;
+ final int var4 = var1 >> 2;
+ final int var5 = var2 >> 2;
+ final double var6 = (double) (var0 & 3) / 4.0;
+ final double var7 = (double) (var1 & 3) / 4.0;
+ final double var8 = (double) (var2 & 3) / 4.0;
+ int var9 = 0;
+ double var10 = Double.POSITIVE_INFINITY;
+ for (int var11 = 0; var11 < 8; ++var11) {
+ boolean var12 = (var11 & 4) == 0;
+ boolean var13 = (var11 & 2) == 0;
+ boolean var14 = (var11 & 1) == 0;
+ long var15 = var12 ? var3 : var3 + 1;
+ long var16 = var13 ? var4 : var4 + 1;
+ long var17 = var14 ? var5 : var5 + 1;
+ double var18 = var12 ? var6 : var6 - 1.0;
+ double var19 = var13 ? var7 : var7 - 1.0;
+ double var20 = var14 ? var8 : var8 - 1.0;
+ long var21 = this.biomeZoomSeed * (this.biomeZoomSeed * 6364136223846793005L + 1442695040888963407L) + var15;
+ var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var16;
+ var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var17;
+ var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var15;
+ var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var16;
+ var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var17;
+ double var22 = (double) ((var21 >> 24) & 1023) / 1024.0;
+ double var23 = (var22 - 0.5) * 0.9;
+ var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + this.biomeZoomSeed;
+ double var24 = (double) ((var21 >> 24) & 1023) / 1024.0;
+ double var25 = (var24 - 0.5) * 0.9;
+ var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + this.biomeZoomSeed;
+ double var26 = (double) ((var21 >> 24) & 1023) / 1024.0;
+ double var27 = (var26 - 0.5) * 0.9;
+ double var28 = Mth.square(var20 + var27) + Mth.square(var19 + var25) + Mth.square(var18 + var23);
+ if (var10 > var28) {
+ var9 = var11;
+ var10 = var28;
+ }
}
- }
- int i7x = (i6 & 4) == 0 ? i3 : i3 + 1;
- int i11 = (i6 & 2) == 0 ? i4 : i4 + 1;
- int i12 = (i6 & 1) == 0 ? i5 : i5 + 1;
- return this.noiseBiomeSource.getNoiseBiome(i7x, i11, i12);
+ int resX = (var9 & 4) == 0 ? var3 : var3 + 1;
+ int resY = (var9 & 2) == 0 ? var4 : var4 + 1;
+ int resZ = (var9 & 1) == 0 ? var5 : var5 + 1;
+ return this.noiseBiomeSource.getNoiseBiome(resX, resY, resZ);
+ }
+ // DivineMC end - C2ME: opts_native_math
}
public Holder<Biome> getNoiseBiomeAtPosition(double x, double y, double z) {
diff --git a/net/minecraft/world/level/levelgen/DensityFunctions.java b/net/minecraft/world/level/levelgen/DensityFunctions.java
index fa08f06be03b2e6120ddc105563f68d551da741c..7178013421233d7dab36eb07a768907ce40e8745 100644
--- a/net/minecraft/world/level/levelgen/DensityFunctions.java
+++ b/net/minecraft/world/level/levelgen/DensityFunctions.java
@@ -501,6 +501,11 @@ public final class DensityFunctions {
}
protected static final class EndIslandDensityFunction implements DensityFunction.SimpleFunction {
+ // DivineMC start - C2ME: opts_native_math
+ private final java.lang.foreign.Arena c2me$arena = java.lang.foreign.Arena.ofAuto();
+ private java.lang.foreign.MemorySegment c2me$samplerData = null;
+ private long c2me$samplerDataPtr;
+ // DivineMC end - C2ME: opts_native_math
public static final KeyDispatchDataCodec<DensityFunctions.EndIslandDensityFunction> CODEC = KeyDispatchDataCodec.of(
MapCodec.unit(new DensityFunctions.EndIslandDensityFunction(0L))
);
@@ -521,6 +526,16 @@ public final class DensityFunctions {
RandomSource randomSource = new LegacyRandomSource(seed);
randomSource.consumeCount(17292);
this.islandNoise = new SimplexNoise(randomSource);
+ // DivineMC start - C2ME: opts_native_math
+ if (org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ int[] permutation = (this.islandNoise).p;
+ java.lang.foreign.MemorySegment segment = this.c2me$arena.allocate(permutation.length * 4L, 64);
+ java.lang.foreign.MemorySegment.copy(java.lang.foreign.MemorySegment.ofArray(permutation), 0L, segment, 0L, permutation.length * 4L);
+ java.lang.invoke.VarHandle.fullFence();
+ this.c2me$samplerData = segment;
+ this.c2me$samplerDataPtr = segment.address();
+ }
+ // DivineMC end - C2ME: opts_native_math
}
private static float getHeightValue(SimplexNoise noise, int x, int z) {
@@ -567,7 +582,13 @@ public final class DensityFunctions {
@Override
public double compute(DensityFunction.FunctionContext context) {
- return (getHeightValue(this.islandNoise, context.blockX() / 8, context.blockZ() / 8) - 8.0) / 128.0;
+ // DivineMC start - C2ME: opts_native_math
+ if (org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled && this.c2me$samplerDataPtr != 0L) {
+ return ((double) org.bxteam.divinemc.math.Bindings.c2me_natives_end_islands_sample(this.c2me$samplerDataPtr, context.blockX() / 8, context.blockZ() / 8) - 8.0) / 128.0;
+ } else {
+ return (getHeightValue(this.islandNoise, context.blockX() / 8, context.blockZ() / 8) - 8.0) / 128.0;
+ }
+ // DivineMC end - C2ME: opts_native_math
}
@Override
@@ -814,10 +835,42 @@ public final class DensityFunctions {
return this.noise.getValue(context.blockX() * this.xzScale, context.blockY() * this.yScale, context.blockZ() * this.xzScale);
}
+ // DivineMC start - C2ME: opts_native_math
@Override
- public void fillArray(double[] array, DensityFunction.ContextProvider contextProvider) {
- contextProvider.fillAllDirectly(array, this);
+ public void fillArray(double[] densities, DensityFunction.ContextProvider applier) {
+ if (!org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ NormalNoise noise = this.noise.noise();
+ if (noise == null) {
+ Arrays.fill(densities, 0.0);
+ return;
+ }
+ long ptr = noise.c2me$getPointer();
+ if (ptr == 0L) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ double[] x = new double[densities.length];
+ double[] y = new double[densities.length];
+ double[] z = new double[densities.length];
+ for (int i = 0; i < densities.length; i++) {
+ FunctionContext pos = applier.forIndex(i);
+ x[i] = pos.blockX() * this.xzScale();
+ y[i] = pos.blockY() * this.yScale();
+ z[i] = pos.blockZ() * this.xzScale();
+ }
+ org.bxteam.divinemc.math.Bindings.c2me_natives_noise_perlin_double_batch(
+ ptr,
+ java.lang.foreign.MemorySegment.ofArray(densities),
+ java.lang.foreign.MemorySegment.ofArray(x),
+ java.lang.foreign.MemorySegment.ofArray(y),
+ java.lang.foreign.MemorySegment.ofArray(z),
+ densities.length
+ );
}
+ // DivineMC end - C2ME: opts_native_math
@Override
public DensityFunction mapAll(DensityFunction.Visitor visitor) {
@@ -938,6 +991,46 @@ public final class DensityFunctions {
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
return CODEC;
}
+
+ // DivineMC start - C2ME: opts_native_math
+ @Override
+ public void fillArray(final double[] densities, final ContextProvider applier) {
+ if (!org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ NormalNoise noise = this.offsetNoise.noise();
+ if (noise == null) {
+ Arrays.fill(densities, 0.0);
+ return;
+ }
+ long ptr = noise.c2me$getPointer();
+ if (ptr == 0L) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ double[] x = new double[densities.length];
+ double[] y = new double[densities.length];
+ double[] z = new double[densities.length];
+ for (int i = 0; i < densities.length; i++) {
+ FunctionContext pos = applier.forIndex(i);
+ x[i] = pos.blockX() * 0.25;
+ y[i] = pos.blockY() * 0.25;
+ z[i] = pos.blockZ() * 0.25;
+ }
+ org.bxteam.divinemc.math.Bindings.c2me_natives_noise_perlin_double_batch(
+ ptr,
+ java.lang.foreign.MemorySegment.ofArray(densities),
+ java.lang.foreign.MemorySegment.ofArray(x),
+ java.lang.foreign.MemorySegment.ofArray(y),
+ java.lang.foreign.MemorySegment.ofArray(z),
+ densities.length
+ );
+ for (int i = 0; i < densities.length; i++) {
+ densities[i] *= 4.0;
+ }
+ }
+ // DivineMC end - C2ME: opts_native_math
}
public record ShiftA(@Override DensityFunction.NoiseHolder offsetNoise) implements DensityFunctions.ShiftNoise {
@@ -959,6 +1052,46 @@ public final class DensityFunctions {
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
return CODEC;
}
+
+ // DivineMC start - C2ME: opts_native_math
+ @Override
+ public void fillArray(final double[] densities, final ContextProvider applier) {
+ if (!org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ NormalNoise noise = this.offsetNoise.noise();
+ if (noise == null) {
+ Arrays.fill(densities, 0.0);
+ return;
+ }
+ long ptr = noise.c2me$getPointer();
+ if (ptr == 0L) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ double[] x = new double[densities.length];
+ double[] y = new double[densities.length];
+ double[] z = new double[densities.length];
+ for (int i = 0; i < densities.length; i++) {
+ FunctionContext pos = applier.forIndex(i);
+ x[i] = pos.blockX() * 0.25;
+ y[i] = 0;
+ z[i] = pos.blockZ() * 0.25;
+ }
+ org.bxteam.divinemc.math.Bindings.c2me_natives_noise_perlin_double_batch(
+ ptr,
+ java.lang.foreign.MemorySegment.ofArray(densities),
+ java.lang.foreign.MemorySegment.ofArray(x),
+ java.lang.foreign.MemorySegment.ofArray(y),
+ java.lang.foreign.MemorySegment.ofArray(z),
+ densities.length
+ );
+ for (int i = 0; i < densities.length; i++) {
+ densities[i] *= 4.0;
+ }
+ }
+ // DivineMC end - C2ME: opts_native_math
}
public record ShiftB(@Override DensityFunction.NoiseHolder offsetNoise) implements DensityFunctions.ShiftNoise {
@@ -980,6 +1113,46 @@ public final class DensityFunctions {
public KeyDispatchDataCodec<? extends DensityFunction> codec() {
return CODEC;
}
+
+ // DivineMC start - C2ME: opts_native_math
+ @Override
+ public void fillArray(final double[] densities, final ContextProvider applier) {
+ if (!org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ NormalNoise noise = this.offsetNoise.noise();
+ if (noise == null) {
+ Arrays.fill(densities, 0.0);
+ return;
+ }
+ long ptr = noise.c2me$getPointer();
+ if (ptr == 0L) {
+ applier.fillAllDirectly(densities, this);
+ return;
+ }
+ double[] x = new double[densities.length];
+ double[] y = new double[densities.length];
+ double[] z = new double[densities.length];
+ for (int i = 0; i < densities.length; i++) {
+ FunctionContext pos = applier.forIndex(i);
+ x[i] = pos.blockZ() * 0.25;
+ y[i] = pos.blockX() * 0.25;
+ z[i] = 0.0;
+ }
+ org.bxteam.divinemc.math.Bindings.c2me_natives_noise_perlin_double_batch(
+ ptr,
+ java.lang.foreign.MemorySegment.ofArray(densities),
+ java.lang.foreign.MemorySegment.ofArray(x),
+ java.lang.foreign.MemorySegment.ofArray(y),
+ java.lang.foreign.MemorySegment.ofArray(z),
+ densities.length
+ );
+ for (int i = 0; i < densities.length; i++) {
+ densities[i] *= 4.0;
+ }
+ }
+ // DivineMC end - C2ME: opts_native_math
}
interface ShiftNoise extends DensityFunction {
diff --git a/net/minecraft/world/level/levelgen/synth/BlendedNoise.java b/net/minecraft/world/level/levelgen/synth/BlendedNoise.java
index af5f714c285aad5ef844b17a266e06b5092d33aa..173c9f4024d085e0591f9eb5502a6f15168673e7 100644
--- a/net/minecraft/world/level/levelgen/synth/BlendedNoise.java
+++ b/net/minecraft/world/level/levelgen/synth/BlendedNoise.java
@@ -36,6 +36,11 @@ public class BlendedNoise implements DensityFunction.SimpleFunction {
private final double maxValue;
public final double xzScale;
public final double yScale;
+ // DivineMC start - C2ME: opts_native_math
+ private final java.lang.foreign.Arena c2me$arena = java.lang.foreign.Arena.ofAuto();
+ private java.lang.foreign.MemorySegment c2me$samplerData = null;
+ private long c2me$samplerDataPtr;
+ // DivineMC end - C2ME: opts_native_math
public static BlendedNoise createUnseeded(double xzScale, double yScale, double xzFactor, double yFactor, double smearScaleMultiplier) {
return new BlendedNoise(new XoroshiroRandomSource(0L), xzScale, yScale, xzFactor, yFactor, smearScaleMultiplier);
@@ -62,6 +67,12 @@ public class BlendedNoise implements DensityFunction.SimpleFunction {
this.xzMultiplier = 684.412 * this.xzScale;
this.yMultiplier = 684.412 * this.yScale;
this.maxValue = minLimitNoise.maxBrokenValue(this.yMultiplier);
+ // DivineMC start - C2ME: opts_native_math
+ if (org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ this.c2me$samplerData = org.bxteam.divinemc.math.BindingsTemplate.interpolated_noise_sampler$create(this.c2me$arena, this);
+ this.c2me$samplerDataPtr = this.c2me$samplerData.address();
+ }
+ // DivineMC end - C2ME: opts_native_math
}
@VisibleForTesting
diff --git a/net/minecraft/world/level/levelgen/synth/NormalNoise.java b/net/minecraft/world/level/levelgen/synth/NormalNoise.java
index 45060882654217eeb9a07357c5149b12fbff02c1..75e3641b40841622a7545bc371197ff1a28968d2 100644
--- a/net/minecraft/world/level/levelgen/synth/NormalNoise.java
+++ b/net/minecraft/world/level/levelgen/synth/NormalNoise.java
@@ -21,6 +21,15 @@ public class NormalNoise {
private final PerlinNoise second;
private final double maxValue;
private final NormalNoise.NoiseParameters parameters;
+ // DivineMC start - C2ME: opts_native_math
+ private final java.lang.foreign.Arena c2me$arena = java.lang.foreign.Arena.ofAuto();
+ private java.lang.foreign.MemorySegment c2me$samplerData = null;
+ private long c2me$samplerDataPtr;
+
+ public long c2me$getPointer() {
+ return this.c2me$samplerDataPtr;
+ }
+ // DivineMC end - C2ME: opts_native_math
@Deprecated
public static NormalNoise createLegacyNetherBiome(RandomSource random, NormalNoise.NoiseParameters parameters) {
@@ -62,6 +71,12 @@ public class NormalNoise {
this.valueFactor = 0.16666666666666666 / expectedDeviation(i2 - i1);
this.maxValue = (this.first.maxValue() + this.second.maxValue()) * this.valueFactor;
+ // DivineMC start - C2ME: opts_native_math
+ if (org.bxteam.divinemc.DivineConfig.nativeAccelerationEnabled) {
+ this.c2me$samplerData = org.bxteam.divinemc.math.BindingsTemplate.double_octave_sampler_data$create(this.c2me$arena, this.first, this.second, this.valueFactor);
+ this.c2me$samplerDataPtr = this.c2me$samplerData.address();
+ }
+ // DivineMC end - C2ME: opts_native_math
}
public double maxValue() {

View File

@@ -0,0 +1,145 @@
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

@@ -0,0 +1,918 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 00:09:39 +0300
Subject: [PATCH] World and Noise gen optimizations
diff --git a/net/minecraft/world/level/ChunkPos.java b/net/minecraft/world/level/ChunkPos.java
index 55ce935a2fab7e32904d9ff599867269035d703f..4fa84743ba7f570f11a4979b7e5381478c844aef 100644
--- a/net/minecraft/world/level/ChunkPos.java
+++ b/net/minecraft/world/level/ChunkPos.java
@@ -110,7 +110,12 @@ public class ChunkPos {
@Override
public boolean equals(Object other) {
- return this == other || other instanceof ChunkPos chunkPos && this.x == chunkPos.x && this.z == chunkPos.z;
+ // DivineMC start - Use standard equals
+ if (other == this) return true;
+ if (other == null || other.getClass() != this.getClass()) return false;
+ ChunkPos thatPos = (ChunkPos) other;
+ return this.x == thatPos.x && this.z == thatPos.z;
+ // DivineMC end - Use standard equals
}
public int getMiddleBlockX() {
diff --git a/net/minecraft/world/level/biome/TheEndBiomeSource.java b/net/minecraft/world/level/biome/TheEndBiomeSource.java
index cf3172be76fa4c7987ed569138439ff42f92fa7f..bfc65a4d8d1e64f42ff13508020e5e0260e83b98 100644
--- a/net/minecraft/world/level/biome/TheEndBiomeSource.java
+++ b/net/minecraft/world/level/biome/TheEndBiomeSource.java
@@ -27,6 +27,33 @@ public class TheEndBiomeSource extends BiomeSource {
private final Holder<Biome> islands;
private final Holder<Biome> barrens;
+ // DivineMC start - World gen optimizations
+ private Holder<Biome> getBiomeForNoiseGenVanilla(int x, int y, int z, Climate.Sampler noise) {
+ int i = QuartPos.toBlock(x);
+ int j = QuartPos.toBlock(y);
+ int k = QuartPos.toBlock(z);
+ int l = SectionPos.blockToSectionCoord(i);
+ int m = SectionPos.blockToSectionCoord(k);
+ if ((long)l * (long)l + (long)m * (long)m <= 4096L) {
+ return this.end;
+ } else {
+ int n = (SectionPos.blockToSectionCoord(i) * 2 + 1) * 8;
+ int o = (SectionPos.blockToSectionCoord(k) * 2 + 1) * 8;
+ double d = noise.erosion().compute(new DensityFunction.SinglePointContext(n, j, o));
+ if (d > 0.25D) {
+ return this.highlands;
+ } else if (d >= -0.0625D) {
+ return this.midlands;
+ } else {
+ return d < -0.21875D ? this.islands : this.barrens;
+ }
+ }
+ }
+
+ private final ThreadLocal<it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap<Holder<Biome>>> cache = ThreadLocal.withInitial(it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap::new);
+ private final int cacheCapacity = 1024;
+ // DivineMC end - World gen optimizations
+
public static TheEndBiomeSource create(HolderGetter<Biome> biomeGetter) {
return new TheEndBiomeSource(
biomeGetter.getOrThrow(Biomes.THE_END),
@@ -55,26 +82,24 @@ public class TheEndBiomeSource extends BiomeSource {
return CODEC;
}
+ // DivineMC start - World gen optimizations
@Override
- public Holder<Biome> getNoiseBiome(int x, int y, int z, Climate.Sampler sampler) {
- int blockPosX = QuartPos.toBlock(x);
- int blockPosY = QuartPos.toBlock(y);
- int blockPosZ = QuartPos.toBlock(z);
- int sectionPosX = SectionPos.blockToSectionCoord(blockPosX);
- int sectionPosZ = SectionPos.blockToSectionCoord(blockPosZ);
- if ((long)sectionPosX * sectionPosX + (long)sectionPosZ * sectionPosZ <= 4096L) {
- return this.end;
+ public Holder<Biome> getNoiseBiome(int biomeX, int biomeY, int biomeZ, Climate.Sampler multiNoiseSampler) {
+ final long key = net.minecraft.world.level.ChunkPos.asLong(biomeX, biomeZ);
+ final it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap<Holder<Biome>> cacheThreadLocal = cache.get();
+ final Holder<Biome> biome = cacheThreadLocal.get(key);
+ if (biome != null) {
+ return biome;
} else {
- int i = (SectionPos.blockToSectionCoord(blockPosX) * 2 + 1) * 8;
- int i1 = (SectionPos.blockToSectionCoord(blockPosZ) * 2 + 1) * 8;
- double d = sampler.erosion().compute(new DensityFunction.SinglePointContext(i, blockPosY, i1));
- if (d > 0.25) {
- return this.highlands;
- } else if (d >= -0.0625) {
- return this.midlands;
- } else {
- return d < -0.21875 ? this.islands : this.barrens;
+ final Holder<Biome> gennedBiome = getBiomeForNoiseGenVanilla(biomeX, biomeY, biomeZ, multiNoiseSampler);
+ cacheThreadLocal.put(key, gennedBiome);
+ if (cacheThreadLocal.size() > cacheCapacity) {
+ for (int i = 0; i < cacheCapacity / 16; i ++) {
+ cacheThreadLocal.removeFirst();
+ }
}
+ return gennedBiome;
}
}
+ // DivineMC end - World gen optimizations
}
diff --git a/net/minecraft/world/level/chunk/LevelChunkSection.java b/net/minecraft/world/level/chunk/LevelChunkSection.java
index c83d0667b19830304f22319a46a23422a8766790..5bc74d860923d6485593cacb67d4c18e20db2634 100644
--- a/net/minecraft/world/level/chunk/LevelChunkSection.java
+++ b/net/minecraft/world/level/chunk/LevelChunkSection.java
@@ -23,6 +23,7 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
public short tickingFluidCount;
public final PalettedContainer<BlockState> states;
private PalettedContainer<Holder<Biome>> biomes; // CraftBukkit - read/write
+ private static final int sliceSize = 4; // DivineMC - World and Noise gen optimizations
// Paper start - block counting
private static final it.unimi.dsi.fastutil.shorts.ShortArrayList FULL_LIST = new it.unimi.dsi.fastutil.shorts.ShortArrayList(16*16*16);
@@ -312,13 +313,15 @@ public class LevelChunkSection implements ca.spottedleaf.moonrise.patches.block_
PalettedContainer<Holder<Biome>> palettedContainer = this.biomes.recreate();
int i = 4;
- for (int i1 = 0; i1 < 4; i1++) {
- for (int i2 = 0; i2 < 4; i2++) {
- for (int i3 = 0; i3 < 4; i3++) {
- palettedContainer.getAndSetUnchecked(i1, i2, i3, biomeResolver.getNoiseBiome(x + i1, y + i2, z + i3, climateSampler));
+ // DivineMC start - World and Noise gen optimizations
+ for (int posY = 0; posY < sliceSize; ++posY) {
+ for (int posZ = 0; posZ < sliceSize; ++posZ) {
+ for (int posX = 0; posX < sliceSize; ++posX) {
+ palettedContainer.getAndSetUnchecked(posX, posY, posZ, biomeResolver.getNoiseBiome(x + posX, y + posY, z + posZ, climateSampler));
}
}
}
+ // DivineMC end - World and Noise gen optimizations
this.biomes = palettedContainer;
}
diff --git a/net/minecraft/world/level/levelgen/Aquifer.java b/net/minecraft/world/level/levelgen/Aquifer.java
index c62a15ea4a1bb22e7bcc2fc544acf8a601892029..43dd5f63fe7834d41874ea30651f3fb738d88ba6 100644
--- a/net/minecraft/world/level/levelgen/Aquifer.java
+++ b/net/minecraft/world/level/levelgen/Aquifer.java
@@ -85,6 +85,15 @@ public interface Aquifer {
private final int minGridZ;
private final int gridSizeX;
private final int gridSizeZ;
+ // DivineMC start - World gen optimizations
+ private int c2me$dist1;
+ private int c2me$dist2;
+ private int c2me$dist3;
+ private long c2me$pos1;
+ private long c2me$pos2;
+ private long c2me$pos3;
+ private double c2me$mutableDoubleThingy;
+ // DivineMC end - World gen optimizations
private static final int[][] SURFACE_SAMPLING_OFFSETS_IN_CHUNKS = new int[][]{
{0, 0}, {-2, -1}, {-1, -1}, {0, -1}, {1, -1}, {-3, 0}, {-2, 0}, {-1, 0}, {1, 0}, {-2, 1}, {-1, 1}, {0, 1}, {1, 1}
};
@@ -120,6 +129,36 @@ public interface Aquifer {
this.aquiferCache = new Aquifer.FluidStatus[i4];
this.aquiferLocationCache = new long[i4];
Arrays.fill(this.aquiferLocationCache, Long.MAX_VALUE);
+ // DivineMC start - World gen optimizations
+ if (this.aquiferLocationCache.length % (this.gridSizeX * this.gridSizeZ) != 0) {
+ throw new AssertionError("Array length");
+ }
+
+ int sizeY = this.aquiferLocationCache.length / (this.gridSizeX * this.gridSizeZ);
+
+ final RandomSource random = org.bxteam.divinemc.util.RandomUtil.getRandom(this.positionalRandomFactory);
+ // index: y, z, x
+ for (int y = 0; y < sizeY; y++) {
+ for (int z = 0; z < this.gridSizeZ; z++) {
+ for (int x = 0; x < this.gridSizeX; x++) {
+ final int x1 = x + this.minGridX;
+ final int y1 = y + this.minGridY;
+ final int z1 = z + this.minGridZ;
+ org.bxteam.divinemc.util.RandomUtil.derive(this.positionalRandomFactory, random, x1, y1, z1);
+ int x2 = x1 * 16 + random.nextInt(10);
+ int y2 = y1 * 12 + random.nextInt(9);
+ int z2 = z1 * 16 + random.nextInt(10);
+ int index = this.getIndex(x1, y1, z1);
+ this.aquiferLocationCache[index] = BlockPos.asLong(x2, y2, z2);
+ }
+ }
+ }
+ for (long blockPosition : this.aquiferLocationCache) {
+ if (blockPosition == Long.MAX_VALUE) {
+ throw new AssertionError("Array initialization");
+ }
+ }
+ // DivineMC end - World gen optimizations
}
private int getIndex(int gridX, int gridY, int gridZ) {
@@ -132,140 +171,24 @@ public interface Aquifer {
@Nullable
@Override
public BlockState computeSubstance(DensityFunction.FunctionContext context, double substance) {
+ // DivineMC start - World gen optimizations
int i = context.blockX();
- int i1 = context.blockY();
- int i2 = context.blockZ();
+ int j = context.blockY();
+ int k = context.blockZ();
if (substance > 0.0) {
this.shouldScheduleFluidUpdate = false;
return null;
} else {
- Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(i, i1, i2);
- if (fluidStatus.at(i1).is(Blocks.LAVA)) {
+ Aquifer.FluidStatus fluidLevel = this.globalFluidPicker.computeFluid(i, j, k);
+ if (fluidLevel.at(j).is(Blocks.LAVA)) {
this.shouldScheduleFluidUpdate = false;
return Blocks.LAVA.defaultBlockState();
} else {
- int i3 = Math.floorDiv(i - 5, 16);
- int i4 = Math.floorDiv(i1 + 1, 12);
- int i5 = Math.floorDiv(i2 - 5, 16);
- int i6 = Integer.MAX_VALUE;
- int i7 = Integer.MAX_VALUE;
- int i8 = Integer.MAX_VALUE;
- int i9 = Integer.MAX_VALUE;
- long l = 0L;
- long l1 = 0L;
- long l2 = 0L;
- long l3 = 0L;
-
- for (int i10 = 0; i10 <= 1; i10++) {
- for (int i11 = -1; i11 <= 1; i11++) {
- for (int i12 = 0; i12 <= 1; i12++) {
- int i13 = i3 + i10;
- int i14 = i4 + i11;
- int i15 = i5 + i12;
- int index = this.getIndex(i13, i14, i15);
- long l4 = this.aquiferLocationCache[index];
- long l5;
- if (l4 != Long.MAX_VALUE) {
- l5 = l4;
- } else {
- RandomSource randomSource = this.positionalRandomFactory.at(i13, i14, i15);
- l5 = BlockPos.asLong(
- i13 * 16 + randomSource.nextInt(10), i14 * 12 + randomSource.nextInt(9), i15 * 16 + randomSource.nextInt(10)
- );
- this.aquiferLocationCache[index] = l5;
- }
-
- int i16 = BlockPos.getX(l5) - i;
- int i17 = BlockPos.getY(l5) - i1;
- int i18 = BlockPos.getZ(l5) - i2;
- int i19 = i16 * i16 + i17 * i17 + i18 * i18;
- if (i6 >= i19) {
- l3 = l2;
- l2 = l1;
- l1 = l;
- l = l5;
- i9 = i8;
- i8 = i7;
- i7 = i6;
- i6 = i19;
- } else if (i7 >= i19) {
- l3 = l2;
- l2 = l1;
- l1 = l5;
- i9 = i8;
- i8 = i7;
- i7 = i19;
- } else if (i8 >= i19) {
- l3 = l2;
- l2 = l5;
- i9 = i8;
- i8 = i19;
- } else if (i9 >= i19) {
- l3 = l5;
- i9 = i19;
- }
- }
- }
- }
-
- Aquifer.FluidStatus aquiferStatus = this.getAquiferStatus(l);
- double d = similarity(i6, i7);
- BlockState blockState = aquiferStatus.at(i1);
- if (d <= 0.0) {
- if (d >= FLOWING_UPDATE_SIMULARITY) {
- Aquifer.FluidStatus aquiferStatus1 = this.getAquiferStatus(l1);
- this.shouldScheduleFluidUpdate = !aquiferStatus.equals(aquiferStatus1);
- } else {
- this.shouldScheduleFluidUpdate = false;
- }
-
- return blockState;
- } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, i1 - 1, i2).at(i1 - 1).is(Blocks.LAVA)) {
- this.shouldScheduleFluidUpdate = true;
- return blockState;
- } else {
- MutableDouble mutableDouble = new MutableDouble(Double.NaN);
- Aquifer.FluidStatus aquiferStatus2 = this.getAquiferStatus(l1);
- double d1 = d * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus2);
- if (substance + d1 > 0.0) {
- this.shouldScheduleFluidUpdate = false;
- return null;
- } else {
- Aquifer.FluidStatus aquiferStatus3 = this.getAquiferStatus(l2);
- double d2 = similarity(i6, i8);
- if (d2 > 0.0) {
- double d3 = d * d2 * this.calculatePressure(context, mutableDouble, aquiferStatus, aquiferStatus3);
- if (substance + d3 > 0.0) {
- this.shouldScheduleFluidUpdate = false;
- return null;
- }
- }
-
- double d3 = similarity(i7, i8);
- if (d3 > 0.0) {
- double d4 = d * d3 * this.calculatePressure(context, mutableDouble, aquiferStatus2, aquiferStatus3);
- if (substance + d4 > 0.0) {
- this.shouldScheduleFluidUpdate = false;
- return null;
- }
- }
-
- boolean flag = !aquiferStatus.equals(aquiferStatus2);
- boolean flag1 = d3 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus2.equals(aquiferStatus3);
- boolean flag2 = d2 >= FLOWING_UPDATE_SIMULARITY && !aquiferStatus.equals(aquiferStatus3);
- if (!flag && !flag1 && !flag2) {
- this.shouldScheduleFluidUpdate = d2 >= FLOWING_UPDATE_SIMULARITY
- && similarity(i6, i9) >= FLOWING_UPDATE_SIMULARITY
- && !aquiferStatus.equals(this.getAquiferStatus(l3));
- } else {
- this.shouldScheduleFluidUpdate = true;
- }
-
- return blockState;
- }
- }
+ aquiferExtracted$refreshDistPosIdx(i, j, k);
+ return aquiferExtracted$applyPost(context, substance, j, i, k);
}
}
+ // DivineMC end - World gen optimizations
}
@Override
@@ -278,65 +201,28 @@ public interface Aquifer {
return 1.0 - Math.abs(secondDistance - firstDistance) / 25.0;
}
+ // DivineMC start - World gen optimizations
private double calculatePressure(
- DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus firstFluid, Aquifer.FluidStatus secondFluid
+ DensityFunction.FunctionContext context, MutableDouble substance, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2 // DivineMC - rename args
) {
int i = context.blockY();
- BlockState blockState = firstFluid.at(i);
- BlockState blockState1 = secondFluid.at(i);
- if ((!blockState.is(Blocks.LAVA) || !blockState1.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState1.is(Blocks.LAVA))) {
- int abs = Math.abs(firstFluid.fluidLevel - secondFluid.fluidLevel);
+ BlockState blockState = fluidLevel.at(i);
+ BlockState blockState2 = fluidLevel2.at(i);
+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) {
+ int abs = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel);
if (abs == 0) {
return 0.0;
} else {
- double d = 0.5 * (firstFluid.fluidLevel + secondFluid.fluidLevel);
- double d1 = i + 0.5 - d;
- double d2 = abs / 2.0;
- double d3 = 0.0;
- double d4 = 2.5;
- double d5 = 1.5;
- double d6 = 3.0;
- double d7 = 10.0;
- double d8 = 3.0;
- double d9 = d2 - Math.abs(d1);
- double d11;
- if (d1 > 0.0) {
- double d10 = 0.0 + d9;
- if (d10 > 0.0) {
- d11 = d10 / 1.5;
- } else {
- d11 = d10 / 2.5;
- }
- } else {
- double d10 = 3.0 + d9;
- if (d10 > 0.0) {
- d11 = d10 / 3.0;
- } else {
- d11 = d10 / 10.0;
- }
- }
-
- double d10x = 2.0;
- double d12;
- if (!(d11 < -2.0) && !(d11 > 2.0)) {
- double value = substance.getValue();
- if (Double.isNaN(value)) {
- double d13 = this.barrierNoise.compute(context);
- substance.setValue(d13);
- d12 = d13;
- } else {
- d12 = value;
- }
- } else {
- d12 = 0.0;
- }
+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel);
+ final double q = aquiferExtracted$getQ(i, d, abs);
- return 2.0 * (d12 + d11);
+ return aquiferExtracted$postCalculateDensity(context, substance, q);
}
} else {
return 2.0;
}
}
+ // DivineMC end - World gen optimizations
private int gridX(int x) {
return Math.floorDiv(x, 16);
@@ -350,23 +236,25 @@ public interface Aquifer {
return Math.floorDiv(z, 16);
}
- private Aquifer.FluidStatus getAquiferStatus(long packedPos) {
- int x = BlockPos.getX(packedPos);
- int y = BlockPos.getY(packedPos);
- int z = BlockPos.getZ(packedPos);
- int i = this.gridX(x);
- int i1 = this.gridY(y);
- int i2 = this.gridZ(z);
- int index = this.getIndex(i, i1, i2);
- Aquifer.FluidStatus fluidStatus = this.aquiferCache[index];
- if (fluidStatus != null) {
- return fluidStatus;
+ // DivineMC start - World gen optimizations
+ private Aquifer.FluidStatus getAquiferStatus(long pos) {
+ int i = BlockPos.getX(pos);
+ int j = BlockPos.getY(pos);
+ int k = BlockPos.getZ(pos);
+ int l = i >> 4; // C2ME - inline: floorDiv(i, 16)
+ int m = Math.floorDiv(j, 12); // C2ME - inline
+ int n = k >> 4; // C2ME - inline: floorDiv(k, 16)
+ int o = this.getIndex(l, m, n);
+ Aquifer.FluidStatus fluidLevel = this.aquiferCache[o];
+ if (fluidLevel != null) {
+ return fluidLevel;
} else {
- Aquifer.FluidStatus fluidStatus1 = this.computeFluid(x, y, z);
- this.aquiferCache[index] = fluidStatus1;
- return fluidStatus1;
+ Aquifer.FluidStatus fluidLevel2 = this.computeFluid(i, j, k);
+ this.aquiferCache[o] = fluidLevel2;
+ return fluidLevel2;
}
}
+ // DivineMC end - World gen optimizations
private Aquifer.FluidStatus computeFluid(int x, int y, int z) {
Aquifer.FluidStatus fluidStatus = this.globalFluidPicker.computeFluid(x, y, z);
@@ -406,23 +294,22 @@ public interface Aquifer {
return new Aquifer.FluidStatus(i7, this.computeFluidType(x, y, z, fluidStatus, i7));
}
+ // DivineMC start - World gen optimizations
private int computeSurfaceLevel(int x, int y, int z, Aquifer.FluidStatus fluidStatus, int maxSurfaceLevel, boolean fluidPresent) {
- DensityFunction.SinglePointContext singlePointContext = new DensityFunction.SinglePointContext(x, y, z);
+ DensityFunction.SinglePointContext unblendedNoisePos = new DensityFunction.SinglePointContext(x, y, z);
double d;
double d1;
- if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, singlePointContext)) {
+ if (OverworldBiomeBuilder.isDeepDarkRegion(this.erosion, this.depth, unblendedNoisePos)) {
d = -1.0;
d1 = -1.0;
} else {
int i = maxSurfaceLevel + 8 - y;
- int i1 = 64;
- double d2 = fluidPresent ? Mth.clampedMap((double)i, 0.0, 64.0, 1.0, 0.0) : 0.0;
- double d3 = Mth.clamp(this.fluidLevelFloodednessNoise.compute(singlePointContext), -1.0, 1.0);
- double d4 = Mth.map(d2, 1.0, 0.0, -0.3, 0.8);
- double d5 = Mth.map(d2, 1.0, 0.0, -0.8, 0.4);
- d = d3 - d5;
- d1 = d3 - d4;
+ double f = fluidPresent ? Mth.clampedLerp(1.0, 0.0, ((double) i) / 64.0) : 0.0; // inline
+ double g = Mth.clamp(this.fluidLevelFloodednessNoise.compute(unblendedNoisePos), -1.0, 1.0);
+ d = g + 0.8 + (f - 1.0) * 1.2; // inline
+ d1 = g + 0.3 + (f - 1.0) * 1.1; // inline
}
+ // DivineMC end - World gen optimizations
int i;
if (d1 > 0.0) {
@@ -466,5 +353,183 @@ public interface Aquifer {
return blockState;
}
+
+ // DivineMC start - World gen optimizations
+ private @org.jetbrains.annotations.Nullable BlockState aquiferExtracted$applyPost(DensityFunction.FunctionContext pos, double density, int j, int i, int k) {
+ Aquifer.FluidStatus fluidLevel2 = this.getAquiferStatus(this.c2me$pos1);
+ double d = similarity(this.c2me$dist1, this.c2me$dist2);
+ BlockState blockState = fluidLevel2.at(j);
+ if (d <= 0.0) {
+ this.shouldScheduleFluidUpdate = d >= FLOWING_UPDATE_SIMULARITY;
+ return blockState;
+ } else if (blockState.is(Blocks.WATER) && this.globalFluidPicker.computeFluid(i, j - 1, k).at(j - 1).is(Blocks.LAVA)) {
+ this.shouldScheduleFluidUpdate = true;
+ return blockState;
+ } else {
+ this.c2me$mutableDoubleThingy = Double.NaN;
+ Aquifer.FluidStatus fluidLevel3 = this.getAquiferStatus(this.c2me$pos2);
+ double e = d * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel3);
+ if (density + e > 0.0) {
+ this.shouldScheduleFluidUpdate = false;
+ return null;
+ } else {
+ return aquiferExtracted$getFinalBlockState(pos, density, d, fluidLevel2, fluidLevel3, blockState);
+ }
+ }
+ }
+
+ private BlockState aquiferExtracted$getFinalBlockState(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, Aquifer.FluidStatus fluidLevel3, BlockState blockState) {
+ Aquifer.FluidStatus fluidLevel4 = this.getAquiferStatus(this.c2me$pos3);
+ double f = similarity(this.c2me$dist1, this.c2me$dist3);
+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel2, f, fluidLevel4)) return null;
+
+ double g = similarity(this.c2me$dist2, this.c2me$dist3);
+ if (aquiferExtracted$extractedCheckFG(pos, density, d, fluidLevel3, g, fluidLevel4)) return null;
+
+ this.shouldScheduleFluidUpdate = true;
+ return blockState;
+ }
+
+ private boolean aquiferExtracted$extractedCheckFG(DensityFunction.FunctionContext pos, double density, double d, Aquifer.FluidStatus fluidLevel2, double f, Aquifer.FluidStatus fluidLevel4) {
+ if (f > 0.0) {
+ double g = d * f * this.c2me$calculateDensityModified(pos, fluidLevel2, fluidLevel4);
+ if (density + g > 0.0) {
+ this.shouldScheduleFluidUpdate = false;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private void aquiferExtracted$refreshDistPosIdx(int x, int y, int z) {
+ int gx = (x - 5) >> 4;
+ int gy = Math.floorDiv(y + 1, 12);
+ int gz = (z - 5) >> 4;
+ int dist1 = Integer.MAX_VALUE;
+ int dist2 = Integer.MAX_VALUE;
+ int dist3 = Integer.MAX_VALUE;
+ long pos1 = 0;
+ long pos2 = 0;
+ long pos3 = 0;
+
+ for (int offY = -1; offY <= 1; ++offY) {
+ for (int offZ = 0; offZ <= 1; ++offZ) {
+ for (int offX = 0; offX <= 1; ++offX) {
+ int posIdx = this.getIndex(gx + offX, gy + offY, gz + offZ);
+
+ long position = this.aquiferLocationCache[posIdx];
+
+ int dx = BlockPos.getX(position) - x;
+ int dy = BlockPos.getY(position) - y;
+ int dz = BlockPos.getZ(position) - z;
+ int dist = dx * dx + dy * dy + dz * dz;
+
+ if (dist3 >= dist) {
+ pos3 = position;
+ dist3 = dist;
+ }
+ if (dist2 >= dist) {
+ pos3 = pos2;
+ dist3 = dist2;
+ pos2 = position;
+ dist2 = dist;
+ }
+ if (dist1 >= dist) {
+ pos2 = pos1;
+ dist2 = dist1;
+ pos1 = position;
+ dist1 = dist;
+ }
+ }
+ }
+ }
+
+ this.c2me$dist1 = dist1;
+ this.c2me$dist2 = dist2;
+ this.c2me$dist3 = dist3;
+ this.c2me$pos1 = pos1;
+ this.c2me$pos2 = pos2;
+ this.c2me$pos3 = pos3;
+ }
+
+ private double c2me$calculateDensityModified(
+ DensityFunction.FunctionContext pos, Aquifer.FluidStatus fluidLevel, Aquifer.FluidStatus fluidLevel2
+ ) {
+ int i = pos.blockY();
+ BlockState blockState = fluidLevel.at(i);
+ BlockState blockState2 = fluidLevel2.at(i);
+ if ((!blockState.is(Blocks.LAVA) || !blockState2.is(Blocks.WATER)) && (!blockState.is(Blocks.WATER) || !blockState2.is(Blocks.LAVA))) {
+ int j = Math.abs(fluidLevel.fluidLevel - fluidLevel2.fluidLevel);
+ if (j == 0) {
+ return 0.0;
+ } else {
+ double d = 0.5 * (double)(fluidLevel.fluidLevel + fluidLevel2.fluidLevel);
+ final double q = aquiferExtracted$getQ(i, d, j);
+
+ return aquiferExtracted$postCalculateDensityModified(pos, q);
+ }
+ } else {
+ return 2.0;
+ }
+ }
+
+ private double aquiferExtracted$postCalculateDensity(DensityFunction.FunctionContext pos, MutableDouble mutableDouble, double q) {
+ double r;
+ if (!(q < -2.0) && !(q > 2.0)) {
+ double s = mutableDouble.getValue();
+ if (Double.isNaN(s)) {
+ double t = this.barrierNoise.compute(pos);
+ mutableDouble.setValue(t);
+ r = t;
+ } else {
+ r = s;
+ }
+ } else {
+ r = 0.0;
+ }
+
+ return 2.0 * (r + q);
+ }
+
+ private double aquiferExtracted$postCalculateDensityModified(DensityFunction.FunctionContext pos, double q) {
+ double r;
+ if (!(q < -2.0) && !(q > 2.0)) {
+ double s = this.c2me$mutableDoubleThingy;
+ if (Double.isNaN(s)) {
+ double t = this.barrierNoise.compute(pos);
+ this.c2me$mutableDoubleThingy = t;
+ r = t;
+ } else {
+ r = s;
+ }
+ } else {
+ r = 0.0;
+ }
+
+ return 2.0 * (r + q);
+ }
+
+ private static double aquiferExtracted$getQ(double i, double d, double j) {
+ double e = i + 0.5 - d;
+ double f = j / 2.0;
+ double o = f - Math.abs(e);
+ double q;
+ if (e > 0.0) {
+ if (o > 0.0) {
+ q = o / 1.5;
+ } else {
+ q = o / 2.5;
+ }
+ } else {
+ double p = 3.0 + o;
+ if (p > 0.0) {
+ q = p / 3.0;
+ } else {
+ q = p / 10.0;
+ }
+ }
+ return q;
+ }
+ // DivineMC end - World gen optimizations
}
}
diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java
index 131923282c9ecbcb1d7f45a826da907c02bd2716..36dd3eb0cb29d546531aec91a9c486be09975797 100644
--- a/net/minecraft/world/level/levelgen/Beardifier.java
+++ b/net/minecraft/world/level/levelgen/Beardifier.java
@@ -29,6 +29,17 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
});
private final ObjectListIterator<Beardifier.Rigid> pieceIterator;
private final ObjectListIterator<JigsawJunction> junctionIterator;
+ // DivineMC start - World gen optimizations
+ private Beardifier.Rigid[] c2me$pieceArray;
+ private JigsawJunction[] c2me$junctionArray;
+
+ private void c2me$initArrays() {
+ this.c2me$pieceArray = com.google.common.collect.Iterators.toArray(this.pieceIterator, Beardifier.Rigid.class);
+ this.pieceIterator.back(Integer.MAX_VALUE);
+ this.c2me$junctionArray = com.google.common.collect.Iterators.toArray(this.junctionIterator, JigsawJunction.class);
+ this.junctionIterator.back(Integer.MAX_VALUE);
+ }
+ // DivineMC end - World gen optimizations
public static Beardifier forStructuresInChunk(StructureManager structureManager, ChunkPos chunkPos) {
int minBlockX = chunkPos.getMinBlockX();
@@ -76,50 +87,44 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
this.junctionIterator = junctionIterator;
}
+ // DivineMC start - World gen optimizations
@Override
public double compute(DensityFunction.FunctionContext context) {
+ if (this.c2me$pieceArray == null || this.c2me$junctionArray == null) {
+ this.c2me$initArrays();
+ }
int i = context.blockX();
- int i1 = context.blockY();
- int i2 = context.blockZ();
+ int j = context.blockY();
+ int k = context.blockZ();
double d = 0.0;
- while (this.pieceIterator.hasNext()) {
- Beardifier.Rigid rigid = this.pieceIterator.next();
- BoundingBox boundingBox = rigid.box();
- int groundLevelDelta = rigid.groundLevelDelta();
- int max = Math.max(0, Math.max(boundingBox.minX() - i, i - boundingBox.maxX()));
- int max1 = Math.max(0, Math.max(boundingBox.minZ() - i2, i2 - boundingBox.maxZ()));
- int i3 = boundingBox.minY() + groundLevelDelta;
- int i4 = i1 - i3;
-
- int i5 = switch (rigid.terrainAdjustment()) {
- case NONE -> 0;
- case BURY, BEARD_THIN -> i4;
- case BEARD_BOX -> Math.max(0, Math.max(i3 - i1, i1 - boundingBox.maxY()));
- case ENCAPSULATE -> Math.max(0, Math.max(boundingBox.minY() - i1, i1 - boundingBox.maxY()));
- };
+ for (Beardifier.Rigid piece : this.c2me$pieceArray) {
+ BoundingBox blockBox = piece.box();
+ int l = piece.groundLevelDelta();
+ int m = Math.max(0, Math.max(blockBox.minX() - i, i - blockBox.maxX()));
+ int n = Math.max(0, Math.max(blockBox.minZ() - k, k - blockBox.maxZ()));
+ int o = blockBox.minY() + l;
+ int p = j - o;
- d += switch (rigid.terrainAdjustment()) {
+ d += switch (piece.terrainAdjustment()) { // 2 switch statement merged
case NONE -> 0.0;
- case BURY -> getBuryContribution(max, i5 / 2.0, max1);
- case BEARD_THIN, BEARD_BOX -> getBeardContribution(max, i5, max1, i4) * 0.8;
- case ENCAPSULATE -> getBuryContribution(max / 2.0, i5 / 2.0, max1 / 2.0) * 0.8;
+ case BURY -> getBuryContribution(m, (double)p / 2.0, n);
+ case BEARD_THIN -> getBeardContribution(m, p, n, p) * 0.8;
+ case BEARD_BOX -> getBeardContribution(m, Math.max(0, Math.max(o - j, j - blockBox.maxY())), n, p) * 0.8;
+ case ENCAPSULATE -> getBuryContribution((double)m / 2.0, (double)Math.max(0, Math.max(blockBox.minY() - j, j - blockBox.maxY())) / 2.0, (double)n / 2.0) * 0.8;
};
}
- this.pieceIterator.back(Integer.MAX_VALUE);
-
- while (this.junctionIterator.hasNext()) {
- JigsawJunction jigsawJunction = this.junctionIterator.next();
- int i6 = i - jigsawJunction.getSourceX();
- int groundLevelDelta = i1 - jigsawJunction.getSourceGroundY();
- int max = i2 - jigsawJunction.getSourceZ();
- d += getBeardContribution(i6, groundLevelDelta, max, groundLevelDelta) * 0.4;
+ for (JigsawJunction jigsawJunction : this.c2me$junctionArray) {
+ int r = i - jigsawJunction.getSourceX();
+ int l = j - jigsawJunction.getSourceGroundY();
+ int m = k - jigsawJunction.getSourceZ();
+ d += getBeardContribution(r, l, m, l) * 0.4;
}
- this.junctionIterator.back(Integer.MAX_VALUE);
return d;
}
+ // DivineMC end - World gen optimizations
@Override
public double minValue() {
@@ -132,8 +137,14 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
}
private static double getBuryContribution(double x, double y, double z) {
- double len = Mth.length(x, y, z);
- return Mth.clampedMap(len, 0.0, 6.0, 1.0, 0.0);
+ // DivineMC start - World gen optimizations
+ double d = Math.sqrt(x * x + y * y + z * z);
+ if (d > 6.0) {
+ return 0.0;
+ } else {
+ return 1.0 - d / 6.0;
+ }
+ // DivineMC end - World gen optimizations
}
private static double getBeardContribution(int x, int y, int z, int height) {
diff --git a/net/minecraft/world/level/levelgen/LegacyRandomSource.java b/net/minecraft/world/level/levelgen/LegacyRandomSource.java
index c67168517774a0ad9ca43422a79ef14a8ea0c2e8..026dfbbb6c3fd5cd274dcbf721e5cf3af889e3d9 100644
--- a/net/minecraft/world/level/levelgen/LegacyRandomSource.java
+++ b/net/minecraft/world/level/levelgen/LegacyRandomSource.java
@@ -53,13 +53,7 @@ public class LegacyRandomSource implements BitRandomSource {
return this.gaussianSource.nextGaussian();
}
- public static class LegacyPositionalRandomFactory implements PositionalRandomFactory {
- private final long seed;
-
- public LegacyPositionalRandomFactory(long seed) {
- this.seed = seed;
- }
-
+ public record LegacyPositionalRandomFactory(long seed) implements PositionalRandomFactory { // DivineMC - make record
@Override
public RandomSource at(int x, int y, int z) {
long seed = Mth.getSeed(x, y, z);
diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
index 65728ef17e63d71833677fdcbd5bb90794b4822b..6ef91bd952d4a0c1ffa6f534e4fcdd5c0a9db40b 100644
--- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
+++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java
@@ -65,11 +65,13 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator {
}
private static Aquifer.FluidPicker createFluidPicker(NoiseGeneratorSettings settings) {
- Aquifer.FluidStatus fluidStatus = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState());
- int seaLevel = settings.seaLevel();
- Aquifer.FluidStatus fluidStatus1 = new Aquifer.FluidStatus(seaLevel, settings.defaultFluid());
- Aquifer.FluidStatus fluidStatus2 = new Aquifer.FluidStatus(DimensionType.MIN_Y * 2, Blocks.AIR.defaultBlockState());
- return (x, y, z) -> y < Math.min(-54, seaLevel) ? fluidStatus : fluidStatus1;
+ // DivineMC start - World gen optimizations
+ Aquifer.FluidStatus fluidLevel = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState());
+ int i = settings.seaLevel();
+ Aquifer.FluidStatus fluidLevel2 = new Aquifer.FluidStatus(i, settings.defaultFluid());
+ final int min = Math.min(-54, i);
+ return (j, k, lx) -> k < min ? fluidLevel : fluidLevel2;
+ // DivineMC end - World gen optimizations
}
@Override
diff --git a/net/minecraft/world/level/levelgen/NoiseSettings.java b/net/minecraft/world/level/levelgen/NoiseSettings.java
index 4cf3a364595ba5f81f741295695cb9a449bdf672..44df2ac0bd972c4d97fc89cd0c2d2d83480ca3e1 100644
--- a/net/minecraft/world/level/levelgen/NoiseSettings.java
+++ b/net/minecraft/world/level/levelgen/NoiseSettings.java
@@ -8,7 +8,7 @@ import net.minecraft.core.QuartPos;
import net.minecraft.world.level.LevelHeightAccessor;
import net.minecraft.world.level.dimension.DimensionType;
-public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) {
+public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical, int horizontalCellBlockCount, int verticalCellBlockCount) { // DivineMC - NoiseSettings optimizations
public static final Codec<NoiseSettings> CODEC = RecordCodecBuilder.<NoiseSettings>create(
instance -> instance.group(
Codec.intRange(DimensionType.MIN_Y, DimensionType.MAX_Y).fieldOf("min_y").forGetter(NoiseSettings::minY),
@@ -16,7 +16,10 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n
Codec.intRange(1, 4).fieldOf("size_horizontal").forGetter(NoiseSettings::noiseSizeHorizontal),
Codec.intRange(1, 4).fieldOf("size_vertical").forGetter(NoiseSettings::noiseSizeVertical)
)
- .apply(instance, NoiseSettings::new)
+ // DivineMC start - NoiseSettings optimizations
+ .apply(instance, (Integer minY1, Integer height1, Integer noiseSizeHorizontal1, Integer noiseSizeVertical1) -> new NoiseSettings(minY1, height1, noiseSizeHorizontal1, noiseSizeVertical1,
+ QuartPos.toBlock(noiseSizeHorizontal1), QuartPos.toBlock(noiseSizeVertical1)))
+ // DivineMC end - NoiseSettings optimizations
)
.comapFlatMap(NoiseSettings::guardY, Function.identity());
protected static final NoiseSettings OVERWORLD_NOISE_SETTINGS = create(-64, 384, 1, 2);
@@ -36,7 +39,7 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n
}
public static NoiseSettings create(int minY, int height, int noiseSizeHorizontal, int noiseSizeVertical) {
- NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical);
+ NoiseSettings noiseSettings = new NoiseSettings(minY, height, noiseSizeHorizontal, noiseSizeVertical, QuartPos.toBlock(noiseSizeHorizontal), QuartPos.toBlock(noiseSizeVertical)); // DivineMC - NoiseSettings optimizations
guardY(noiseSettings).error().ifPresent(error -> {
throw new IllegalStateException(error.message());
});
@@ -44,16 +47,16 @@ public record NoiseSettings(int minY, int height, int noiseSizeHorizontal, int n
}
public int getCellHeight() {
- return QuartPos.toBlock(this.noiseSizeVertical());
+ return verticalCellBlockCount(); // DivineMC - NoiseSettings optimizations
}
public int getCellWidth() {
- return QuartPos.toBlock(this.noiseSizeHorizontal());
+ return horizontalCellBlockCount(); // DivineMC - NoiseSettings optimizations
}
public NoiseSettings clampToHeightAccessor(LevelHeightAccessor heightAccessor) {
int max = Math.max(this.minY, heightAccessor.getMinY());
int i = Math.min(this.minY + this.height, heightAccessor.getMaxY() + 1) - max;
- return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical);
+ return new NoiseSettings(max, i, this.noiseSizeHorizontal, this.noiseSizeVertical, QuartPos.toBlock(this.noiseSizeHorizontal), QuartPos.toBlock(this.noiseSizeVertical)); // DivineMC - NoiseSettings optimizations
}
}
diff --git a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
index 9d3a9ca1e13cd80f468f1352bbb74345f03903dd..d97b9b43686bda0a95fc02f6ca31b2d07d603a32 100644
--- a/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
+++ b/net/minecraft/world/level/levelgen/XoroshiroRandomSource.java
@@ -106,15 +106,7 @@ public class XoroshiroRandomSource implements RandomSource {
return this.randomNumberGenerator.nextLong() >>> 64 - bits;
}
- public static class XoroshiroPositionalRandomFactory implements PositionalRandomFactory {
- private final long seedLo;
- private final long seedHi;
-
- public XoroshiroPositionalRandomFactory(long seedLo, long seedHi) {
- this.seedLo = seedLo;
- this.seedHi = seedHi;
- }
-
+ public record XoroshiroPositionalRandomFactory(long seedLo, long seedHi) implements PositionalRandomFactory { // DivineMC - make record
@Override
public RandomSource at(int x, int y, int z) {
long seed = Mth.getSeed(x, y, z);
diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
index ffac5b7b1eb1364ab8442d7145a7b4ebde68ee10..ef28df96ed569113a9d61f6ac4b4d84d578c02da 100644
--- a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
+++ b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java
@@ -187,7 +187,7 @@ public class PerlinNoise {
}
public static double wrap(double value) {
- return value - Mth.lfloor(value / 3.3554432E7 + 0.5) * 3.3554432E7;
+ return value - Math.floor(value / 3.3554432E7 + 0.5) * 3.3554432E7; // DivineMC - avoid casting
}
protected int firstOctave() {

View File

@@ -0,0 +1,95 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 00:33:03 +0300
Subject: [PATCH] Chunk System optimization
diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java
index 26c8c1e5598daf3550aef05b12218c47bda6618b..94c824ab1457939c425e1f99929d3222ee2c18a0 100644
--- a/net/minecraft/world/level/LevelReader.java
+++ b/net/minecraft/world/level/LevelReader.java
@@ -70,10 +70,27 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste
@Override
default Holder<Biome> getNoiseBiome(int x, int y, int z) {
- ChunkAccess chunk = this.getChunk(QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false);
+ ChunkAccess chunk = this.fasterChunkAccess(this, QuartPos.toSection(x), QuartPos.toSection(z), ChunkStatus.BIOMES, false); // DivineMC - Chunk System optimization
return chunk != null ? chunk.getNoiseBiome(x, y, z) : this.getUncachedNoiseBiome(x, y, z);
}
+ // DivineMC start - Chunk System optimization
+ private @Nullable ChunkAccess fasterChunkAccess(LevelReader instance, int x, int z, ChunkStatus chunkStatus, boolean create) {
+ if (!create && instance instanceof net.minecraft.server.level.ServerLevel world) {
+ final net.minecraft.server.level.ChunkHolder holder = (world.getChunkSource().chunkMap).getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
+ if (holder != null) {
+ final java.util.concurrent.CompletableFuture<net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk>> future = holder.getFullChunkFuture();
+ final net.minecraft.server.level.ChunkResult<net.minecraft.world.level.chunk.LevelChunk> either = future.getNow(null);
+ if (either != null) {
+ final net.minecraft.world.level.chunk.LevelChunk chunk = either.orElse(null);
+ if (chunk != null) return chunk;
+ }
+ }
+ }
+ return instance.getChunk(x, z, chunkStatus, create);
+ }
+ // DivineMC end - Chunk System optimization
+
Holder<Biome> getUncachedNoiseBiome(int x, int y, int z);
boolean isClientSide();
diff --git a/net/minecraft/world/level/chunk/storage/IOWorker.java b/net/minecraft/world/level/chunk/storage/IOWorker.java
index 2199a9e2a0141c646d108f2687a27f1d165453c5..c28c2583b257f92207b822a1fdde8f5b7e480992 100644
--- a/net/minecraft/world/level/chunk/storage/IOWorker.java
+++ b/net/minecraft/world/level/chunk/storage/IOWorker.java
@@ -212,7 +212,38 @@ public class IOWorker implements ChunkScanAccess, AutoCloseable {
});
}
+ // DivineMC start - Chunk System optimization
+ private void checkHardLimit() {
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheLimit) {
+ LOGGER.warn("Chunk data cache size exceeded hard limit ({} >= {}), forcing writes to disk (you can increase chunkDataCacheLimit in c2me.toml)", this.pendingWrites.size(), org.bxteam.divinemc.DivineConfig.chunkDataCacheLimit);
+ while (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit * 0.75) {
+ writeResult0();
+ }
+ }
+ }
+
+ private void writeResult0() {
+ java.util.Iterator<java.util.Map.Entry<net.minecraft.world.level.ChunkPos, net.minecraft.world.level.chunk.storage.IOWorker.PendingStore>> iterator = this.pendingWrites.entrySet().iterator();
+ if (iterator.hasNext()) {
+ java.util.Map.Entry<ChunkPos, IOWorker.PendingStore> entry = iterator.next();
+ iterator.remove();
+ this.runStore(entry.getKey(), entry.getValue());
+ }
+ }
+ // DivineMC end - Chunk System optimization
+
private void storePendingChunk() {
+ // DivineMC start - Chunk System optimization
+ if (!this.pendingWrites.isEmpty()) {
+ checkHardLimit();
+ if (this.pendingWrites.size() >= org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit) {
+ int writeFrequency = Math.min(1, (this.pendingWrites.size() - (int) org.bxteam.divinemc.DivineConfig.chunkDataCacheSoftLimit) / 16);
+ for (int i = 0; i < writeFrequency; i++) {
+ writeResult0();
+ }
+ }
+ }
+ // DivineMC end - Chunk System optimization
Entry<ChunkPos, IOWorker.PendingStore> entry = this.pendingWrites.pollFirstEntry();
if (entry != null) {
this.runStore(entry.getKey(), entry.getValue());
diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
index 6ebd1300c2561116b83cb2472ac7939ead36d576..16cd10ab8de69ca3d29c84cf93715645322fd72a 100644
--- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java
@@ -244,7 +244,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise
protected RegionFileStorage(RegionStorageInfo info, Path folder, boolean sync) { // Paper - protected
this.folder = folder;
- this.sync = sync;
+ this.sync = Boolean.parseBoolean(System.getProperty("com.ishland.c2me.chunkio.syncDiskWrites", String.valueOf(sync))); // DivineMC - C2ME: sync disk writes
this.info = info;
this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers
}

View File

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

View File

@@ -0,0 +1,144 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 15:59:29 +0300
Subject: [PATCH] Some optimizations
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..762cba15597623f95a242bdd44742d9b892ad042 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 - Some 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 - Some 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/world/entity/Mob.java b/net/minecraft/world/entity/Mob.java
index 70ee86993d381445855ac7e7290da384d6675987..532d71cc1eaee799c193eb43085beb8c5892eac7 100644
--- a/net/minecraft/world/entity/Mob.java
+++ b/net/minecraft/world/entity/Mob.java
@@ -841,7 +841,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());
@@ -870,6 +870,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/LocalMobCapCalculator.java b/net/minecraft/world/level/LocalMobCapCalculator.java
index 9641219c190261dea0db5f95f040a705ba0a3ff9..7ba64e71cfed16f07a9e1283145653745adb6388 100644
--- a/net/minecraft/world/level/LocalMobCapCalculator.java
+++ b/net/minecraft/world/level/LocalMobCapCalculator.java
@@ -42,14 +42,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 - Some optimizations
public void add(MobCategory category) {
- this.counts.computeInt(category, (key, value) -> value == null ? 1 : value + 1);
+ this.spawnGroupDensities[category.ordinal()] ++; // DivineMC - Some optimizations
}
public boolean canSpawn(MobCategory category) {
- return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk();
+ return this.spawnGroupDensities[category.ordinal()] < category.getMaxInstancesPerChunk(); // DivineMC - Some optimizations
}
}
}
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;

View File

@@ -0,0 +1,394 @@
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/animal/goat/Goat.java b/net/minecraft/world/entity/animal/goat/Goat.java
index 6f106f10466440f8e65e04511f67d48f082d703f..15728d4fbe7a12c7a3b94a9ef88e7141b1225fa3 100644
--- a/net/minecraft/world/entity/animal/goat/Goat.java
+++ b/net/minecraft/world/entity/animal/goat/Goat.java
@@ -98,6 +98,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

@@ -0,0 +1,211 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 16:47:09 +0300
Subject: [PATCH] Clump experience orbs
diff --git a/net/minecraft/world/entity/ExperienceOrb.java b/net/minecraft/world/entity/ExperienceOrb.java
index a43e5190c0f9ae14ccecccd5b58dc0e17f18b0a1..06ffba13f211851e8f6d630a72b41474673e8df8 100644
--- a/net/minecraft/world/entity/ExperienceOrb.java
+++ b/net/minecraft/world/entity/ExperienceOrb.java
@@ -49,6 +49,10 @@ public class ExperienceOrb extends Entity {
@javax.annotation.Nullable
public java.util.UUID triggerEntityId;
public org.bukkit.entity.ExperienceOrb.SpawnReason spawnReason = org.bukkit.entity.ExperienceOrb.SpawnReason.UNKNOWN;
+ // DivineMC start - Clump experience orbs
+ public java.util.Map<Integer, Integer> clumps$clumpedMap;
+ public Optional<EnchantedItemInUse> clumps$currentEntry;
+ // DivineMC end - Clump experience orbs
private void loadPaperNBT(CompoundTag tag) {
if (!tag.contains("Paper.ExpData", net.minecraft.nbt.Tag.TAG_COMPOUND)) {
@@ -239,6 +243,28 @@ public class ExperienceOrb extends Entity {
}
private static boolean tryMergeToExisting(ServerLevel level, Vec3 pos, int amount) {
+ // DivineMC start - Clump experience orbs
+ if (org.bxteam.divinemc.DivineConfig.clumpOrbs) {
+ AABB aABB = AABB.ofSize(pos, 1.0D, 1.0D, 1.0D);
+ int id = level.getRandom().nextInt(40);
+ List<ExperienceOrb> list = level.getEntities(EntityTypeTest.forClass(ExperienceOrb.class), aABB, (experienceOrbx) -> canMerge(experienceOrbx, id, amount));
+ if(!list.isEmpty()) {
+ ExperienceOrb experienceOrb = list.getFirst();
+ java.util.Map<Integer, Integer> clumpedMap = (experienceOrb).clumps$getClumpedMap();
+ (experienceOrb).clumps$setClumpedMap(java.util.stream.Stream.of(clumpedMap, java.util.Collections.singletonMap(amount, 1))
+ .flatMap(map -> map.entrySet().stream())
+ .collect(java.util.stream.Collectors.toMap(java.util.Map.Entry::getKey, java.util.Map.Entry::getValue, Integer::sum)));
+ (experienceOrb).count = (clumpedMap.values()
+ .stream()
+ .reduce(Integer::sum)
+ .orElse(1));
+ (experienceOrb).age = (0);
+ return true;
+ } else {
+ return false;
+ }
+ }
+ // DivineMC end - Clump experience orbs
// Paper - TODO some other event for this kind of merge
AABB aabb = AABB.ofSize(pos, 1.0, 1.0, 1.0);
int randomInt = level.getRandom().nextInt(40);
@@ -254,11 +280,11 @@ public class ExperienceOrb extends Entity {
}
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
}
private static boolean canMerge(ExperienceOrb orb, int amount, int other) {
- return !orb.isRemoved() && (orb.getId() - amount) % 40 == 0 && orb.value == other;
+ return org.bxteam.divinemc.DivineConfig.clumpOrbs ? orb.isAlive() : !orb.isRemoved() && (orb.getId() - amount) % 40 == 0 && orb.value == other; // DivineMC - Clump experience orbs
}
private void merge(ExperienceOrb orb) {
@@ -267,6 +293,18 @@ public class ExperienceOrb extends Entity {
return;
}
// Paper end - call orb merge event
+ // DivineMC start - Clump experience orbs
+ if (org.bxteam.divinemc.DivineConfig.clumpOrbs) {
+ java.util.Map<Integer, Integer> otherMap = (orb).clumps$getClumpedMap();
+ this.count = clumps$getClumpedMap().values().stream().reduce(Integer::sum).orElse(1);
+ this.age = Math.min(this.age, (orb).age);
+ clumps$setClumpedMap(java.util.stream.Stream.of(clumps$getClumpedMap(), otherMap)
+ .flatMap(map -> map.entrySet().stream())
+ .collect(java.util.stream.Collectors.toMap(java.util.Map.Entry::getKey, java.util.Map.Entry::getValue, Integer::sum)));
+ orb.discard(EntityRemoveEvent.Cause.MERGE); // DivineMC - add Bukkit remove cause
+ return;
+ }
+ // DivineMC end - Clump experience orbs
this.count = this.count + orb.count;
this.age = Math.min(this.age, orb.age);
orb.discard(EntityRemoveEvent.Cause.MERGE); // CraftBukkit - add Bukkit remove cause
@@ -308,6 +346,13 @@ public class ExperienceOrb extends Entity {
compound.putInt("Value", this.value); // Paper - save as Integer
compound.putInt("Count", this.count);
this.savePaperNBT(compound); // Paper
+ // DivineMC start - Clump experience orbs
+ if (clumps$clumpedMap != null) {
+ CompoundTag map = new CompoundTag();
+ clumps$getClumpedMap().forEach((value, count) -> map.putInt(String.valueOf(value), count));
+ compound.put("clumpedMap", map);
+ }
+ // DivineMC end - Clump experience orbs
}
@Override
@@ -317,10 +362,51 @@ public class ExperienceOrb extends Entity {
this.value = compound.getInt("Value"); // Paper - load as Integer
this.count = Math.max(compound.getInt("Count"), 1);
this.loadPaperNBT(compound); // Paper
+ // DivineMC start - Clump experience orbs
+ java.util.Map<Integer, Integer> map = new java.util.HashMap<>();
+ if (compound.contains("clumpedMap")) {
+ CompoundTag clumpedMap = compound.getCompound("clumpedMap");
+ for (String s : clumpedMap.getAllKeys()) {
+ map.put(Integer.parseInt(s), clumpedMap.getInt(s));
+ }
+ } else {
+ map.put(value, count);
+ }
+
+ clumps$setClumpedMap(map);
+ // DivineMC end - Clump experience orbs
}
@Override
public void playerTouch(Player entity) {
+ // DivineMC start - Clump experience orbs
+ if(entity instanceof ServerPlayer && org.bxteam.divinemc.DivineConfig.clumpOrbs) {
+ entity.takeXpDelay = 0;
+ entity.take(this, 1);
+
+ if(this.value != 0 || clumps$resolve()) {
+ java.util.concurrent.atomic.AtomicInteger toGive = new java.util.concurrent.atomic.AtomicInteger();
+ clumps$getClumpedMap().forEach((value, amount) -> {
+ int actualValue = value;
+
+ for(int i = 0; i < amount; i++) {
+ int leftOver = actualValue;
+ if(leftOver == actualValue) {
+ leftOver = this.repairPlayerItems((ServerPlayer) entity, actualValue);
+ }
+ if(leftOver > 0) {
+ toGive.addAndGet(leftOver);
+ }
+ }
+ });
+ if(toGive.get() > 0) {
+ entity.giveExperiencePoints(toGive.get());
+ }
+ }
+ this.discard();
+ return;
+ }
+ // DivineMC end - Clump experience orbs
if (entity instanceof ServerPlayer serverPlayer) {
if (entity.takeXpDelay == 0 && new com.destroystokyo.paper.event.player.PlayerPickupExperienceEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.ExperienceOrb) this.getBukkitEntity()).callEvent()) { // Paper - PlayerPickupExperienceEvent
entity.takeXpDelay = CraftEventFactory.callPlayerXpCooldownEvent(entity, this.level().purpurConfig.playerExpPickupDelay, PlayerExpCooldownChangeEvent.ChangeReason.PICKUP_ORB).getNewCooldown(); // CraftBukkit - entityhuman.takeXpDelay = 2; // Purpur - Configurable player pickup exp delay
@@ -338,10 +424,57 @@ public class ExperienceOrb extends Entity {
}
}
- private int repairPlayerItems(ServerPlayer player, int value) {
- Optional<EnchantedItemInUse> randomItemWith = level().purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player) : EnchantmentHelper.getRandomItemWith( // Purpur - Add option to mend the most damaged equipment first
- EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged
- );
+ // DivineMC start - Clump experience orbs
+ public Optional<EnchantedItemInUse> clumps$captureCurrentEntry(Optional<EnchantedItemInUse> entry) {
+ clumps$currentEntry = entry;
+ return entry;
+ }
+
+ public java.util.Map<Integer, Integer> clumps$getClumpedMap() {
+ if (clumps$clumpedMap == null) {
+ clumps$clumpedMap = new java.util.HashMap<>();
+ clumps$clumpedMap.put(this.value, 1);
+ }
+
+ return clumps$clumpedMap;
+ }
+
+ public void clumps$setClumpedMap(java.util.Map<Integer, Integer> map) {
+ clumps$clumpedMap = map;
+ clumps$resolve();
+ }
+
+ public boolean clumps$resolve() {
+ value = clumps$getClumpedMap().entrySet()
+ .stream()
+ .map(entry -> entry.getKey() * entry.getValue())
+ .reduce(Integer::sum)
+ .orElse(1);
+
+ return value > 0;
+ }
+
+ private int repairPlayerItems(ServerPlayer player, int amount) {
+ Optional<EnchantedItemInUse> randomItemWith = clumps$captureCurrentEntry(level().purpurConfig.useBetterMending ? EnchantmentHelper.getMostDamagedItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player) : EnchantmentHelper.getRandomItemWith(EnchantmentEffectComponents.REPAIR_WITH_XP, player, ItemStack::isDamaged)); // Purpur - Add option to mend the most damaged equipment first
+
+ if (org.bxteam.divinemc.DivineConfig.clumpOrbs) {
+ return clumps$currentEntry
+ .map(foundItem -> {
+ ItemStack itemstack = foundItem.itemStack();
+ int xpToRepair = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.serverLevel(), itemstack, (int) (amount * 1));
+ int toRepair = Math.min(xpToRepair, itemstack.getDamageValue());
+ itemstack.setDamageValue(itemstack.getDamageValue() - toRepair);
+ if(toRepair > 0) {
+ int used = amount - toRepair * amount / xpToRepair;
+ if(used > 0) {
+ return this.repairPlayerItems(player, used);
+ }
+ }
+ return 0;
+ })
+ .orElse(amount);
+ }
+ // DivineMC end - Clump experience orbs
if (randomItemWith.isPresent()) {
ItemStack itemStack = randomItemWith.get().itemStack();
int i = EnchantmentHelper.modifyDurabilityToRepairFromXp(player.serverLevel(), itemStack, value);

View File

@@ -0,0 +1,192 @@
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 278761647a6095581f8d8ff4f94ccc28b6e9c8a7..6d1a73c319e19dbc17122abb508aff462c4a56f4 100644
--- a/net/minecraft/world/level/ServerExplosion.java
+++ b/net/minecraft/world/level/ServerExplosion.java
@@ -377,6 +377,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<>();
@@ -475,6 +480,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);
@@ -567,6 +723,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

@@ -0,0 +1,51 @@
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] Stop teleporting players when they move too quickly
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
index aabce23007006fe2dca1e4ac7c0657d2a1cae30e..f52e0ba1ef613895c2f21f39da852593d2f7883f 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -1444,18 +1444,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
}
}
}
@@ -1516,6 +1520,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

@@ -0,0 +1,331 @@
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 ee45df82c3328d5cf91cb3e56786aec2d5263641..138de3fed3cc7a4dd0633dfdaf9c883f5f6fbd54 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -307,6 +307,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
@@ -1577,6 +1578,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 5dfab22692947e0e372044c6dca181f6847fc58a..dc91371fcaffc8477b1732b79174e7fb2bf7c6b3 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
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
@@ -776,6 +777,8 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
}
+ this.tpsCalculator.doTick(); // DivineMC - Lag compensation
+
this.updateSkyBrightness();
if (runsNormally) {
this.tickTime();
@@ -877,11 +880,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 30d02d18c3bfc891eb543428143149ed2044fc0f..ef4d526a343aaede08fa4dee48b146f7597a0b75 100644
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -559,6 +559,7 @@ public abstract class LivingEntity extends Entity implements Attackable {
}
}
+ lagCompensation(); // DivineMC - Lag Compensation
this.tickEffects();
this.animStepO = this.animStep;
this.yBodyRotO = this.yBodyRot;
@@ -568,6 +569,17 @@ public abstract class LivingEntity extends Entity implements Attackable {
profilerFiller.pop();
}
+ // 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 88b07fbb96b20124777889830afa480673629d43..d2661ea79536010414f77256332f214d19106dd9 100644
--- a/net/minecraft/world/entity/PortalProcessor.java
+++ b/net/minecraft/world/entity/PortalProcessor.java
@@ -24,10 +24,20 @@ public class PortalProcessor {
return false;
} else {
this.insidePortalThisTick = false;
- return canChangeDimensions && this.portalTime++ >= this.portal.getPortalTransitionTime(level, entity);
+ return canChangeDimensions && lagCompensation(this.portalTime++, level) >= this.portal.getPortalTransitionTime(level, entity); // DivineMC - Lag compensation
}
}
+ // DivineMC start - Lag compensation
+ private int lagCompensation(int original, ServerLevel world) {
+ if (!org.bxteam.divinemc.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 6167f72d1e374a7093f9880ab50e27eda603a680..88dc5f6e6668d802dc1a21bd894f8ddb1e568033 100644
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -913,6 +913,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()) {
@@ -923,7 +936,11 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
profilerFiller.push(this::getType);
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

@@ -0,0 +1,43 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 18:55:59 +0300
Subject: [PATCH] MSPT Tracking for each world
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 138de3fed3cc7a4dd0633dfdaf9c883f5f6fbd54..506f0469d1a9ee58de0e7a34a61a8092e451dcfd 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1778,7 +1778,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread currentThread = (ca.spottedleaf.moonrise.common.util.TickThread.ServerLevelTickThread) Thread.currentThread();
currentThread.currentlyTickingServerLevel = serverLevel;
+ // DivineMC start - MSPT Tracking for each world
+ long i = Util.getNanos();
serverLevel.tick(hasTimeLeft);
+ long j = Util.getNanos() - i;
+
+ serverLevel.tickTimes5s.add(this.tickCount, j);
+ serverLevel.tickTimes10s.add(this.tickCount, j);
+ serverLevel.tickTimes60s.add(this.tickCount, j);
+ // DivineMC end - MSPT Tracking for each world
} catch (Throwable throwable) {
CrashReport crashreport = CrashReport.forThrowable(throwable, "Exception ticking world");
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index dc91371fcaffc8477b1732b79174e7fb2bf7c6b3..ba5a803b3ecd2b76c2d3ffd2dc9ea1e95914dd03 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -575,6 +575,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
// Paper end - chunk tick iteration
+ // DivineMC start - MSPT Tracking for each world
+ public final MinecraftServer.TickTimes tickTimes5s = new MinecraftServer.TickTimes(100);
+ public final MinecraftServer.TickTimes tickTimes10s = new MinecraftServer.TickTimes(200);
+ public final MinecraftServer.TickTimes tickTimes60s = new MinecraftServer.TickTimes(1200);
+ // DivineMC end - MSPT Tracking for each world
+
public ServerLevel(
MinecraftServer server,
Executor dispatcher,

View File

@@ -0,0 +1,48 @@
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 506f0469d1a9ee58de0e7a34a61a8092e451dcfd..b7815831ff1a2fa9aa52e96f1a50a5aa6823ff8a 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -308,6 +308,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
@@ -1715,17 +1716,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
profilerFiller.push("commandFunctions");

View File

@@ -0,0 +1,52 @@
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 aefaac550b58be479cc282f52dea91d4b1e530f6..2877a3229e03285e9ba5ec2bb68e17c9da202816 100644
--- a/net/minecraft/world/item/crafting/RecipeManager.java
+++ b/net/minecraft/world/item/crafting/RecipeManager.java
@@ -167,7 +167,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

@@ -0,0 +1,42 @@
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

@@ -0,0 +1,34 @@
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 f52e0ba1ef613895c2f21f39da852593d2f7883f..9e4ea539afcd07294bdc5018f479e496ee011451 100644
--- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java
+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
@@ -2409,6 +2409,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
@@ -2437,6 +2438,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

@@ -0,0 +1,36 @@
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 8f37c27bba829733fb8db5f35470092a76c83e98..595ebb40f47dd55127c630813813d21d8a1274cd 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -115,7 +115,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;
@@ -1527,7 +1527,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
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();
// Paper start - rewrite chunk system
@@ -1539,6 +1539,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
}
this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
+ this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removals - Fix MC-117075
this.tickingBlockEntities = false;
profilerFiller.pop();
this.spigotConfig.currentPrimedTnt = 0; // Spigot

View File

@@ -0,0 +1,53 @@
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 3ee43ca5c49af83a067c7ffe74d3f2bc6e4a6c9e..a03dced5231ca47abf5919e3eca358c16a25337b 100644
--- a/net/minecraft/server/level/ServerEntity.java
+++ b/net/minecraft/server/level/ServerEntity.java
@@ -200,23 +200,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

@@ -0,0 +1,19 @@
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 e3427e7aecfc4e1fafb38316824aa1ee50c9901a..9bca28f33aa3b3cb8964c06b2f4d2f0a591e81f5 100644
--- a/net/minecraft/server/level/ChunkMap.java
+++ b/net/minecraft/server/level/ChunkMap.java
@@ -1317,7 +1317,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

@@ -0,0 +1,309 @@
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 e5e5d9bc095ccd9fbf1c8aaa09e5c4ebb1d1c920..af94dd26b553b5e64f305135328aa30b6fae6b0b 100644
--- a/net/minecraft/network/FriendlyByteBuf.java
+++ b/net/minecraft/network/FriendlyByteBuf.java
@@ -101,7 +101,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));
@@ -113,6 +134,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 697f690305db56ae5a05483aae37994d4e8f9f83..dc6417943ec339326684323c3ec3d132d55be354 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 398c1733824b689520170de0be94006731afa5cd..072e9b8810a6ccc292f1eb5ffe02355ab4719c5e 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 6b23cf5122fe65b2ad253ed8536658441297e953..e8c0a87cec53788573748b5e900370bb968e3fab 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
@@ -1328,6 +1328,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

@@ -0,0 +1,275 @@
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 ab1dcbe416e2c3c94cfddf04b7ed053425a71806..985d11f0b72858d66ad011d83106730b07e25242 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

@@ -0,0 +1,38 @@
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 680369af59fd2aa36bf1cf4e28b598854383abe3..d415a175ea1e7b5a5bf1149187247dd7b2619c29 100644
--- a/net/minecraft/server/Main.java
+++ b/net/minecraft/server/Main.java
@@ -143,7 +143,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"));
@@ -166,19 +165,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) {

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,15 @@
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -381,8 +_,10 @@
final int centerZ = PlayerChunkLoaderData.this.lastChunkZ;
return Integer.compare(
- Math.abs(c1x - centerX) + Math.abs(c1z - centerZ),
- Math.abs(c2x - centerX) + Math.abs(c2z - centerZ)
+ // DivineMC start - Chunk Loading Priority Optimization
+ (c1x - centerX) * (c1x - centerX) + (c1z - centerZ) * (c1z - centerZ),
+ (c2x - centerX) * (c2x - centerX) + (c2z - centerZ) * (c2z - centerZ)
+ // DivineMC end - Chunk Loading Priority Optimization
);
};
private final LongHeapPriorityQueue sendQueue = new LongHeapPriorityQueue(CLOSEST_MANHATTAN_DIST);

View File

@@ -0,0 +1,32 @@
--- a/io/papermc/paper/command/subcommands/FixLightCommand.java
+++ b/io/papermc/paper/command/subcommands/FixLightCommand.java
@@ -95,17 +_,22 @@
((StarLightLightingProvider)lightengine).starlight$serverRelightChunks(chunks,
(final ChunkPos chunkPos) -> {
++relitChunks[0];
- sender.getBukkitEntity().sendMessage(text().color(DARK_AQUA).append(
- text("Relit chunk ", BLUE), text(chunkPos.toString()),
- text(", progress: ", BLUE), text(ONE_DECIMAL_PLACES.get().format(100.0 * (double) (relitChunks[0]) / (double) pending[0]) + "%")
- ));
+ // DivineMC start - Make FixLight use action bar
+ sender.getBukkitEntity().sendActionBar(text().color(DARK_AQUA).append(
+ text("Relighting Chunks: ", DARK_AQUA), text(chunkPos.toString()),
+ text(" " + relitChunks[0], net.kyori.adventure.text.format.NamedTextColor.YELLOW),
+ text("/", DARK_AQUA),
+ text(pending[0] + " ", net.kyori.adventure.text.format.NamedTextColor.YELLOW),
+ text("(" + (int) (Math.round(100.0 * (double) (relitChunks[0]) / (double) pending[0])) + "%)", net.kyori.adventure.text.format.NamedTextColor.YELLOW)
+ )); // DivineMC end - Make FixLight use action bar
},
(final int totalRelit) -> {
final long end = System.nanoTime();
sender.getBukkitEntity().sendMessage(text().color(DARK_AQUA).append(
- text("Relit ", BLUE), text(totalRelit),
- text(" chunks. Took ", BLUE), text(ONE_DECIMAL_PLACES.get().format(1.0e-6 * (end - start)) + "ms")
- ));
+ // DivineMC start - Make FixLight use action bar
+ text("Relit ", DARK_AQUA), text(totalRelit, net.kyori.adventure.text.format.NamedTextColor.YELLOW),
+ text(" chunks. Took ", DARK_AQUA), text(ONE_DECIMAL_PLACES.get().format(1.0e-6 * (end - start)) + "ms", net.kyori.adventure.text.format.NamedTextColor.YELLOW)
+ )); // DivineMC end - Make FixLight use action bar
if (done != null) {
done.run();
}

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
+++ b/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
@@ -19,7 +_,7 @@
@Override
public final void addPlayerListener(PlayerAdvancements playerAdvancements, CriterionTrigger.Listener<T> listener) {
- playerAdvancements.criterionData.computeIfAbsent(this, managerx -> Sets.newHashSet()).add(listener); // Paper - fix PlayerAdvancements leak
+ playerAdvancements.criterionData.computeIfAbsent(this, managerx -> Sets.newConcurrentHashSet()).add(listener); // Paper - fix PlayerAdvancements leak // DivineMC - use concurrent set
}
@Override

View File

@@ -0,0 +1,16 @@
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -994,6 +_,13 @@
if (this.hasStopped) return;
this.hasStopped = true;
}
+ // DivineMC start - Respawn players that were dead on server restart
+ for (ServerPlayer player : this.playerList.players) {
+ if (player.isDeadOrDying() || (player.isRemoved() && player.getRemovalReason() == net.minecraft.world.entity.Entity.RemovalReason.KILLED)) {
+ this.playerList.respawn(player, false, net.minecraft.world.entity.Entity.RemovalReason.KILLED, org.bukkit.event.player.PlayerRespawnEvent.RespawnReason.DEATH);
+ }
+ }
+ // DivineMC end - Respawn players that were dead on server restart
if (!hasLoggedStop && isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
shutdownThread = Thread.currentThread(); // Paper - Improved watchdog support
org.spigotmc.WatchdogThread.doStop(); // Paper - Improved watchdog support

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/server/PlayerAdvancements.java
+++ b/net/minecraft/server/PlayerAdvancements.java
@@ -60,7 +_,7 @@
private AdvancementHolder lastSelectedTab;
private boolean isFirstPacket = true;
private final Codec<PlayerAdvancements.Data> codec;
- public final Map<net.minecraft.advancements.critereon.SimpleCriterionTrigger<?>, Set<CriterionTrigger.Listener<?>>> criterionData = new java.util.IdentityHashMap<>(); // Paper - fix advancement data player leakage
+ public final Map<net.minecraft.advancements.critereon.SimpleCriterionTrigger<?>, Set<CriterionTrigger.Listener<?>>> criterionData = new org.bxteam.divinemc.util.map.ConcurrentReferenceHashMap<>(); // Paper - fix advancement data player leakage // DivineMC - Use ConcurrentReferenceHashMap
public PlayerAdvancements(DataFixer dataFixer, PlayerList playerList, ServerAdvancementManager manager, Path playerSavePath, ServerPlayer player) {
this.playerList = playerList;

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/server/level/ServerPlayer.java
+++ b/net/minecraft/server/level/ServerPlayer.java
@@ -2259,6 +_,7 @@
this.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.CHANGE_GAME_MODE, gameMode.getId()));
if (gameMode == GameType.SPECTATOR) {
this.removeEntitiesOnShoulder();
+ this.stopSleeping(); // DivineMC - Fix MC-119417
this.stopRiding();
EnchantmentHelper.stopLocationBasedEffects(this);
} else {

View File

@@ -0,0 +1,28 @@
--- a/net/minecraft/stats/ServerStatsCounter.java
+++ b/net/minecraft/stats/ServerStatsCounter.java
@@ -81,12 +_,6 @@
this.dirty.add(stat);
}
- private Set<Stat<?>> getDirty() {
- Set<Stat<?>> set = Sets.newHashSet(this.dirty);
- this.dirty.clear();
- return set;
- }
-
public void parseLocal(DataFixer fixerUpper, String json) {
try {
try (JsonReader jsonReader = new JsonReader(new StringReader(json))) {
@@ -190,9 +_,11 @@
public void sendStats(ServerPlayer player) {
Object2IntMap<Stat<?>> map = new Object2IntOpenHashMap<>();
- for (Stat<?> stat : this.getDirty()) {
+ for (Stat<?> stat : this.dirty) { // DivineMC - Skip dirty stats copy when requesting player stats
map.put(stat, this.getValue(stat));
}
+
+ this.dirty.clear(); // DivineMC - Skip dirty stats copy when requesting player stats
player.connection.send(new ClientboundAwardStatsPacket(map));
}

View File

@@ -0,0 +1,16 @@
--- a/net/minecraft/util/Mth.java
+++ b/net/minecraft/util/Mth.java
@@ -46,11 +_,11 @@
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 - lithium: CompactSineLUT
}
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 - lithium: CompactSineLUT
}
public static float sqrt(float value) {

View File

@@ -0,0 +1,21 @@
--- a/net/minecraft/util/thread/BlockableEventLoop.java
+++ b/net/minecraft/util/thread/BlockableEventLoop.java
@@ -22,7 +_,7 @@
import org.slf4j.Logger;
public abstract class BlockableEventLoop<R extends Runnable> implements ProfilerMeasured, TaskScheduler<R>, Executor {
- public static final long BLOCK_TIME_NANOS = 100000L;
+ public static final long BLOCK_TIME_NANOS = 2000000L; // DivineMC - Fix MC-183518
private final String name;
private static final Logger LOGGER = LogUtils.getLogger();
private final Queue<R> pendingRunnables = Queues.newConcurrentLinkedQueue();
@@ -146,8 +_,7 @@
}
protected void waitForTasks() {
- Thread.yield();
- LockSupport.parkNanos("waiting for tasks", 100000L);
+ LockSupport.parkNanos("waiting for tasks", 2000000L); // DivineMC - Fix MC-183518
}
protected void doRunTask(R task) {

View File

@@ -0,0 +1,27 @@
--- a/net/minecraft/world/entity/LivingEntity.java
+++ b/net/minecraft/world/entity/LivingEntity.java
@@ -1385,7 +_,7 @@
player.setRealHealth(health);
}
- player.updateScaledHealth(false);
+ this.entityData.set(LivingEntity.DATA_HEALTH_ID, player.getScaledHealth()); // DivineMC - Fix sprint glitch
return;
}
// CraftBukkit end
@@ -2666,6 +_,7 @@
}
protected void updateSwingTime() {
+ if (!this.swinging && this.swingTime == 0) return; // DivineMC - lithium: entity.fast_hand_swing
int currentSwingDuration = this.getCurrentSwingDuration();
if (this.swinging) {
this.swingTime++;
@@ -3635,6 +_,7 @@
protected void updateFallFlying() {
this.checkSlowFallDistance();
if (!this.level().isClientSide) {
+ if (!this.isFallFlying() && this.fallFlyTicks == 0) return; // DivineMC - lithium: entity.fast_elytra_check
if (!this.canGlide()) {
if (this.getSharedFlag(7) != false && !CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) // CraftBukkit
this.setSharedFlag(7, false);

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
+++ b/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java
@@ -114,6 +_,7 @@
}
protected void alertOther(Mob mob, LivingEntity target) {
+ if (mob == target) return; // DivineMC - Fix MC-110386
mob.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - reason
}
}

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
+++ b/net/minecraft/world/entity/ai/sensing/SecondaryPoiSensor.java
@@ -22,6 +_,12 @@
@Override
protected void doTick(ServerLevel level, Villager entity) {
+ // DivineMC start - skip useless secondary poi sensor
+ if (org.bxteam.divinemc.DivineConfig.skipUselessSecondaryPoiSensor && entity.getVillagerData().getProfession().secondaryPoi().isEmpty()) {
+ entity.getBrain().eraseMemory(MemoryModuleType.SECONDARY_JOB_SITE);
+ return;
+ }
+ // DivineMC end - skip useless secondary poi sensor
// Purpur start - Option for Villager Clerics to farm Nether Wart - make sure clerics don't wander to soul sand when the option is off
Brain<?> brain = entity.getBrain();
if (!level.purpurConfig.villagerClericsFarmWarts && entity.getVillagerData().getProfession() == net.minecraft.world.entity.npc.VillagerProfession.CLERIC) {

View File

@@ -0,0 +1,15 @@
--- a/net/minecraft/world/entity/monster/ZombieVillager.java
+++ b/net/minecraft/world/entity/monster/ZombieVillager.java
@@ -320,6 +_,12 @@
if (!this.isSilent()) {
serverLevel.levelEvent(null, 1027, this.blockPosition(), 0);
}
+
+ // DivineMC start - Fix MC-200418
+ if (villager.isPassenger() && villager.getVehicle() instanceof net.minecraft.world.entity.animal.Chicken && villager.isBaby()) {
+ villager.removeVehicle();
+ }
+ // DivineMC end - Fix MC-200418
// CraftBukkit start
}, org.bukkit.event.entity.EntityTransformEvent.TransformReason.CURED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CURED // CraftBukkit
);

View File

@@ -0,0 +1,14 @@
--- a/net/minecraft/world/entity/player/Player.java
+++ b/net/minecraft/world/entity/player/Player.java
@@ -1879,6 +_,11 @@
}
public void causeFoodExhaustion(float exhaustion, org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason reason) {
+ // DivineMC start - Fix MC-31819
+ if (this.level().getDifficulty() == Difficulty.PEACEFUL) {
+ return;
+ }
+ // DivineMC end - Fix MC-31819
// CraftBukkit end
if (!this.abilities.invulnerable) {
if (!this.level().isClientSide) {

View File

@@ -0,0 +1,11 @@
--- a/net/minecraft/world/level/GameRules.java
+++ b/net/minecraft/world/level/GameRules.java
@@ -249,7 +_,7 @@
}
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

View File

@@ -0,0 +1,10 @@
--- a/net/minecraft/world/level/block/Blocks.java
+++ b/net/minecraft/world/level/block/Blocks.java
@@ -6632,6 +_,7 @@
.mapColor(MapColor.COLOR_ORANGE)
.instrument(NoteBlockInstrument.BASEDRUM)
.requiresCorrectToolForDrops()
+ .sound(SoundType.COPPER) // DivineMC - Fix MC-223153
.strength(5.0F, 6.0F)
);
public static final Block RAW_GOLD_BLOCK = register(

View File

@@ -0,0 +1,27 @@
--- a/net/minecraft/world/level/block/LeavesBlock.java
+++ b/net/minecraft/world/level/block/LeavesBlock.java
@@ -82,7 +_,23 @@
@Override
protected void tick(BlockState state, ServerLevel level, BlockPos pos, RandomSource random) {
- level.setBlock(pos, updateDistance(state, level, pos), 3);
+ // DivineMC start - Make leaves not suffocate the server
+ int newValue = 7;
+ int oldValue = state.getValue(DISTANCE);
+ BlockPos.MutableBlockPos mutable = new BlockPos.MutableBlockPos();
+
+ for (Direction direction : Direction.values()) {
+ mutable.setWithOffset(pos, direction);
+ newValue = Math.min(newValue, getDistanceAt(level.getBlockState(mutable)) + 1);
+ if (newValue == 1) {
+ break;
+ }
+ }
+
+ if (newValue != oldValue) {
+ level.setBlock(pos, state.setValue(DISTANCE, newValue), 3);
+ }
+ // DivineMC end - Make leaves not suffocate the server
}
@Override

View File

@@ -0,0 +1,26 @@
--- a/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/net/minecraft/world/level/chunk/LevelChunk.java
@@ -267,11 +_,18 @@
public BlockState getBlockStateFinal(final int x, final int y, final int z) {
// Copied and modified from below
final int sectionIndex = this.getSectionIndex(y);
- if (sectionIndex < 0 || sectionIndex >= this.sections.length
- || this.sections[sectionIndex].nonEmptyBlockCount == 0) {
- return Blocks.AIR.defaultBlockState();
- }
- return this.sections[sectionIndex].states.get((y & 15) << 8 | (z & 15) << 4 | x & 15);
+ // DivineMC start - optimize block state lookup
+ if (sectionIndex < 0 || sectionIndex >= this.sections.length) {
+ return Blocks.AIR.defaultBlockState();
+ }
+
+ final LevelChunkSection section = this.sections[sectionIndex];
+ if (section.nonEmptyBlockCount == 0) {
+ return Blocks.AIR.defaultBlockState();
+ }
+
+ return section.states.get((y & 15) << 8 | (z & 15) << 4 | (x & 15));
+ // DivineMC end - optimize block state lookup
}
@Override
public BlockState getBlockState(BlockPos pos) {

View File

@@ -1,36 +1,14 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 11 Jan 2025 22:11:40 +0300 Date: Mon, 27 Jan 2025 01:35:41 +0300
Subject: [PATCH] Rebrand Subject: [PATCH] Rebrand
diff --git a/src/main/java/com/destroystokyo/paper/Metrics.java b/src/main/java/com/destroystokyo/paper/Metrics.java
index be1bb14dca9367b9685841985b6198376986c496..58f16cdf593dbf874652a46799ecfa5c418c0486 100644
--- a/src/main/java/com/destroystokyo/paper/Metrics.java
+++ b/src/main/java/com/destroystokyo/paper/Metrics.java
@@ -592,7 +592,7 @@ public class Metrics {
boolean logFailedRequests = config.getBoolean("logFailedRequests", false);
// Only start Metrics, if it's enabled in the config
if (config.getBoolean("enabled", true)) {
- Metrics metrics = new Metrics("Purpur", serverUUID, logFailedRequests, Bukkit.getLogger()); // Pufferfish // Purpur - Purpur config files
+ Metrics metrics = new Metrics("DivineMC", serverUUID, logFailedRequests, Bukkit.getLogger()); // DivineMC
metrics.addCustomChart(new Metrics.SimplePie("minecraft_version", () -> {
String minecraftVersion = Bukkit.getVersion();
@@ -602,7 +602,7 @@ public class Metrics {
metrics.addCustomChart(new Metrics.SingleLineChart("players", () -> Bukkit.getOnlinePlayers().size()));
metrics.addCustomChart(new Metrics.SimplePie("online_mode", () -> Bukkit.getOnlineMode() ? "online" : (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() ? "bungee" : "offline"))); // Purpur - Purpur config files
- metrics.addCustomChart(new Metrics.SimplePie("purpur_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // Purpur - Purpur config files
+ metrics.addCustomChart(new Metrics.SimplePie("divinemc_version", () -> (org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() != null) ? org.bukkit.craftbukkit.Main.class.getPackage().getImplementationVersion() : "unknown")); // DivineMC
metrics.addCustomChart(new Metrics.DrilldownPie("java_version", () -> {
Map<String, Map<String, Integer>> map = new HashMap<>();
diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java diff --git a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
index fe66e43c27e0798770e102d1385bacbaa90bda07..8c72ac3376ee1ea6f2c98de4d4fdbea91df2cfd7 100644 index fe66e43c27e0798770e102d1385bacbaa90bda07..5aef1f7aa8c614e50b34747456e7d5a3f0045aff 100644
--- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java --- a/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
+++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java +++ b/src/main/java/com/destroystokyo/paper/PaperVersionFetcher.java
@@ -36,13 +36,13 @@ public class PaperVersionFetcher implements VersionFetcher { @@ -36,7 +36,7 @@ public class PaperVersionFetcher implements VersionFetcher {
private static final int DISTANCE_ERROR = -1; private static final int DISTANCE_ERROR = -1;
private static final int DISTANCE_UNKNOWN = -2; private static final int DISTANCE_UNKNOWN = -2;
// Purpur start - Rebrand // Purpur start - Rebrand
@@ -39,19 +17,12 @@ index fe66e43c27e0798770e102d1385bacbaa90bda07..8c72ac3376ee1ea6f2c98de4d4fdbea9
private static int distance = DISTANCE_UNKNOWN; public int distance() { return distance; } private static int distance = DISTANCE_UNKNOWN; public int distance() { return distance; }
// Purpur end - Rebrand // Purpur end - Rebrand
@Override
public long getCacheTime() {
- return 720000;
+ return 600000; // DivineMC - Decrease cache time to 10 minutes
}
@Override
@@ -52,7 +52,7 @@ public class PaperVersionFetcher implements VersionFetcher { @@ -52,7 +52,7 @@ public class PaperVersionFetcher implements VersionFetcher {
if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) { if (build.buildNumber().isEmpty() && build.gitCommit().isEmpty()) {
updateMessage = text("You are running a development version without access to version information", color(0xFF5300)); updateMessage = text("You are running a development version without access to version information", color(0xFF5300));
} else { } else {
- updateMessage = getUpdateStatusMessage("PurpurMC/Purpur", build); // Purpur - Rebrand - updateMessage = getUpdateStatusMessage("PurpurMC/Purpur", build); // Purpur - Rebrand
+ updateMessage = getUpdateStatusMessage("BX-Team/DivineMC", build); // DivineMC - Branding + updateMessage = getUpdateStatusMessage("BX-Team/DivineMC", build); // DivineMC - Rebrand
} }
final @Nullable Component history = this.getHistory(); final @Nullable Component history = this.getHistory();
@@ -70,13 +41,13 @@ index fe66e43c27e0798770e102d1385bacbaa90bda07..8c72ac3376ee1ea6f2c98de4d4fdbea9
- if (gitBranch.isPresent() && gitCommit.isPresent()) { - if (gitBranch.isPresent() && gitCommit.isPresent()) {
- distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get()); - distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get());
- } - }
+ // DivineMC start - Branding + // DivineMC start - Rebrand
+ final Optional<String> gitBranch = build.gitBranch(); + final Optional<String> gitBranch = build.gitBranch();
+ final Optional<String> gitCommit = build.gitCommit(); + final Optional<String> gitCommit = build.gitCommit();
+ if (gitBranch.isPresent() && gitCommit.isPresent()) { + if (gitBranch.isPresent() && gitCommit.isPresent()) {
+ distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get()); + distance = fetchDistanceFromGitHub(repo, gitBranch.get(), gitCommit.get());
} }
+ // DivineMC end - Branding + // DivineMC end - Rebrand
return switch (distance) { return switch (distance) {
case DISTANCE_ERROR -> text("* Error obtaining version information", NamedTextColor.RED); // Purpur - Rebrand case DISTANCE_ERROR -> text("* Error obtaining version information", NamedTextColor.RED); // Purpur - Rebrand
@@ -121,31 +92,50 @@ index bc7e4e5560708fea89c584b1d8b471f4966f311a..6567ff18cb1c21230565c2d92caf3a7f
.completer(new ConsoleCommandCompleter(this.server)) .completer(new ConsoleCommandCompleter(this.server))
.option(LineReader.Option.COMPLETE_IN_WORD, true); .option(LineReader.Option.COMPLETE_IN_WORD, true);
diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java diff --git a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
index b36e30fd4057a938e4d90cb42a2dca661f16478e..fd860b1f3acbffa923dcfd39f7cb6f23cacbd408 100644 index b36e30fd4057a938e4d90cb42a2dca661f16478e..4e29f5f55b9a894099bef6f7c7f11e2a96b02fc8 100644
--- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java --- a/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
+++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java +++ b/src/main/java/io/papermc/paper/ServerBuildInfoImpl.java
@@ -32,6 +32,7 @@ public record ServerBuildInfoImpl( @@ -23,15 +23,18 @@ public record ServerBuildInfoImpl(
Optional<String> gitBranch,
Optional<String> gitCommit
) implements ServerBuildInfo {
+ public static boolean IS_EXPERIMENTAL = false; // DivineMC - Rebrand
private static final String ATTRIBUTE_BRAND_ID = "Brand-Id";
private static final String ATTRIBUTE_BRAND_NAME = "Brand-Name";
private static final String ATTRIBUTE_BUILD_TIME = "Build-Time";
private static final String ATTRIBUTE_BUILD_NUMBER = "Build-Number";
private static final String ATTRIBUTE_GIT_BRANCH = "Git-Branch";
private static final String ATTRIBUTE_GIT_COMMIT = "Git-Commit";
+ private static final String ATTRIBUTE_EXPERIMENTAL = "Experimental"; // DivineMC - Rebrand
private static final String BRAND_PAPER_NAME = "Paper"; private static final String BRAND_PAPER_NAME = "Paper";
private static final String BRAND_PURPUR_NAME = "Purpur"; // Purpur - Rebrand private static final String BRAND_PURPUR_NAME = "Purpur"; // Purpur - Rebrand
+ private static final String BRAND_DIVINEMC_NAME = "DivineMC"; // DivineMC - Branding + private static final String BRAND_DIVINEMC_NAME = "DivineMC"; // DivineMC - Rebrand
private static final String BUILD_DEV = "DEV"; private static final String BUILD_DEV = "DEV";
@@ -43,9 +44,9 @@ public record ServerBuildInfoImpl( @@ -43,9 +46,9 @@ public record ServerBuildInfoImpl(
this( this(
getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID) getManifestAttribute(manifest, ATTRIBUTE_BRAND_ID)
.map(Key::key) .map(Key::key)
- .orElse(BRAND_PURPUR_ID), // Purpur - Fix pufferfish issues // Purpur - Rebrand - .orElse(BRAND_PURPUR_ID), // Purpur - Fix pufferfish issues // Purpur - Rebrand
+ .orElse(BRAND_DIVINEMC_ID), // DivineMC - Branding + .orElse(BRAND_DIVINEMC_ID), // DivineMC - Rebrand
getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME) getManifestAttribute(manifest, ATTRIBUTE_BRAND_NAME)
- .orElse(BRAND_PURPUR_NAME), // Purpur - Fix pufferfish issues // Purpur - Rebrand - .orElse(BRAND_PURPUR_NAME), // Purpur - Fix pufferfish issues // Purpur - Rebrand
+ .orElse(BRAND_DIVINEMC_NAME), // DivineMC - Branding + .orElse(BRAND_DIVINEMC_NAME), // DivineMC - Rebrand
SharedConstants.getCurrentVersion().getId(), SharedConstants.getCurrentVersion().getId(),
SharedConstants.getCurrentVersion().getName(), SharedConstants.getCurrentVersion().getName(),
getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER) getManifestAttribute(manifest, ATTRIBUTE_BUILD_NUMBER)
@@ -58,6 +61,7 @@ public record ServerBuildInfoImpl(
getManifestAttribute(manifest, ATTRIBUTE_GIT_BRANCH),
getManifestAttribute(manifest, ATTRIBUTE_GIT_COMMIT)
);
+ IS_EXPERIMENTAL = Boolean.parseBoolean(getManifestAttribute(manifest, ATTRIBUTE_EXPERIMENTAL).orElse("false")); // DivineMC - Rebrand
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
index 2e7c3d4befeb6256ce81ecaa9ed4e8fbcb21651e..7f3d6dc1c37ffce387ddd04bdd7328e0154b33ed 100644 index 2e7c3d4befeb6256ce81ecaa9ed4e8fbcb21651e..a839dbbb72f48b8f8736d9f4693c528686570732 100644
--- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java --- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java +++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java
@@ -491,7 +491,7 @@ public class CraftScheduler implements BukkitScheduler { @@ -491,7 +491,7 @@ public class CraftScheduler implements BukkitScheduler {
@@ -153,7 +143,7 @@ index 2e7c3d4befeb6256ce81ecaa9ed4e8fbcb21651e..7f3d6dc1c37ffce387ddd04bdd7328e0
} else { } else {
// this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(this.currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper // this.debugTail = this.debugTail.setNext(new CraftAsyncDebugger(this.currentTick + CraftScheduler.RECENT_TICKS, task.getOwner(), task.getTaskClass())); // Paper
- task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Purpur"); // Paper // Purpur - Rebrand - task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to Purpur"); // Paper // Purpur - Rebrand
+ task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to DivineMC"); // Paper // DivineMC - Rebrand + task.getOwner().getLogger().log(Level.SEVERE, "Unexpected Async Task in the Sync Scheduler. Report this to DivineMC"); // DivineMC - Rebrand
// We don't need to parse pending // We don't need to parse pending
// (async tasks must live with race-conditions if they attempt to cancel between these few lines of code) // (async tasks must live with race-conditions if they attempt to cancel between these few lines of code)
} }
@@ -171,7 +161,7 @@ index 99eb04643fce44c37fd96c99756837ccafe7b559..4aef151bd162c4c99a3eaec1854b5463
if (stream != null) { if (stream != null) {
diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java diff --git a/src/main/java/org/spigotmc/WatchdogThread.java b/src/main/java/org/spigotmc/WatchdogThread.java
index 776bc01784b53e3f1d9a35046109c3b9ee4f0882..26a3a0ab93ffd4d0a172e47fafeb26485c8d87ab 100644 index 776bc01784b53e3f1d9a35046109c3b9ee4f0882..3731ca80ed58cd385cd66ffbe67f2eeaae642d0f 100644
--- a/src/main/java/org/spigotmc/WatchdogThread.java --- a/src/main/java/org/spigotmc/WatchdogThread.java
+++ b/src/main/java/org/spigotmc/WatchdogThread.java +++ b/src/main/java/org/spigotmc/WatchdogThread.java
@@ -77,14 +77,14 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre @@ -77,14 +77,14 @@ public class WatchdogThread extends ca.spottedleaf.moonrise.common.util.TickThre
@@ -179,7 +169,7 @@ index 776bc01784b53e3f1d9a35046109c3b9ee4f0882..26a3a0ab93ffd4d0a172e47fafeb2648
// Paper end // Paper end
logger.log(Level.SEVERE, "------------------------------"); logger.log(Level.SEVERE, "------------------------------");
- logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Purpur bug."); // Paper // Purpur - Rebrand - logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a Purpur bug."); // Paper // Purpur - Rebrand
+ logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a DivineMC bug."); // Paper // DivineMC - Rebrand + logger.log(Level.SEVERE, "The server has stopped responding! This is (probably) not a DivineMC bug."); // DivineMC - Rebrand
logger.log(Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author"); logger.log(Level.SEVERE, "If you see a plugin in the Server thread dump below, then please report it to that author");
logger.log(Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring"); logger.log(Level.SEVERE, "\t *Especially* if it looks like HTTP or MySQL operations are occurring");
logger.log(Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once"); logger.log(Level.SEVERE, "If you see a world save or edit, then it means you did far more than your server can handle at once");
@@ -203,7 +193,7 @@ index 776bc01784b53e3f1d9a35046109c3b9ee4f0882..26a3a0ab93ffd4d0a172e47fafeb2648
// Paper end - Different message for short timeout // Paper end - Different message for short timeout
logger.log(Level.SEVERE, "------------------------------"); logger.log(Level.SEVERE, "------------------------------");
- logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Purpur!):" ); // Paper // Purpur - Rebrand - logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to Purpur!):" ); // Paper // Purpur - Rebrand
+ logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to DivineMC!):" ); // Paper // DivineMC - Rebrand + logger.log(Level.SEVERE, "Server thread dump (Look for plugins here before reporting to DivineMC!):" ); // DivineMC - Rebrand
FeatureHooks.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - log detailed tick information FeatureHooks.dumpAllChunkLoadInfo(MinecraftServer.getServer(), isLongTimeout); // Paper - log detailed tick information
WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE), logger); WatchdogThread.dumpThread(ManagementFactory.getThreadMXBean().getThreadInfo(MinecraftServer.getServer().serverThread.getId(), Integer.MAX_VALUE), logger);
logger.log(Level.SEVERE, "------------------------------"); logger.log(Level.SEVERE, "------------------------------");
@@ -216,315 +206,3 @@ index 776bc01784b53e3f1d9a35046109c3b9ee4f0882..26a3a0ab93ffd4d0a172e47fafeb2648
} }
logger.log(Level.SEVERE, "------------------------------"); logger.log(Level.SEVERE, "------------------------------");
diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png
index 518591dd83289e041a16e2c2e7d7e7640d4b2e1b..f54753531b3bf2e8b5377f342465e727c7da98f2 100644
GIT binary patch
literal 6677
zcmZ`ecT^MIvk65y(vr|S0wD$n1T=z3m0m+wF=$9cr3j%}P!W;dMd>0)Cy6mZP(Xpu
z`KXEn5Jf2hLO#R>ih{iOJMX-A-XCxG+?_jjX7=vRopyIq-Cd813CjzEKp-&(dmB#>
z2#omK1bMk5u9dOJxq$DSrHds9#LO1i@#p8_sw8_)7Z51s00<P900RBu4#j;0fuapS
zpfv&rgee4pVB~wP9%fvEpSv^GmJ5#<8XD;69=ACTcmtS27%K}a$75Db_D&i~$_6?*
zP$_9`HFae<c}-<yj44JRp>J<zZ;CcWYU}7D^$~CcQb*Us$V5{^^C;%1uC}hZv5Atb
z+yPa!y}iA0#xqIo1mGx7S1-`9<>|A35u(#^8|4ULRXr{u5ar-vE3hmqE3r=>bw!l>
zCLnNFgew+2R&lAAi)cmJ0#RrDqXICbhyX4Cp$t%{gN6nNQN~z96O4fg24$*eV1O|&
z`24~m`2Pr82s;ya_R9Y+a5FP`iYwq7063g=aRI@(eL)aESPJx4yI}4K0?UK`s+8LU
zIf51br|${Y`EMQ`5Qs<mfBCt5e-C?Z`z!MwsN(s<7zC0<JJ?uaFVC#cu3Aws5}-NG
z#qSfoFTDOGUf-K~9^g=jE=q7;L)~b+>-kkkt%z@DqvQS0OciO<6(B~X-Ttj8^Ly;I
zo6TV6_jdf1w>dz}4f>(bF>w9Nl+(tmyuNjboV5a{jFW#sdhZ3z{C6FC!V#*o?@AZ*
z6@#2M7W4S(D=_e$&8q=XmdM!qgOR%?ntYTjPFBys6aK5aZOW9A-@mVhM4$Tn#+hCB
zNpgxYSKw4B-@=Ml8HJRuwG70o3_~8YcHFp3NRQPixJk)8jWlBG`$)0fR?<9ouc(Iq
z@M>AWUQmUPC;T+To4^Nb6>2S#hFq7L&p%!1Cs%tkSst0NNYZm;6BFuVg$q)J!)F7(
z%(e_;?{knc?~C+ODT}S?y_c3y-kj+)Wgt5{`{U-T!|fUc+rlYhRs);U0u{fq@D7>$
z_>Lp=enScNrA5b3pV^mFIh4g1^)G(S4aMb`J2kRvHwN--6UVxbA8uFjF<}pE*7ZMK
zD7IlonkOy3A<Gq)*8^^DhO|fj1e6n%mInf-NeT7s>IJvqJ+^v3B{iHk+09aQ#>kl{
zmaISJQBQP<omSvWf{7uu*5XDx53JPMJ0a~}H1qN2`n|VJkuP6g>8%5~(PD4NTU;H%
zN4-1eLAj|t8F9I*tOJKM3*6eu_ik{zyQXVr`+F=q1YAwrdHH=#%BbwO{yyyY;)#O9
zGoK`Ujx6-fNTj483E1!FGtYVz6zXJkTq}>qH=7wK@z<-uMz+lx_|+jFzKR&rwU*h7
z-SX~-k+=i6A(lrB*0r`9T8GUNIhfO&-z;_$ZArSIsvPp?xN$s|$dHe^`OM^F>B%4e
z+B+^26JapEmg)E{;0#))&Eg{uHb-Q`84A;T-g<0_D1txOzm@fAkH7Bi)a>I9KNL*w
z8u{ixFO<d6eq$7K79U3u!zI^5GP{n$dMqSIV5iE99P4Kuxl|Q@3jB4S9J9&uFowIV
zuZ1z0Lpy$$DSnKleBNHnRm*QJxmm;_4$t*I3Gb&Of&3$jj&zm7K2>8tyq?{r4KmQm
zSNiE?)c%L{xJxhP4&5oKhr-|T5c1%mU!3b24|v+PPTx7XiKE<3_og)W8hwd4bQ{h>
zw@BZ$Vn;F^AsxsUQYH4)WS37yHJ(jv^McSfJ!KYWI{j#p^1Z|(l4aXFHm%b)_D;p6
zeK-F2{zQ2YFT{AfE%km<h_?NGr@1u?!TOnI5M<gb##aX$r+1HZ8HN4KrS0>cleZA9
zmujwY7rUA^wck?=KmRZL&VyCf#rO}){K)5E`+yI=l9Y}ctF9gtg(oT>q(z-%>r+DF
zn{-;VUxR+9B~Sb8RDV(I_k9?;D(8Gj$fHRTu6IN%?`EkCa{IH0=Sw41*UgZwulPmn
z)laGv2^e*bcaeZY?uLkYS|UaAAk@XKvKj$Q#dtIDN(~iqeqPuo)DqqwP}x9whzk*E
z)NIrkYyrM~c0&+-xfVm0sHynpwS>3uWK3zFR@OKpKT68yUK+jEWMymEb@OX(VqRCZ
zco5SyxoF6ae@doaqTnW6VQ3Jd$a`kjNV=eO@Zm$xZF6G}7ghtgdVi5!%XnRn%eXw-
z5iK<2&Q31*PFo0_vOm)B@jz8@r(e!mQfMwD=&?h;ZzRnDPg}ScJk3G;N{Twj!p|gP
zZ1NJDPDRo}kV&8^LC@`mm!?g5{Tm`pfl(A^nzA4%Aly)})h>skcaj#dh-WUB+2v)j
zr95b|Q+IN*So~Kd)bW>BXBm)nA4YzIBN`l>!5-{FPw;~?1hk@%>!qrYPf1$tE?pFO
zR(1GIYDWAQ2|+onsA2wkJGv%3*?Z~)U_KQDSyW$#ffv=J6c6A``RiloHWXzl{V~&*
z&V~<beeir8tL?j+irWnVceLgZ0`C@x^;0+wfOnH`V)NYzqazwz74*_jPL*9kt=}wr
z7;7=8Ne*=sGBEMD)g%+n>V*Q_`REbq*sw5LhB1AB)yLbGR_mdQ53v;X9z)~53wn#^
zhY>6hMd{+ahRAWu&JX=eM<CIkx&H;y^moZGD9?kzZuw?|$td~_zbcR0?CHRPdi$h!
zHnjY(ZCwNtgG@tba>}xe;S4x+E`U2F-MVhwq3$bl6tAdP#!*Q#rrb<ND@AdyO=NrP
zQg@e5-!@^u1Zjf!ooy%2zGaXzMBM~}vNwYS*~YXfAF$pidtGiMd>=PvH*R#*&lq@s
zX-}W#0!mYyVBv!INAOqqnnSQTPBlFE`K%FwcSl|yCbF%4rsak5(c8l<0|B)Wcnq5b
z;qZ#jE*)l^din^5G{0FHZdjz6H_Zrec>!FyViZ*%hx6hIKAA!_w~WU-FWRLUK+M}s
z&5}N$I)jR>0Ig;`n;K!5sc^81J5~A2&&QeWdELc>{Q7I^uvg7OwuOV?sn{?c+$)*B
z8QeC$v1qV4G*@HNZ_CAf((f$bV#JG!Hl+XLiK%Y#@}Sie32{*PFZ_*S1y+g7;<I+N
z?Un_R^Bby}!bJ4QFz_v+7xp6d9GsoPHioeVm!(irds4Sz|LBjb+tw>i{{F299LdV-
zt=1$T@Z7b<@1rPlc1ua?PK5P~ih4zQIUB|H=+IdkHnFWElD69}f$R77-p1elK4(L@
zKV-kTwe@F|x%E39IEPG%K2+FJ@fv&4&$-g`BnJcOnb{B_t@F`}n$J(hLMf7*<_?KT
zQGAry`2+CeXtPriR0G&2@TfhTq?8ToYlwWfI<POeX8cdYVM@(B&|ewHHvUFD(K5+F
zSLFI`MtX$P7Cl%&K8V!KFP+Q~{H(pH(rfpYLC+$_FUSya6Q67ipE5{az%?&sgy+?u
z2rUq8f_GjVJ3>jk9v_?J+L-R5aa8nyhmwNE<XJC1>WVs`qQVt|6;3F8s7O6OWRPGL
zZA@%BSq|u50S>~t9apT3%Ds`89)E=-_d3~pj+{CzRza4tq@^Iz(|;TZD?%b8UUnLB
zxPrC}d>`1q<>4_}sHTa^kjhCF6-jz&U+?my5q-yBP=50^sl^#56D&Jl7LO)hzh=`s
zsyB%5$`rJuZ$%&Q9%15n&C{07W;yq)H6sAjl-ep?><1=2&7Zxw#I<-6L@H<J{x)6g
zC+1cffxU?Wj_5&G*509Kn=Cbog#Fn~acsOCbfiXnBNFkTD9x&HUgZG~5Pgt<9zg(~
z;Dw2aEj#j7`>!fhEC7b^>|R<>!C<ifRX_Rw^aGEJ;e+J1$$A~!y&x8Gg^<34sxtC#
zS~?2|XiN?y&OGGGJ@oKLh<GRWu3a>4mhUdkjh+LNZ%J|%ty%H-cJRe6Y;427PH?td
zdXro(qo(HkAzXhi1D?grRmzh67%+V#iFBgg?hb+`wT;M%US0r<sjnXC6AmL&mYQ34
zwSkKi2cSClhGKf~{JYzCCm#5PWUwQ|erGd0>uLy);kyxtm;>YYP2JXBAWeEP7Y^my
zYXNvj{uB>TsCR$jfy?hh`BrE!wOw?Qd_WyBz~6V{Zk70k0M{k#9t`$TIO+b;c)nnK
z+`gfns;r5?3FZus4z>uGbxZRmvaGm%{+cmUAj7GYVqlP9s(zdmq&N4SY%Gz6syrf}
zKb7Wx6Kw`vB|d{3&e!7-J1N#+rlVNmDnNQ>9N*h)Ultw`Cy5AS>tIK_t1~2VehSRN
zOofI~k+m&ZrXXz92oC&FOaNTEnQz@~e19ssc3R?I=*ckp{xp)!dq(uLmRd9sr=MEW
zu5&pge3Wsoh7%Ga(d{2R>2@q0e7RT+VcUeahll^`d~VMbVD^9@E>-t<qeUC9RzU>X
zj+T|~-zErreB@U5m64RGN^2e1L7=@C-;_@Dr9>~I2)Dfw-Ioa4BOuzR%-7sBV2v=Q
z!P7RMtN@pnyHp8wyb536D8DO48TO=TxlnZzmPRd8Y-_K4$4+X9DwXrsI>f`<WG9jQ
zL+o`yjvp)6^|&F|b=n)arYeI#aZqtfGol`d`cG2Qr~Zwn_%CHEM9{*0Pl`hqJek){
z8Yg*oL?R52OdH$LP`7A|5j4LDSr<@Ug!NH^v$SeFOZrm0gKXrVuJ9vXgbI_kui|YG
zcO8@mBkwZsv&y|e@*237`KyzUmjPi|zx<~%DaL@Hty{DV17D(+#^&BNH&RIl$`Q`}
z^G=rQ^5KREldo(qA)rYz{Zc1{)*x+t2)ZiVfRFEwnBq(Lk3#ALQvuI*tDd0K1wAvN
zhoNi2?LofnBpb$)a9X7#^){pGgLt8oeVDvXIy>?uWiW*uF_OqO=E=V+Wc^KhHSdWr
zZm9Z+ED>0IGDwULbEkdLg%_?>0E^dIA_S#u#b6!XKAz*#3N@_;`FcCO%$YLU(hKeq
zMd9VC`hOCczshK~gG~F`Xb*(NhH!yFRQD@U013Dy`?Kv3u|9w#?Phx3=kjn{CXQ-M
zV^+}wN>kZ?P|~>mfKJa}W{T962LH}njNYD;X!_XwFCC*v(aR0~y1Ri{?1&Q#vV#Dn
zQc`3~%sl^hfE}&7Go_l3TahgQja9sPVj`ES>e<f$UZ1zN4oAs|j!iy9#8EhQ(OZ&q
z(<QGbx5Ud1k(f>rdt*vs4pmt3^Mvq(QFQX(-a`>n@lv=SVs;4kaY-sY6PPep8F~-g
zQgBMDVkT*k{{dDu4E!JD3b*_)m}D9f<@S;j<MJS+rgJ?MQJ|`7axsX-bMS{jexT0q
zdkH`$oxDV1=FY59!6MO-*CL%*s4RtFB`zW)H98(K&k)25=t5Vef5AkD%m&uZoltQk
zf$3(n$|&*rbv@|uEcRZm#nSm6dEt{1Ly=2dtyeSO>Ti2xsp5R_t_I-XImdpCvJ)v)
zw>Y#Hk4QbRbbgVW?Y{!Yb<5DS!t830X1KQ|wBM>M3h?^F^!@k4LYR)2&%Dq<HkMWi
z5qUmuVR`g5=|aRGk<t!ZJzr@dK-kAy7heQ0!eo1_!d{%x>RD??2n5d!c1yKT9OsEZ
zFmFEgOx|Du`q~L)Tz_7=7TMcT5a?b%g2~5z0Of&)uKSow7U`*^hX(>|9BZw)f)`po
zU`f&8rX*1CW>D{p!vQ<mI*!GSNKAFCM*d~zP?JPP;}*DkW?fSnoIbL;hNAOK&ZMDT
zDV}wTxL1Nei3_*Pa$>Eu0Fh}VNxE7|Svvo@a$T%B^jXpq=4+Y0+~$uO2a`<hke@gJ
zDe1egTQUeUKexw0eKeKr@1npX9%yV8f5|MglSj{$RS~J+jZpdiYGTb82EA65Xdq`0
z-&B&-WJ<ibEVFCy024saJ$yL{{f_eZO&~s<)VVC9;H8DV0x%V?NjN=+5uS=dLtN2O
zG-aaLY?2wmP+-r$N9q$ld1wKs^)f`f-3s}vD3K6doTBw%&fHCAh*XZw0L%-L*Z`CK
zCK70TKbFuN@mYBw4o%MCQVtemXkpDz&<l0ljchYOb7Upe8Bh}Rt3(n1xo*wO&!4Gk
ze1KH;>1DbLZ{M=x<2ZLQ&Ob8-J3X&*xUTe$D!E2I!8j(atSZO62<h*-u57{9OVje(
z<A>+_N-WbxQkJyi$~6X4Z1+W86N&e4c>?g{XF9eX7*0hyBh_omBt^uQ8Gj^-Z3+_t
zs&jo6z7eCV{iE|FMMRe`YyQwH3J>fXEFWYwI3Lbsj4t^DpPuUAv<RE}|9U-B!<7c)
zr3I9fX^}4IagFtUD!YBSlfvl&w1tK+MK0YHZXV%}8knA;@&vg}PoVZrTtL}&Eor{C
z?!_C=4)w`ZO+vNv9Z~<z+PaLfXa;e8kksbVi77qXx3Is~TG1czOORd<goQ~nTx&(R
z$#kbjLIWDhH)YI?@_58WJU3uPzU-%d#D}Q$HoP}J#;vP?>u7D<Nz4|a_+el5De&Br
zSBxD6Lt0y0Fa6f8&uB9G=yjQkr_LawCEsm{0>91siR*el5@qzBKGX1L3jBzot|R8f
zO<UKyfYMBU>ghP<*WXDf=oRu9qax~wuD6^DLnj42-NSs#lY*|+n00Y*Z`OgX5Qjc$
z+aWFtdZ6+jl}9jY0+gQYMiszi-#qN<%}-=}&^<ob<lfB#YmcJU>lTBZK70*$9|}P}
zL1bvT9F}?m$U}qNtBKWS6X<v?^7eSxQ(@RiXt%EjKwE#;ciFUX#?!4kXitZqi8~3V
z>g`>ml9>Uk0L^XMD;zOX@4<BC!QE(p^{V^W-3TpWv{u_PK3`8V7gSNgGR`Yd#V$z}
z#Vw`rF(sy4O+1*RLn4HiC8(=#4d{hu-HSo$xYIfr{KAD<OSQk2NNtgbD{oJ*Dy~}r
zry;DMbX(>%$w)>L$Ho$IA?Ln7^Ut@y=i<=6`!lo*YCm-mo`gO+r4}D86(0j*eZ|*J
zOEX6CiHtdGgLpuV(gpCsbbs<8PVFrb=Czaf7+u&q4DQqR2biXkUIqtapx2+Lr9mpc
z0%M2&+DG*AOeiD|fp{D0)GN<c2f`^}&h}wx>LPKrB#255Aa)+Ll!u!2!~;-@IA{9`
z&twsmLc_lXsMexXDC6^Xoy&<gC+kOnu`y|;Ywh458a$-LLgl*~Y<)O+VbHhH_s5qV
zJZNaRckPc1?Y>hN#To~4`q$pA97VW-Y`pHkQI&LN1+{Psu+33s53Tzx_I~=c<hbZV
z_I%QeosPrb0bxjYP}TPJf^zxh=^uhXVftqBIP<d$ufD!8q%*h1@N@=cQL5dETR74`
zmX+aXZdvGe#xKMh&f_GUiu(|mqhogLKHaV*rvc_Z`k~1c?f$he`Hun{3&6PX+3=`X
zSIVKO`D4whxPDvaj$GO#UdZiE)U7T<#Esv4J-K!(D>Z51O5zD3q|%l{lPufGVQ%>V
zc9Jjc;PWozkX7+AoNr#-!27Y-gJue*2J#_}KEyrvs!_jGXN4D#R}7vb77W=SUZ6Gs
z7Y)KXZ)A=Tq#u5)I#Nkocxpv^o_H{6Oa?Krs5W~x0i89Q0W2V}7T+q(^7^6=>EO#W
z`DpX-^DK4qz{Ir-et}j+Xc=(gmYnT3_kZw%i$RC-!!A91v3jnPs4JfsG&~GKU@Uk%
zENNX>DcG=i<<A{#Gp>rB<}b8O6NIoLHgvK2Tj%WZ=ep`+B)qH1538Kw(zLYpwj?RL
zKQC*8IZKJ85gXf<j|2Nyp3R<&D(BTxKf^kV(P=f8RcQsVEVKq>`D@XmrZ}z0B4$-%
z#5u_aJlT~Rz#nDlIJ6PugYP2<a;j&l1;yBxE(p0itkxBjt)3PQrrZv0!!`H4tL)3m
zSfXu7!pS%ESZl$xwsneAF%QX|^e4l4DcmA40aC*Qe4;#+@E)^e{$$W*a_qYzqK|Z?
zc?en8q<b`VGCwjx%4Y-mA};JpXnNgKm!S5Fzn%{{CA1*-C<JjjDuvxHSt*s|467#M
z>0>(80*@KTjt2Lvz5mZ0M7$)CcUk@p_s$^h?o_rF$>!zEoV+I-e)}5CY2o9PEjay*
zV>Cj8ZChL}gx7qpb>?}aNx}GS69W2l#$e=$@mq@2rNQ3ZaqlTtH2F0b9YVEg_&cmp
z9vx$cf7u~q1PkZir56Xw60;6fM=X)hnQ`bvgB}QZiFos!aZPc!EHRvJhPYeZiG3_?
zjZbnKVSm#-9*)S}?Zz7Ix5mdiDb3_8pG#x{I61G8qoRfu1(?S9zqVOT5UPa0RFVoy
zxGZG6EN57Ym|95?5w#v3susU+2$|LdW!O*>lhl?!cqW?wb$~FN*e&rbyxv*?dCe5X
zA3X1$($YNfAX74Uu7Tv&Y0zVaUwg5SyFa7>J}6Pc<8{{Dz36a2cWZ@ziU|3oYtGnA
znJD06B5HU9wr-RKbRVXY{N@dMhVhN*V%+a3VjRb0wX;hVazYu=%el;UduXEp%w^7<
zb|+!8yUq+Ya!HO6tIB5eqD~poR2<piLa!$zCim9_Emn~o0E>H$D+@pe77pwERgEIA
z0!|y>AQ6FFu;Cr?4;OGC36S8`-RHRs!ojv|9~nbh^^c7~^@OJH?SB5}xeQZzNnGTp
zU${G$vNFg^JlLjxT2*m!{P!2zieBFsmDoj7By5jYgbdVWx_kcpnE-OIb+w^e5#s*~
DA-Nv<
literal 9260
zcmWk!Wmptl7+qlLS~|W3b}1=IK|*5b5@|#_l<sa=8WvatrA11R22nr|NnMaG>0AUP
zC6t~Ie$33hbMG7HJ?G9mbDv4n)lnlSVI~2AK;#<g%KEog%-unRcYDr_v#bVzaIbZ>
z4OMQt9~6LaN1#s_Fh>FQQNXigV2~Fm&;xWcfNA!dm*#+<AE1{FEHmANcmS@U0MZHA
zq5{4N0?jhO^GKi`0eA)ic?N)M2w;>B)G7nz8bF6QFw6s>Er4EOK&%?bF$4;AfiW&%
zoCBC(2Ns!cigf^wAiz2NZqBnLz$Fx@R=#VuNdgNjK)EK+fB@F$fJ{?BsqoI$ED5Mo
z1rqE4Uti#zCSVl@%tLSX$$)HQ;Jq4<X9&m@1K;lhU82An{k!~!c!1|oK)CCj)k`zL
zCi=$D8*m8&O0@v%xH|}5fxyT;;EVX3!)zlU#TwAa0U})iEG^I@3Mdu=w$VVaJ5Znx
zSj7V}Wq?V_T{5lGcXw_}bc^WLZL$sUMFN;)2g<a7J|Vy?5x6baE%sXz_dr15Es$k$
zH?+hIv`PXo4nT=E5bXeTirx7asks}vHMw<i3qi8{cK*!=xjR3)FK^sK?uNFh?r<p-
z0by=;T_3+YjBO7Aw-6xO3Fs07Y>~ho`CY^a7vP8(5UvMwUftX}AK<&Iwsa{VUUgUh
z2@c>vB_LZ0XlDV+Z-B?IZf;?2Q{C)P0>ZVx9Q3a7hXhz;0*3DaKX~ub_6P=EnF2ok
zcR7!90-gbPNmi@e3BV~F2=oSCMBV|pg>WmCTgLr-01Q8169d>q-)SS&0%(`GBd$p2
zE<~Lo5bOy|!S8arrBXcyc!~mEJ_FLt@08Ob4a7eO9#jGH#Xy)lfU>@0<fH6e8I4kJ
z7MX4=67Dc|ivYi90GW5dXURJT1sd*9ACdqo3^ytTfc9&kQ65ONy_4K20id4_#Jm93
z>405w;9)s13%z-g3FI09k4gZC@SEGh21MSdMw@%zE`WMpeH{Z3F$F%s4K+W4gOWCo
zM2#hp$Mq4nbl;~?VJ4<NUuWsASJv?DFM7g4C);&i&IVdq%(iQjnL@27^^@Jri6QaR
zg+BD=^Ns1jwlsgwXL_n9+x5BrdaDaxQ#=io9-SQSHw7Gy_Sc0Q?ybyCzcPDry1qJF
z^cHD#ygM~9^trw`H{4lQRpR95;QQidQ@uT1O_dcTIT>luX8W7#1E`a&x!wY&zb88l
zN1p;u{w(({h5e>J1%Y6K8p;U6z`4mh7wrra#_v{h<9beb_Uu_ssLuklU5mIC>bM*t
zcnDp3!57GGcIWN~=GwhPk`|qj+4X29PCWJ%!mm8dv^)i!1KFLpM5tu4Zu)l4x1`+4
zuool8`RpVod-L>kH&(y$T!#xcuSSC206r^ApC6SB-*ez^5f|E=>CVr`YArBlJ*aH=
zv9&F3YdaKfe*MZ~i5LpP{mi>QT}i><&#tzbf_0y?pPchedeE97X-j8))~zv`+-R^c
zXW+`~MJv5ye2+%Kvb|-$zve#6Fq3j>e(Z$inlS;)z#xljVJ?019I=wkGZKCb>mY`{
zC8KIq#mXl@3vR}_b~1^fB_&=iJ$$n&3S*05tirE<8!l{ZZCzis{#|hXxvFTM`o}iR
zq}ASGAx!t@bKd6MjeH3iBEIB}%Yan>#e?6>$^PrcHJlA)z3Hwi9`j3t3g5m_#CTR2
zJWL`g(S4CEDe2|vYOlPr-diIV^oy)GsZk29-<yVVGHbejzQC8^`{V3vch}lU;GSV)
zWUEw7*#_T-ft2DurlUb6Bn#+45v>%}jHck!wdB5f==uk13XY9^5>Drj(Jal(oLc`8
z7D=J9cm#rVYK(uzdmUKaOiVbY*(WAOkmLNmxVRVy4%oluYjcE3ejCZtD>w+KsRMI;
z87X<1i$@!2V<|7#NM2W6ZEQ5}eehW7L)rSeirL`4wOgYhpON3G_`a-$K8jR7b1;WL
z!~?6_@enfHT1uN@893H{iZNi1|9834^3*)D`mGffWf%2a)wvAK&u>(jHANwD#zmPX
zb+%6usxsHvd2-@g4UX8e(%gfc=yCIMYT;LE&!w^Hm;hjMmbIls&Ko=!h)JjeBiK7j
zJg8+Wwf=llHxatzP37JYP2MYV!uiXB_G}g(g)9DJKdnb9^WJMK(TfEmW8+Fb{$ocI
zd<hygvdBllzJ0kNZASu33Un4&+r&~a)41eJ3!MhXcjbDoUN=&oi2g{dRXK=@i<6J9
zoiY7U_z35v8sReE0DX5hcZp14VF7*snLdQ?^x(}~L&LN5JQarEK;d~?atxJEiW~(l
z=6JJhIoF7@p*hml|C90`zF53MN}Wuxs)hXg-8cCHJ~aNGn^PR|nyGBlHZgx3X0ANi
z&liq2M=md)gb#cnx8QU4U}JO?YB^DzOO-gVH*WR)5<<<%N%zr+`n%CR-=wwxG4FQ0
zK{o06w4{YkYmAK#N*SLn;A&pufHQYdTJ-WNI0uh&x<siAgQimDUgoBAEI5rJAT9qX
zypcV8YFfqfX`y?AafaQ3n^mRoNoK1CdWSpGnvZW)XaS)q8lQq^6DYJ!n1^u~c_SM*
z%G`v6J|vk-FH!z<_2x&>_IJNIpT-3}l*&5tlx{G{r<aPm*zC(^CdA2!QQi|d5PB(L
zh@XxXDHU1rG=h}Ti~yF=QikEnK1jU~&|;}G9Knf;rYZQk+Uup_agUusdU0-U{!*aN
zR;9bgf3oK3O%cVg7x%pq#~u9dHXR}IKZ7)6*QDba1>8LcDpgZGm&_LCN*L6GgC7m*
z9Ckq~9^@3|Q4>gQQNDOZ2HyVd9pW<)EoE)RyU2C+kH**{1?C-Xq|NDRXjCBSZu!dW
zkWoaF%%=W+tXxD?vrJiW1>QdCcU?IwSAAVKXSF08Ri&so^yCRhU8OJJ-7;U}%kOXh
z;uh`2naxh}@bu)!tqCu)Xf)+K3I8Q5)ZcBvHOp43NX8R{ud%yohLd|fFsJPE=-WnM
zy9)c2e5+K_=dT7ym;4dn(y2MkPN*C+c_fH{ZfA<eqZ7iXr)ku8csPhEA+Akxi$KAg
z-h3<Y%z1#ZDX$X<a8;fk_lC)L>Wh`@@h_TYs$2*8y!HC~F*!SDduQi((Yakpx9^)x
zJx6lr@C*IFi6C32_c%iv6B`G$;M6Q37L;6Uui3x9r{WSzT7DwjzcfM?D1LbD#A$qd
zu4>LOEHC&2!$+8)#A2;xEg(p|Jdy(=RRcM>kUoYG*Qz;+&oyU511wbY(v-jRqxsns
z%#|?EAim6T>_zCj2<-iPVp$G)<1~m`qSX7m3`(@)$3!@_Il;X3RXlkq+00DbtS7gY
z>#I3K0|TFc5y9cN<3t=oP_kgwm69oEvtnYz&nRnvO7Njr5W~StAj9NIY?n)l*H$Iz
z2YURl{gS{bBrJXar(<X`b+qmA<Hz9ybx1QJee{cc;4t%vmR7QAMgxf6GEt6F?BBy1
z94Tj)f5Zt4qg#QtIdG@A*TWX=WKtRlsE@3m;%fJ$k(?qoOYs)gBAFQ111+v<*N4~V
zZ_FNe)#J^uTp*^u#n~J27r9bC44USao|ue*#!;>$8yfT4n#w=5%{AEV-@Grkiy0_J
z=#<qY)GB#66BSj7s#u*(E#Rl7$gh<(?x09V`bqa&5GwxOGG&RQbIkmkKb~RheM`F8
z(}WfHETX8@gZc}jzLm7NRwGg;Edmp-T8e7-fB0SGQS$kJC=*D`BS`u0znE`o9E9^m
z`mI&W3YjJr{hOw{#_fs?j;M6wbDl3X1c>2;?ULHsk`lZB<ca+B67*4=c=+)tQdJZv
z6pk9`nxIR=8QaMz^7MW8O*Gg3rCl71KFqr>!Pq?X9XYS_xO{hASO}zKeLGkV?N1%z
z>{sH;{En>vxtZU%K&AU5%Gwj}B-+Pkl=AbytOz{;6ed;B5v9!jh)%X6>$P18-6BW0
z9}ExHska~pvMsOcE?mMPyWj`s*pbbrIhx_ij%6Esl?wROHn#vuvN1k)+M*(8X8`A{
zS4o(sjn)kE#;i6MtveA?5(&g98!Mc<Q@HVtbelr4nO2#M57ZVI|LPs9)e=Z~n%sAc
zkUYOyc(Eq^j|gw+1Hq+<SGO#-LgS2RC|%bq8Ad#P3F?hy0EblKib{VN=wp|_NDX?V
z_KIK+$2K@#Gk;Y5f^~~iW>r!J5=}Qa@!L1e14aJEQmcLzXKl5nn2bAJ$tZtP$P8Z1
zZ>}d+7jWYR^n<^KOqhO^N==PYrD)O9EEFNs=im5ICPNsHVP!Zx`PfqbpT-5=sn650
zHSeafmr~){Zr!JcC1%$s2t+!}=}Ip+y3BYtETmoWiR}1P><_9ZZ0FT%gEZStrgdbp
zI0aw6jiD;PvU!g!GH_nZQDTX%5h%9pk4-fdm}0u~yzd;=Cni~sWY3r;O}XL;q&8-M
z47pHP%S*mY4oBx}PU^}#j%4iThs7lM7N=#@Fdn{XdiIW0L(=<T>C2~Fu=G5&Vq%Yr
zY&qWfrH35E^L#BnOgMwRc8B)xMX+GlbUbtr`nPrR=jS(Tb=kQ6o7eVqUZd`0fo9D@
z`vyo59#*A!saE#!$G7Cxfh7n>ZWX!0gkro``0W{b9=XxNGqu#u6^e-7Kk1lUvA@1|
zbiNNGZAv0UHvN5<U^P<r)g@-ialS1%)x3@yJ98Y|-=-l+Boj89EtWS_YS|uX*d!1h
zuEy_=OEANsq$z9D#HF5bZ{?yihjwlq>m{KO8QNS~$+u-B>s_5L`L`jBdrke`Xe{0N
zj*umKyN|_A>O3@@8y|M457h5tzNEqIDV$3|c%QOiW7;H(RNLM9W0najA-;HEwdD>u
zkW^fo^J0f?_u(^NWw(nT>JS~~smIbnC8QxFcuQkHNQUJyj;eYMTmvVN^O|RPDvczq
z>kslY@C$0YBmZR=Y@IEsCWJ9}K@HOu`c4n=$kr9!;n+9We=f8unlK5@c*o|I7(=zG
zS}lWvH_fp;i}4qt9>h_?QzN~ap@7nLh*7DJwfvLZA<V1CA-;}Ue~o+;dKMLq-ri8y
zikJ69`xKaRWgS_7`*rKX(ZaYWcag1=J-5B>S*_S4BW3*FwwCv)lD1Vg1t7><usf4m
zup`Lc+-g*3BF+4XfNOLe4Z%60c!!YYai||v?*gK{Zsre$>@!DLp5Su@bc$d;D_VX!
z57eDlJm5IkuTyc>aw+Wt#V5hkX-B+t+|!Fa@@x7=`8`3dZm3$aHF*y2VcD$(D>J3y
z%YwpO#gY%mqyin8q9uH?7OBC}Uv-@<Msy*~Nvry^su7=0x82-E)nk8ChDluiAzV&U
z2<tOh8_)LPqk+>)Hl0)Z2+y3x`{XluljPt{<4TU-m$XDvYU9HDGKSg&cT(@MVe23D
z<<w-7WUrsFSZxtTfqSUs&=EIdlxvhm#YJxmhO0_;`8k=7skM9}9DkoBCfVpFC0Ohf
z%}`!2CA@!leO$E-;~Y_b`cgTypBF@7iEd+J^tUv^tjfq6f2i#0!U;Q!z8b*8of34=
zl@qQBGh&YiI|>wCdy-3tTl}j4kzaCmrni9<xi<;Vr$W&`EbLm?-R1s>Diizn#a{@0
zu;<>ZBofe$`#ML)Z*Aj8mbPS3-(VgSdF3LA8LJgBPj{3IaB~uLBuylK<S`<40r_-M
zoAmqT`YvtUUk(<9&TZp3#LaaUTWN+^#exVp-Py|>O*>ev*i|tuS(Wff3`Ogj^{GsE
zb-&NcY_)d|4#vv+AW}skSWrN{p$KOp?oug)BPoM*O}*h=wrr-PGYCt{qwP-&I!~hn
z&+*{EI5^09slk8i%kFcTjCcO6Oc}M9iiS}cuLLw0fyMPfjZ_M`;HWDHP^ke=f*5^!
z(0!2p!N9nZ8J+AP5sfunmbw64l@2)3@53_`Q@g&4FYKeDLbz2F-Pl@Er#INAtM()n
z<;MFT;osC<bQdAh7ukANy6Uo{LpNoJ5JR#ZS?MQZM$7>}L2=Y4P1?cm)V{7nauSgh
zx4)k@#lLT}(uM?{Z&NvzT8pnJk@-MDvv4wOKsY+l9S8OdOw}cex#$t*B6ppAEloQy
z8u`9L`Ky$*$*G}A=)h6BjVn=_YuPie5epXe0vLKZP=Pxps%a&uGrdg4y#R{YobnDn
zWlMl5J;9|5ev`f`BO3Uh(yuK%@i^`+fAimq+_>*)z(;wrFdXn2nVJw1y_>PcV%p-)
zt#ZCU`}~DIE5y1BiI$qSd5XIebq(uRB-FnL#^x=bDHO-ls3({4R}-PgePOPH8ggGN
z^EAdT|N11qATWCZQ}ZY#=hum&;_xeyp*|O{VN?%jM$?&+DK=8LzLP4?U!YQ_JT0`M
z`m!W@TCB5mlr9&jJ{^cX4Ye=uf(7g!BDG1LQfZM#P5u-^$L1K~rOMk<H0023v|Tg!
z@<`0{o=Z{LBf>7oWI24W>ZJVoZ8!*NX>jC%2pgw@7$v*amGL8JnA`*TjN)y=JPix$
zHom^xjfr~ZFvhO?xbJHg&jfEZgboIqN@pk*%G-#&cX5DM>_>dMo{P<(#6bOBlgEyG
zzi7pMrVsz<*TT+n%Xo*+rUV<N^pGwpI6#DG$bDv{0i5)d@1mV;xmg}Wb_OS@^o9%P
zF#V0~d?t@Ez~S$v#O2LL)9K+Q5V<4HkHp@q@knGeChs~ZMNcp|{!@^b#M?o5^kyL^
zMbPEA3LRg=<{=5)D@heWx381fV@moa582tdi<JjliS(nCwtPwb(v(Engz{oD@CcvF
zzd~$BNPA|mS2m$u|0%)V15A+WyQcy7y)R#^UDlG!`;Y}^5uP{JDnW?6B0HvlM~UCq
z^av2YiIwqT7Y_Q@*IN|+7mdeRzX${b#y+sKNTa`!M}{7Wdxu_0l|Ok2RJHxgZb{;y
zSn+B7HpQh+`q7w*lcY?}HhJ_+aBfuLcN;Q|-fHZEuh@~+keZD+8(s01NP<A_Pz6>N
ztJqe<9EEg`YU)i$PQ+gn%oA5sG>b*6QUjZVf+Ju4QKWr32^B^>#t1pQ*dNT#SxuC8
zGNJ9mH6R-92O+m#!DECXMrB|3+|cZ$?^qoag;w8-vr)Z5hx@2MVoazOwqdLo2-lu(
ziwF<xL&6n-Lw^N|f3DMxm<_)@Rd-usrtOFEhAX5<Uqh8=vZhDSEcrKIX29ctvIybD
zk8_USJ*Q4~re>(a3SNH{+U_=d6KFp}-N^eInrfTZ{p%Yc;K{NXO^Sl0qy(%)%sUXL
zA6Ic}&$4}O+ulD-?|#%otX@aO$zD_RW;|WXeL`u5;iz`2Ja937zabkT*wwyB&2HIU
z%>tpNcvDWCsG=IjRr(V|Z7N`9^tphbhiC}fIrVcS>=>)uMStm;g&z-HK{fFz2ud&X
zKo;y87PhB3IZGZ&D%bJ2dZ<-Z7I$fCrPWl6O0ir})>f~+rM8k@!Q(EpWCD9f!k>me
zRhs@Q3_eZ!{s3QHUMaN0uS<rI{r;Qp%hmh)`<m<F-c_OKUDcphTas*?ZC+jIOHR&7
z=5Y_AhBB%7F7^Itr>hhn$<I{W5YxK8Eq=;a0}Jxgt{imOB@yy@CUt3IuCdj!9h?un
zN4A}f(~$LvrbNyHMqSzYcIG)*5EV(scW-Ek5Zl#i_wj!wga3K!Juv_kS1E>y!N+)a
z6F#K#O21}#Wz2NGar1LUq3S|3=0~&VTjxVeqcysO1QIGwgglMcjXc3^9R9i556MW!
zA%G1+Y)mPX16<vM|IO3}+7XE&8+HWuH=itySZvI)L1tD8NSy32dia>RcVB#B?R~Xl
zIeR6G9EBEo<!NPj`1l_*1iQMLG>U+Sk|=Q=4gQ<j4<3!sVEnV_N2#qa$LMWH+-Ra`
zE{KmwwH#KDkB2w<NET$K>dT~j9ecG~G45m|E+IkhfuBxT`M%^wZkNkXpL0AjS!$%u
zg-={lr6QW@$p<#-f}T{y|0rAEpY~$9`Ffd=BP+`1#;?ge=@mLGkdmI~u?Dai2i+}>
zr-d}7M&xTHsK7@<3$tPd^Yg3fLzxDa!oOJ_N!hGt&$}5!9&TOIuzhIP>)^&CM1CIF
zY>A-293)fzq2lbB(1wKk=>#3=G1eTT&8(iBSJab=V@AGnDSwOhxKg{m8sa~TR||^x
zH?*-f-l|Zq;GkYEt~~O`56i(Z6gi`*^TxMZuc-f=NM<b?&atrP|2+?p`a~XaL3?_v
zis~@WSUcV;T#VWjWjy+4jE`|*KuFWU*vs)CvUsO+SBkchc5D3%U8KBf)6Vc;<WwfM
z7Fy4B1nXku#^XBwDJk9<N9Fr#sAp04Mx*Q>lvry~%u2a>kz*@R^tJ@{7%-A@wfa)Z
z0~dL|Z*tTjEX7ED(M%2gZ|Zi_L4TWr%=BR=y4%;?-COo)8t(xaW)#f?Uhc9^d-1?K
z=UDW-cu<en^c|7YEA({$pTeUd86t0Lz1+?=lZO1%7LXFlksTzVWhH&*Oe%8Zxk(VS
z(7LDUjeg`?*4VZ*llKa~3TUeTF5<7e?ceps(n^0fhev>8J#%~t1$>T7o{K5NXC7Z^
z;*V>fuSp>3%L~xxUi%mG*w7fJS9FTtSX8!B_=C>_+{-q^3-7Yf_esz?&oN2)zkaPH
z=7a>>$VgQh6LDY?h_Px)L~(27=d%@0UX!M7G~G|aMRJuU!|xkIYM`l6jEi407=MtW
z4YA)qqP8SmCj;2g*%y+BObhJICRimEtC(yhX|B>fl9#O|OsP0h{YfJM(l{DjCSf;_
zp3jZ#S5YfJ*b;<R6mYOg2I?kRF;LN1+TK7+`pf>u0&zd}UOl+UMYMCH3kOBnUGziK
zo__#J<(BObj|aew5%LI%9K>!}5UVhW*2b`jvkYQXN*iuj#{{Oatl}s!dyhU&jWEAS
zdKj4YrSTiJ_b6i{@5nk1r@W#B=YNdtri~y>StL>N%B6Gj6O_fwN*T-2>1Q1KuQAXE
zF|^na>CtL$iCMfa_^Bio0%XY3)>F9Uqzf-cky+Lb_H)#4=L+?00yMptx;^o9v}fkd
zWN%~1Sj%)#ggvPi=IpG67#q)qrgFi21qV^a=2vb1s|%}692RR2)zei^W-5JD7Y!4^
zKfyt1dP(!slOA11Of$_Q<M(4m-xsoF{41>uYE4W{Uu+DO027{)!<nRB+N?VnRnnx#
zy^B5g{ySEwgMklX&zT92x9SjzIneNuB2gJOMJthYmAQreiVrQT!%NQ^lBcyRR^NG6
zJ%pn-fN{KiYSi6-uMpnG0ugSpzPxf%T(Wa2M($NIp_OnjvKOe~)nh$5O{EGSLt1Gn
zM*j&=mv6vnH=K{@JOu`Su-l>7+#Y;Ih{M{`=>H7?QlKD!&7BO7X`Q1_b071zS3lNp
z@&Iv~QHe@3e;q{$b7pE51fo%ee_qC4)CR?kSh?lvkF}D2UuE>>^dhlmktVcN14leO
zB6JLU^U}S?*F=`1q~sTqli@HC^RzgoXWg7-*R1R~2xL-K^`XjV%3c-JMf~;^ILFoK
z%NIwJAU)}8T@nI{XRp;rWaD7cuvC1dj!R2oZ(K-<6)PFEe1C`3{NVSlqPF<~-&+*O
z8>_z7E5JY^sY(1!jgGp<)OE9!*nx9!RX3U}7tvu5m2XXS(V8#x+t;nz?=xkI(DDsz
z;3foX=tMqziX%?kztoj_MYP1$@9}OUi0@Z>26`$9-KBzz0d+H_Z`PU9?gSA=7?H}0
z{c+|*bet;11)bfWS<)JER^z_5PKJN$@9unBRX+W*oX^32ly<xVw{^8wg!tS@5$mOA
zvV-*+V_0#NIvJfmlhan*-J;}~VIOEsd}aFrm(Zij%h4&)Q}r_gg_CQ0C$l#So^7p>
zKo%s>e!Q4Gb1DeiV*R&fzDz|t8*WBSo1ove3somHjybczT^qp^D^Tpx97n^9WuuqI
zTCFUlzMc<9(@Ng!L9ebpnk>0!&~jV<V^T|KFe>#<spUg}5Y$_N>PR~Lz8p-9KECK6
z;7<rs=qt;RJT@>0`vR#D6@#_MoD+$Wl*AAbY|FVo2J6vOlP={WYAqT#$Q!S^VW9|!
zl45qcN$prx36zxggrb_z0Ri=i%$I(SJ6jHx(uR<;b(=zb>GDa-cZTt=EWQ$^+AKKp
z!qtgInkt}{k=PN-erHn(dHX?T{g44@;}a%oYTE7q*K<=mU`H~sCkX#6pyH?M+0W>N
zUr<(Whv)VbXit9iJY4V&;_6xGNVK9d_P*yRzW_7PgbR$4WPdD<VSusjLlI()Q82sY
z+kMUXO0rqfgfSoPD0eyWlcPt4ltYz_5Af6<BEHeWh}&>P<bwXH=XFQhN1kLWK^`vl
zvxIFVF&S7E-eW6|LBSSrFcLP*e;W(Rwc$TlH>8K}{V;@u;E04A#lw1fxY9qPYX%78
z<E6hN;j7lL0qtd*NWA&tJf%UHY`A)%NK96vr*%^?g-zB@SE_dfYL5oe%)}Y=P|Tm(
z47xne{xGmP7m>?2?m&UC)5IREFbfd%r<*8}KZbL-)2J(s!Ni>DER#ah4jLH0*2GPn
zFP?pTI`d2+=5;~B0pYU=P03Hk<$aGh?7&|CDV>N4L&S*{xjJ6{dn!jPj@;!U64ZH$
zxcv;Jen{NFvhysj-qs<-RN>Q}{r7$Q(|cMV#FVvG1ygSsC^0)`=DwB(4Z7$pIxu3h
zGr}-!!|aUp$DUaVeC9=coIL@I)g|Fm7a7u6JRy|q_3SIEsEkSTn?R2}SIm-}g0D#x
zbFUgC%_08XTvJ@!3#F5}f?b~Rz6CpeASaHdWnNs?a*HD&&M#AO;^>?RDV?gRN(Q&_
zi^f)H(H|$Fg#yiJBfM<kXbR+8_qS-OW-~?AcS^3}(a>*7wTkz_6un^+@bW^qdO0rV
z#80Zot!buo$fS$UtrjI&1`2u(g>;~*Z@I;ZrS@=@)pCyAT-4)ZtWEg^;2QgIBuYCv
zCOT@SpdJ=?l}vNgolDevUl8e7VBri&69qGA<l<=PFtgy72x<!`D%&pU{QUIO<p$OA
zjF-bg6OyK;s8eZg@0b9$JowZZYM%*}>FHzdn>vz;Z2PIH&X0IdJxq5&G|lD{8;FN)
zyoId^NoH`da-U0H$$EV_2u9QwI2NQ6xr#xsr4!7>PZTS-+^Ser28(<ufWAbzK^iL}
zs)K+^CDFW1{QfC7@xj|5V|KHulJ#Aef4_lBRp1=q2?oTXqKfE0ULI7834iAL955Do
zSy~-pe;|nZurhRdl$28Y`nt@lo;`yDk8TFLI)hSu#B=h*&Ttu}xf-}FJI8wOj2n%E
zu;MZ@I;|)66I4G&8E?FnLgR&+MXh9y*Pbe>?H>pkyr(t|p)Hl*Rcc?7hPzry4)mHP
zWLX9>Jcr0gs2&(aNg9b2@BIl*r~2X;kn=eI%P577nIX=auf8fXGcC+->CfU?wHoJM
z@{%ht0!KC%-tamvUWKvNx!08PvLF(w-EK-u?Lgd+WfX$LOYI=5t00MKD|Q)#@9mL5
zWZQ?eQkgCCqwANoAm&<MrorQa@YB;5=z7i<ld%Ofgz_!qgzU};NJx4Xbn2tO*M2c9
z9d?~K8;6b~@JV2`9HJOh8+HrL{3(yRSote{jC^a9g67~g%|9M3Il5>K4|fw*k7ipV
zB1v2pR!seE-oV-2@pAb2ne;%k;&0+LB7z16@)VH1MO9)MHU9kSp)dCNVB91j?4mmO
zv3NP2%#IeX=+W7Ni#8IjoTpc(!3<Z^&wgraQ+Ie66!#M2gbtQ34Uz6O<}jO*XaM8g
z6C;4cj!mOQ|J||_)bfCXJ$~f0tTvCt3sM@w#~JVwVq5y+y(mvHNdc`$`Um)5h0U2x
z)Mu{QO70#@WOQ8uNn4C0bVBT<?z(@Eo(2Ew(3$a-w+Ab}7*^JBmw<FTZ2pMaB)izF
zgR1AVZ@axD<4}7I2AeCsuJwt>T*dt7!EX8Vl<I;?FO50vnpx1YTJ1jCX)(4)Nj{N%
zQ849yy&@&j=J^g(>AzQq6uvFcs%W{$71OuAvW8Wpseg+*PVYLv?WMN=C|H@$;E<?2
zy{V$HT%SB%FYRPvzJD%)C7_fo`ov>_S5fVp$L;GyupU7jZ$kfvC58X?uLqEZijH!v
HqBZh=dic2S

View File

@@ -1,45 +1,45 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 12 Jan 2025 16:19:01 +0300 Date: Mon, 27 Jan 2025 20:53:24 +0300
Subject: [PATCH] DivineMC Configuration Subject: [PATCH] Configuration
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 472c649e08fa1fb5f050d178d1c49fbb1e5c6adf..0c03829de02f31a15b5f2686d03bf3977e3710cb 100644 index 6a08a42acdb2ee24b5e403b15fb825f3cb49c968..c3c6e23b4da16025d0f6472290183732f5eb9880 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1104,6 +1104,7 @@ public final class CraftServer implements Server { @@ -1103,6 +1103,7 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot org.spigotmc.SpigotConfig.init((File) this.console.options.valueOf("spigot-settings")); // Spigot
this.console.paperConfigurations.reloadConfigs(this.console); this.console.paperConfigurations.reloadConfigs(this.console);
org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur - Purpur config files org.purpurmc.purpur.PurpurConfig.init((File) console.options.valueOf("purpur-settings")); // Purpur - Purpur config files
+ org.bxteam.divinemc.configuration.DivineConfig.init((File) console.options.valueOf("divinemc-settings")); // DivineMC - DivineMC config files + org.bxteam.divinemc.DivineConfig.init((File) console.options.valueOf("divinemc-settings")); // DivineMC - Configuration
for (ServerLevel world : this.console.getAllLevels()) { for (ServerLevel world : this.console.getAllLevels()) {
// world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty // world.serverLevelData.setDifficulty(config.difficulty); // Paper - per level difficulty
world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean)) world.setSpawnSettings(world.serverLevelData.getDifficulty() != Difficulty.PEACEFUL && config.spawnMonsters); // Paper - per level difficulty (from MinecraftServer#setDifficulty(ServerLevel, Difficulty, boolean))
@@ -1120,6 +1121,7 @@ public final class CraftServer implements Server { @@ -1119,6 +1120,7 @@ public final class CraftServer implements Server {
} }
world.spigotConfig.init(); // Spigot world.spigotConfig.init(); // Spigot
world.purpurConfig.init(); // Purpur - Purpur config files world.purpurConfig.init(); // Purpur - Purpur config files
+ world.divinemcConfig.init(); // DivineMC - DivineMC config files + world.divineConfig.init(); // DivineMC - Configuration
} }
Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper Plugin[] pluginClone = pluginManager.getPlugins().clone(); // Paper
@@ -3126,6 +3128,13 @@ public final class CraftServer implements Server { @@ -3134,6 +3136,13 @@ public final class CraftServer implements Server {
return CraftServer.this.console.paperConfigurations.createLegacyObject(CraftServer.this.console);
} }
// Purpur end - Purpur config files
+ // DivineMC start - DivineMC configuration + // DivineMC start - Configuration
+ @Override + @Override
+ public YamlConfiguration getDivineConfig() { + public YamlConfiguration getDivineConfig() {
+ return org.bxteam.divinemc.configuration.DivineConfig.config; + return org.bxteam.divinemc.DivineConfig.config;
+ } + }
+ // DivineMC end - DivineMC configuration + // DivineMC end - Configuration
+ +
// Purpur start - Purpur config files
@Override @Override
public YamlConfiguration getPurpurConfig() { public void restart() {
org.spigotmc.RestartCommand.restart();
diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java diff --git a/src/main/java/org/bukkit/craftbukkit/Main.java b/src/main/java/org/bukkit/craftbukkit/Main.java
index 2e1b7f613de8876095ef39bb0341a3f9520c8d5d..8c619b7d72cb153a3204cb9e215f7f5de83e8347 100644 index 2e1b7f613de8876095ef39bb0341a3f9520c8d5d..5eb36ddf8eea7a84299a91f28a031e2b750975ce 100644
--- a/src/main/java/org/bukkit/craftbukkit/Main.java --- a/src/main/java/org/bukkit/craftbukkit/Main.java
+++ b/src/main/java/org/bukkit/craftbukkit/Main.java +++ b/src/main/java/org/bukkit/craftbukkit/Main.java
@@ -183,6 +183,15 @@ public class Main { @@ -183,6 +183,15 @@ public class Main {
@@ -47,13 +47,13 @@ index 2e1b7f613de8876095ef39bb0341a3f9520c8d5d..8c619b7d72cb153a3204cb9e215f7f5d
.describedAs("Yml file"); .describedAs("Yml file");
// Purpur end - Purpur config files // Purpur end - Purpur config files
+ +
+ // DivineMC start - DivineMC config files + // DivineMC start - Configuration
+ acceptsAll(asList("divinemc", "divinemc-settings"), "File for divinemc settings") + acceptsAll(asList("divinemc", "divinemc-settings"), "File for DivineMC settings")
+ .withRequiredArg() + .withRequiredArg()
+ .ofType(File.class) + .ofType(File.class)
+ .defaultsTo(new File("divinemc.yml")) + .defaultsTo(new File("divinemc.yml"))
+ .describedAs("Yml file"); + .describedAs("Yml file");
+ // DivineMC end - DivineMC config files + // DivineMC end - Configuration
+ +
// Paper start // Paper start
acceptsAll(asList("server-name"), "Name of the server") acceptsAll(asList("server-name"), "Name of the server")

View File

@@ -0,0 +1,62 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Mon, 27 Jan 2025 18:42:29 +0300
Subject: [PATCH] Delete timings
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
index 14949b9b0a14e4b6f38bf04a6246f181db2a7b3f..534510a94694d013fc11f6985088c6cf14dbb695 100644
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
@@ -1,6 +1,5 @@
package io.papermc.paper.plugin.manager;
-import co.aikar.timings.TimedEventExecutor;
import com.destroystokyo.paper.event.server.ServerExceptionEvent;
import com.destroystokyo.paper.exception.ServerEventException;
import com.google.common.collect.Sets;
@@ -102,7 +101,6 @@ class PaperEventManager {
throw new IllegalPluginAccessException("Plugin attempted to register " + event + " while not enabled");
}
- executor = new TimedEventExecutor(executor, plugin, null, event);
this.getEventListeners(event).register(new RegisteredListener(listener, executor, priority, plugin, ignoreCancelled));
}
@@ -189,7 +187,7 @@ class PaperEventManager {
}
}
- EventExecutor executor = new TimedEventExecutor(EventExecutor.create(method, eventClass), plugin, method, eventClass);
+ EventExecutor executor = EventExecutor.create(method, eventClass); // DivineMC - Delete timings
eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled()));
}
return ret;
diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java
index 097500a59336db1bbfffcd1aa4cff7a8586e46ec..69341cb3b11409e41b9ff756b11d9bd1b9e6da10 100644
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java
@@ -232,7 +232,7 @@ public class PaperPluginManagerImpl implements PluginManager, DependencyContext
@Override
public boolean useTimings() {
- return co.aikar.timings.Timings.isTimingsEnabled();
+ return false; // DivineMC - Delete timings
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index c3c6e23b4da16025d0f6472290183732f5eb9880..652acceb96843e8242a0989518dec5c65fbcf953 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1048,10 +1048,8 @@ public final class CraftServer implements Server {
commands.performCommand(results, commandLine, commandLine, true);
} catch (CommandException ex) {
this.pluginManager.callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper
- //target.timings.stopTiming(); // Spigot // Paper
throw ex;
} catch (Throwable ex) {
- //target.timings.stopTiming(); // Spigot // Paper
String msg = "Unhandled exception executing '" + commandLine + "' in " + target;
this.pluginManager.callEvent(new com.destroystokyo.paper.event.server.ServerExceptionEvent(new com.destroystokyo.paper.exception.ServerCommandException(ex, target, sender, args))); // Paper
throw new CommandException(msg, ex);

View File

@@ -1,377 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 11 Jan 2025 23:18:11 +0300
Subject: [PATCH] Optimize default values for configs
diff --git a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
index 42777adb028fe282c1619aeb5431c442ad5df0d0..3afcf93d1e9519577ca9b6974f23f2258ecaad3e 100644
--- a/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
+++ b/src/main/java/io/papermc/paper/configuration/GlobalConfiguration.java
@@ -343,9 +343,9 @@ public class GlobalConfiguration extends ConfigurationPart {
public boolean fixEntityPositionDesync = true;
public boolean loadPermissionsYmlBeforePlugins = true;
@Constraints.Min(4)
- public int regionFileCacheSize = 256;
+ public int regionFileCacheSize = 512; // DivineMC - Optimize default values for configs
@Comment("See https://luckformula.emc.gs")
- public boolean useAlternativeLuckFormula = false;
+ public boolean useAlternativeLuckFormula = true; // DivineMC - Optimize default values for configs
public boolean useDimensionTypeForCustomSpawners = false;
public boolean strictAdvancementDimensionCheck = false;
public IntOr.Default compressionLevel = IntOr.Default.USE_DEFAULT;
diff --git a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
index a426ba82af695426952bb5e04fa721e6ccff2f89..6ae624f873c77625c7ff9a1b94ff015cc6d321f0 100644
--- a/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
+++ b/src/main/java/io/papermc/paper/configuration/WorldConfiguration.java
@@ -145,9 +145,9 @@ public class WorldConfiguration extends ConfigurationPart {
public ArmorStands armorStands;
- public class ArmorStands extends ConfigurationPart {
- public boolean doCollisionEntityLookups = true;
- public boolean tick = true;
+ public class ArmorStands extends ConfigurationPart { // DivineMC - optimize default values for configs
+ public boolean doCollisionEntityLookups = false;
+ public boolean tick = false;
}
public Markers markers;
@@ -270,8 +270,8 @@ public class WorldConfiguration extends ConfigurationPart {
public Behavior behavior;
public class Behavior extends ConfigurationPart {
- public boolean disableChestCatDetection = false;
- public boolean spawnerNerfedMobsShouldJump = false;
+ public boolean disableChestCatDetection = true; // DivineMC - Optimize default values for configs
+ public boolean spawnerNerfedMobsShouldJump = true; // DivineMC - Optimize default values for configs
public int experienceMergeMaxValue = -1;
public boolean shouldRemoveDragon = false;
public boolean zombiesTargetTurtleEggs = true;
@@ -295,7 +295,7 @@ public class WorldConfiguration extends ConfigurationPart {
public int playerInsomniaStartTicks = 72000;
public int phantomsSpawnAttemptMinSeconds = 60;
public int phantomsSpawnAttemptMaxSeconds = 119;
- public boolean parrotsAreUnaffectedByPlayerMovement = false;
+ public boolean parrotsAreUnaffectedByPlayerMovement = true; // DivineMC - Optimize default values for configs
@BelowZeroToEmpty
public DoubleOr.Default zombieVillagerInfectionChance = DoubleOr.Default.USE_DEFAULT;
public MobsCanAlwaysPickUpLoot mobsCanAlwaysPickUpLoot;
@@ -306,7 +306,7 @@ public class WorldConfiguration extends ConfigurationPart {
}
public boolean disablePlayerCrits = false;
- public boolean nerfPigmenFromNetherPortals = false;
+ public boolean nerfPigmenFromNetherPortals = true; // DivineMC - Optimize default values for configs
@Comment("Prevents merging items that are not on the same y level, preventing potential visual artifacts.")
public boolean onlyMergeItemsHorizontally = false;
public PillagerPatrols pillagerPatrols;
@@ -404,7 +404,7 @@ public class WorldConfiguration extends ConfigurationPart {
public class Environment extends ConfigurationPart {
public boolean disableThunder = false;
public boolean disableIceAndSnow = false;
- public boolean optimizeExplosions = false;
+ public boolean optimizeExplosions = true; // DivineMC - Optimize default values for configs
public boolean disableExplosionKnockback = false;
public boolean generateFlatBedrock = false;
public FrostedIce frostedIce;
@@ -453,7 +453,7 @@ public class WorldConfiguration extends ConfigurationPart {
public class Maps extends ConfigurationPart {
public int itemFrameCursorLimit = 128;
- public int itemFrameCursorUpdateInterval = 10;
+ public int itemFrameCursorUpdateInterval = 20; // DivineMC - Optimize default values for configs
}
public Fixes fixes;
@@ -479,7 +479,7 @@ public class WorldConfiguration extends ConfigurationPart {
public class Hopper extends ConfigurationPart {
public boolean cooldownWhenFull = true;
public boolean disableMoveEvent = false;
- public boolean ignoreOccludingBlocks = false;
+ public boolean ignoreOccludingBlocks = true; // DivineMC - Optimize default values for configs
}
public Collisions collisions;
@@ -487,9 +487,9 @@ public class WorldConfiguration extends ConfigurationPart {
public class Collisions extends ConfigurationPart {
public boolean onlyPlayersCollide = false;
public boolean allowVehicleCollisions = true;
- public boolean fixClimbingBypassingCrammingRule = false;
+ public boolean fixClimbingBypassingCrammingRule = true; // DivineMC - Optimize default values for configs
@RequiresSpigotInitialization(MaxEntityCollisionsInitializer.class)
- public int maxEntityCollisions = 8;
+ public int maxEntityCollisions = 2; // DivineMC - Optimize default values for configs
public boolean allowPlayerCrammingDamage = false;
}
@@ -497,18 +497,31 @@ public class WorldConfiguration extends ConfigurationPart {
public class Chunks extends ConfigurationPart {
public AutosavePeriod autoSaveInterval = AutosavePeriod.def();
- public int maxAutoSaveChunksPerTick = 24;
+ public int maxAutoSaveChunksPerTick = 12; // DivineMC - Optimize default values for configs
public int fixedChunkInhabitedTime = -1;
- public boolean preventMovingIntoUnloadedChunks = false;
- public Duration delayChunkUnloadsBy = Duration.of("10s");
+ public boolean preventMovingIntoUnloadedChunks = true;
+ public Duration delayChunkUnloadsBy = Duration.of("5s");
public Reference2IntMap<EntityType<?>> entityPerChunkSaveLimit = Util.make(new Reference2IntOpenHashMap<>(BuiltInRegistries.ENTITY_TYPE.size()), map -> {
- map.defaultReturnValue(-1);
- map.put(EntityType.EXPERIENCE_ORB, -1);
- map.put(EntityType.SNOWBALL, -1);
- map.put(EntityType.ENDER_PEARL, -1);
- map.put(EntityType.ARROW, -1);
- map.put(EntityType.FIREBALL, -1);
- map.put(EntityType.SMALL_FIREBALL, -1);
+ // DivineMC start - Optimize default values for configs
+ map.put(EntityType.EXPERIENCE_ORB, 16);
+ map.put(EntityType.SNOWBALL, 8);
+ map.put(EntityType.ENDER_PEARL, 8);
+ map.put(EntityType.ARROW, 16);
+ map.put(EntityType.FIREBALL, 8);
+ map.put(EntityType.SMALL_FIREBALL, 8);
+ map.put(EntityType.DRAGON_FIREBALL, 3);
+ map.put(EntityType.EGG, 8);
+ map.put(EntityType.EYE_OF_ENDER, 8);
+ map.put(EntityType.FIREWORK_ROCKET, 8);
+ map.put(EntityType.POTION, 8);
+ map.put(EntityType.LLAMA_SPIT, 3);
+ map.put(EntityType.SHULKER_BULLET, 8);
+ map.put(EntityType.SPECTRAL_ARROW, 16);
+ map.put(EntityType.EXPERIENCE_BOTTLE, 3);
+ map.put(EntityType.TRIDENT, 16);
+ map.put(EntityType.WITHER_SKULL, 4);
+ map.put(EntityType.AREA_EFFECT_CLOUD, 8);
+ // DivineMC end
});
public boolean flushRegionsOnSave = false;
}
@@ -523,13 +536,13 @@ public class WorldConfiguration extends ConfigurationPart {
public TickRates tickRates;
public class TickRates extends ConfigurationPart {
- public int grassSpread = 1;
- public int containerUpdate = 1;
- public int mobSpawner = 1;
+ public int grassSpread = 4; // DivineMC - Optimize default values for configs
+ public int containerUpdate = 3; // DivineMC - Optimize default values for configs
+ public int mobSpawner = 2; // DivineMC - Optimize default values for configs
public int wetFarmland = 1;
public int dryFarmland = 1;
- public Table<EntityType<?>, String, Integer> sensor = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "secondarypoisensor", 40));
- public Table<EntityType<?>, String, Integer> behavior = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "validatenearbypoi", -1));
+ public Table<EntityType<?>, String, Integer> sensor = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "secondarypoisensor", 80)); // DivineMC - Optimize default values for configs
+ public Table<EntityType<?>, String, Integer> behavior = Util.make(HashBasedTable.create(), table -> table.put(EntityType.VILLAGER, "validatenearbypoi", 60)); // DivineMC - Optimize default values for configs
}
@Setting(FeatureSeedsGeneration.FEATURE_SEEDS_KEY)
@@ -538,7 +551,7 @@ public class WorldConfiguration extends ConfigurationPart {
public class FeatureSeeds extends ConfigurationPart {
@SuppressWarnings("unused") // Is used in FeatureSeedsGeneration
@Setting(FeatureSeedsGeneration.GENERATE_KEY)
- public boolean generateRandomSeedsForAll = false;
+ public boolean generateRandomSeedsForAll = true; // DivineMC - Optimize default values for configs
@Setting(FeatureSeedsGeneration.FEATURES_KEY)
public Reference2LongMap<Holder<ConfiguredFeature<?, ?>>> features = new Reference2LongOpenHashMap<>();
@@ -559,9 +572,9 @@ public class WorldConfiguration extends ConfigurationPart {
public class Misc extends ConfigurationPart {
public int lightQueueSize = 20;
- public boolean updatePathfindingOnBlockUpdate = true;
+ public boolean updatePathfindingOnBlockUpdate = false; // DivineMC - Optimize default values for configs
public boolean showSignClickCommandFailureMsgsToPlayer = false;
- public RedstoneImplementation redstoneImplementation = RedstoneImplementation.VANILLA;
+ public RedstoneImplementation redstoneImplementation = RedstoneImplementation.ALTERNATE_CURRENT; // DivineMC - Optimize default values for configs
public AlternateCurrentUpdateOrder alternateCurrentUpdateOrder = AlternateCurrentUpdateOrder.HORIZONTAL_FIRST_OUTWARD;
public boolean disableEndCredits = false;
public DoubleOr.Default maxLeashDistance = DoubleOr.Default.USE_DEFAULT;
diff --git a/src/main/java/org/spigotmc/SpigotConfig.java b/src/main/java/org/spigotmc/SpigotConfig.java
index e0d4222a99f22d7130d95cf29b034a98f2f3b76e..ecedb1ba79fa40180ff7eb16d12a4602ab357de3 100644
--- a/src/main/java/org/spigotmc/SpigotConfig.java
+++ b/src/main/java/org/spigotmc/SpigotConfig.java
@@ -269,7 +269,7 @@ public class SpigotConfig {
public static boolean saveUserCacheOnStopOnly;
private static void saveUserCacheOnStopOnly() {
- SpigotConfig.saveUserCacheOnStopOnly = SpigotConfig.getBoolean("settings.save-user-cache-on-stop-only", false);
+ SpigotConfig.saveUserCacheOnStopOnly = SpigotConfig.getBoolean("settings.save-user-cache-on-stop-only", true); // DivineMC - Optimize default values for configs
}
public static double movedWronglyThreshold;
@@ -323,9 +323,9 @@ public class SpigotConfig {
public static boolean logVillagerDeaths;
public static boolean logNamedDeaths;
- private static void logDeaths() {
- SpigotConfig.logVillagerDeaths = SpigotConfig.getBoolean("settings.log-villager-deaths", true);
- SpigotConfig.logNamedDeaths = SpigotConfig.getBoolean("settings.log-named-deaths", true);
+ private static void logDeaths() { // DivineMC - Optimize default values for configs
+ SpigotConfig.logVillagerDeaths = SpigotConfig.getBoolean("settings.log-villager-deaths", false);
+ SpigotConfig.logNamedDeaths = SpigotConfig.getBoolean("settings.log-named-deaths", false);
}
public static boolean disablePlayerDataSaving;
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index 89e2adbc1e1a0709d03e151e3ffcdbff10a44098..5b305092a808c2b9b339b9072bf7f7bfc00f0b8a 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -135,13 +135,13 @@ public class SpigotWorldConfig {
public double itemMerge;
private void itemMerge() {
- this.itemMerge = this.getDouble("merge-radius.item", 0.5);
+ this.itemMerge = this.getDouble("merge-radius.item", 3.5); // DivineMC - Optimize default values for configs
this.log("Item Merge Radius: " + this.itemMerge);
}
public double expMerge;
private void expMerge() {
- this.expMerge = this.getDouble("merge-radius.exp", -1);
+ this.expMerge = this.getDouble("merge-radius.exp", 4.0); // DivineMC - Optimize default values for configs
this.log("Experience Merge Radius: " + this.expMerge);
}
@@ -174,7 +174,7 @@ public class SpigotWorldConfig {
public byte mobSpawnRange;
private void mobSpawnRange() {
- this.mobSpawnRange = (byte) getInt("mob-spawn-range", 8); // Paper - Vanilla
+ this.mobSpawnRange = (byte) getInt("mob-spawn-range", 2); // DivineMC - Optimize default values for configs
this.log("Mob Spawn Range: " + this.mobSpawnRange);
}
@@ -184,14 +184,16 @@ public class SpigotWorldConfig {
this.log("Item Despawn Rate: " + this.itemDespawnRate);
}
- public int animalActivationRange = 32;
- public int monsterActivationRange = 32;
- public int raiderActivationRange = 64;
- public int miscActivationRange = 16;
+ // DivineMC start - Optimize default values for configs
+ public int animalActivationRange = 16;
+ public int monsterActivationRange = 24;
+ public int raiderActivationRange = 48;
+ public int miscActivationRange = 8;
+ // DivineMC end - Optimize default values for configs
// Paper start
public int flyingMonsterActivationRange = 32;
- public int waterActivationRange = 16;
- public int villagerActivationRange = 32;
+ public int waterActivationRange = 8; // DivineMC - Optimize default values for configs
+ public int villagerActivationRange = 16; // DivineMC - Optimize default values for configs
public int wakeUpInactiveAnimals = 4;
public int wakeUpInactiveAnimalsEvery = 60 * 20;
public int wakeUpInactiveAnimalsFor = 5 * 20;
@@ -208,7 +210,7 @@ public class SpigotWorldConfig {
public int villagersWorkImmunityFor = 20;
public boolean villagersActiveForPanic = true;
// Paper end
- public boolean tickInactiveVillagers = true;
+ public boolean tickInactiveVillagers = false; // DivineMC - Optimize default values for configs
public boolean ignoreSpectatorActivation = false;
private void activationRange() {
@@ -273,7 +275,7 @@ public class SpigotWorldConfig {
if (SpigotConfig.version < 11) {
this.set("ticks-per.hopper-check", 1);
}
- this.hopperCheck = this.getInt("ticks-per.hopper-check", 1);
+ this.hopperCheck = this.getInt("ticks-per.hopper-check", 8); // DivineMC - Optimize default values for configs
this.hopperAmount = this.getInt("hopper-amount", 1);
this.hopperCanLoadChunks = this.getBoolean("hopper-can-load-chunks", false);
this.log("Hopper Transfer: " + this.hopperTransfer + " Hopper Check: " + this.hopperCheck + " Hopper Amount: " + this.hopperAmount + " Hopper Can Load Chunks: " + this.hopperCanLoadChunks);
@@ -282,7 +284,7 @@ public class SpigotWorldConfig {
public int arrowDespawnRate;
public int tridentDespawnRate;
private void arrowDespawnRate() {
- this.arrowDespawnRate = this.getInt("arrow-despawn-rate", 1200);
+ this.arrowDespawnRate = this.getInt("arrow-despawn-rate", 300); // DivineMC - Optimize default values for configs
this.tridentDespawnRate = this.getInt("trident-despawn-rate", this.arrowDespawnRate);
this.log("Arrow Despawn Rate: " + this.arrowDespawnRate + " Trident Respawn Rate:" + this.tridentDespawnRate);
}
@@ -295,13 +297,13 @@ public class SpigotWorldConfig {
public boolean nerfSpawnerMobs;
private void nerfSpawnerMobs() {
- this.nerfSpawnerMobs = this.getBoolean("nerf-spawner-mobs", false);
+ this.nerfSpawnerMobs = this.getBoolean("nerf-spawner-mobs", true); // DivineMC - Optimize default values for configs
this.log("Nerfing mobs spawned from spawners: " + this.nerfSpawnerMobs);
}
public boolean enableZombiePigmenPortalSpawns;
private void enableZombiePigmenPortalSpawns() {
- this.enableZombiePigmenPortalSpawns = this.getBoolean("enable-zombie-pigmen-portal-spawns", true);
+ this.enableZombiePigmenPortalSpawns = this.getBoolean("enable-zombie-pigmen-portal-spawns", false); // DivineMC - Optimize default values for configs
this.log("Allow Zombie Pigmen to spawn from portal blocks: " + this.enableZombiePigmenPortalSpawns);
}
@@ -413,7 +415,7 @@ public class SpigotWorldConfig {
public int hangingTickFrequency;
private void hangingTickFrequency() {
- this.hangingTickFrequency = this.getInt("hanging-tick-frequency", 100);
+ this.hangingTickFrequency = this.getInt("hanging-tick-frequency", 200); // DivineMC - Optimize default values for configs
}
public int tileMaxTickTime;
diff --git a/src/main/resources/configurations/bukkit.yml b/src/main/resources/configurations/bukkit.yml
index eef7c125b2689f29cae5464659eacdf33f5695b2..c6b04acb5371a0ac454c5e377bccad5b0972aed8 100644
--- a/src/main/resources/configurations/bukkit.yml
+++ b/src/main/resources/configurations/bukkit.yml
@@ -18,28 +18,28 @@ settings:
update-folder: update
plugin-profiling: false
connection-throttle: 4000
- query-plugins: true
+ query-plugins: false
deprecated-verbose: default
shutdown-message: Server closed
minimum-api: none
use-map-color-cache: true
spawn-limits:
- monsters: 70
- animals: 10
- water-animals: 5
- water-ambient: 20
- water-underground-creature: 5
- axolotls: 5
- ambient: 15
+ monsters: 20
+ animals: 5
+ water-animals: 2
+ water-ambient: 2
+ water-underground-creature: 3
+ axolotls: 3
+ ambient: 1
chunk-gc:
- period-in-ticks: 600
+ period-in-ticks: 400
ticks-per:
animal-spawns: 400
- monster-spawns: 1
- water-spawns: 1
- water-ambient-spawns: 1
- water-underground-creature-spawns: 1
- axolotl-spawns: 1
- ambient-spawns: 1
+ monster-spawns: 10
+ water-spawns: 400
+ water-ambient-spawns: 400
+ water-underground-creature-spawns: 400
+ axolotl-spawns: 400
+ ambient-spawns: 400
autosave: 6000
aliases: now-in-commands.yml
diff --git a/src/main/resources/configurations/commands.yml b/src/main/resources/configurations/commands.yml
index 18f54571200e2eca09a39b88f170fe7b99d8618f..1b57d51d92c5c69286800d10baeaa936fa208cae 100644
--- a/src/main/resources/configurations/commands.yml
+++ b/src/main/resources/configurations/commands.yml
@@ -12,5 +12,3 @@
command-block-overrides: []
ignore-vanilla-permissions: false
aliases:
- icanhasbukkit:
- - "version $1-"

View File

@@ -0,0 +1,43 @@
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/src/main/java/org/bukkit/craftbukkit/CraftChunk.java b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
index de8b9048c8395c05b8688bc9d984b8ad680f15b3..98bd60111797225f3be5e2a19e25d654379ca30d 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftChunk.java
@@ -206,7 +206,12 @@ public class CraftChunk implements Chunk {
@Override
public boolean isSlimeChunk() {
// 987234911L is deterimined in EntitySlime when seeing if a slime can spawn in a chunk
- return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
+ // DivineMC start - Implement Secure Seed
+ boolean isSlimeChunk = org.bxteam.divinemc.DivineConfig.enableSecureSeed
+ ? worldServer.getChunk(this.getX(), this.getZ()).isSlimeChunk()
+ : WorldgenRandom.seedSlimeChunk(this.getX(), this.getZ(), this.getWorld().getSeed(), worldServer.spigotConfig.slimeSeed).nextInt(10) == 0; // Paper
+ return this.worldServer.paperConfig().entities.spawning.allChunksAreSlimeChunks || isSlimeChunk;
+ // DivineMC end - Implement Secure Seed
}
@Override
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
index 652acceb96843e8242a0989518dec5c65fbcf953..be2859b2bb31bdf342c1e8fb14ccac8b6d215439 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -1402,7 +1402,11 @@ public final class CraftServer implements Server {
registryAccess = levelDataAndDimensions.dimensions().dimensionsRegistryAccess();
} else {
LevelSettings levelSettings;
- WorldOptions worldOptions = new WorldOptions(creator.seed(), creator.generateStructures(), false);
+ // DivineMC start - Implement Secure Seed
+ WorldOptions worldOptions = org.bxteam.divinemc.DivineConfig.enableSecureSeed
+ ? new WorldOptions(creator.seed(), su.plo.matter.Globals.createRandomWorldSeed(), creator.generateStructures(), false)
+ : new WorldOptions(creator.seed(), creator.generateStructures(), false);
+ // DivineMC end - Implement Secure Seed
WorldDimensions worldDimensions;
DedicatedServerProperties.WorldDimensionData properties = new DedicatedServerProperties.WorldDimensionData(GsonHelper.parse((creator.generatorSettings().isEmpty()) ? "{}" : creator.generatorSettings()), creator.type().name().toLowerCase(Locale.ROOT));

View File

@@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 12 Jan 2025 01:47:27 +0300
Subject: [PATCH] Remove Spigot tick limiter
diff --git a/src/main/java/org/spigotmc/SpigotWorldConfig.java b/src/main/java/org/spigotmc/SpigotWorldConfig.java
index 5b305092a808c2b9b339b9072bf7f7bfc00f0b8a..c9ff04efcdf063326119b9f65630979d38dc7abf 100644
--- a/src/main/java/org/spigotmc/SpigotWorldConfig.java
+++ b/src/main/java/org/spigotmc/SpigotWorldConfig.java
@@ -418,6 +418,7 @@ public class SpigotWorldConfig {
this.hangingTickFrequency = this.getInt("hanging-tick-frequency", 200); // DivineMC - Optimize default values for configs
}
+ /* DivineMC - remove tick limiter
public int tileMaxTickTime;
public int entityMaxTickTime;
private void maxTickTimes() {
@@ -425,6 +426,7 @@ public class SpigotWorldConfig {
this.entityMaxTickTime = this.getInt("max-tick-time.entity", 50);
this.log("Tile Max Tick Time: " + this.tileMaxTickTime + "ms Entity max Tick Time: " + this.entityMaxTickTime + "ms");
}
+ */
public int thunderChance;
private void thunderChance() {
diff --git a/src/main/java/org/spigotmc/TickLimiter.java b/src/main/java/org/spigotmc/TickLimiter.java
deleted file mode 100644
index 961489499e220d71339771dcabf151edeaf6d231..0000000000000000000000000000000000000000
--- a/src/main/java/org/spigotmc/TickLimiter.java
+++ /dev/null
@@ -1,20 +0,0 @@
-package org.spigotmc;
-
-public class TickLimiter {
-
- private final int maxTime;
- private long startTime;
-
- public TickLimiter(int maxTime) {
- this.maxTime = maxTime;
- }
-
- public void initTick() {
- this.startTime = System.currentTimeMillis();
- }
-
- public boolean shouldContinue() {
- long remaining = System.currentTimeMillis() - this.startTime;
- return remaining < this.maxTime;
- }
-}

View File

@@ -0,0 +1,613 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Wed, 29 Jan 2025 01:41:25 +0300
Subject: [PATCH] Parallel world ticking
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
index 69cdd304d255d52c9b7dc9b6a33ffdb630b79abe..09357f2ef583af04f6b8dc5ba67ef7e1d83e3462 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/util/TickThread.java
@@ -14,6 +14,7 @@ import java.util.concurrent.atomic.AtomicInteger;
public class TickThread extends Thread {
private static final Logger LOGGER = LoggerFactory.getLogger(TickThread.class);
+ public static final boolean HARD_THROW = !Boolean.getBoolean("divinemc.disableHardThrow"); // DivineMC - parallel world ticking - THIS SHOULD NOT BE DISABLED SINCE IT CAN CAUSE DATA CORRUPTION!
private static String getThreadContext() {
return "thread=" + Thread.currentThread().getName();
@@ -26,14 +27,14 @@ public class TickThread extends Thread {
public static void ensureTickThread(final String reason) {
if (!isTickThread()) {
LOGGER.error("Thread failed main thread check: " + reason + ", context=" + getThreadContext(), new Throwable());
- throw new IllegalStateException(reason);
+ if (HARD_THROW) throw new IllegalStateException(reason); // DivineMC - parallel world ticking - THIS SHOULD NOT BE DISABLED SINCE IT CAN CAUSE DATA CORRUPTION!
}
}
public static void ensureTickThread(final Level world, final BlockPos pos, final String reason) {
if (!isTickThreadFor(world, pos)) {
final String ex = "Thread failed main thread check: " +
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos;
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + " - " + getTickThreadInformation(world.getServer()); // DivineMC - parallel world ticking
LOGGER.error(ex, new Throwable());
throw new IllegalStateException(ex);
}
@@ -42,7 +43,7 @@ public class TickThread extends Thread {
public static void ensureTickThread(final Level world, final BlockPos pos, final int blockRadius, final String reason) {
if (!isTickThreadFor(world, pos, blockRadius)) {
final String ex = "Thread failed main thread check: " +
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius;
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius + " - " + getTickThreadInformation(world.getServer()); // DivineMC - parallel world ticking
LOGGER.error(ex, new Throwable());
throw new IllegalStateException(ex);
}
@@ -60,7 +61,7 @@ public class TickThread extends Thread {
public static void ensureTickThread(final Level world, final int chunkX, final int chunkZ, final String reason) {
if (!isTickThreadFor(world, chunkX, chunkZ)) {
final String ex = "Thread failed main thread check: " +
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ);
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ) + " - " + getTickThreadInformation(world.getServer()); // DivineMC - parallel world ticking
LOGGER.error(ex, new Throwable());
throw new IllegalStateException(ex);
}
@@ -69,7 +70,7 @@ public class TickThread extends Thread {
public static void ensureTickThread(final Entity entity, final String reason) {
if (!isTickThreadFor(entity)) {
final String ex = "Thread failed main thread check: " +
- reason + ", context=" + getThreadContext() + ", entity=" + EntityUtil.dumpEntity(entity);
+ reason + ", context=" + getThreadContext() + ", entity=" + EntityUtil.dumpEntity(entity) + " - " + getTickThreadInformation(entity.getServer()); // DivineMC - parallel world ticking
LOGGER.error(ex, new Throwable());
throw new IllegalStateException(ex);
}
@@ -78,7 +79,7 @@ public class TickThread extends Thread {
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
if (!isTickThreadFor(world, aabb)) {
final String ex = "Thread failed main thread check: " +
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb;
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb + " - " + getTickThreadInformation(world.getServer()); // DivineMC - parallel world ticking
LOGGER.error(ex, new Throwable());
throw new IllegalStateException(ex);
}
@@ -87,12 +88,69 @@ public class TickThread extends Thread {
public static void ensureTickThread(final Level world, final double blockX, final double blockZ, final String reason) {
if (!isTickThreadFor(world, blockX, blockZ)) {
final String ex = "Thread failed main thread check: " +
- reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ);
+ reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ) + " - " + getTickThreadInformation(world.getServer()); // DivineMC - parallel world ticking
LOGGER.error(ex, new Throwable());
throw new IllegalStateException(ex);
}
}
+ // DivineMC start - parallel world ticking
+ public static void ensureTickThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
+ if (!isTickThreadFor(world)) {
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable());
+ if (HARD_THROW)
+ throw new IllegalStateException(reason);
+ }
+ }
+
+ public static void ensureOnlyTickThread(final String reason) {
+ boolean isTickThread = isTickThread();
+ boolean isServerLevelTickThread = isServerLevelTickThread();
+ if (!isTickThread || isServerLevelTickThread) {
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread ONLY tick thread check: " + reason, new Throwable());
+ if (HARD_THROW)
+ throw new IllegalStateException(reason);
+ }
+ }
+
+ public static void ensureTickThreadOrAsyncThread(final net.minecraft.server.level.ServerLevel world, final String reason) {
+ boolean isValidTickThread = isTickThreadFor(world);
+ boolean isAsyncThread = !isTickThread();
+ boolean isValid = isAsyncThread || isValidTickThread;
+ if (!isValid) {
+ LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread or async thread check: " + reason + " @ world " + world.getWorld().getName() + " - " + getTickThreadInformation(world.getServer()), new Throwable());
+ if (HARD_THROW)
+ throw new IllegalStateException(reason);
+ }
+ }
+
+ public static String getTickThreadInformation(net.minecraft.server.MinecraftServer minecraftServer) {
+ StringBuilder sb = new StringBuilder();
+ Thread currentThread = Thread.currentThread();
+ sb.append("Is tick thread? ");
+ sb.append(currentThread instanceof TickThread);
+ sb.append("; Is server level tick thread? ");
+ sb.append(currentThread instanceof ServerLevelTickThread);
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ sb.append("; Currently ticking level: ");
+ if (serverLevelTickThread.currentlyTickingServerLevel != null) {
+ sb.append(serverLevelTickThread.currentlyTickingServerLevel.getWorld().getName());
+ } else {
+ sb.append("null");
+ }
+ }
+ sb.append("; Is iterating over levels? ");
+ sb.append(minecraftServer.isIteratingOverLevels);
+ sb.append("; Are we going to hard throw? ");
+ sb.append(HARD_THROW);
+ return sb.toString();
+ }
+
+ public static boolean isServerLevelTickThread() {
+ return Thread.currentThread() instanceof ServerLevelTickThread;
+ }
+ // DivineMC end - parallel world ticking
+
public final int id; /* We don't override getId as the spec requires that it be unique (with respect to all other threads) */
private static final AtomicInteger ID_GENERATOR = new AtomicInteger();
@@ -126,8 +184,13 @@ public class TickThread extends Thread {
return false;
}
+ // DivineMC start - parallel world ticking
public static boolean isTickThreadFor(final Level world, final BlockPos pos) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final BlockPos pos, final int blockRadius) {
@@ -135,38 +198,99 @@ public class TickThread extends Thread {
}
public static boolean isTickThreadFor(final Level world, final ChunkPos pos) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final Vec3 pos) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final AABB aabb) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final double blockX, final double blockZ) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final Vec3 position, final Vec3 deltaMovement, final int buffer) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final int fromChunkX, final int fromChunkZ, final int toChunkX, final int toChunkZ) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Level world, final int chunkX, final int chunkZ, final int radius) {
- return isTickThread();
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
+ }
+
+ public static boolean isTickThreadFor(final Level world) {
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == world;
+ } else return currentThread instanceof TickThread;
}
public static boolean isTickThreadFor(final Entity entity) {
- return isTickThread();
+ if (entity == null) {
+ return true;
+ }
+
+ Thread currentThread = Thread.currentThread();
+
+ if (currentThread instanceof ServerLevelTickThread serverLevelTickThread) {
+ return serverLevelTickThread.currentlyTickingServerLevel == entity.level();
+ } else return currentThread instanceof TickThread;
+ }
+
+ public static class ServerLevelTickThread extends TickThread {
+ public ServerLevelTickThread(String name) {
+ super(name);
+ }
+
+ public ServerLevelTickThread(Runnable run, String name) {
+ super(run, name);
+ }
+
+ public net.minecraft.server.level.ServerLevel currentlyTickingServerLevel;
}
+ // DivineMC end - parallel world ticking
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
index ca60f91ef012c94174a0803eb77699ba9ecff5e1..35afd7268a6f8c5c9d0da751459867c1d8e404bf 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
@@ -446,7 +446,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public boolean unloadChunkRequest(int x, int z) {
- org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot unload chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
if (this.isChunkLoaded(x, z)) {
this.world.getChunkSource().removeRegionTicket(TicketType.PLUGIN, new ChunkPos(x, z), 1, Unit.INSTANCE);
}
@@ -472,6 +472,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public boolean refreshChunk(int x, int z) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot refresh chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
ChunkHolder playerChunk = this.world.getChunkSource().chunkMap.getVisibleChunkIfPresent(ChunkPos.asLong(x, z));
if (playerChunk == null) return false;
@@ -522,7 +523,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public boolean loadChunk(int x, int z, boolean generate) {
- org.spigotmc.AsyncCatcher.catchOp("chunk load"); // Spigot
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.getHandle(), x, z, "May not sync load chunks asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
warnUnsafeChunk("loading a faraway chunk", x, z); // Paper
ChunkAccess chunk = this.world.getChunkSource().getChunk(x, z, generate || isChunkGenerated(x, z) ? ChunkStatus.FULL : ChunkStatus.EMPTY, true); // Paper
@@ -750,6 +751,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public boolean generateTree(Location loc, TreeType type, BlockChangeDelegate delegate) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, loc.getX(), loc.getZ(), "Cannot generate tree asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
this.world.captureTreeGeneration = true;
this.world.captureBlockStates = true;
boolean grownTree = this.generateTree(loc, type);
@@ -865,6 +867,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
}
public boolean createExplosion(double x, double y, double z, float power, boolean setFire, boolean breakBlocks, Entity source, Consumer<net.minecraft.world.level.ServerExplosion> configurator) {
// Paper end - expand explosion API
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x, z, "Cannot create explosion asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
net.minecraft.world.level.Level.ExplosionInteraction explosionType;
if (!breakBlocks) {
explosionType = net.minecraft.world.level.Level.ExplosionInteraction.NONE; // Don't break blocks
@@ -956,6 +959,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public int getHighestBlockYAt(int x, int z, org.bukkit.HeightMap heightMap) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, x >> 4, z >> 4, "Cannot retrieve chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
warnUnsafeChunk("getting a faraway chunk", x >> 4, z >> 4); // Paper
// Transient load for this tick
return this.world.getChunk(x >> 4, z >> 4).getHeight(CraftHeightMap.toNMS(heightMap), x, z);
@@ -986,6 +990,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public void setBiome(int x, int y, int z, Holder<net.minecraft.world.level.biome.Biome> bb) {
BlockPos pos = new BlockPos(x, 0, z);
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, pos, "Cannot retrieve chunk asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
if (this.world.hasChunkAt(pos)) {
net.minecraft.world.level.chunk.LevelChunk chunk = this.world.getChunkAt(pos);
@@ -2289,6 +2294,7 @@ public class CraftWorld extends CraftRegionAccessor implements World {
@Override
public void sendGameEvent(Entity sourceEntity, org.bukkit.GameEvent gameEvent, Vector position) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(this.world, position.getX(), position.getZ(), "Cannot send game event asynchronously"); // DivineMC - parallel world ticking (additional concurrency issues logs)
getHandle().gameEvent(sourceEntity != null ? ((CraftEntity) sourceEntity).getHandle(): null, net.minecraft.core.registries.BuiltInRegistries.GAME_EVENT.get(org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(gameEvent.getKey())).orElseThrow(), org.bukkit.craftbukkit.util.CraftVector.toBlockPos(position));
}
// Paper end
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
index 5cb69d0b822e11a99a96aef4f59986d083b079f4..1bfcb513f2d9a9b86a3833a7f57700b330450fbc 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlock.java
@@ -75,6 +75,11 @@ public class CraftBlock implements Block {
}
public net.minecraft.world.level.block.state.BlockState getNMS() {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
return this.world.getBlockState(this.position);
}
@@ -157,6 +162,11 @@ public class CraftBlock implements Block {
}
private void setData(final byte data, int flag) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
this.world.setBlock(this.position, CraftMagicNumbers.getBlock(this.getType(), data), flag);
}
@@ -198,6 +208,11 @@ public class CraftBlock implements Block {
}
public static boolean setTypeAndData(LevelAccessor world, BlockPos position, net.minecraft.world.level.block.state.BlockState old, net.minecraft.world.level.block.state.BlockState blockData, boolean applyPhysics) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
// SPIGOT-611: need to do this to prevent glitchiness. Easier to handle this here (like /setblock) than to fix weirdness in tile entity cleanup
if (old.hasBlockEntity() && blockData.getBlock() != old.getBlock()) { // SPIGOT-3725 remove old tile entity if block changes
// SPIGOT-4612: faster - just clear tile
@@ -343,18 +358,33 @@ public class CraftBlock implements Block {
@Override
public Biome getBiome() {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
return this.getWorld().getBiome(this.getX(), this.getY(), this.getZ());
}
// Paper start
@Override
public Biome getComputedBiome() {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
return this.getWorld().getComputedBiome(this.getX(), this.getY(), this.getZ());
}
// Paper end
@Override
public void setBiome(Biome bio) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
this.getWorld().setBiome(this.getX(), this.getY(), this.getZ(), bio);
}
@@ -402,6 +432,11 @@ public class CraftBlock implements Block {
@Override
public boolean isBlockFaceIndirectlyPowered(BlockFace face) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
int power = this.world.getMinecraftWorld().getSignal(this.position, CraftBlock.blockFaceToNotch(face));
Block relative = this.getRelative(face);
@@ -414,6 +449,11 @@ public class CraftBlock implements Block {
@Override
public int getBlockPower(BlockFace face) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
int power = 0;
net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
int x = this.getX();
@@ -484,6 +524,11 @@ public class CraftBlock implements Block {
@Override
public boolean breakNaturally() {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
return this.breakNaturally(null);
}
@@ -543,6 +588,11 @@ public class CraftBlock implements Block {
@Override
public boolean applyBoneMeal(BlockFace face) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
Direction direction = CraftBlock.blockFaceToNotch(face);
BlockFertilizeEvent event = null;
ServerLevel world = this.getCraftWorld().getHandle();
@@ -554,8 +604,10 @@ public class CraftBlock implements Block {
world.captureTreeGeneration = false;
if (world.capturedBlockStates.size() > 0) {
- TreeType treeType = SaplingBlock.treeType;
- SaplingBlock.treeType = null;
+ // DivineMC start - parallel world ticking
+ TreeType treeType = SaplingBlock.treeTypeRT.get();
+ SaplingBlock.treeTypeRT.set(null);
+ // DivineMC end - parallel world ticking
List<BlockState> blocks = new ArrayList<>(world.capturedBlockStates.values());
world.capturedBlockStates.clear();
StructureGrowEvent structureEvent = null;
@@ -644,6 +696,11 @@ public class CraftBlock implements Block {
@Override
public RayTraceResult rayTrace(Location start, Vector direction, double maxDistance, FluidCollisionMode fluidCollisionMode) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
Preconditions.checkArgument(start != null, "Location start cannot be null");
Preconditions.checkArgument(this.getWorld().equals(start.getWorld()), "Location start cannot be a different world");
start.checkFinite();
@@ -685,6 +742,11 @@ public class CraftBlock implements Block {
@Override
public boolean canPlace(BlockData data) {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot read world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
Preconditions.checkArgument(data != null, "BlockData cannot be null");
net.minecraft.world.level.block.state.BlockState iblockdata = ((CraftBlockData) data).getState();
net.minecraft.world.level.Level world = this.world.getMinecraftWorld();
@@ -719,6 +781,11 @@ public class CraftBlock implements Block {
@Override
public void tick() {
+ // DivineMC start - parallel world ticking
+ if (world instanceof ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
final ServerLevel level = this.world.getMinecraftWorld();
this.getNMS().tick(level, this.position, level.random);
}
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
index 768d3f93da2522d467183654260a8bd8653588b1..762bb2827dc1c0c0649a4cb3d8b0c8c0c9ea95d1 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockEntityState.java
@@ -25,7 +25,7 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
private final T tileEntity;
private final T snapshot;
public boolean snapshotDisabled; // Paper
- public static boolean DISABLE_SNAPSHOT = false; // Paper
+ public static ThreadLocal<Boolean> DISABLE_SNAPSHOT = ThreadLocal.withInitial(() -> Boolean.FALSE); // DivineMC - parallel world ticking
public CraftBlockEntityState(World world, T tileEntity) {
super(world, tileEntity.getBlockPos(), tileEntity.getBlockState());
@@ -34,8 +34,10 @@ public abstract class CraftBlockEntityState<T extends BlockEntity> extends Craft
try { // Paper - Show blockstate location if we failed to read it
// Paper start
- this.snapshotDisabled = DISABLE_SNAPSHOT;
- if (DISABLE_SNAPSHOT) {
+ // DivineMC start - parallel world ticking
+ this.snapshotDisabled = DISABLE_SNAPSHOT.get();
+ if (DISABLE_SNAPSHOT.get()) {
+ // DivineMC end - parallel world ticking
this.snapshot = this.tileEntity;
} else {
this.snapshot = this.createSnapshot(tileEntity);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
index fa63a6cfcfcc4eee4503a82d85333c139c8c8b2b..951e47811e861dffd59cc39e2dcd6fd68900fc72 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockState.java
@@ -215,6 +215,12 @@ public class CraftBlockState implements BlockState {
LevelAccessor access = this.getWorldHandle();
CraftBlock block = this.getBlock();
+ // DivineMC start - parallel world ticking
+ if (access instanceof net.minecraft.server.level.ServerLevel serverWorld) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(serverWorld, position, "Cannot modify world asynchronously");
+ }
+ // DivineMC end - parallel world ticking
+
if (block.getType() != this.getType()) {
if (!force) {
return false;
@@ -350,6 +356,7 @@ public class CraftBlockState implements BlockState {
@Override
public java.util.Collection<org.bukkit.inventory.ItemStack> getDrops(org.bukkit.inventory.ItemStack item, org.bukkit.entity.Entity entity) {
+ ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread(world.getHandle(), position, "Cannot modify world asynchronously"); // DivineMC - parallel world ticking
this.requirePlaced();
net.minecraft.world.item.ItemStack nms = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(item);
diff --git a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
index 56453454cbd4b9e9270fc833f8ab38d5fa7a3763..cfc4237211b994a222983a2d1f879cb0f515b581 100644
--- a/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
+++ b/src/main/java/org/bukkit/craftbukkit/block/CraftBlockStates.java
@@ -249,8 +249,8 @@ public final class CraftBlockStates {
net.minecraft.world.level.block.state.BlockState blockData = craftBlock.getNMS();
BlockEntity tileEntity = craftBlock.getHandle().getBlockEntity(blockPosition);
// Paper start - block state snapshots
- boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT;
- CraftBlockEntityState.DISABLE_SNAPSHOT = !useSnapshot;
+ boolean prev = CraftBlockEntityState.DISABLE_SNAPSHOT.get(); // DivineMC - parallel world ticking
+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(!useSnapshot); // DivineMC - parallel world ticking
try {
// Paper end
CraftBlockState blockState = CraftBlockStates.getBlockState(world, blockPosition, blockData, tileEntity);
@@ -258,7 +258,7 @@ public final class CraftBlockStates {
return blockState;
// Paper start
} finally {
- CraftBlockEntityState.DISABLE_SNAPSHOT = prev;
+ CraftBlockEntityState.DISABLE_SNAPSHOT.set(prev); // DivineMC - parallel world ticking
}
// Paper end
}
diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
index 822ee4a2515ad1d4400bafeaf7177622e88b4aaf..69c44017e7ca2861200c83a16fa9dacaa822d505 100644
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -960,7 +960,7 @@ public class CraftEventFactory {
return CraftEventFactory.handleBlockSpreadEvent(world, source, target, block, 2);
}
- public static BlockPos sourceBlockOverride = null; // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep.
+ public static final ThreadLocal<BlockPos> sourceBlockOverrideRT = new ThreadLocal<>(); // SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. // DivineMC - parallel world ticking (this is from Folia, fixes concurrency bugs with sculk catalysts)
public static boolean handleBlockSpreadEvent(LevelAccessor world, BlockPos source, BlockPos target, net.minecraft.world.level.block.state.BlockState block, int flag) {
// Suppress during worldgen
@@ -972,7 +972,7 @@ public class CraftEventFactory {
CraftBlockState state = CraftBlockStates.getBlockState(world, target, flag);
state.setData(block);
- BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverride != null ? CraftEventFactory.sourceBlockOverride : source), state);
+ BlockSpreadEvent event = new BlockSpreadEvent(state.getBlock(), CraftBlock.at(world, CraftEventFactory.sourceBlockOverrideRT.get() != null ? CraftEventFactory.sourceBlockOverrideRT.get() : source), state); // DivineMC - parallel world ticking
Bukkit.getPluginManager().callEvent(event);
if (!event.isCancelled()) {
@@ -2242,7 +2242,7 @@ public class CraftEventFactory {
CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemStack.copyWithCount(1));
org.bukkit.event.block.BlockDispenseEvent event = new org.bukkit.event.block.BlockDispenseEvent(bukkitBlock, craftItem.clone(), CraftVector.toBukkit(to));
- if (!net.minecraft.world.level.block.DispenserBlock.eventFired) {
+ if (!net.minecraft.world.level.block.DispenserBlock.eventFired.get()) { // DivineMC - parallel world ticking
if (!event.callEvent()) {
return itemStack;
}

View File

@@ -0,0 +1,90 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 19:10:42 +0300
Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
tasks to be run
Original project: https://github.com/SparklyPower/SparklyPaper
diff --git a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
index c03608fec96b51e1867f43d8f42e5aefb1520e46..eda35b81c36ca8ebe4f9487cb41e2b0c4cbfc686 100644
--- a/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
+++ b/src/main/java/io/papermc/paper/threadedregions/EntityScheduler.java
@@ -36,6 +36,7 @@ public final class EntityScheduler {
* The Entity. Note that it is the CraftEntity, since only that class properly tracks world transfers.
*/
public final CraftEntity entity;
+ public final net.minecraft.server.MinecraftServer server; // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
private static final record ScheduledTask(Consumer<? extends Entity> run, Consumer<? extends Entity> retired) {}
@@ -46,7 +47,8 @@ public final class EntityScheduler {
private final ArrayDeque<ScheduledTask> currentlyExecuting = new ArrayDeque<>();
- public EntityScheduler(final CraftEntity entity) {
+ public EntityScheduler(final net.minecraft.server.MinecraftServer server, final CraftEntity entity) { // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
+ this.server = Validate.notNull(server);
this.entity = Validate.notNull(entity);
}
@@ -61,15 +63,15 @@ public final class EntityScheduler {
* @throws IllegalStateException If the scheduler is already retired.
*/
public void retire() {
+ final Entity thisEntity = this.entity.getHandleRaw(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
synchronized (this.stateLock) {
if (this.tickCount == RETIRED_TICK_COUNT) {
throw new IllegalStateException("Already retired");
}
this.tickCount = RETIRED_TICK_COUNT;
+ this.server.entitiesWithScheduledTasks.remove(thisEntity); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
}
- final Entity thisEntity = this.entity.getHandleRaw();
-
// correctly handle and order retiring while running executeTick
for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) {
final ScheduledTask task = this.currentlyExecuting.pollFirst();
@@ -124,6 +126,7 @@ public final class EntityScheduler {
if (this.tickCount == RETIRED_TICK_COUNT) {
return false;
}
+ this.server.entitiesWithScheduledTasks.add(this.entity.getHandleRaw()); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
this.oneTimeDelayed.computeIfAbsent(this.tickCount + Math.max(1L, delay), (final long keyInMap) -> {
return new ArrayList<>();
}).add(task);
@@ -143,6 +146,12 @@ public final class EntityScheduler {
TickThread.ensureTickThread(thisEntity, "May not tick entity scheduler asynchronously");
final List<ScheduledTask> toRun;
synchronized (this.stateLock) {
+ // DivineMC start - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
+ if (this.currentlyExecuting.isEmpty() && this.oneTimeDelayed.isEmpty()) {
+ this.server.entitiesWithScheduledTasks.remove(thisEntity);
+ return;
+ }
+ // DivineMC end - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
if (this.tickCount == RETIRED_TICK_COUNT) {
throw new IllegalStateException("Ticking retired scheduler");
}
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 8635cd772c5c2ae0ba326812ff2a1a179285a86f..614e407814fe47dab58fbcbc49d8e9dd54b4245e 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -75,7 +75,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
private final CraftPersistentDataContainer persistentDataContainer = new CraftPersistentDataContainer(CraftEntity.DATA_TYPE_REGISTRY);
protected net.kyori.adventure.pointer.Pointers adventure$pointers; // Paper - implement pointers
// Paper start - Folia shedulers
- public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this);
+ public final io.papermc.paper.threadedregions.EntityScheduler taskScheduler; // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
private final io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler apiScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaEntityScheduler(this);
@Override
@@ -88,6 +88,7 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
this.server = server;
this.entity = entity;
this.entityType = CraftEntityType.minecraftToBukkit(entity.getType());
+ this.taskScheduler = new io.papermc.paper.threadedregions.EntityScheduler(this.entity.getServer(), this); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
}
// Purpur start - Fire Immunity API

View File

@@ -0,0 +1,36 @@
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/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
index 36fc0ec6e21af31e10f63b6bb3952008530b8f81..e744c4a13092f20a591d092fe537f790d23d1db1 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java
@@ -214,7 +214,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
private boolean hasPlayedBefore = false;
private final ConversationTracker conversationTracker = new ConversationTracker();
private final Set<String> channels = new HashSet<String>();
- private final Map<UUID, Set<WeakReference<Plugin>>> invertedVisibilityEntities = new HashMap<>();
+ private final Map<UUID, Set<WeakReference<Plugin>>> invertedVisibilityEntities = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // DivineMC - optimize canSee checks
private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
private int hash = 0;
@@ -2270,9 +2270,15 @@ public class CraftPlayer extends CraftHumanEntity implements Player {
@Override
public boolean canSee(org.bukkit.entity.Entity entity) {
- return this.equals(entity) || entity.isVisibleByDefault() ^ this.invertedVisibilityEntities.containsKey(entity.getUniqueId()); // SPIGOT-7312: Can always see self
+ return this.equals(entity) || entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); // SPIGOT-7312: Can always see self // DivineMC - optimize canSee checks
}
+ // DivineMC start - optimize canSee checks
+ public boolean canSeeChunkMapUpdatePlayer(org.bukkit.entity.Entity entity) {
+ return entity.isVisibleByDefault() ^ (!invertedVisibilityEntities.isEmpty() && this.invertedVisibilityEntities.containsKey(entity.getUniqueId())); // SPIGOT-7312: Can always see self // SparklyPaper - optimize canSee checks
+ }
+ // DivineMC end - optimize canSee checks
+
public boolean canSeePlayer(UUID uuid) {
org.bukkit.entity.Entity entity = this.getServer().getPlayer(uuid);

View File

@@ -0,0 +1,45 @@
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/src/main/java/io/papermc/paper/PaperBootstrap.java b/src/main/java/io/papermc/paper/PaperBootstrap.java
index d543b1b107ab8d3eeb1fc3c1cadf489928d2786e..b25afd2a33a61cfbe3dabe65a26aca0669329e32 100644
--- a/src/main/java/io/papermc/paper/PaperBootstrap.java
+++ b/src/main/java/io/papermc/paper/PaperBootstrap.java
@@ -1,8 +1,11 @@
package io.papermc.paper;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.List;
import joptsimple.OptionSet;
import net.minecraft.SharedConstants;
+import net.minecraft.server.Eula;
import net.minecraft.server.Main;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -16,6 +19,22 @@ public final class PaperBootstrap {
public static void boot(final OptionSet options) {
SharedConstants.tryDetectVersion();
+ // DivineMC start - Verify Minecraft EULA earlier
+ Path path2 = Paths.get("eula.txt");
+ Eula eula = new Eula(path2);
+ 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) {
+ LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
+ return;
+ }
+ System.out.println("Loading libraries, please wait..."); // Restore CraftBukkit log
+ // DivineMC end - Verify Minecraft EULA earlier
+
getStartupVersionMessages().forEach(LOGGER::info);
Main.main(options);

View File

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

View File

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

View File

@@ -0,0 +1,50 @@
--- a/src/main/java/io/papermc/paper/command/MSPTCommand.java
+++ b/src/main/java/io/papermc/paper/command/MSPTCommand.java
@@ -78,6 +_,47 @@
)
)
);
+
+ // DivineMC start - MSPT Tracking for each world
+ sender.sendMessage(text());
+ sender.sendMessage(text().content("World tick times ").color(GOLD)
+ .append(text().color(YELLOW)
+ .append(
+ text("("),
+ text("avg", GRAY),
+ text("/"),
+ text("min", GRAY),
+ text("/"),
+ text("max", GRAY),
+ text(")")
+ )
+ ).append(
+ text(" from last 5s"),
+ text(",", GRAY),
+ text(" 10s"),
+ text(",", GRAY),
+ text(" 1m"),
+ text(":", YELLOW)
+ )
+ );
+ for (net.minecraft.server.level.ServerLevel serverLevel : server.getAllLevels()) {
+ List<Component> worldTimes = new ArrayList<>();
+ worldTimes.addAll(eval(serverLevel.tickTimes5s.getTimes()));
+ worldTimes.addAll(eval(serverLevel.tickTimes10s.getTimes()));
+ worldTimes.addAll(eval(serverLevel.tickTimes60s.getTimes()));
+
+ sender.sendMessage(text().content("◴ " + serverLevel.getWorld().getName() + ": ").color(GOLD)
+ .append(text().color(GRAY)
+ .append(
+ worldTimes.get(0), SLASH, worldTimes.get(1), SLASH, worldTimes.get(2), text(", ", YELLOW),
+ worldTimes.get(3), SLASH, worldTimes.get(4), SLASH, worldTimes.get(5), text(", ", YELLOW),
+ worldTimes.get(6), SLASH, worldTimes.get(7), SLASH, worldTimes.get(8)
+ )
+ )
+ );
+ }
+ // DivineMC end - MSPT Tracking for each world
+
return true;
}

View File

@@ -0,0 +1,27 @@
--- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java
@@ -36,14 +_,21 @@
// SimplePluginManager
public void callEvent(@NotNull Event event) {
+ // DivineMC start - Skip event if no listeners
+ RegisteredListener[] listeners = event.getHandlers().getRegisteredListeners();
+ if (listeners.length == 0) return;
+ // DivineMC end - Skip event if no listeners
if (event.isAsynchronous() && this.server.isPrimaryThread()) {
throw new IllegalStateException(event.getEventName() + " may only be triggered asynchronously.");
} else if (!event.isAsynchronous() && !this.server.isPrimaryThread() && !this.server.isStopping()) {
+ // DivineMC start - Multithreaded tracker
+ if (org.bxteam.divinemc.DivineConfig.multithreadedEnabled) {
+ net.minecraft.server.MinecraftServer.getServer().scheduleOnMain(event::callEvent);
+ return;
+ }
+ // DivineMC end - Multithreaded tracker
throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously.");
}
-
- HandlerList handlers = event.getHandlers();
- RegisteredListener[] listeners = handlers.getRegisteredListeners();
for (RegisteredListener registration : listeners) {
if (!registration.getPlugin().isEnabled()) {

View File

@@ -0,0 +1,11 @@
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -989,7 +_,7 @@
@Override
public List<World> getWorlds() {
- return new ArrayList<World>(this.worlds.values());
+ return new it.unimi.dsi.fastutil.objects.ObjectArrayList<World>(this.worlds.values()); // DivineMC - optimize getWorlds
}
@Override

View File

@@ -0,0 +1,11 @@
--- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java
@@ -1976,7 +_,7 @@
BlockFormEvent event = (entity == null) ? new BlockFormEvent(blockState.getBlock(), blockState) : new EntityBlockFormEvent(entity.getBukkitEntity(), blockState.getBlock(), blockState);
world.getCraftServer().getPluginManager().callEvent(event);
- if (!event.isCancelled()) {
+ if (!event.isCancelled() && (BlockFormEvent.getHandlerList().getRegisteredListeners().length != 0)) { // DivineMC - skip block update if no listeners
blockState.update(true);
}

View File

@@ -0,0 +1,32 @@
cmake_minimum_required(VERSION 3.25)
set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
project(c2me-opts-natives-math C)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_COMPILER clang)
SET(CMAKE_C_FLAGS_RELWITHDEBINFO "-O3 -g")
set(CMAKE_C_STANDARD_LIBRARIES "")
set(CMAKE_CXX_STANDARD_LIBRARIES "")
add_library(c2me-opts-natives-math SHARED
exports.c
system_isa_x86_64.c
exports_x86_64_nogather.c
system_isa_aarch64.c
flibc.c
)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)")
set_source_files_properties(exports_x86_64_nogather.c PROPERTIES COMPILE_FLAGS "-mno-gather -mno-scatter")
endif()
execute_process(COMMAND llvm-config --prefix OUTPUT_VARIABLE LLVM_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
target_include_directories(c2me-opts-natives-math PRIVATE includes/)
target_compile_options(c2me-opts-natives-math PRIVATE $<$<COMPILE_LANGUAGE:C>:-Wall -Wextra -Wpedantic -ffreestanding -ffile-prefix-map=${CMAKE_SOURCE_DIR}=. -fdebug-compilation-dir=. -fdebug-prefix-map=${CMAKE_SOURCE_DIR}=. -fdebug-prefix-map=${LLVM_PREFIX}=.../llvm-prefix -fno-math-errno -mprefer-vector-width=512 -ffp-contract=off -Rpass-analysis=loop-vectorize -mno-stack-arg-probe -fsave-optimization-record "SHELL:-mllvm -extra-vectorizer-passes" "SHELL:-mllvm -slp-vectorize-hor-store" "SHELL:-mllvm -slp-min-tree-size=1" "SHELL:-mllvm -slp-min-reg-size=64" "SHELL:-mllvm -slp-threshold=-1" "SHELL:-mllvm -enable-epilogue-vectorization">)
target_link_options(c2me-opts-natives-math PRIVATE -v -nostdlib -fuse-ld=lld -ffile-prefix-map=${CMAKE_SOURCE_DIR}=. -fdebug-compilation-dir=. -fdebug-prefix-map=${CMAKE_SOURCE_DIR}=. -fdebug-prefix-map=${LLVM_PREFIX}=.../llvm-prefix)

View File

@@ -0,0 +1,34 @@
#include <ext_math.h>
#include <target_macros.h>
TARGET_IMPL(c2me_natives_noise_perlin_sample, double, (const aligned_uint32_ptr permutations, const double originX,
const double originY, const double originZ, const double x,
const double y, const double z, const double yScale,
const double yMax) {
return math_noise_perlin_sample(permutations, originX, originY, originZ, x, y, z, yScale, yMax);
})
TARGET_IMPL(c2me_natives_noise_perlin_double, double, (const double_octave_sampler_data_t *const data,
const double x, const double y, const double z) {
return math_noise_perlin_double_octave_sample(data, x, y, z);
})
TARGET_IMPL(c2me_natives_noise_perlin_double_batch, void, (const double_octave_sampler_data_t *const data,
double *const res, const double *const x,
const double *const y, const double *const z,
const uint32_t length) {
math_noise_perlin_double_octave_sample_batch(data, res, x, y, z, length);
})
TARGET_IMPL(c2me_natives_noise_interpolated, double, (const interpolated_noise_sampler_t *const data,
const double x, const double y, const double z) {
return math_noise_perlin_interpolated_sample(data, x, y, z);
})
TARGET_IMPL(c2me_natives_end_islands_sample, float, (const aligned_uint32_ptr simplex_permutations, const int32_t x, const int32_t z) {
return math_end_islands_sample(simplex_permutations, x, z);
})
TARGET_IMPL(c2me_natives_biome_access_sample, uint32_t, (const int64_t theSeed, const int32_t x, const int32_t y, const int32_t z) {
return math_biome_access_sample(theSeed, x, y, z);
})

View File

@@ -0,0 +1,9 @@
#ifdef __x86_64__
#define GATHER_DISABLED 1
#include "exports.c"
#endif
typedef int make_iso_compiler_happy;

View File

@@ -0,0 +1,672 @@
#include <stddef.h>
#include <stdint.h>
#include <float.h>
typedef int make_iso_compilers_happy;
#ifdef WIN32
// ld.lld: error: <root>: undefined symbol: DllMainCRTStartup
int __stdcall DllMainCRTStartup(void* instance, unsigned reason, void* reserved)
{
(void) instance;
(void) reason;
(void) reserved;
return 1;
}
// ld.lld: error: undefined symbol: _fltused
int _fltused = 0;
// ld.lld: error: undefined symbol: abort
void abort(void)
{
__builtin_trap();
}
#endif // WIN32
/*
The following code is from musl, original license below:
musl as a whole is licensed under the following standard MIT license:
----------------------------------------------------------------------
Copyright © 2005-2020 Rich Felker, et al.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------
*/
// src/internal/libm.h
#if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
union ldshape {
long double f;
struct {
uint64_t m;
uint16_t se;
} i;
};
#elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
/* This is the m68k variant of 80-bit long double, and this definition only works
* on archs where the alignment requirement of uint64_t is <= 4. */
union ldshape {
long double f;
struct {
uint16_t se;
uint16_t pad;
uint64_t m;
} i;
};
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __LITTLE_ENDIAN
union ldshape {
long double f;
struct {
uint64_t lo;
uint32_t mid;
uint16_t top;
uint16_t se;
} i;
struct {
uint64_t lo;
uint64_t hi;
} i2;
};
#elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384 && __BYTE_ORDER == __BIG_ENDIAN
union ldshape {
long double f;
struct {
uint16_t se;
uint16_t top;
uint32_t mid;
uint64_t lo;
} i;
struct {
uint64_t hi;
uint64_t lo;
} i2;
};
#else
#error Unsupported long double representation
#endif
/* Support non-nearest rounding mode. */
#define WANT_ROUNDING 1
/* Support signaling NaNs. */
#define WANT_SNAN 0
#if WANT_SNAN
#error SNaN is unsupported
#else
#define issignalingf_inline(x) 0
#define issignaling_inline(x) 0
#endif
#ifndef TOINT_INTRINSICS
#define TOINT_INTRINSICS 0
#endif
#if TOINT_INTRINSICS
/* Round x to nearest int in all rounding modes, ties have to be rounded
consistently with converttoint so the results match. If the result
would be outside of [-2^31, 2^31-1] then the semantics is unspecified. */
static double_t roundtoint(double_t);
/* Convert x to nearest int in all rounding modes, ties have to be rounded
consistently with roundtoint. If the result is not representible in an
int32_t then the semantics is unspecified. */
static int32_t converttoint(double_t);
#endif
/* Helps static branch prediction so hot path can be better optimized. */
#ifdef __GNUC__
#define predict_true(x) __builtin_expect(!!(x), 1)
#define predict_false(x) __builtin_expect(x, 0)
#else
#define predict_true(x) (x)
#define predict_false(x) (x)
#endif
/* Evaluate an expression as the specified type. With standard excess
precision handling a type cast or assignment is enough (with
-ffloat-store an assignment is required, in old compilers argument
passing and return statement may not drop excess precision). */
static inline float eval_as_float(float x) {
float y = x;
return y;
}
static inline double eval_as_double(double x) {
double y = x;
return y;
}
/* fp_barrier returns its input, but limits code transformations
as if it had a side-effect (e.g. observable io) and returned
an arbitrary value. */
#ifndef fp_barrierf
#define fp_barrierf fp_barrierf
static inline float fp_barrierf(float x) {
volatile float y = x;
return y;
}
#endif
#ifndef fp_barrier
#define fp_barrier fp_barrier
static inline double fp_barrier(double x) {
volatile double y = x;
return y;
}
#endif
#ifndef fp_barrierl
#define fp_barrierl fp_barrierl
static inline long double fp_barrierl(long double x) {
volatile long double y = x;
return y;
}
#endif
/* fp_force_eval ensures that the input value is computed when that's
otherwise unused. To prevent the constant folding of the input
expression, an additional fp_barrier may be needed or a compilation
mode that does so (e.g. -frounding-math in gcc). Then it can be
used to evaluate an expression for its fenv side-effects only. */
#ifndef fp_force_evalf
#define fp_force_evalf fp_force_evalf
static inline void fp_force_evalf(float x) {
volatile float y;
y = x;
}
#endif
#ifndef fp_force_eval
#define fp_force_eval fp_force_eval
static inline void fp_force_eval(double x) {
volatile double y;
y = x;
}
#endif
#ifndef fp_force_evall
#define fp_force_evall fp_force_evall
static inline void fp_force_evall(long double x) {
volatile long double y;
y = x;
}
#endif
#define FORCE_EVAL(x) do { \
if (sizeof(x) == sizeof(float)) { \
fp_force_evalf(x); \
} else if (sizeof(x) == sizeof(double)) { \
fp_force_eval(x); \
} else { \
fp_force_evall(x); \
} \
} while(0)
#define asuint(f) ((union{float _f; uint32_t _i;}){f})._i
#define asfloat(i) ((union{uint32_t _i; float _f;}){i})._f
#define asuint64(f) ((union{double _f; uint64_t _i;}){f})._i
#define asdouble(i) ((union{uint64_t _i; double _f;}){i})._f
#define EXTRACT_WORDS(hi, lo, d) \
do { \
uint64_t __u = asuint64(d); \
(hi) = __u >> 32; \
(lo) = (uint32_t)__u; \
} while (0)
#define GET_HIGH_WORD(hi, d) \
do { \
(hi) = asuint64(d) >> 32; \
} while (0)
#define GET_LOW_WORD(lo, d) \
do { \
(lo) = (uint32_t)asuint64(d); \
} while (0)
#define INSERT_WORDS(d, hi, lo) \
do { \
(d) = asdouble(((uint64_t)(hi)<<32) | (uint32_t)(lo)); \
} while (0)
#define SET_HIGH_WORD(d, hi) \
INSERT_WORDS(d, hi, (uint32_t)asuint64(d))
#define SET_LOW_WORD(d, lo) \
INSERT_WORDS(d, asuint64(d)>>32, lo)
#define GET_FLOAT_WORD(w, d) \
do { \
(w) = asuint(d); \
} while (0)
#define SET_FLOAT_WORD(d, w) \
do { \
(d) = asfloat(w); \
} while (0)
static int __rem_pio2_large(double *, double *, int, int, int);
static int __rem_pio2(double, double *);
static double __sin(double, double, int);
static double __cos(double, double);
static double __tan(double, double, int);
static double __expo2(double, double);
static int __rem_pio2f(float, double *);
static float __sindf(double);
static float __cosdf(double);
static float __tandf(double, int);
static float __expo2f(float, float);
static int __rem_pio2l(long double, long double *);
static long double __sinl(long double, long double, int);
static long double __cosl(long double, long double);
static long double __tanl(long double, long double, int);
static long double __polevll(long double, const long double *, int);
static long double __p1evll(long double, const long double *, int);
//extern int __signgam;
static double __lgamma_r(double, int *);
static float __lgammaf_r(float, int *);
/* error handling functions */
static float __math_xflowf(uint32_t, float);
static float __math_uflowf(uint32_t);
static float __math_oflowf(uint32_t);
static float __math_divzerof(uint32_t);
static float __math_invalidf(float);
static double __math_xflow(uint32_t, double);
static double __math_uflow(uint32_t);
static double __math_oflow(uint32_t);
static double __math_divzero(uint32_t);
static double __math_invalid(double);
#if LDBL_MANT_DIG != DBL_MANT_DIG
static long double __math_invalidl(long double);
#endif
// src/math/__math_invalidf.c
static float __math_invalidf(float x)
{
return (x - x) / (x - x);
}
// src/math/truncf.c
float truncf(float x) {
union {
float f;
uint32_t i;
} u = {x};
int e = (int) (u.i >> 23 & 0xff) - 0x7f + 9;
uint32_t m;
if (e >= 23 + 9)
return x;
if (e < 9)
e = 1;
m = -1U >> e;
if ((u.i & m) == 0)
return x;
FORCE_EVAL(x + 0x1p120f);
u.i &= ~m;
return u.f;
}
// src/math/floor.c
#if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1
#define EPS DBL_EPSILON
#elif FLT_EVAL_METHOD == 2
#define EPS LDBL_EPSILON
#endif
static const double toint = 1 / EPS;
double floor(double x) {
union {
double f;
uint64_t i;
} u = {x};
int e = u.i >> 52 & 0x7ff;
double y;
if (e >= 0x3ff + 52 || x == 0)
return x;
/* y = int(x) - x, where int(x) is an integer neighbor of x */
if (u.i >> 63)
y = x - toint + toint - x;
else
y = x + toint - toint - x;
/* special case because of non-nearest rounding modes */
if (e <= 0x3ff - 1) {
FORCE_EVAL(y);
return u.i >> 63 ? -1 : 0;
}
if (y > 0)
return x + y - 1;
return x + y;
}
// src/math/fmodf.c
float fmodf(float x, float y) {
union {
float f;
uint32_t i;
} ux = {x}, uy = {y};
int ex = ux.i >> 23 & 0xff;
int ey = uy.i >> 23 & 0xff;
uint32_t sx = ux.i & 0x80000000;
uint32_t i;
uint32_t uxi = ux.i;
if (uy.i << 1 == 0 || __builtin_isnan(y) || ex == 0xff)
return (x * y) / (x * y);
if (uxi << 1 <= uy.i << 1) {
if (uxi << 1 == uy.i << 1)
return 0 * x;
return x;
}
/* normalize x and y */
if (!ex) {
for (i = uxi << 9; i >> 31 == 0; ex--, i <<= 1);
uxi <<= -ex + 1;
} else {
uxi &= -1U >> 9;
uxi |= 1U << 23;
}
if (!ey) {
for (i = uy.i << 9; i >> 31 == 0; ey--, i <<= 1);
uy.i <<= -ey + 1;
} else {
uy.i &= -1U >> 9;
uy.i |= 1U << 23;
}
/* x mod y */
for (; ex > ey; ex--) {
i = uxi - uy.i;
if (i >> 31 == 0) {
if (i == 0)
return 0 * x;
uxi = i;
}
uxi <<= 1;
}
i = uxi - uy.i;
if (i >> 31 == 0) {
if (i == 0)
return 0 * x;
uxi = i;
}
for (; uxi >> 23 == 0; uxi <<= 1, ex--);
/* scale result up */
if (ex > 0) {
uxi -= 1U << 23;
uxi |= (uint32_t) ex << 23;
} else {
uxi >>= -ex + 1;
}
uxi |= sx;
ux.i = uxi;
return ux.f;
}
// src/string/memset.c
void *memset(void *dest, int c, size_t n) {
unsigned char *s = dest;
size_t k;
/* Fill head and tail with minimal branching. Each
* conditional ensures that all the subsequently used
* offsets are well-defined and in the dest region. */
if (!n) return dest;
s[0] = c;
s[n - 1] = c;
if (n <= 2) return dest;
s[1] = c;
s[2] = c;
s[n - 2] = c;
s[n - 3] = c;
if (n <= 6) return dest;
s[3] = c;
s[n - 4] = c;
if (n <= 8) return dest;
/* Advance pointer to align it at a 4-byte boundary,
* and truncate n to a multiple of 4. The previous code
* already took care of any head/tail that get cut off
* by the alignment. */
k = -(uintptr_t) s & 3;
s += k;
n -= k;
n &= -4;
#ifdef __GNUC__
typedef uint32_t __attribute__((__may_alias__)) u32;
typedef uint64_t __attribute__((__may_alias__)) u64;
u32 c32 = ((u32) -1) / 255 * (unsigned char) c;
/* In preparation to copy 32 bytes at a time, aligned on
* an 8-byte bounary, fill head/tail up to 28 bytes each.
* As in the initial byte-based head/tail fill, each
* conditional below ensures that the subsequent offsets
* are valid (e.g. !(n<=24) implies n>=28). */
*(u32 *) (s + 0) = c32;
*(u32 *) (s + n - 4) = c32;
if (n <= 8) return dest;
*(u32 *) (s + 4) = c32;
*(u32 *) (s + 8) = c32;
*(u32 *) (s + n - 12) = c32;
*(u32 *) (s + n - 8) = c32;
if (n <= 24) return dest;
*(u32 *) (s + 12) = c32;
*(u32 *) (s + 16) = c32;
*(u32 *) (s + 20) = c32;
*(u32 *) (s + 24) = c32;
*(u32 *) (s + n - 28) = c32;
*(u32 *) (s + n - 24) = c32;
*(u32 *) (s + n - 20) = c32;
*(u32 *) (s + n - 16) = c32;
/* Align to a multiple of 8 so we can fill 64 bits at a time,
* and avoid writing the same bytes twice as much as is
* practical without introducing additional branching. */
k = 24 + ((uintptr_t) s & 4);
s += k;
n -= k;
/* If this loop is reached, 28 tail bytes have already been
* filled, so any remainder when n drops below 32 can be
* safely ignored. */
u64 c64 = c32 | ((u64) c32 << 32);
for (; n >= 32; n -= 32, s += 32) {
*(u64 *) (s + 0) = c64;
*(u64 *) (s + 8) = c64;
*(u64 *) (s + 16) = c64;
*(u64 *) (s + 24) = c64;
}
#else
/* Pure C fallback with no aliasing violations. */
for (; n; n--, s++) *s = c;
#endif
return dest;
}
// src/math/sqrt_data.[c|h]
/* if x in [1,2): i = (int)(64*x);
if x in [2,4): i = (int)(32*x-64);
__rsqrt_tab[i]*2^-16 is estimating 1/sqrt(x) with small relative error:
|__rsqrt_tab[i]*0x1p-16*sqrt(x) - 1| < -0x1.fdp-9 < 2^-8 */
extern const uint16_t __rsqrt_tab[128] = {
0xb451, 0xb2f0, 0xb196, 0xb044, 0xaef9, 0xadb6, 0xac79, 0xab43,
0xaa14, 0xa8eb, 0xa7c8, 0xa6aa, 0xa592, 0xa480, 0xa373, 0xa26b,
0xa168, 0xa06a, 0x9f70, 0x9e7b, 0x9d8a, 0x9c9d, 0x9bb5, 0x9ad1,
0x99f0, 0x9913, 0x983a, 0x9765, 0x9693, 0x95c4, 0x94f8, 0x9430,
0x936b, 0x92a9, 0x91ea, 0x912e, 0x9075, 0x8fbe, 0x8f0a, 0x8e59,
0x8daa, 0x8cfe, 0x8c54, 0x8bac, 0x8b07, 0x8a64, 0x89c4, 0x8925,
0x8889, 0x87ee, 0x8756, 0x86c0, 0x862b, 0x8599, 0x8508, 0x8479,
0x83ec, 0x8361, 0x82d8, 0x8250, 0x81c9, 0x8145, 0x80c2, 0x8040,
0xff02, 0xfd0e, 0xfb25, 0xf947, 0xf773, 0xf5aa, 0xf3ea, 0xf234,
0xf087, 0xeee3, 0xed47, 0xebb3, 0xea27, 0xe8a3, 0xe727, 0xe5b2,
0xe443, 0xe2dc, 0xe17a, 0xe020, 0xdecb, 0xdd7d, 0xdc34, 0xdaf1,
0xd9b3, 0xd87b, 0xd748, 0xd61a, 0xd4f1, 0xd3cd, 0xd2ad, 0xd192,
0xd07b, 0xcf69, 0xce5b, 0xcd51, 0xcc4a, 0xcb48, 0xca4a, 0xc94f,
0xc858, 0xc764, 0xc674, 0xc587, 0xc49d, 0xc3b7, 0xc2d4, 0xc1f4,
0xc116, 0xc03c, 0xbf65, 0xbe90, 0xbdbe, 0xbcef, 0xbc23, 0xbb59,
0xba91, 0xb9cc, 0xb90a, 0xb84a, 0xb78c, 0xb6d0, 0xb617, 0xb560,
};
// src/math/sqrtf.c
#define FENV_SUPPORT 1
static inline uint32_t mul32(uint32_t a, uint32_t b) {
return (uint64_t) a * b >> 32;
}
/* see sqrt.c for more detailed comments. */
float sqrtf(float x) {
uint32_t ix, m, m1, m0, even, ey;
ix = asuint(x);
if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) {
/* x < 0x1p-126 or inf or nan. */
if (ix * 2 == 0)
return x;
if (ix == 0x7f800000)
return x;
if (ix > 0x7f800000)
return __math_invalidf(x);
/* x is subnormal, normalize it. */
ix = asuint(x * 0x1p23f);
ix -= 23 << 23;
}
/* x = 4^e m; with int e and m in [1, 4). */
even = ix & 0x00800000;
m1 = (ix << 8) | 0x80000000;
m0 = (ix << 7) & 0x7fffffff;
m = even ? m0 : m1;
/* 2^e is the exponent part of the return value. */
ey = ix >> 1;
ey += 0x3f800000 >> 1;
ey &= 0x7f800000;
/* compute r ~ 1/sqrt(m), s ~ sqrt(m) with 2 goldschmidt iterations. */
static const uint32_t three = 0xc0000000;
uint32_t r, s, d, u, i;
i = (ix >> 17) % 128;
r = (uint32_t) __rsqrt_tab[i] << 16;
/* |r*sqrt(m) - 1| < 0x1p-8 */
s = mul32(m, r);
/* |s/sqrt(m) - 1| < 0x1p-8 */
d = mul32(s, r);
u = three - d;
r = mul32(r, u) << 1;
/* |r*sqrt(m) - 1| < 0x1.7bp-16 */
s = mul32(s, u) << 1;
/* |s/sqrt(m) - 1| < 0x1.7bp-16 */
d = mul32(s, r);
u = three - d;
s = mul32(s, u);
/* -0x1.03p-28 < s/sqrt(m) - 1 < 0x1.fp-31 */
s = (s - 1) >> 6;
/* s < sqrt(m) < s + 0x1.08p-23 */
/* compute nearest rounded result. */
uint32_t d0, d1, d2;
float y, t;
d0 = (m << 16) - s * s;
d1 = s - d0;
d2 = d1 + s + 1;
s += d1 >> 31;
s &= 0x007fffff;
s |= ey;
y = asfloat(s);
if (FENV_SUPPORT) {
/* handle rounding and inexact exception. */
uint32_t tiny = predict_false(d2 == 0) ? 0 : 0x01000000;
tiny |= (d1 ^ d2) & 0x80000000;
t = asfloat(tiny);
y = eval_as_float(y + t);
}
return y;
}

View File

@@ -0,0 +1,744 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include <stddef.h>
#include <float.h>
__attribute__((aligned(64))) static const double FLAT_SIMPLEX_GRAD[] = {
1, 1, 0, 0,
-1, 1, 0, 0,
1, -1, 0, 0,
-1, -1, 0, 0,
1, 0, 1, 0,
-1, 0, 1, 0,
1, 0, -1, 0,
-1, 0, -1, 0,
0, 1, 1, 0,
0, -1, 1, 0,
0, 1, -1, 0,
0, -1, -1, 0,
1, 1, 0, 0,
0, -1, 1, 0,
-1, 1, 0, 0,
0, -1, -1, 0,
};
static const double SQRT_3 = 1.7320508075688772;
// 0.5 * (SQRT_3 - 1.0)
static const double SKEW_FACTOR_2D = 0.3660254037844386;
// (3.0 - SQRT_3) / 6.0
static const double UNSKEW_FACTOR_2D = 0.21132486540518713;
typedef const double *aligned_double_ptr __attribute__((align_value(64)));
typedef const uint8_t *aligned_uint8_ptr __attribute__((align_value(64)));
typedef const uint32_t *aligned_uint32_ptr __attribute__((align_value(64)));
#pragma clang attribute push (__attribute__((always_inline)), apply_to = function)
static inline __attribute__((const)) float fminf(const float x, const float y) {
return __builtin_fminf(x, y);
}
static inline __attribute__((const)) float fmaxf(const float x, const float y) {
return __builtin_fmaxf(x, y);
}
static inline __attribute__((const)) float fabsf(const float x) {
union {
float f;
uint32_t i;
} u = {x};
u.i &= 0x7fffffff;
return u.f;
}
static inline __attribute__((const)) int64_t labs(const int64_t x) {
return __builtin_labs(x);
}
static inline __attribute__((const)) double floor(double x) {
return __builtin_floor(x);
}
static inline __attribute__((const)) float sqrtf(float x) {
return __builtin_sqrtf(x);
}
static inline __attribute__((const)) float fmodf(float x, float y) {
return __builtin_fmodf(x, y);
}
static inline __attribute__((const)) int32_t math_floorDiv(const int32_t x, const int32_t y) {
int r = x / y;
// if the signs are different and modulo not zero, round down
if ((x ^ y) < 0 && (r * y != x)) {
r--;
}
return r;
}
static inline __attribute__((const)) float clampf(const float value, const float min, const float max) {
return fminf(fmaxf(value, min), max);
}
static inline __attribute__((const)) double math_octave_maintainPrecision(const double value) {
return value - floor(value / 3.3554432E7 + 0.5) * 3.3554432E7;
}
static inline __attribute__((const)) double math_simplex_grad(const int32_t hash, const double x, const double y,
const double z, const double distance) {
double d = distance - x * x - y * y - z * z;
if (d < 0.0) {
return 0.0;
} else {
int32_t i = hash << 2;
double var0 = FLAT_SIMPLEX_GRAD[i | 0] * x;
double var1 = FLAT_SIMPLEX_GRAD[i | 1] * y;
double var2 = FLAT_SIMPLEX_GRAD[i | 2] * z;
return d * d * d * d * (var0 + var1 + var2);
}
}
static inline __attribute__((const)) double math_lerp(const double delta, const double start, const double end) {
return start + delta * (end - start);
}
static inline __attribute__((const)) float math_lerpf(const float delta, const float start, const float end) {
return start + delta * (end - start);
}
static inline __attribute__((const)) double math_clampedLerp(const double start, const double end, const double delta) {
if (delta < 0.0) {
return start;
} else {
return delta > 1.0 ? end : math_lerp(delta, start, end);
}
}
static inline __attribute__((const)) double math_square(const double operand) {
return operand * operand;
}
static inline __attribute__((const)) double math_lerp2(const double deltaX, const double deltaY, const double x0y0,
const double x1y0, const double x0y1, const double x1y1) {
return math_lerp(deltaY, math_lerp(deltaX, x0y0, x1y0), math_lerp(deltaX, x0y1, x1y1));
}
static inline __attribute__((const)) double math_lerp3(
const double deltaX,
const double deltaY,
const double deltaZ,
const double x0y0z0,
const double x1y0z0,
const double x0y1z0,
const double x1y1z0,
const double x0y0z1,
const double x1y0z1,
const double x0y1z1,
const double x1y1z1
) {
return math_lerp(deltaZ, math_lerp2(deltaX, deltaY, x0y0z0, x1y0z0, x0y1z0, x1y1z0),
math_lerp2(deltaX, deltaY, x0y0z1, x1y0z1, x0y1z1, x1y1z1));
}
static inline __attribute__((const)) double math_getLerpProgress(const double value, const double start,
const double end) {
return (value - start) / (end - start);
}
static inline __attribute__((const)) double
math_clampedLerpFromProgress(const double lerpValue, const double lerpStart, const double lerpEnd, const double start,
const double end) {
return math_clampedLerp(start, end, math_getLerpProgress(lerpValue, lerpStart, lerpEnd));
}
static inline __attribute__((const)) int32_t math_floorMod(const int32_t x, const int32_t y) {
int32_t mod = x % y;
// if the signs are different and modulo not zero, adjust result
if ((mod ^ y) < 0 && mod != 0) {
mod += y;
}
return mod;
}
static inline __attribute__((const)) int32_t math_biome2block(const int32_t biomeCoord) {
return biomeCoord << 2;
}
static inline __attribute__((const)) int32_t math_block2biome(const int32_t blockCoord) {
return blockCoord >> 2;
}
static inline __attribute__((const)) uint32_t
__math_simplex_map(const aligned_uint32_ptr permutations, const int32_t input) {
return permutations[input & 0xFF];
}
static inline __attribute__((const)) double math_simplex_dot(const int32_t hash, const double x, const double y,
const double z) {
const int32_t loc = hash << 2;
return FLAT_SIMPLEX_GRAD[loc + 0] * x + FLAT_SIMPLEX_GRAD[loc + 1] * y + FLAT_SIMPLEX_GRAD[loc + 2] * z;
}
static inline __attribute__((const)) double __math_simplex_grad(const int32_t hash, const double x, const double y,
const double z, const double distance) {
double d = distance - x * x - y * y - z * z;
double e;
if (d < 0.0) {
e = 0.0;
} else {
d *= d;
e = d * d * math_simplex_dot(hash, x, y, z);
}
return e;
// double tmp = d * d; // speculative execution
// return d < 0.0 ? 0.0 : tmp * tmp * math_simplex_dot(hash, x, y, z);
}
static inline double __attribute__((const))
math_noise_simplex_sample2d(const aligned_uint32_ptr permutations, const double x, const double y) {
const double d = (x + y) * SKEW_FACTOR_2D;
const double i = floor(x + d);
const double j = floor(y + d);
const double e = (i + j) * UNSKEW_FACTOR_2D;
const double f = i - e;
const double g = j - e;
const double h = x - f;
const double k = y - g;
double l;
int32_t li;
double m;
int32_t mi;
if (h > k) {
l = 1;
li = 1;
m = 0;
mi = 0;
} else {
l = 0;
li = 1;
m = 1;
mi = 1;
}
const double n = h - (double) l + UNSKEW_FACTOR_2D;
const double o = k - (double) m + UNSKEW_FACTOR_2D;
const double p = h - 1.0 + 2.0 * UNSKEW_FACTOR_2D;
const double q = k - 1.0 + 2.0 * UNSKEW_FACTOR_2D;
const int32_t r = (int32_t) i & 0xFF;
const int32_t s = (int32_t) j & 0xFF;
const int32_t t = __math_simplex_map(permutations, r + __math_simplex_map(permutations, s)) % 12;
const int32_t u = __math_simplex_map(permutations, r + li + __math_simplex_map(permutations, s + mi)) % 12;
const int32_t v = __math_simplex_map(permutations, r + 1 + __math_simplex_map(permutations, s + 1)) % 12;
const double w = __math_simplex_grad(t, h, k, 0.0, 0.5);
const double z = __math_simplex_grad(u, n, o, 0.0, 0.5);
const double aa = __math_simplex_grad(v, p, q, 0.0, 0.5);
return 70.0 * (w + z + aa);
}
static inline __attribute__((const)) double math_perlinFade(const double value) {
return value * value * value * (value * (value * 6.0 - 15.0) + 10.0);
}
static inline __attribute__((const)) double __math_perlin_grad(const aligned_uint32_ptr permutations, const int32_t px,
const int32_t py, const int32_t pz, const double fx,
const double fy, const double fz) {
const double f[3] = {fx, fy, fz};
const int32_t p[3] = {px, py, pz};
const uint32_t q[3] = {p[0] & 0xFF, p[1] & 0xFF, p[2] & 0xFF};
const uint32_t hash = permutations[(permutations[(permutations[q[0]] + q[1]) & 0xFF] + q[2]) & 0xFF] & 0xF;
const double *const grad = FLAT_SIMPLEX_GRAD + (hash << 2);
return grad[0] * f[0] + grad[1] * f[1] + grad[2] * f[2];
}
static inline __attribute__((const)) double
math_noise_perlin_sampleScalar(const aligned_uint32_ptr permutations,
const int32_t px0, const int32_t py0, const int32_t pz0,
const double fx0, const double fy0, const double fz0, const double fadeLocalY) {
const int32_t px1 = px0 + 1;
const int32_t py1 = py0 + 1;
const int32_t pz1 = pz0 + 1;
const double fx1 = fx0 - 1;
const double fy1 = fy0 - 1;
const double fz1 = fz0 - 1;
const double f000 = __math_perlin_grad(permutations, px0, py0, pz0, fx0, fy0, fz0);
const double f100 = __math_perlin_grad(permutations, px1, py0, pz0, fx1, fy0, fz0);
const double f010 = __math_perlin_grad(permutations, px0, py1, pz0, fx0, fy1, fz0);
const double f110 = __math_perlin_grad(permutations, px1, py1, pz0, fx1, fy1, fz0);
const double f001 = __math_perlin_grad(permutations, px0, py0, pz1, fx0, fy0, fz1);
const double f101 = __math_perlin_grad(permutations, px1, py0, pz1, fx1, fy0, fz1);
const double f011 = __math_perlin_grad(permutations, px0, py1, pz1, fx0, fy1, fz1);
const double f111 = __math_perlin_grad(permutations, px1, py1, pz1, fx1, fy1, fz1);
const double dx = math_perlinFade(fx0);
const double dy = math_perlinFade(fadeLocalY);
const double dz = math_perlinFade(fz0);
return math_lerp3(dx, dy, dz, f000, f100, f010, f110, f001, f101, f011, f111);
}
static inline __attribute__((const)) double
math_noise_perlin_sample(const aligned_uint32_ptr permutations,
const double originX, const double originY, const double originZ,
const double x, const double y, const double z,
const double yScale, const double yMax) {
const double d = x + originX;
const double e = y + originY;
const double f = z + originZ;
const double i = floor(d);
const double j = floor(e);
const double k = floor(f);
const double g = d - i;
const double h = e - j;
const double l = f - k;
const double o = yScale != 0 ? floor(((yMax >= 0.0 && yMax < h) ? yMax : h) / yScale + 1.0E-7) * yScale : 0;
return math_noise_perlin_sampleScalar(permutations, (int32_t) i, (int32_t) j, (int32_t) k, g, h - o, l, h);
}
typedef const struct double_octave_sampler_data {
const uint64_t length;
const double amplitude;
const bool *const need_shift;
const aligned_double_ptr lacunarity_powd;
const aligned_double_ptr persistence_powd;
const aligned_uint32_ptr sampler_permutations;
const aligned_double_ptr sampler_originX;
const aligned_double_ptr sampler_originY;
const aligned_double_ptr sampler_originZ;
const aligned_double_ptr amplitudes;
} double_octave_sampler_data_t;
static inline __attribute__((const)) double
math_noise_perlin_double_octave_sample_impl(const double_octave_sampler_data_t *const data,
const double x, const double y, const double z,
const double yScale, const double yMax, const uint8_t useOrigin) {
double ds[data->length];
#pragma clang loop vectorize(enable) interleave(enable) interleave_count(2)
for (uint32_t i = 0; i < data->length; i++) {
const double e = data->lacunarity_powd[i];
const double f = data->persistence_powd[i];
const aligned_uint32_ptr permutations = data->sampler_permutations + 256 * i;
const double sampleX = data->need_shift[i] ? x * 1.0181268882175227 : x;
const double sampleY = data->need_shift[i] ? y * 1.0181268882175227 : y;
const double sampleZ = data->need_shift[i] ? z * 1.0181268882175227 : z;
const double g = math_noise_perlin_sample(
permutations,
data->sampler_originX[i],
data->sampler_originY[i],
data->sampler_originZ[i],
math_octave_maintainPrecision(sampleX * e),
useOrigin ? -(data->sampler_originY[i]) : math_octave_maintainPrecision(sampleY * e),
math_octave_maintainPrecision(sampleZ * e),
yScale * e,
yMax * e);
ds[i] = data->amplitudes[i] * g * f;
}
double d1 = 0.0;
double d2 = 0.0;
for (uint32_t i = 0; i < data->length; i++) {
if (!data->need_shift[i]) {
d1 += ds[i];
} else {
d2 += ds[i];
}
}
return (d1 + d2) * data->amplitude;
}
//static inline void
//math_noise_perlin_double_octave_sample_impl_batch(const double_octave_sampler_data_t *const data, double *const res,
// const double *const x, const double *const y, const double *const z,
// const uint32_t length) {
// double ds[data->length][length];
//
// for (uint32_t si = 0; si < data->length; si ++) {
//#pragma clang loop vectorize(enable) interleave(enable) interleave_count(2)
// for (uint32_t bi = 0; bi < length; bi++) {
// const double e = data->lacunarity_powd[si];
// const double f = data->persistence_powd[si];
// const aligned_uint32_ptr permutations = data->sampler_permutations + 256 * si;
// const double sampleX = data->need_shift[si] ? x[bi] * 1.0181268882175227 : x[bi];
// const double sampleY = data->need_shift[si] ? y[bi] * 1.0181268882175227 : y[bi];
// const double sampleZ = data->need_shift[si] ? z[bi] * 1.0181268882175227 : z[bi];
// const double g = math_noise_perlin_sample(
// permutations,
// data->sampler_originX[si],
// data->sampler_originY[si],
// data->sampler_originZ[si],
// math_octave_maintainPrecision(sampleX * e),
// math_octave_maintainPrecision(sampleY * e),
// math_octave_maintainPrecision(sampleZ * e),
// 0.0,
// 0.0);
// ds[si][bi] = data->amplitudes[si] * g * f;
// }
// }
//
// double d1[length];
// double d2[length];
// for (uint32_t i = 0; i < length; i ++) {
// d1[i] = 0.0;
// d2[i] = 0.0;
// }
// for (uint32_t bi = 0; bi < length; bi++) {
// for (uint32_t si = 0; si < data->length; si ++) {
// if (!data->need_shift[si]) {
// d1[bi] += ds[si][bi];
// } else {
// d2[bi] += ds[si][bi];
// }
// }
// }
// for (uint32_t bi = 0; bi < length; bi++) {
// res[bi] = (d1[bi] + d2[bi]) * data->amplitude;
// }
//}
//static inline void
//math_noise_perlin_double_octave_sample_impl_batch(const double_octave_sampler_data_t *restrict const data,
// double *restrict const res, const double *restrict const x,
// const double *restrict const y, const double *restrict const z,
// const uint32_t length) {
// const uint32_t total_len = data->length * length;
//
// double ds[total_len];
// uint32_t sia[total_len]; // sampler index array
// uint32_t bia[total_len]; // batch index array
// double xa[total_len]; // x array
// double ya[total_len]; // y array
// double za[total_len]; // z array
//
// double lacunarity_powd[total_len];
// double persistence_powd[total_len];
// bool need_shift[total_len];
// double sampler_originX[total_len];
// double sampler_originY[total_len];
// double sampler_originZ[total_len];
// double amplitudes[total_len];
//
// {
// uint32_t idx = 0;
// for (uint32_t si = 0; si < data->length; si++) {
// for (uint32_t bi = 0; bi < length; bi++) {
// sia[idx] = si;
// bia[idx] = bi;
// xa[idx] = x[bi];
// ya[idx] = y[bi];
// za[idx] = z[bi];
// lacunarity_powd[idx] = data->lacunarity_powd[si];
// persistence_powd[idx] = data->persistence_powd[si];
// need_shift[idx] = data->need_shift[si];
// sampler_originX[idx] = data->sampler_originX[si];
// sampler_originY[idx] = data->sampler_originY[si];
// sampler_originZ[idx] = data->sampler_originZ[si];
// amplitudes[idx] = data->amplitudes[si];
// idx++;
// }
// }
// }
//
//#pragma clang loop vectorize(enable) interleave(enable) interleave_count(2)
// for (uint32_t idx = 0; idx < total_len; idx++) {
// const uint32_t si = sia[idx];
// const double xi = xa[idx];
// const double yi = ya[idx];
// const double zi = za[idx];
// const double e = lacunarity_powd[idx];
// const double f = persistence_powd[idx];
// const aligned_uint32_ptr permutations = data->sampler_permutations + 256 * si;
// const double sampleX = need_shift[idx] ? xi * 1.0181268882175227 : xi;
// const double sampleY = need_shift[idx] ? yi * 1.0181268882175227 : yi;
// const double sampleZ = need_shift[idx] ? zi * 1.0181268882175227 : zi;
// const double g = math_noise_perlin_sample(
// permutations,
// sampler_originX[idx],
// sampler_originY[idx],
// sampler_originZ[idx],
// math_octave_maintainPrecision(sampleX * e),
// math_octave_maintainPrecision(sampleY * e),
// math_octave_maintainPrecision(sampleZ * e),
// 0.0,
// 0.0);
// ds[idx] = amplitudes[idx] * g * f;
// }
//
// double d1[length];
// double d2[length];
// for (uint32_t i = 0; i < length; i++) {
// d1[i] = 0.0;
// d2[i] = 0.0;
// }
// for (uint32_t idx = 0; idx < total_len; idx++) {
// const uint32_t si = sia[idx];
// const uint32_t bi = bia[idx];
// if (!data->need_shift[si]) {
// d1[bi] += ds[idx];
// } else {
// d2[bi] += ds[idx];
// }
// }
// for (uint32_t bi = 0; bi < length; bi++) {
// res[bi] = (d1[bi] + d2[bi]) * data->amplitude;
// }
//}
static inline __attribute__((const)) double
math_noise_perlin_double_octave_sample(const double_octave_sampler_data_t *const data,
const double x, const double y, const double z) {
return math_noise_perlin_double_octave_sample_impl(data, x, y, z, 0.0, 0.0, 0);
}
static inline void
math_noise_perlin_double_octave_sample_batch(const double_octave_sampler_data_t *const data, double *const res,
const double *const x, const double *const y, const double *const z,
const uint32_t length) {
// math_noise_perlin_double_octave_sample_impl_batch(data, res, x, y, z, length);
for (uint32_t i = 0; i < length; i ++) {
res[i] = math_noise_perlin_double_octave_sample_impl(data, x[i], y[i], z[i], 0.0, 0.0, 0);
}
}
typedef const struct interpolated_noise_sub_sampler {
const aligned_uint32_ptr sampler_permutations;
const aligned_double_ptr sampler_originX;
const aligned_double_ptr sampler_originY;
const aligned_double_ptr sampler_originZ;
const aligned_double_ptr sampler_mulFactor;
const uint32_t length;
} interpolated_noise_sub_sampler_t;
typedef const struct interpolated_noise_sampler {
const double scaledXzScale;
const double scaledYScale;
const double xzFactor;
const double yFactor;
const double smearScaleMultiplier;
const double xzScale;
const double yScale;
const interpolated_noise_sub_sampler_t lower;
const interpolated_noise_sub_sampler_t upper;
const interpolated_noise_sub_sampler_t normal;
} interpolated_noise_sampler_t;
static inline __attribute__((const)) double
math_noise_perlin_interpolated_sample(const interpolated_noise_sampler_t *const data,
const double x, const double y, const double z) {
const double d = x * data->scaledXzScale;
const double e = y * data->scaledYScale;
const double f = z * data->scaledXzScale;
const double g = d / data->xzFactor;
const double h = e / data->yFactor;
const double i = f / data->xzFactor;
const double j = data->scaledYScale * data->smearScaleMultiplier;
const double k = j / data->yFactor;
double l = 0.0;
double m = 0.0;
double n = 0.0;
double ns[data->normal.length];
#pragma clang loop vectorize(enable)
for (uint32_t offset = 0; offset < data->normal.length; offset++) {
ns[offset] = math_noise_perlin_sample(
data->normal.sampler_permutations + 256 * offset,
data->normal.sampler_originX[offset],
data->normal.sampler_originY[offset],
data->normal.sampler_originZ[offset],
math_octave_maintainPrecision(g * data->normal.sampler_mulFactor[offset]),
math_octave_maintainPrecision(h * data->normal.sampler_mulFactor[offset]),
math_octave_maintainPrecision(i * data->normal.sampler_mulFactor[offset]),
k * data->normal.sampler_mulFactor[offset],
h * data->normal.sampler_mulFactor[offset]
) / data->normal.sampler_mulFactor[offset];
}
for (uint32_t offset = 0; offset < data->normal.length; offset++) {
n += ns[offset];
}
const double q = (n / 10.0 + 1.0) / 2.0;
const uint8_t bl2 = q >= 1.0;
const uint8_t bl3 = q <= 0.0;
if (!bl2) {
double ls[data->lower.length];
#pragma clang loop vectorize(enable) interleave_count(2)
for (uint32_t offset = 0; offset < data->lower.length; offset++) {
ls[offset] = math_noise_perlin_sample(
data->lower.sampler_permutations + 256 * offset,
data->lower.sampler_originX[offset],
data->lower.sampler_originY[offset],
data->lower.sampler_originZ[offset],
math_octave_maintainPrecision(d * data->lower.sampler_mulFactor[offset]),
math_octave_maintainPrecision(e * data->lower.sampler_mulFactor[offset]),
math_octave_maintainPrecision(f * data->lower.sampler_mulFactor[offset]),
j * data->lower.sampler_mulFactor[offset],
e * data->lower.sampler_mulFactor[offset]
) / data->lower.sampler_mulFactor[offset];
}
for (uint32_t offset = 0; offset < data->lower.length; offset++) {
l += ls[offset];
}
}
if (!bl3) {
double ms[data->upper.length];
#pragma clang loop vectorize(enable) interleave_count(2)
for (uint32_t offset = 0; offset < data->upper.length; offset++) {
ms[offset] = math_noise_perlin_sample(
data->upper.sampler_permutations + 256 * offset,
data->upper.sampler_originX[offset],
data->upper.sampler_originY[offset],
data->upper.sampler_originZ[offset],
math_octave_maintainPrecision(d * data->upper.sampler_mulFactor[offset]),
math_octave_maintainPrecision(e * data->upper.sampler_mulFactor[offset]),
math_octave_maintainPrecision(f * data->upper.sampler_mulFactor[offset]),
j * data->upper.sampler_mulFactor[offset],
e * data->upper.sampler_mulFactor[offset]
) / data->upper.sampler_mulFactor[offset];
}
for (uint32_t offset = 0; offset < data->upper.length; offset++) {
m += ms[offset];
}
}
return math_clampedLerp(l / 512.0, m / 512.0, q) / 128.0;
}
static inline __attribute__((const)) float
math_end_islands_sample(const aligned_uint32_ptr simplex_permutations, const int32_t x, const int32_t z) {
const int32_t i = x / 2;
const int32_t j = z / 2;
const int32_t k = x % 2;
const int32_t l = z % 2;
const int32_t muld = x * x + z * z; // int32_t intentionally
if (muld < 0) {
return __builtin_nanf("");
}
float f = 100.0F - sqrtf((float) muld) * 8.0F;
f = clampf(f, -100.0F, 80.0F);
int8_t ms[25 * 25], ns[25 * 25], hit[25 * 25];
const int64_t omin = labs(i) - 12LL;
const int64_t pmin = labs(j) - 12LL;
const int64_t omax = labs(i) + 12LL;
const int64_t pmax = labs(j) + 12LL;
{
uint32_t idx = 0;
#pragma clang loop vectorize(enable)
for (int8_t m = -12; m < 13; m++) {
for (int8_t n = -12; n < 13; n++) {
ms[idx] = m;
ns[idx] = n;
idx++;
}
}
if (idx != 25 * 25) {
__builtin_trap();
}
}
if (omin * omin + pmin * pmin > 4096LL) {
for (uint32_t idx = 0; idx < 25 * 25; idx++) {
const int64_t o = (int64_t) i + (int64_t) ms[idx];
const int64_t p = (int64_t) j + (int64_t) ns[idx];
hit[idx] = math_noise_simplex_sample2d(simplex_permutations, (double) o, (double) p) < -0.9F;
}
} else {
for (uint32_t idx = 0; idx < 25 * 25; idx++) {
const int64_t o = (int64_t) i + (int64_t) ms[idx];
const int64_t p = (int64_t) j + (int64_t) ns[idx];
hit[idx] = (o * o + p * p > 4096LL) && math_noise_simplex_sample2d(
simplex_permutations, (double) o, (double) p) < -0.9F;
}
}
#pragma clang loop vectorize(enable) interleave(enable)
for (uint32_t idx = 0; idx < 25 * 25; idx++) {
if (hit[idx]) {
const int32_t m = ms[idx];
const int32_t n = ns[idx];
const int64_t o = (int64_t) i + (int64_t) m;
const int64_t p = (int64_t) j + (int64_t) n;
const float g1 = fabsf((float) o) * 3439.0F;
const float g2 = fabsf((float) p) * 147.0F;
const float g = fmodf((g1 + g2), 13.0F) + 9.0F;
const float h = (float) (k - m * 2);
const float q = (float) (l - n * 2);
float r = 100.0F - sqrtf(h * h + q * q) * g;
r = clampf(r, -100.0F, 80.0F);
f = fmaxf(f, r);
}
}
return f;
}
static inline __attribute__((const)) uint32_t
math_biome_access_sample(const int64_t theSeed, const int32_t x, const int32_t y, const int32_t z) {
const int32_t var0 = x - 2;
const int32_t var1 = y - 2;
const int32_t var2 = z - 2;
const int32_t var3 = var0 >> 2;
const int32_t var4 = var1 >> 2;
const int32_t var5 = var2 >> 2;
const double var6 = (double) (var0 & 3) / 4.0;
const double var7 = (double) (var1 & 3) / 4.0;
const double var8 = (double) (var2 & 3) / 4.0;
uint32_t var9 = 0;
double var10 = DBL_MAX;
double var28s[8];
#pragma clang loop interleave_count(2)
for (uint32_t var11 = 0; var11 < 8; ++var11) {
uint32_t var12 = var11 & 4;
uint32_t var13 = var11 & 2;
uint32_t var14 = var11 & 1;
int64_t var15 = var12 ? var3 + 1 : var3;
int64_t var16 = var13 ? var4 + 1 : var4;
int64_t var17 = var14 ? var5 + 1 : var5;
double var18 = var12 ? var6 - 1.0 : var6;
double var19 = var13 ? var7 - 1.0 : var7;
double var20 = var14 ? var8 - 1.0 : var8;
int64_t var21 = theSeed * (theSeed * 6364136223846793005L + 1442695040888963407L) + var15;
var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var16;
var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var17;
var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var15;
var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var16;
var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + var17;
double var22 = (double) ((var21 >> 24) & 1023) / 1024.0;
double var23 = (var22 - 0.5) * 0.9;
var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + theSeed;
double var24 = (double) ((var21 >> 24) & 1023) / 1024.0;
double var25 = (var24 - 0.5) * 0.9;
var21 = var21 * (var21 * 6364136223846793005L + 1442695040888963407L) + theSeed;
double var26 = (double) ((var21 >> 24) & 1023) / 1024.0;
double var27 = (var26 - 0.5) * 0.9;
double var28 = math_square(var20 + var27) + math_square(var19 + var25) + math_square(var18 + var23);
var28s[var11] = var28;
}
for (int i = 0; i < 8; ++i) {
if (var10 > var28s[i]) {
var9 = i;
var10 = var28s[i];
}
}
return var9;
}
#pragma clang attribute pop

View File

@@ -0,0 +1,28 @@
#pragma once
#define TARGET_IMPL_ARCH(suffix, func_prefix, func_ret, func_call) \
func_ret func_prefix##_##suffix func_call
#ifdef __x86_64__
#ifdef GATHER_DISABLED
#define TARGET_IMPL(func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=haswell"))) TARGET_IMPL_ARCH(avx2, func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=skylake-avx512"))) TARGET_IMPL_ARCH(avx512skx, func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=icelake-server"))) TARGET_IMPL_ARCH(avx512icl, func_prefix, func_ret, func_call)
#else
#define TARGET_IMPL(func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=x86-64"))) TARGET_IMPL_ARCH(sse2, func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=x86-64-v2"))) TARGET_IMPL_ARCH(sse4_2, func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=sandybridge"))) TARGET_IMPL_ARCH(avx, func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=alderlake"))) TARGET_IMPL_ARCH(avx2adl, func_prefix, func_ret, func_call) \
__attribute__((pure, target("arch=sapphirerapids"))) TARGET_IMPL_ARCH(avx512spr, func_prefix, func_ret, func_call)
#endif
#else
#define TARGET_IMPL(func_prefix, func_ret, func_call) \
__attribute__((pure)) TARGET_IMPL_ARCH(generic, func_prefix, func_ret, func_call)
#endif

View File

@@ -0,0 +1,11 @@
#ifdef __aarch64__
#include <stdint.h>
int32_t c2me_natives_get_system_isa(_Bool allowAVX512) {
return 0;
}
#endif
typedef int make_iso_compiler_happy;

View File

@@ -0,0 +1,154 @@
#ifdef __x86_64__
#include <stdint.h>
static void __cpuid(int info[4], int infoType) {
__asm__ __volatile__("cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "0"(infoType));
}
static void __cpuidex(int info[4], int level, int count) {
__asm__ __volatile__("cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "0"(level), "2"(count));
}
static int __os_has_avx_support(void) {
// Check xgetbv; this uses a .byte sequence instead of the instruction
// directly because older assemblers do not include support for xgetbv and
// there is no easy way to conditionally compile based on the assembler used.
int rEAX, rEDX;
__asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" : "=a"(rEAX), "=d"(rEDX) : "c"(0));
return (rEAX & 6) == 6;
}
#if !defined(__APPLE__)
static int __os_has_avx512_support(void) {
// Check if the OS saves the XMM, YMM and ZMM registers, i.e. it supports AVX2 and AVX512.
// See section 2.1 of software.intel.com/sites/default/files/managed/0d/53/319433-022.pdf
// Check xgetbv; this uses a .byte sequence instead of the instruction
// directly because older assemblers do not include support for xgetbv and
// there is no easy way to conditionally compile based on the assembler used.
int rEAX, rEDX;
__asm__ __volatile__(".byte 0x0f, 0x01, 0xd0" : "=a"(rEAX), "=d"(rEDX) : "c"(0));
return (rEAX & 0xE6) == 0xE6;
}
#endif // !__APPLE__
// __get_system_isa should return a value corresponding to one of the
// Target::ISA enumerant values that gives the most capable ISA that the
// current system can run.
int32_t c2me_natives_get_system_isa(_Bool allowAVX512) {
int info[4];
__cpuid(info, 1);
// Call cpuid with eax=7, ecx=0
int info2[4];
__cpuidex(info2, 7, 0);
int info3[4] = {0, 0, 0, 0};
int max_subleaf = info2[0];
// Call cpuid with eax=7, ecx=1
if (max_subleaf >= 1)
__cpuidex(info3, 7, 1);
// clang-format off
_Bool sse2 = (info[3] & (1 << 26)) != 0;
_Bool sse41 = (info[2] & (1 << 19)) != 0;
_Bool sse42 = (info[2] & (1 << 20)) != 0;
_Bool avx = (info[2] & (1 << 28)) != 0;
_Bool avx2 = (info2[1] & (1 << 5)) != 0;
_Bool avx_vnni = (info3[0] & (1 << 4)) != 0;
_Bool avx_f16c = (info[2] & (1 << 29)) != 0;
_Bool avx_rdrand = (info[2] & (1 << 30)) != 0;
_Bool osxsave = (info[2] & (1 << 27)) != 0;
_Bool avx512_f = (info2[1] & (1 << 16)) != 0;
// clang-format on
// NOTE: the values returned below must be the same as the
// corresponding enumerant values in Target::ISA.
if (allowAVX512 && osxsave && avx2 && avx512_f
#if !defined(__APPLE__)
&& __os_has_avx512_support()
#endif // !__APPLE__
) {
// We need to verify that AVX2 is also available,
// as well as AVX512, because our targets are supposed
// to use both.
// clang-format off
_Bool avx512_dq = (info2[1] & (1 << 17)) != 0;
_Bool avx512_pf = (info2[1] & (1 << 26)) != 0;
_Bool avx512_er = (info2[1] & (1 << 27)) != 0;
_Bool avx512_cd = (info2[1] & (1 << 28)) != 0;
_Bool avx512_bw = (info2[1] & (1 << 30)) != 0;
_Bool avx512_vl = (info2[1] & (1 << 31)) != 0;
#if !defined(__APPLE__)
_Bool avx512_vbmi2 = (info2[2] & (1 << 6)) != 0;
_Bool avx512_gfni = (info2[2] & (1 << 8)) != 0;
_Bool avx512_vaes = (info2[2] & (1 << 9)) != 0;
_Bool avx512_vpclmulqdq = (info2[2] & (1 << 10)) != 0;
_Bool avx512_vnni = (info2[2] & (1 << 11)) != 0;
_Bool avx512_bitalg = (info2[2] & (1 << 12)) != 0;
_Bool avx512_vpopcntdq = (info2[2] & (1 << 14)) != 0;
_Bool avx512_bf16 = (info3[0] & (1 << 5)) != 0;
_Bool avx512_vp2intersect = (info2[3] & (1 << 8)) != 0;
_Bool avx512_amx_bf16 = (info2[3] & (1 << 22)) != 0;
_Bool avx512_amx_tile = (info2[3] & (1 << 24)) != 0;
_Bool avx512_amx_int8 = (info2[3] & (1 << 25)) != 0;
_Bool avx512_fp16 = (info2[3] & (1 << 23)) != 0;
#endif // !__APPLE__
// clang-format on
// Knights Landing: KNL = F + PF + ER + CD
// Skylake server: SKX = F + DQ + CD + BW + VL
// Cascade Lake server: CLX = SKX + VNNI
// Cooper Lake server: CPX = CLX + BF16
// Ice Lake client & server: ICL = CLX + VBMI2 + GFNI + VAES + VPCLMULQDQ + BITALG + VPOPCNTDQ
// Tiger Lake: TGL = ICL + VP2INTERSECT
// Sapphire Rapids: SPR = ICL + BF16 + AMX_BF16 + AMX_TILE + AMX_INT8 + AVX_VNNI + FP16
_Bool knl = avx512_pf && avx512_er && avx512_cd;
_Bool skx = avx512_dq && avx512_cd && avx512_bw && avx512_vl;
#if !defined(__APPLE__)
_Bool clx = skx && avx512_vnni;
_Bool cpx = clx && avx512_bf16;
_Bool icl =
clx && avx512_vbmi2 && avx512_gfni && avx512_vaes && avx512_vpclmulqdq && avx512_bitalg && avx512_vpopcntdq;
_Bool tgl = icl && avx512_vp2intersect;
_Bool spr =
icl && avx512_bf16 && avx512_amx_bf16 && avx512_amx_tile && avx512_amx_int8 && avx_vnni && avx512_fp16;
if (spr) {
return 9; // SPR
} else if (icl) {
return 8; // ICL
}
#endif // !__APPLE__
if (skx) {
return 7; // SKX
} else if (knl) {
return 6; // KNL
}
// If it's unknown AVX512 target, fall through and use AVX2
// or whatever is available in the machine.
}
if (osxsave && avx && __os_has_avx_support()) {
// if (avx_vnni) {
// return 5; // ADL
// }
if (avx_f16c && avx_rdrand && avx2) {
return 4;
}
// Regular AVX
return 3;
} else if (sse42) {
return 2; // SSE4.2
} else if (sse41) {
return 1; // SSE4.1
} else if (sse2) {
return 0; // SSE2
} else {
__builtin_trap();
}
}
#endif
typedef int make_iso_compiler_happy;

View File

@@ -0,0 +1,11 @@
set(CMAKE_SYSTEM_NAME Darwin)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(triple x86_64-apple-darwin)
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_C_FLAGS "-march=x86-64 -Wl,-no_uuid")

View File

@@ -0,0 +1,10 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR arm64)
set(triple aarch64-unknown-linux-musl)
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})

View File

@@ -0,0 +1,11 @@
set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR x86_64)
set(triple x86_64-unknown-linux-musl)
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_C_FLAGS -march=x86-64)

View File

@@ -0,0 +1,11 @@
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR AMD64)
set(triple x86_64-pc-windows-gnu)
set(CMAKE_C_COMPILER clang)
set(CMAKE_C_COMPILER_TARGET ${triple})
set(CMAKE_CXX_COMPILER clang++)
set(CMAKE_CXX_COMPILER_TARGET ${triple})
set(CMAKE_C_FLAGS "-march=x86-64 -Wl,--no-insert-timestamp")

View File

@@ -0,0 +1,89 @@
package net.caffeinemc.mods.lithium.common.util.math;
import net.minecraft.util.Mth;
/**
* A replacement for the sine angle lookup table used in {@link Mth}, both reducing the size of LUT and improving
* the access patterns for common paired sin/cos operations.
* <p>
* sin(-x) = -sin(x)
* ... to eliminate negative angles from the LUT.
* <p>
* sin(x) = sin(pi/2 - x)
* ... to eliminate supplementary angles from the LUT.
* <p>
* Using these identities allows us to reduce the LUT from 64K entries (256 KB) to just 16K entries (64 KB), enabling
* it to better fit into the CPU's caches at the expense of some cycles on the fast path. The implementation has been
* tightly optimized to avoid branching where possible and to use very quick integer operations.
* <p>
* Generally speaking, reducing the size of a lookup table is always a good optimization, but since we need to spend
* extra CPU cycles trying to maintain parity with vanilla, there is the potential risk that this implementation ends
* up being slower than vanilla when the lookup table is able to be kept in cache memory.
* <p>
* Unlike other "fast math" implementations, the values returned by this class are *bit-for-bit identical* with those
* from {@link Mth}. Validation is performed during runtime to ensure that the table is correct.
*
* @author coderbot16 Author of the original (and very clever) implementation in <a href="https://gitlab.com/coderbot16/i73/-/tree/master/i73-trig/src">Rust</a>
* @author jellysquid3 Additional optimizations, port to Java
*/
public class CompactSineLUT {
private static final int[] SINE_TABLE_INT = new int[16384 + 1];
private static final float SINE_TABLE_MIDPOINT;
static {
final float[] SINE_TABLE = Mth.SIN;
// Copy the sine table, covering to raw int bits
for (int i = 0; i < SINE_TABLE_INT.length; i++) {
SINE_TABLE_INT[i] = Float.floatToRawIntBits(SINE_TABLE[i]);
}
SINE_TABLE_MIDPOINT = SINE_TABLE[SINE_TABLE.length / 2];
// Test that the lookup table is correct during runtime
for (int i = 0; i < SINE_TABLE.length; i++) {
float expected = SINE_TABLE[i];
float value = lookup(i);
if (expected != value) {
throw new IllegalArgumentException(String.format("LUT error at index %d (expected: %s, found: %s)", i, expected, value));
}
}
}
// [VanillaCopy] MathHelper#sin(float)
public static float sin(float f) {
return lookup((int) (f * 10430.378f) & 0xFFFF);
}
// [VanillaCopy] MathHelper#cos(float)
public static float cos(float f) {
return lookup((int) (f * 10430.378f + 16384.0f) & 0xFFFF);
}
private static float lookup(int index) {
// A special case... Is there some way to eliminate this?
if (index == 32768) {
return SINE_TABLE_MIDPOINT;
}
// Trigonometric identity: sin(-x) = -sin(x)
// Given a domain of 0 <= x <= 2*pi, just negate the value if x > pi.
// This allows the sin table size to be halved.
int neg = (index & 0x8000) << 16;
// All bits set if (pi/2 <= x), none set otherwise
// Extracts the 15th bit from 'half'
int mask = (index << 17) >> 31;
// Trigonometric identity: sin(x) = sin(pi/2 - x)
int pos = (0x8001 & mask) + (index ^ mask);
// Wrap the position in the table. Moving this down to immediately before the array access
// seems to help the Hotspot compiler optimize the bit math better.
pos &= 0x7fff;
// Fetch the corresponding value from the LUT and invert the sign bit as needed
// This directly manipulate the sign bit on the float bits to simplify logic
return Float.intBitsToFloat(SINE_TABLE_INT[pos] ^ neg);
}
}

View File

@@ -0,0 +1,372 @@
package org.bxteam.divinemc;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bxteam.divinemc.server.chunk.ChunkSystemAlgorithms;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
@SuppressWarnings("unused")
@NullMarked
public final class DivineConfig {
private DivineConfig() {
throw new IllegalStateException("Utility class");
}
private static final String HEADER = "This is the main configuration file for DivineMC.\n"
+ "If you need help with the configuration or have any questions related to DivineMC,\n"
+ "join us in our Discord server.\n"
+ "\n"
+ "Discord: https://discord.gg/p7cxhw7E2M \n"
+ "Docs: https://bxteam.org/docs/divinemc \n"
+ "New builds: https://github.com/BX-Team/DivineMC/releases/latest";
private static File configFile;
public static YamlConfiguration config;
private static Map<String, Command> commands;
public static int version;
static boolean verbose;
public static void init(File configFile) {
DivineConfig.configFile = configFile;
config = new YamlConfiguration();
try {
config.load(configFile);
} catch (IOException ignored) {
} catch (InvalidConfigurationException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Could not load divinemc.yml, please correct your syntax errors", ex);
throw Throwables.propagate(ex);
}
config.options().header(HEADER);
config.options().copyDefaults(true);
verbose = getBoolean(config, "verbose", false);
version = getInt(config, "config-version", 5);
set(config, "config-version", 5);
readConfig(DivineConfig.class, null);
}
public static void log(String s) {
if (verbose) {
log(Level.INFO, s);
}
}
public static void log(Level level, String s) {
Bukkit.getLogger().log(level, s);
}
static void readConfig(Class<?> clazz, @Nullable Object instance) {
readConfig(configFile, config, clazz, instance);
}
public static void readConfig(File configFile, YamlConfiguration config, Class<?> clazz, @Nullable Object instance) {
for (Method method : clazz.getDeclaredMethods()) {
if (!Modifier.isPrivate(method.getModifiers())) continue;
if (method.getParameterTypes().length != 0) continue;
if (method.getReturnType() != Void.TYPE) continue;
try {
method.setAccessible(true);
method.invoke(instance);
} catch (InvocationTargetException ex) {
throw Throwables.propagate(ex.getCause());
} catch (Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex);
}
}
try {
config.save(configFile);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Could not save " + configFile, ex);
}
}
private static void set(YamlConfiguration config, String path, Object val, String... comments) {
config.addDefault(path, val);
config.set(path, val);
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
}
private static String getString(YamlConfiguration config, String path, String def, String... comments) {
config.addDefault(path, def);
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
return config.getString(path, config.getString(path));
}
private static boolean getBoolean(YamlConfiguration config, String path, boolean def, String... comments) {
config.addDefault(path, def);
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
return config.getBoolean(path, config.getBoolean(path));
}
private static double getDouble(YamlConfiguration config, String path, double def, String... comments) {
config.addDefault(path, def);
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
return config.getDouble(path, config.getDouble(path));
}
private static int getInt(YamlConfiguration config, String path, int def, String... comments) {
config.addDefault(path, def);
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
return config.getInt(path, config.getInt(path));
}
private static long getLong(YamlConfiguration config, String path, long def, String... comments) {
config.addDefault(path, def);
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
return config.getLong(path, config.getLong(path));
}
private static <T> List<T> getList(YamlConfiguration config, String path, List<T> def, String... comments) {
config.addDefault(path, def);
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
return (List<T>) config.getList(path, def);
}
static Map<String, Object> getMap(YamlConfiguration config, String path, Map<String, Object> def, String... comments) {
if (def != null && config.getConfigurationSection(path) == null) {
config.addDefault(path, def);
return def;
}
if (comments.length > 0) {
config.setComments(path, List.of(comments));
}
return toMap(config.getConfigurationSection(path));
}
private static Map<String, Object> toMap(ConfigurationSection section) {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
if (section != null) {
for (String key : section.getKeys(false)) {
Object obj = section.get(key);
if (obj != null) {
builder.put(key, obj instanceof ConfigurationSection val ? toMap(val) : obj);
}
}
}
return builder.build();
}
public static int parallelThreadCount = 4;
public static boolean logContainerCreationStacktraces = false;
private static void parallelWorldTicking() {
parallelThreadCount = getInt(config, "settings.parallel-world-ticking.thread-count", parallelThreadCount);
logContainerCreationStacktraces = getBoolean(config, "settings.parallel-world-ticking.log-container-creation-stacktraces", logContainerCreationStacktraces);
}
public static boolean nativeAccelerationEnabled = true;
public static boolean allowAVX512 = false;
public static int isaTargetLevelOverride = -1;
public static long chunkDataCacheSoftLimit = 8192L;
public static long chunkDataCacheLimit = 32678L;
public static int maxViewDistance = 32;
public static ChunkSystemAlgorithms chunkWorkerAlgorithm = ChunkSystemAlgorithms.C2ME;
public static boolean enableSecureSeed = false;
public static boolean enableDensityFunctionCompiler = false;
public static boolean enableStructureLayoutOptimizer = true;
public static boolean deduplicateShuffledTemplatePoolElementList = false;
private static void chunkGeneration() {
nativeAccelerationEnabled = getBoolean(config, "settings.chunk-generation.native-acceleration-enabled", nativeAccelerationEnabled);
allowAVX512 = getBoolean(config, "settings.chunk-generation.allow-avx512", allowAVX512,
"Enables AVX512 support for natives-math optimizations",
"",
"Read more about AVX512: https://en.wikipedia.org/wiki/AVX-512");
isaTargetLevelOverride = getInt(config, "settings.chunk-generation.isa-target-level-override", isaTargetLevelOverride,
"Overrides the ISA target located by the native loader, which allows forcing AVX512 (must be a value between 6-9 for AVX512 support).",
"Value must be between 1-9, and -1 to disable override");
if (isaTargetLevelOverride < -1 || isaTargetLevelOverride > 9) {
log(Level.WARNING, "Invalid ISA target level override: " + isaTargetLevelOverride + ", resetting to -1");
isaTargetLevelOverride = -1;
}
chunkDataCacheSoftLimit = getLong(config, "settings.chunk-generation.chunk-data-cache-soft-limit", chunkDataCacheSoftLimit);
chunkDataCacheLimit = getLong(config, "settings.chunk-generation.chunk-data-cache-limit", chunkDataCacheLimit);
maxViewDistance = getInt(config, "settings.chunk-generation.max-view-distance", maxViewDistance,
"Changes the maximum view distance for the server, allowing clients to have render distances higher than 32");
chunkWorkerAlgorithm = ChunkSystemAlgorithms.valueOf(getString(config, "settings.chunk-generation.chunk-worker-algorithm", chunkWorkerAlgorithm.name(),
"Modifies what algorithm the chunk system will use to define thread counts. values: MOONRISE, C2ME, C2ME_AGGRESSIVE"));
enableSecureSeed = getBoolean(config, "settings.misc.enable-secure-seed", enableSecureSeed,
"This feature is based on Secure Seed mod by Earthcomputer.",
"",
"Terrain and biome generation remains the same, but all the ores and structures are generated with 1024-bit seed, instead of the usual 64-bit seed.",
"This seed is almost impossible to crack, and there are no weird links between structures.");
enableDensityFunctionCompiler = getBoolean(config, "settings.chunk-generation.experimental.enable-density-function-compiler", enableDensityFunctionCompiler,
"Whether to use density function compiler to accelerate world generation",
"",
"Density function: https://minecraft.wiki/w/Density_function",
"",
"This functionality compiles density functions from world generation",
"datapacks (including vanilla generation) to JVM bytecode to increase",
"performance by allowing JVM JIT to better optimize the code.",
"All functions provided by vanilla are implemented.",
"",
"Please test if this optimization actually benefits your server, as",
"it can sometimes slow down chunk performance than speed it up.");
enableStructureLayoutOptimizer = getBoolean(config, "settings.chunk-generation.experimental.enable-structure-layout-optimizer", enableStructureLayoutOptimizer,
"Enables a port of the mod StructureLayoutOptimizer, which optimizes general Jigsaw structure generation");
deduplicateShuffledTemplatePoolElementList = getBoolean(config, "settings.chunk-generation.experimental.deduplicate-shuffled-template-pool-element-list", deduplicateShuffledTemplatePoolElementList,
"Whether to use an alternative strategy to make structure layouts generate slightly even faster than",
"the default optimization this mod has for template pool weights. This alternative strategy works by",
"changing the list of pieces that structures collect from the template pool to not have duplicate entries.",
"",
"This will not break the structure generation, but it will make the structure layout different than",
"if this config was off (breaking vanilla seed parity). The cost of speed may be worth it in large",
"modpacks where many structure mods are using very high weight values in their template pools.");
}
public static boolean skipUselessSecondaryPoiSensor = true;
public static boolean clumpOrbs = true;
public static boolean ignoreMovedTooQuicklyWhenLagging = true;
public static boolean alwaysAllowWeirdMovement = true;
private static void miscSettings() {
skipUselessSecondaryPoiSensor = getBoolean(config, "settings.misc.skip-useless-secondary-poi-sensor", skipUselessSecondaryPoiSensor);
clumpOrbs = getBoolean(config, "settings.misc.clump-orbs", clumpOrbs,
"Clumps experience orbs together to reduce entity count");
ignoreMovedTooQuicklyWhenLagging = getBoolean(config, "settings.misc.ignore-moved-too-quickly-when-lagging", ignoreMovedTooQuicklyWhenLagging,
"Improves general gameplay experience of the player when the server is lagging, as they won't get lagged back (message 'moved too quickly')");
alwaysAllowWeirdMovement = getBoolean(config, "settings.misc.always-allow-weird-movement", alwaysAllowWeirdMovement,
"Means ignoring messages like 'moved too quickly' and 'moved wrongly'");
}
public static boolean enableFasterTntOptimization = true;
public static boolean explosionNoBlockDamage = false;
public static double tntRandomRange = -1;
private static void tntOptimization() {
enableFasterTntOptimization = getBoolean(config, "settings.tnt-optimization.enable-faster-tnt-optimization", enableFasterTntOptimization);
explosionNoBlockDamage = getBoolean(config, "settings.tnt-optimization.explosion-no-block-damage", explosionNoBlockDamage);
tntRandomRange = getDouble(config, "settings.tnt-optimization.tnt-random-range", tntRandomRange);
}
public static boolean lagCompensationEnabled = true;
public static boolean blockEntityAcceleration = false;
public static boolean blockBreakingAcceleration = true;
public static boolean eatingAcceleration = true;
public static boolean potionEffectAcceleration = true;
public static boolean fluidAcceleration = true;
public static boolean pickupAcceleration = true;
public static boolean portalAcceleration = true;
public static boolean timeAcceleration = true;
public static boolean randomTickSpeedAcceleration = true;
private static void lagCompensation() {
lagCompensationEnabled = getBoolean(config, "settings.lag-compensation.enabled", lagCompensationEnabled, "Improves the player experience when TPS is low");
blockEntityAcceleration = getBoolean(config, "settings.lag-compensation.block-entity-acceleration", blockEntityAcceleration);
blockBreakingAcceleration = getBoolean(config, "settings.lag-compensation.block-breaking-acceleration", blockBreakingAcceleration);
eatingAcceleration = getBoolean(config, "settings.lag-compensation.eating-acceleration", eatingAcceleration);
potionEffectAcceleration = getBoolean(config, "settings.lag-compensation.potion-effect-acceleration", potionEffectAcceleration);
fluidAcceleration = getBoolean(config, "settings.lag-compensation.fluid-acceleration", fluidAcceleration);
pickupAcceleration = getBoolean(config, "settings.lag-compensation.pickup-acceleration", pickupAcceleration);
portalAcceleration = getBoolean(config, "settings.lag-compensation.portal-acceleration", portalAcceleration);
timeAcceleration = getBoolean(config, "settings.lag-compensation.time-acceleration", timeAcceleration);
randomTickSpeedAcceleration = getBoolean(config, "settings.lag-compensation.random-tick-speed-acceleration", randomTickSpeedAcceleration);
}
public static boolean noChatReportsEnabled = false;
public static boolean noChatReportsAddQueryData = true;
public static boolean noChatReportsConvertToGameMessage = true;
public static boolean noChatReportsDebugLog = false;
public static boolean noChatReportsDemandOnClient = false;
public static String noChatReportsDisconnectDemandOnClientMessage = "You do not have No Chat Reports, and this server is configured to require it on client!";
private static void noChatReports() {
noChatReportsEnabled = getBoolean(config, "settings.no-chat-reports.enabled", noChatReportsEnabled,
"Enables or disables the No Chat Reports feature");
noChatReportsAddQueryData = getBoolean(config, "settings.no-chat-reports.add-query-data", noChatReportsAddQueryData,
"Should server include extra query data to help clients know that your server is secure");
noChatReportsConvertToGameMessage = getBoolean(config, "settings.no-chat-reports.convert-to-game-message", noChatReportsConvertToGameMessage,
"Should the server convert all player messages to system messages");
noChatReportsDebugLog = getBoolean(config, "settings.no-chat-reports.debug-log", noChatReportsDebugLog);
noChatReportsDemandOnClient = getBoolean(config, "settings.no-chat-reports.demand-on-client", noChatReportsDemandOnClient,
"Should the server require No Chat Reports on the client side");
noChatReportsDisconnectDemandOnClientMessage = getString(config, "settings.no-chat-reports.disconnect-demand-on-client-message", noChatReportsDisconnectDemandOnClientMessage,
"Message to send to the client when they are disconnected for not having No Chat Reports");
}
public static boolean asyncPathfinding = true;
public static int asyncPathfindingMaxThreads = 2;
public static int asyncPathfindingKeepalive = 60;
private static void asyncPathfinding() {
asyncPathfinding = getBoolean(config, "settings.async-pathfinding.enable", asyncPathfinding);
asyncPathfindingMaxThreads = getInt(config, "settings.async-pathfinding.max-threads", asyncPathfindingMaxThreads);
asyncPathfindingKeepalive = getInt(config, "settings.async-pathfinding.keepalive", asyncPathfindingKeepalive);
if (asyncPathfindingMaxThreads < 0) {
asyncPathfindingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncPathfindingMaxThreads, 1);
} else if (asyncPathfindingMaxThreads == 0) {
asyncPathfindingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() / 4, 1);
}
if (!asyncPathfinding) {
asyncPathfindingMaxThreads = 0;
} else {
Bukkit.getLogger().log(Level.INFO, "Using " + asyncPathfindingMaxThreads + " threads for Async Pathfinding");
}
}
public static boolean multithreadedEnabled = true;
public static boolean multithreadedCompatModeEnabled = false;
public static int asyncEntityTrackerMaxThreads = 1;
public static int asyncEntityTrackerKeepalive = 60;
private static void multithreadedTracker() {
multithreadedEnabled = getBoolean(config, "settings.multithreaded-tracker.enable", multithreadedEnabled);
multithreadedCompatModeEnabled = getBoolean(config, "settings.multithreaded-tracker.compat-mode", multithreadedCompatModeEnabled);
asyncEntityTrackerMaxThreads = getInt(config, "settings.multithreaded-tracker.max-threads", asyncEntityTrackerMaxThreads);
asyncEntityTrackerKeepalive = getInt(config, "settings.multithreaded-tracker.keepalive", asyncEntityTrackerKeepalive);
if (asyncEntityTrackerMaxThreads < 0) {
asyncEntityTrackerMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncEntityTrackerMaxThreads, 1);
} else if (asyncEntityTrackerMaxThreads == 0) {
asyncEntityTrackerMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() / 4, 1);
}
if (!multithreadedEnabled) {
asyncEntityTrackerMaxThreads = 0;
} else {
Bukkit.getLogger().log(Level.INFO, "Using " + asyncEntityTrackerMaxThreads + " threads for Async Entity Tracker");
}
}
}

View File

@@ -0,0 +1,82 @@
package org.bxteam.divinemc;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.YamlConfiguration;
import org.jspecify.annotations.NullMarked;
import java.util.List;
import java.util.Map;
import static org.bxteam.divinemc.DivineConfig.log;
@NullMarked
public final class DivineWorldConfig {
private final YamlConfiguration config;
private final String worldName;
private final World.Environment environment;
public DivineWorldConfig(String worldName, World.Environment environment) {
this.config = DivineConfig.config;
this.worldName = worldName;
this.environment = environment;
init();
}
public void init() {
log("-------- World Settings For [" + worldName + "] --------");
DivineConfig.readConfig(DivineWorldConfig.class, this);
}
private void set(String path, Object val) {
this.config.addDefault("world-settings.default." + path, val);
this.config.set("world-settings.default." + path, val);
if (this.config.get("world-settings." + worldName + "." + path) != null) {
this.config.addDefault("world-settings." + worldName + "." + path, val);
this.config.set("world-settings." + worldName + "." + path, val);
}
}
private ConfigurationSection getConfigurationSection(String path) {
ConfigurationSection section = this.config.getConfigurationSection("world-settings." + worldName + "." + path);
return section != null ? section : this.config.getConfigurationSection("world-settings.default." + path);
}
private String getString(String path, String def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getString("world-settings." + worldName + "." + path, this.config.getString("world-settings.default." + path));
}
private boolean getBoolean(String path, boolean def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getBoolean("world-settings." + worldName + "." + path, this.config.getBoolean("world-settings.default." + path));
}
private double getDouble(String path, double def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getDouble("world-settings." + worldName + "." + path, this.config.getDouble("world-settings.default." + path));
}
private int getInt(String path, int def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getInt("world-settings." + worldName + "." + path, this.config.getInt("world-settings.default." + path));
}
private <T> List<?> getList(String path, T def) {
this.config.addDefault("world-settings.default." + path, def);
return this.config.getList("world-settings." + worldName + "." + path, this.config.getList("world-settings.default." + path));
}
private Map<String, Object> getMap(String path, Map<String, Object> def) {
final Map<String, Object> fallback = this.getMap("world-settings.default." + path, def);
final Map<String, Object> value = this.getMap("world-settings." + worldName + "." + path, null);
return value.isEmpty() ? fallback : value;
}
public boolean snowballCanKnockback = true;
public boolean eggCanKnockback = true;
private void setSnowballAndEggKnockback() {
snowballCanKnockback = getBoolean("gameplay-mechanics.projectiles.snowball.knockback", snowballCanKnockback);
eggCanKnockback = getBoolean("gameplay-mechanics.projectiles.egg.knockback", eggCanKnockback);
}
}

View File

@@ -2,7 +2,6 @@ package org.bxteam.divinemc.command;
import net.minecraft.server.MinecraftServer; import net.minecraft.server.MinecraftServer;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.craftbukkit.util.permissions.CraftDefaultPermissions;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier; import org.checkerframework.framework.qual.DefaultQualifier;
@@ -11,7 +10,7 @@ import java.util.Map;
@DefaultQualifier(NonNull.class) @DefaultQualifier(NonNull.class)
public final class DivineCommands { public final class DivineCommands {
public static final String COMMAND_BASE_PERM = CraftDefaultPermissions.DIVINEMC_ROOT + ".command"; public static final String COMMAND_BASE_PERM = "divinemc.command";
private DivineCommands() {} private DivineCommands() {}

View File

@@ -8,7 +8,7 @@ import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.permissions.PermissionDefault; import org.bukkit.permissions.PermissionDefault;
import org.bxteam.divinemc.command.DivineCommand; import org.bxteam.divinemc.command.DivineCommand;
import org.bxteam.divinemc.command.DivineSubCommandPermission; import org.bxteam.divinemc.command.DivineSubCommandPermission;
import org.bxteam.divinemc.configuration.DivineConfig; import org.bxteam.divinemc.DivineConfig;
import java.io.File; import java.io.File;
@@ -37,7 +37,7 @@ public final class ReloadCommand extends DivineSubCommandPermission {
MinecraftServer server = ((CraftServer) sender.getServer()).getServer(); MinecraftServer server = ((CraftServer) sender.getServer()).getServer();
DivineConfig.init((File) server.options.valueOf("divinemc-settings")); DivineConfig.init((File) server.options.valueOf("divinemc-settings"));
for (ServerLevel level : server.getAllLevels()) { for (ServerLevel level : server.getAllLevels()) {
level.divinemcConfig.init(); level.divineConfig.init();
level.resetBreedingCooldowns(); level.resetBreedingCooldowns();
} }
server.server.reloadCount++; server.server.reloadCount++;

View File

@@ -1,218 +0,0 @@
package org.bxteam.divinemc.configuration;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableMap;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import org.bukkit.Bukkit;
import org.bukkit.command.Command;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.InvalidConfigurationException;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
@SuppressWarnings("unused")
public class DivineConfig {
private static final String HEADER = "This is the main configuration file for DivineMC.\n"
+ "If you need help with the configuration or have any questions related to DivineMC,\n"
+ "join us in our Discord server.\n"
+ "\n"
+ "Discord: https://discord.gg/p7cxhw7E2M \n"
+ "Docs: https://bxteam.org/docs/divinemc \n"
+ "New builds: https://github.com/BX-Team/DivineMC/releases/latest";
private static File CONFIG_FILE;
public static YamlConfiguration config;
private static Map<String, Command> commands;
public static int version;
static boolean verbose;
public static void init(File configFile) {
CONFIG_FILE = configFile;
config = new YamlConfiguration();
try {
config.load(CONFIG_FILE);
} catch (IOException ignore) {
} catch (InvalidConfigurationException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Could not load divinemc.yml, please correct your syntax errors", ex);
throw Throwables.propagate(ex);
}
config.options().header(HEADER);
config.options().copyDefaults(true);
verbose = getBoolean("verbose", false);
version = getInt("config-version", 4);
set("config-version", 4);
readConfig(DivineConfig.class, null);
Block.BLOCK_STATE_REGISTRY.forEach(BlockBehaviour.BlockStateBase::initCache);
}
protected static void log(String s) {
if (verbose) {
log(Level.INFO, s);
}
}
protected static void log(Level level, String s) {
Bukkit.getLogger().log(level, s);
}
static void readConfig(Class<?> clazz, Object instance) {
for (Method method : clazz.getDeclaredMethods()) {
if (Modifier.isPrivate(method.getModifiers())) {
if (method.getParameterTypes().length == 0 && method.getReturnType() == Void.TYPE) {
try {
method.setAccessible(true);
method.invoke(instance);
} catch (InvocationTargetException ex) {
throw Throwables.propagate(ex.getCause());
} catch (Exception ex) {
Bukkit.getLogger().log(Level.SEVERE, "Error invoking " + method, ex);
}
}
}
}
try {
config.save(CONFIG_FILE);
} catch (IOException ex) {
Bukkit.getLogger().log(Level.SEVERE, "Could not save " + CONFIG_FILE, ex);
}
}
private static void set(String path, Object val) {
config.addDefault(path, val);
config.set(path, val);
}
private static String getString(String path, String def) {
config.addDefault(path, def);
return config.getString(path, config.getString(path));
}
private static boolean getBoolean(String path, boolean def) {
config.addDefault(path, def);
return config.getBoolean(path, config.getBoolean(path));
}
private static double getDouble(String path, double def) {
config.addDefault(path, def);
return config.getDouble(path, config.getDouble(path));
}
private static int getInt(String path, int def) {
config.addDefault(path, def);
return config.getInt(path, config.getInt(path));
}
private static <T> List getList(String path, T def) {
config.addDefault(path, def);
return config.getList(path, config.getList(path));
}
static Map<String, Object> getMap(String path, Map<String, Object> def) {
if (def != null && config.getConfigurationSection(path) == null) {
config.addDefault(path, def);
return def;
}
return toMap(config.getConfigurationSection(path));
}
private static Map<String, Object> toMap(ConfigurationSection section) {
ImmutableMap.Builder<String, Object> builder = ImmutableMap.builder();
if (section != null) {
for (String key : section.getKeys(false)) {
Object obj = section.get(key);
if (obj != null) {
builder.put(key, obj instanceof ConfigurationSection val ? toMap(val) : obj);
}
}
}
return builder.build();
}
public static boolean noChatSign = true;
private static void chatMessageSignatures() {
noChatSign = getBoolean("settings.no-chat-sign", noChatSign);
}
public static boolean optimizedDragonRespawn = true;
public static boolean lagCompensationEnabled = false;
public static boolean lagCompensationEnableForWater = false;
public static boolean lagCompensationEnableForLava = false;
private static void optimizations() {
optimizedDragonRespawn = getBoolean("settings.optimizations.optimized-dragon-respawn", optimizedDragonRespawn);
lagCompensationEnabled = getBoolean("settings.optimizations.lag-compensation.enabled", lagCompensationEnabled);
lagCompensationEnableForWater = getBoolean("settings.optimizations.lag-compensation.enable-for-water", lagCompensationEnableForWater);
lagCompensationEnableForLava = getBoolean("settings.optimizations.lag-compensation.enable-for-lava", lagCompensationEnableForLava);
}
public static boolean disableNonEditableSignWarning = true;
public static boolean removeVanillaUsernameCheck = false;
public static boolean disableMovedWronglyThreshold = false;
public static boolean enableSecureSeed = false;
public static boolean asyncPlayerDataSaveEnabled = false;
private static void miscSettings() {
disableNonEditableSignWarning = getBoolean("settings.misc.disable-non-editable-sign-warning", disableNonEditableSignWarning);
removeVanillaUsernameCheck = getBoolean("settings.misc.remove-vanilla-username-check", removeVanillaUsernameCheck);
disableMovedWronglyThreshold = getBoolean("settings.misc.disable-moved-wrongly-threshold", disableMovedWronglyThreshold);
enableSecureSeed = getBoolean("settings.misc.enable-secure-seed", enableSecureSeed);
asyncPlayerDataSaveEnabled = getBoolean("settings.misc.experimental.async-player-data-save-enabled", asyncPlayerDataSaveEnabled);
}
public static int linearFlushFrequency = 5;
public static boolean throwOnUnknownExtension = false;
private static void linearSettings() {
linearFlushFrequency = getInt("settings.region-format.linear.flush-frequency", linearFlushFrequency);
throwOnUnknownExtension = getBoolean("settings.region-format.linear.throw-on-unknown-extension", throwOnUnknownExtension);
}
public static boolean asyncPathfinding = true;
public static int asyncPathfindingMaxThreads = 0;
public static int asyncPathfindingKeepalive = 60;
private static void asyncPathfinding() {
asyncPathfinding = getBoolean("settings.async-pathfinding.enable", asyncPathfinding);
asyncPathfindingMaxThreads = getInt("settings.async-pathfinding.max-threads", asyncPathfindingMaxThreads);
asyncPathfindingKeepalive = getInt("settings.async-pathfinding.keepalive", asyncPathfindingKeepalive);
if (asyncPathfindingMaxThreads < 0)
asyncPathfindingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncPathfindingMaxThreads, 1);
else if (asyncPathfindingMaxThreads == 0)
asyncPathfindingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() / 4, 1);
if (!asyncPathfinding)
asyncPathfindingMaxThreads = 0;
else
Bukkit.getLogger().log(Level.INFO, "Using " + asyncPathfindingMaxThreads + " threads for Async Pathfinding");
}
public static boolean multithreadedEnabled = false;
public static boolean multithreadedCompatModeEnabled = false;
public static int asyncEntityTrackerMaxThreads = 0;
public static int asyncEntityTrackerKeepalive = 60;
private static void multithreadedTracker() {
multithreadedEnabled = getBoolean("settings.multithreaded-tracker.enable", multithreadedEnabled);
multithreadedCompatModeEnabled = getBoolean("settings.multithreaded-tracker.compat-mode", multithreadedCompatModeEnabled);
asyncEntityTrackerMaxThreads = getInt("settings.multithreaded-tracker.max-threads", asyncEntityTrackerMaxThreads);
asyncEntityTrackerKeepalive = getInt("settings.multithreaded-tracker.keepalive", asyncEntityTrackerKeepalive);
if (asyncEntityTrackerMaxThreads < 0)
asyncEntityTrackerMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncEntityTrackerMaxThreads, 1);
else if (asyncEntityTrackerMaxThreads == 0)
asyncEntityTrackerMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() / 4, 1);
if (!multithreadedEnabled)
asyncEntityTrackerMaxThreads = 0;
else
Bukkit.getLogger().log(Level.INFO, "Using " + asyncEntityTrackerMaxThreads + " threads for Async Entity Tracker");
}
}

View File

@@ -1,121 +0,0 @@
package org.bxteam.divinemc.configuration;
import org.apache.commons.lang.BooleanUtils;
import org.bukkit.World;
import org.bukkit.configuration.ConfigurationSection;
import org.bxteam.divinemc.region.RegionFileFormat;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import java.util.logging.Level;
import static org.bxteam.divinemc.configuration.DivineConfig.log;
@SuppressWarnings("unused")
public class DivineWorldConfig {
private final String worldName;
private final World.Environment environment;
public DivineWorldConfig(String worldName, World.Environment environment) {
this.worldName = worldName;
this.environment = environment;
init();
}
public void init() {
log("-------- World Settings For [" + worldName + "] --------");
DivineConfig.readConfig(DivineWorldConfig.class, this);
}
private void set(String path, Object val) {
DivineConfig.config.addDefault("world-settings.default." + path, val);
DivineConfig.config.set("world-settings.default." + path, val);
if (DivineConfig.config.get("world-settings." + worldName + "." + path) != null) {
DivineConfig.config.addDefault("world-settings." + worldName + "." + path, val);
DivineConfig.config.set("world-settings." + worldName + "." + path, val);
}
}
private ConfigurationSection getConfigurationSection(String path) {
ConfigurationSection section = DivineConfig.config.getConfigurationSection("world-settings." + worldName + "." + path);
return section != null ? section : DivineConfig.config.getConfigurationSection("world-settings.default." + path);
}
private String getString(String path, String def) {
DivineConfig.config.addDefault("world-settings.default." + path, def);
return DivineConfig.config.getString("world-settings." + worldName + "." + path, DivineConfig.config.getString("world-settings.default." + path));
}
private boolean getBoolean(String path, boolean def) {
DivineConfig.config.addDefault("world-settings.default." + path, def);
return DivineConfig.config.getBoolean("world-settings." + worldName + "." + path, DivineConfig.config.getBoolean("world-settings.default." + path));
}
private boolean getBoolean(String path, Predicate<Boolean> predicate) {
String val = getString(path, "default").toLowerCase();
Boolean bool = BooleanUtils.toBooleanObject(val, "true", "false", "default");
return predicate.test(bool);
}
private double getDouble(String path, double def) {
DivineConfig.config.addDefault("world-settings.default." + path, def);
return DivineConfig.config.getDouble("world-settings." + worldName + "." + path, DivineConfig.config.getDouble("world-settings.default." + path));
}
private int getInt(String path, int def) {
DivineConfig.config.addDefault("world-settings.default." + path, def);
return DivineConfig.config.getInt("world-settings." + worldName + "." + path, DivineConfig.config.getInt("world-settings.default." + path));
}
private <T> List<?> getList(String path, T def) {
DivineConfig.config.addDefault("world-settings.default." + path, def);
return DivineConfig.config.getList("world-settings." + worldName + "." + path, DivineConfig.config.getList("world-settings.default." + path));
}
private Map<String, Object> getMap(String path, Map<String, Object> def) {
final Map<String, Object> fallback = DivineConfig.getMap("world-settings.default." + path, def);
final Map<String, Object> value = DivineConfig.getMap("world-settings." + worldName + "." + path, null);
return value.isEmpty() ? fallback : value;
}
public boolean despawnShulkerBulletsOnOwnerDeath = true;
private void despawnShulkerBulletsOnOwnerDeath() {
despawnShulkerBulletsOnOwnerDeath = getBoolean("gameplay-mechanics.mob.shulker.despawn-bullets-on-player-death", despawnShulkerBulletsOnOwnerDeath);
}
public boolean saveFireworks = false;
private void projectiles() {
saveFireworks = getBoolean("gameplay-mechanics.should-save-fireworks", saveFireworks);
}
public boolean suppressErrorsFromDirtyAttributes = true;
private void suppressErrorsFromDirtyAttributes() {
suppressErrorsFromDirtyAttributes = getBoolean("suppress-errors-from-dirty-attributes", suppressErrorsFromDirtyAttributes);
}
public boolean snowballCanKnockback = true;
public boolean eggCanKnockback = true;
private void setSnowballAndEggKnockback() {
snowballCanKnockback = getBoolean("gameplay-mechanics.projectiles.snowball.knockback", snowballCanKnockback);
eggCanKnockback = getBoolean("gameplay-mechanics.projectiles.egg.knockback", eggCanKnockback);
}
public RegionFileFormat regionFormatName = RegionFileFormat.MCA;
public int linearCompressionLevel = 1;
private void regionFormatSettings() {
regionFormatName = RegionFileFormat.fromExtension(getString("region-format.format", regionFormatName.name()));
if (regionFormatName.equals(RegionFileFormat.UNKNOWN)) {
log(Level.SEVERE, "Unknown region file type!");
log(Level.SEVERE, "Falling back to ANVIL region file format.");
regionFormatName = RegionFileFormat.MCA;
}
linearCompressionLevel = getInt("region-format.linear.compression-level", linearCompressionLevel);
if (linearCompressionLevel > 23 || linearCompressionLevel < 1) {
log(Level.SEVERE, "Linear region compression level should be between 1 and 22 in config: " + linearCompressionLevel);
log(Level.SEVERE, "Falling back to compression level 1.");
linearCompressionLevel = 1;
}
}
}

View File

@@ -0,0 +1,13 @@
package org.bxteam.divinemc.dfc.common;
import net.minecraft.world.level.levelgen.NoiseRouterData;
public interface IDensityFunctionsCaveScaler {
static double invokeScaleCaves(double value) {
return NoiseRouterData.QuantizedSpaghettiRarity.getSphaghettiRarity2D(value);
}
static double invokeScaleTunnels(double value) {
return NoiseRouterData.QuantizedSpaghettiRarity.getSpaghettiRarity3D(value);
}
}

View File

@@ -0,0 +1,22 @@
package org.bxteam.divinemc.dfc.common.ast;
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
import org.objectweb.asm.commons.InstructionAdapter;
public interface AstNode {
double evalSingle(int var1, int var2, int var3, EvalType var4);
void evalMulti(double[] var1, int[] var2, int[] var3, int[] var4, EvalType var5);
AstNode[] getChildren();
AstNode transform(AstTransformer var1);
void doBytecodeGenSingle(BytecodeGen.Context var1, InstructionAdapter var2, BytecodeGen.Context.LocalVarConsumer var3);
void doBytecodeGenMulti(BytecodeGen.Context var1, InstructionAdapter var2, BytecodeGen.Context.LocalVarConsumer var3);
boolean relaxedEquals(AstNode var1);
int relaxedHashCode();
}

View File

@@ -0,0 +1,5 @@
package org.bxteam.divinemc.dfc.common.ast;
public interface AstTransformer {
AstNode transform(AstNode var1);
}

View File

@@ -0,0 +1,25 @@
package org.bxteam.divinemc.dfc.common.ast;
import org.bxteam.divinemc.dfc.common.vif.EachApplierVanillaInterface;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.NoiseChunk;
public enum EvalType {
NORMAL,
INTERPOLATION;
private EvalType() {
}
public static EvalType from(DensityFunction.FunctionContext pos) {
return pos instanceof NoiseChunk ? INTERPOLATION : NORMAL;
}
public static EvalType from(DensityFunction.ContextProvider applier) {
if (applier instanceof EachApplierVanillaInterface vif) {
return vif.getType();
} else {
return applier instanceof NoiseChunk ? INTERPOLATION : NORMAL;
}
}
}

View File

@@ -0,0 +1,106 @@
package org.bxteam.divinemc.dfc.common.ast;
import org.bxteam.divinemc.dfc.common.ast.binary.AddNode;
import org.bxteam.divinemc.dfc.common.ast.binary.MaxNode;
import org.bxteam.divinemc.dfc.common.ast.binary.MaxShortNode;
import org.bxteam.divinemc.dfc.common.ast.binary.MinNode;
import org.bxteam.divinemc.dfc.common.ast.binary.MinShortNode;
import org.bxteam.divinemc.dfc.common.ast.binary.MulNode;
import org.bxteam.divinemc.dfc.common.ast.misc.CacheLikeNode;
import org.bxteam.divinemc.dfc.common.ast.misc.ConstantNode;
import org.bxteam.divinemc.dfc.common.ast.misc.DelegateNode;
import org.bxteam.divinemc.dfc.common.ast.misc.RangeChoiceNode;
import org.bxteam.divinemc.dfc.common.ast.misc.YClampedGradientNode;
import org.bxteam.divinemc.dfc.common.ast.noise.DFTNoiseNode;
import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftANode;
import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftBNode;
import org.bxteam.divinemc.dfc.common.ast.noise.DFTShiftNode;
import org.bxteam.divinemc.dfc.common.ast.noise.DFTWeirdScaledSamplerNode;
import org.bxteam.divinemc.dfc.common.ast.noise.ShiftedNoiseNode;
import org.bxteam.divinemc.dfc.common.ast.spline.SplineAstNode;
import org.bxteam.divinemc.dfc.common.ast.unary.AbsNode;
import org.bxteam.divinemc.dfc.common.ast.unary.CubeNode;
import org.bxteam.divinemc.dfc.common.ast.unary.NegMulNode;
import org.bxteam.divinemc.dfc.common.ast.unary.SquareNode;
import org.bxteam.divinemc.dfc.common.ast.unary.SqueezeNode;
import org.bxteam.divinemc.dfc.common.ducks.IEqualityOverriding;
import org.bxteam.divinemc.dfc.common.ducks.IFastCacheLike;
import org.bxteam.divinemc.dfc.common.vif.AstVanillaInterface;
import java.util.Objects;
import net.minecraft.world.level.levelgen.DensityFunction;
import net.minecraft.world.level.levelgen.DensityFunctions;
import net.minecraft.world.level.levelgen.NoiseChunk;
import org.jetbrains.annotations.NotNull;
public class McToAst {
public McToAst() {
}
public static AstNode toAst(DensityFunction df) {
Objects.requireNonNull(df);
return switch (df) {
case AstVanillaInterface f -> f.getAstNode();
case NoiseChunk.BlendAlpha f -> new ConstantNode(1.0);
case NoiseChunk.BlendOffset f -> new ConstantNode(0.0);
case DensityFunctions.BlendAlpha f -> new ConstantNode(1.0);
case DensityFunctions.BlendOffset f -> new ConstantNode(0.0);
case DensityFunctions.TwoArgumentSimpleFunction f -> switch (f.type()) {
case ADD -> new AddNode(toAst(f.argument1()), toAst(f.argument2()));
case MUL -> new MulNode(toAst(f.argument1()), toAst(f.argument2()));
case MIN -> {
double rightMin = f.argument2().minValue();
if (f.argument1().minValue() < rightMin) {
yield new MinShortNode(toAst(f.argument1()), toAst(f.argument2()), rightMin);
} else {
yield new MinNode(toAst(f.argument1()), toAst(f.argument2()));
}
}
case MAX -> {
double rightMax = f.argument2().maxValue();
if (f.argument1().maxValue() > rightMax) {
yield new MaxShortNode(toAst(f.argument1()), toAst(f.argument2()), rightMax);
} else {
yield new MaxNode(toAst(f.argument1()), toAst(f.argument2()));
}
}
};
case DensityFunctions.BlendDensity f -> toAst(f.input());
case DensityFunctions.Clamp f -> new MaxNode(new ConstantNode(f.minValue()), new MinNode(new ConstantNode(f.maxValue()), toAst(f.input())));
case DensityFunctions.Constant f -> new ConstantNode(f.value());
case DensityFunctions.HolderHolder f -> toAst(f.function().value());
case DensityFunctions.Mapped f -> switch (f.type()) {
case ABS -> new AbsNode(toAst(f.input()));
case SQUARE -> new SquareNode(toAst(f.input()));
case CUBE -> new CubeNode(toAst(f.input()));
case HALF_NEGATIVE -> new NegMulNode(toAst(f.input()), 0.5);
case QUARTER_NEGATIVE -> new NegMulNode(toAst(f.input()), 0.25);
case SQUEEZE -> new SqueezeNode(toAst(f.input()));
};
case DensityFunctions.RangeChoice f -> new RangeChoiceNode(toAst(f.input()), f.minInclusive(), f.maxExclusive(), toAst(f.whenInRange()), toAst(f.whenOutOfRange()));
case DensityFunctions.Marker f -> {
DensityFunctions.Marker wrapping = new DensityFunctions.Marker(f.type(), new AstVanillaInterface(toAst(f.wrapped()), null));
((IEqualityOverriding) (Object) wrapping).c2me$overrideEquality(wrapping);
yield new DelegateNode(wrapping);
}
case IFastCacheLike f -> new CacheLikeNode(f, toAst(f.c2me$getDelegate()));
case DensityFunctions.ShiftedNoise f -> new ShiftedNoiseNode(toAst(f.shiftX()), toAst(f.shiftY()), toAst(f.shiftZ()), f.xzScale(), f.yScale(), f.noise());
case DensityFunctions.Noise f -> new DFTNoiseNode(f.noise(), f.xzScale(), f.yScale());
case DensityFunctions.Shift f -> new DFTShiftNode(f.offsetNoise());
case DensityFunctions.ShiftA f -> new DFTShiftANode(f.offsetNoise());
case DensityFunctions.ShiftB f -> new DFTShiftBNode(f.offsetNoise());
case DensityFunctions.YClampedGradient f -> new YClampedGradientNode(f.fromY(), f.toY(), f.fromValue(), f.toValue());
case DensityFunctions.WeirdScaledSampler f -> new DFTWeirdScaledSamplerNode(toAst(f.input()), f.noise(), f.rarityValueMapper());
case DensityFunctions.Spline f -> new SplineAstNode(f.spline());
default -> {
// delegateStatistics.computeIfAbsent(df.getClass(), unused -> new LongAdder()).increment();;
yield new DelegateNode(df);
}
};
}
public static @NotNull DensityFunction wrapVanilla(DensityFunction densityFunction) {
return new AstVanillaInterface(toAst(densityFunction), densityFunction);
}
}

View File

@@ -0,0 +1,106 @@
package org.bxteam.divinemc.dfc.common.ast.binary;
import org.bxteam.divinemc.dfc.common.ast.AstNode;
import org.bxteam.divinemc.dfc.common.ast.AstTransformer;
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen.Context;
import org.bxteam.divinemc.dfc.common.util.ArrayCache;
import java.util.Objects;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
public abstract class AbstractBinaryNode implements AstNode {
protected final AstNode left;
protected final AstNode right;
public AbstractBinaryNode(AstNode left, AstNode right) {
this.left = (AstNode)Objects.requireNonNull(left);
this.right = (AstNode)Objects.requireNonNull(right);
}
public AstNode[] getChildren() {
return new AstNode[]{this.left, this.right};
}
public boolean equals(Object o) {
if (this == o) {
return true;
} else if (o != null && this.getClass() == o.getClass()) {
AbstractBinaryNode that = (AbstractBinaryNode)o;
return Objects.equals(this.left, that.left) && Objects.equals(this.right, that.right);
} else {
return false;
}
}
public int hashCode() {
int result = 1;
result = 31 * result + this.getClass().hashCode();
result = 31 * result + this.left.hashCode();
result = 31 * result + this.right.hashCode();
return result;
}
public boolean relaxedEquals(AstNode o) {
if (this == o) {
return true;
} else if (o != null && this.getClass() == o.getClass()) {
AbstractBinaryNode that = (AbstractBinaryNode)o;
return this.left.relaxedEquals(that.left) && this.right.relaxedEquals(that.right);
} else {
return false;
}
}
public int relaxedHashCode() {
int result = 1;
result = 31 * result + this.getClass().hashCode();
result = 31 * result + this.left.relaxedHashCode();
result = 31 * result + this.right.relaxedHashCode();
return result;
}
protected abstract AstNode newInstance(AstNode var1, AstNode var2);
public AstNode transform(AstTransformer transformer) {
AstNode left = this.left.transform(transformer);
AstNode right = this.right.transform(transformer);
return left == this.left && right == this.right ? transformer.transform(this) : transformer.transform(this.newInstance(left, right));
}
public void doBytecodeGenSingle(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
String leftMethod = context.newSingleMethod(this.left);
String rightMethod = context.newSingleMethod(this.right);
context.callDelegateSingle(m, leftMethod);
context.callDelegateSingle(m, rightMethod);
}
public void doBytecodeGenMulti(Context context, InstructionAdapter m, Context.LocalVarConsumer localVarConsumer) {
String leftMethod = context.newMultiMethod(this.left);
String rightMethod = context.newMultiMethod(this.right);
int res1 = localVarConsumer.createLocalVariable("res1", Type.getDescriptor(double[].class));
m.load(6, InstructionAdapter.OBJECT_TYPE);
m.load(1, InstructionAdapter.OBJECT_TYPE);
m.arraylength();
m.iconst(0);
m.invokevirtual(Type.getInternalName(ArrayCache.class), "getDoubleArray", Type.getMethodDescriptor(Type.getType(double[].class), new Type[]{Type.INT_TYPE, Type.BOOLEAN_TYPE}), false);
m.store(res1, InstructionAdapter.OBJECT_TYPE);
context.callDelegateMulti(m, leftMethod);
m.load(0, InstructionAdapter.OBJECT_TYPE);
m.load(res1, InstructionAdapter.OBJECT_TYPE);
m.load(2, InstructionAdapter.OBJECT_TYPE);
m.load(3, InstructionAdapter.OBJECT_TYPE);
m.load(4, InstructionAdapter.OBJECT_TYPE);
m.load(5, InstructionAdapter.OBJECT_TYPE);
m.load(6, InstructionAdapter.OBJECT_TYPE);
m.invokevirtual(context.className, rightMethod, Context.MULTI_DESC, false);
context.doCountedLoop(m, localVarConsumer, (idx) -> {
this.bytecodeGenMultiBody(m, idx, res1);
});
m.load(6, InstructionAdapter.OBJECT_TYPE);
m.load(res1, InstructionAdapter.OBJECT_TYPE);
m.invokevirtual(Type.getInternalName(ArrayCache.class), "recycle", Type.getMethodDescriptor(Type.VOID_TYPE, new Type[]{Type.getType(double[].class)}), false);
m.areturn(Type.VOID_TYPE);
}
protected abstract void bytecodeGenMultiBody(InstructionAdapter var1, int var2, int var3);
}

View File

@@ -0,0 +1,50 @@
package org.bxteam.divinemc.dfc.common.ast.binary;
import org.bxteam.divinemc.dfc.common.ast.AstNode;
import org.bxteam.divinemc.dfc.common.ast.EvalType;
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
public class AddNode extends AbstractBinaryNode {
public AddNode(AstNode left, AstNode right) {
super(left, right);
}
protected AstNode newInstance(AstNode left, AstNode right) {
return new AddNode(left, right);
}
public double evalSingle(int x, int y, int z, EvalType type) {
return this.left.evalSingle(x, y, z, type) + this.right.evalSingle(x, y, z, type);
}
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
double[] res1 = new double[res.length];
this.left.evalMulti(res, x, y, z, type);
this.right.evalMulti(res1, x, y, z, type);
for(int i = 0; i < res1.length; ++i) {
res[i] += res1[i];
}
}
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
super.doBytecodeGenSingle(context, m, localVarConsumer);
m.add(Type.DOUBLE_TYPE);
m.areturn(Type.DOUBLE_TYPE);
}
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
m.load(1, InstructionAdapter.OBJECT_TYPE);
m.load(idx, Type.INT_TYPE);
m.dup2();
m.aload(Type.DOUBLE_TYPE);
m.load(res1, InstructionAdapter.OBJECT_TYPE);
m.load(idx, Type.INT_TYPE);
m.aload(Type.DOUBLE_TYPE);
m.add(Type.DOUBLE_TYPE);
m.astore(Type.DOUBLE_TYPE);
}
}

View File

@@ -0,0 +1,50 @@
package org.bxteam.divinemc.dfc.common.ast.binary;
import org.bxteam.divinemc.dfc.common.ast.AstNode;
import org.bxteam.divinemc.dfc.common.ast.EvalType;
import org.bxteam.divinemc.dfc.common.gen.BytecodeGen;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.InstructionAdapter;
public class MaxNode extends AbstractBinaryNode {
public MaxNode(AstNode left, AstNode right) {
super(left, right);
}
protected AstNode newInstance(AstNode left, AstNode right) {
return new MaxNode(left, right);
}
public double evalSingle(int x, int y, int z, EvalType type) {
return Math.max(this.left.evalSingle(x, y, z, type), this.right.evalSingle(x, y, z, type));
}
public void evalMulti(double[] res, int[] x, int[] y, int[] z, EvalType type) {
double[] res1 = new double[res.length];
this.left.evalMulti(res, x, y, z, type);
this.right.evalMulti(res1, x, y, z, type);
for(int i = 0; i < res1.length; ++i) {
res[i] = Math.max(res[i], res1[i]);
}
}
public void doBytecodeGenSingle(BytecodeGen.Context context, InstructionAdapter m, BytecodeGen.Context.LocalVarConsumer localVarConsumer) {
super.doBytecodeGenSingle(context, m, localVarConsumer);
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
m.areturn(Type.DOUBLE_TYPE);
}
protected void bytecodeGenMultiBody(InstructionAdapter m, int idx, int res1) {
m.load(1, InstructionAdapter.OBJECT_TYPE);
m.load(idx, Type.INT_TYPE);
m.dup2();
m.aload(Type.DOUBLE_TYPE);
m.load(res1, InstructionAdapter.OBJECT_TYPE);
m.load(idx, Type.INT_TYPE);
m.aload(Type.DOUBLE_TYPE);
m.invokestatic(Type.getInternalName(Math.class), "max", Type.getMethodDescriptor(Type.DOUBLE_TYPE, new Type[]{Type.DOUBLE_TYPE, Type.DOUBLE_TYPE}), false);
m.astore(Type.DOUBLE_TYPE);
}
}

Some files were not shown because too many files have changed in this diff Show More