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:
@@ -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
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
38
divinemc-api/paper-patches/features/0001-Rebrand.patch
Normal file
38
divinemc-api/paper-patches/features/0001-Rebrand.patch
Normal 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
|
||||||
|
);
|
||||||
24
divinemc-api/paper-patches/features/0002-Configuration.patch
Normal file
24
divinemc-api/paper-patches/features/0002-Configuration.patch
Normal 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
|
||||||
|
*
|
||||||
@@ -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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
@@ -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
|
|
||||||
@@ -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()
|
||||||
@@ -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];
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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() {
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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() {
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
@@ -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() {
|
||||||
@@ -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);
|
||||||
@@ -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);
|
||||||
|
|
||||||
@@ -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()
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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,
|
||||||
@@ -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");
|
||||||
@@ -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
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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))) {
|
||||||
@@ -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
|
||||||
@@ -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) {
|
||||||
@@ -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
|
||||||
@@ -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());
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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() {
|
||||||
@@ -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
@@ -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);
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
@@ -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 {
|
||||||
@@ -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));
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
@@ -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) {
|
||||||
@@ -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);
|
||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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) {
|
||||||
@@ -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
|
||||||
|
);
|
||||||
@@ -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) {
|
||||||
@@ -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
|
||||||
@@ -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(
|
||||||
@@ -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
|
||||||
@@ -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) {
|
||||||
@@ -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
|
|
||||||
|
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -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);
|
||||||
@@ -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-"
|
|
||||||
@@ -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));
|
||||||
@@ -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;
|
|
||||||
- }
|
|
||||||
-}
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
|
|
||||||
@@ -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);
|
||||||
@@ -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(
|
||||||
@@ -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() {}
|
||||||
|
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -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()) {
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
32
divinemc-server/src/c/CMakeLists.txt
Normal file
32
divinemc-server/src/c/CMakeLists.txt
Normal 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)
|
||||||
|
|
||||||
34
divinemc-server/src/c/exports.c
Normal file
34
divinemc-server/src/c/exports.c
Normal 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);
|
||||||
|
})
|
||||||
9
divinemc-server/src/c/exports_x86_64_nogather.c
Normal file
9
divinemc-server/src/c/exports_x86_64_nogather.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
#define GATHER_DISABLED 1
|
||||||
|
|
||||||
|
#include "exports.c"
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef int make_iso_compiler_happy;
|
||||||
672
divinemc-server/src/c/flibc.c
Normal file
672
divinemc-server/src/c/flibc.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
744
divinemc-server/src/c/includes/ext_math.h
Normal file
744
divinemc-server/src/c/includes/ext_math.h
Normal 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
|
||||||
|
|
||||||
28
divinemc-server/src/c/includes/target_macros.h
Normal file
28
divinemc-server/src/c/includes/target_macros.h
Normal 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
|
||||||
|
|
||||||
11
divinemc-server/src/c/system_isa_aarch64.c
Normal file
11
divinemc-server/src/c/system_isa_aarch64.c
Normal 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;
|
||||||
154
divinemc-server/src/c/system_isa_x86_64.c
Normal file
154
divinemc-server/src/c/system_isa_x86_64.c
Normal 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;
|
||||||
11
divinemc-server/src/c/targets/darwin-x86_64.cmake
Normal file
11
divinemc-server/src/c/targets/darwin-x86_64.cmake
Normal 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")
|
||||||
10
divinemc-server/src/c/targets/linux-aarch_64.cmake
Normal file
10
divinemc-server/src/c/targets/linux-aarch_64.cmake
Normal 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})
|
||||||
|
|
||||||
11
divinemc-server/src/c/targets/linux-x86_64.cmake
Normal file
11
divinemc-server/src/c/targets/linux-x86_64.cmake
Normal 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)
|
||||||
11
divinemc-server/src/c/targets/windows-x86_64.cmake
Normal file
11
divinemc-server/src/c/targets/windows-x86_64.cmake
Normal 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")
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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() {}
|
||||||
|
|
||||||
|
|||||||
@@ -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++;
|
||||||
|
|||||||
@@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
package org.bxteam.divinemc.dfc.common.ast;
|
||||||
|
|
||||||
|
public interface AstTransformer {
|
||||||
|
AstNode transform(AstNode var1);
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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
Reference in New Issue
Block a user