diff --git a/divinemc-api/paper-patches/features/0003-Expanded-Adventure-support.patch b/divinemc-api/paper-patches/features/0003-Expanded-Adventure-support.patch deleted file mode 100644 index 3641c37..0000000 --- a/divinemc-api/paper-patches/features/0003-Expanded-Adventure-support.patch +++ /dev/null @@ -1,77 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Tue, 14 Jan 2025 19:49:49 +0300 -Subject: [PATCH] Expanded Adventure support - -Adds support for Adventure in a few places where it was previously missing. -Original patch was taken from Parchment: https://github.com/ProjectEdenGG/Parchment - -diff --git a/src/main/java/org/bukkit/Color.java b/src/main/java/org/bukkit/Color.java -index f8edb964c4af597b03a2de06c464cc06a96b791c..596e2e09c6a64fa5861221789185d2fd7b004248 100644 ---- a/src/main/java/org/bukkit/Color.java -+++ b/src/main/java/org/bukkit/Color.java -@@ -17,7 +17,7 @@ import org.jetbrains.annotations.Nullable; - * but subject to change. - */ - @SerializableAs("Color") --public final class Color implements ConfigurationSerializable { -+public final class Color implements ConfigurationSerializable, net.kyori.adventure.text.format.TextColor { // DivineMC - Expanded Adventure support - private static final int BIT_MASK = 0xff; - private static final int DEFAULT_ALPHA = 255; - -@@ -310,6 +310,13 @@ public final class Color implements ConfigurationSerializable { - return getAlpha() << 24 | getRed() << 16 | getGreen() << 8 | getBlue(); - } - -+ // DivineMC start - Expanded Adventure support -+ @Override -+ public int value() { -+ return asRGB(); -+ } -+ // DivineMC end - Expanded Adventure support -+ - /** - * Gets the color as an BGR integer. - * -diff --git a/src/main/java/org/bukkit/DyeColor.java b/src/main/java/org/bukkit/DyeColor.java -index 2f038f233afd4210687586800070d5f61e40562a..24068f23f45a0d3b837b04565d143a5cd8cd8869 100644 ---- a/src/main/java/org/bukkit/DyeColor.java -+++ b/src/main/java/org/bukkit/DyeColor.java -@@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; - /** - * All supported color values for dyes and cloth - */ --public enum DyeColor { -+public enum DyeColor implements net.kyori.adventure.util.RGBLike, net.kyori.adventure.text.format.StyleBuilderApplicable { // DivineMC - Expanded Adventure support - - /** - * Represents white dye. -@@ -135,6 +135,28 @@ public enum DyeColor { - return firework; - } - -+ // DivineMC start - Expanded Adventure support -+ @Override -+ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int red() { -+ return color.getRed(); -+ } -+ -+ @Override -+ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int green() { -+ return color.getGreen(); -+ } -+ -+ @Override -+ public @org.jetbrains.annotations.Range(from = 0L, to = 255L) int blue() { -+ return color.getBlue(); -+ } -+ -+ @Override -+ public void styleApply(net.kyori.adventure.text.format.Style.@org.jetbrains.annotations.NotNull Builder style) { -+ style.color(net.kyori.adventure.text.format.TextColor.color(color)); -+ } -+ // DivineMC end - Expanded Adventure support -+ - /** - * Gets the DyeColor with the given wool data value. - * diff --git a/divinemc-api/paper-patches/features/0004-Extend-Location-API.patch b/divinemc-api/paper-patches/features/0004-Extend-Location-API.patch deleted file mode 100644 index 73d292c..0000000 --- a/divinemc-api/paper-patches/features/0004-Extend-Location-API.patch +++ /dev/null @@ -1,181 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Tue, 14 Jan 2025 20:36:30 +0300 -Subject: [PATCH] Extend Location API - - -diff --git a/src/main/java/org/bukkit/Location.java b/src/main/java/org/bukkit/Location.java -index 20e30fa5a33c68a4dec12e51a6b81f4afbda35b5..8b71277d3cab283eeab43df3e4dc4fb4fbad2388 100644 ---- a/src/main/java/org/bukkit/Location.java -+++ b/src/main/java/org/bukkit/Location.java -@@ -1253,4 +1253,170 @@ public class Location implements Cloneable, ConfigurationSerializable, io.paperm - public @NotNull Location toLocation(@NotNull World world) { - return new Location(world, this.x(), this.y(), this.z(), this.getYaw(), this.getPitch()); - } -+ -+ // DivineMC start - Extend Location API -+ /** -+ * Sets the x-coordinate of this location. -+ * -+ * @param x The x-coordinate -+ * @return this location -+ */ -+ public @NotNull Location x(double x) { -+ this.x = x; -+ return this; -+ } -+ -+ /** -+ * Sets the y-coordinate of this location. -+ * -+ * @param y The y-coordinate -+ * @return this location -+ */ -+ public @NotNull Location y(double y) { -+ this.y = y; -+ return this; -+ } -+ -+ /** -+ * Sets the z-coordinate of this location. -+ * -+ * @param z The z-coordinate -+ * @return this location -+ */ -+ public @NotNull Location z(double z) { -+ this.z = z; -+ return this; -+ } -+ -+ /** -+ * Sets the yaw of this location, measured in degrees. -+ * -+ * Increasing yaw values are the equivalent of turning to your -+ * right-facing, increasing the scale of the next respective axis, and -+ * decreasing the scale of the previous axis. -+ * -+ * @param yaw new rotation's yaw -+ * @return this location -+ */ -+ public @NotNull Location yaw(float yaw) { -+ this.yaw = yaw; -+ return this; -+ } -+ -+ /** -+ * Sets the pitch of this location, measured in degrees. -+ * -+ * Increasing pitch values the equivalent of looking down. -+ * -+ * @param pitch new incline's pitch -+ * @return this location -+ */ -+ public @NotNull Location pitch(float pitch) { -+ this.pitch = pitch; -+ return this; -+ } -+ -+ /** -+ * Sets the world that this location resides in -+ * -+ * @param world New world that this location resides in -+ * @return this location -+ */ -+ public @NotNull Location world(@Nullable World world) { -+ this.world = (world == null) ? null : new WeakReference<>(world); -+ return this; -+ } -+ -+ /** -+ * Increments the x-coordinate by the given value. -+ * -+ * @param x Amount to increment the x-coordinate by -+ * @return this location -+ */ -+ public @NotNull Location addX(double x) { -+ this.x += x; -+ return this; -+ } -+ -+ /** -+ * Increments the y-coordinate by the given value. -+ * -+ * @param y Amount to increment the y-coordinate by -+ * @return this location -+ */ -+ public @NotNull Location addY(double y) { -+ this.y += y; -+ return this; -+ } -+ -+ /** -+ * Increments the z-coordinate by the given value. -+ * -+ * @param z Amount to increment the z-coordinate by -+ * @return this location -+ */ -+ public @NotNull Location addZ(double z) { -+ this.z += z; -+ return this; -+ } -+ -+ /** -+ * Returns location with centered X, Y and Z values. -+ * -+ * @return this location -+ */ -+ public @NotNull Location center() { -+ return center(0.5); -+ } -+ -+ /** -+ * Returns location with centered X and Z values. -+ * Y will be set to provided. -+ * -+ * @param y Y adding value -+ * @return this location -+ */ -+ public @NotNull Location center(double y) { -+ return set(getBlockX() + 0.5, getBlockY() + y, getBlockZ() + 0.5); -+ } -+ -+ /** -+ * Checks if locations have the same X, Y and Z values. -+ * -+ * @param loc Location to check -+ * @return true if locations have same coordinates -+ * @apiNote Ignores world -+ */ -+ public boolean isSame(@NotNull Location loc) { -+ return getY() == loc.getY() && getX() == loc.getX() && getZ() == loc.getZ(); -+ } -+ -+ /** -+ * Shifts this location by one block up -+ * -+ * @return this location -+ */ -+ public @NotNull Location above() { -+ return addY(1); -+ } -+ -+ /** -+ * Shifts this location by one block down -+ * -+ * @return this location -+ */ -+ public @NotNull Location below() { -+ return addY(-1); -+ } -+ // DivineMC end - Extend Location API - } diff --git a/divinemc-api/paper-patches/features/0005-Extend-Sound-API.patch b/divinemc-api/paper-patches/features/0005-Extend-Sound-API.patch deleted file mode 100644 index 3275a03..0000000 --- a/divinemc-api/paper-patches/features/0005-Extend-Sound-API.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Tue, 14 Jan 2025 20:42:04 +0300 -Subject: [PATCH] Extend Sound API - - -diff --git a/src/main/java/org/bukkit/block/Block.java b/src/main/java/org/bukkit/block/Block.java -index b703ad820ff873097dadff9e55b53fcc6b1b8698..b35c3852a3b8e62c7d2f67fc3ff651c8e0a4d5f2 100644 ---- a/src/main/java/org/bukkit/block/Block.java -+++ b/src/main/java/org/bukkit/block/Block.java -@@ -817,4 +817,29 @@ public interface Block extends Metadatable, Translatable, net.kyori.adventure.tr - return this.getBlockData().getDestroySpeed(itemStack, considerEnchants); - } - // Paper end - destroy speed API -+ -+ // DivineMC start - Extend Sound API -+ /** -+ * Plays a sound at the location of the block -+ * -+ * @param sound sound to play -+ * @param volume volume of the sound -+ * @param pitch pitch of the sound -+ */ -+ default void emitSound(@NotNull org.bukkit.Sound sound, float volume, float pitch) { -+ emitSound(sound, org.bukkit.SoundCategory.BLOCKS, volume, pitch); -+ } -+ -+ /** -+ * Plays a sound at the location of the block -+ * -+ * @param sound sound to play -+ * @param category category of the sound -+ * @param volume volume of the sound -+ * @param pitch pitch of the sound -+ */ -+ default void emitSound(@NotNull org.bukkit.Sound sound, @NotNull org.bukkit.SoundCategory category, float volume, float pitch) { -+ getWorld().playSound(getLocation().toCenterLocation(), sound, category, volume, pitch); -+ } -+ // DivineMC end - Extend Sound API - } -diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 49d3ca54a761e08cfe1bc770cb879223bf0e21e8..942f7497a56baa8e717980795e605a8907039fe6 100644 ---- a/src/main/java/org/bukkit/entity/Entity.java -+++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -1251,4 +1251,35 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent - */ - void setImmuneToFire(@Nullable Boolean fireImmune); - // Purpur end - Fire Immunity API -+ -+ // DivineMC start - Extend Sound API -+ /** -+ * Plays a sound at the location of the entity -+ * -+ * @param sound sound to play -+ * @param volume volume of the sound -+ * @param pitch pitch of the sound -+ */ -+ default void emitSound(@NotNull org.bukkit.Sound sound, float volume, float pitch) { -+ org.bukkit.SoundCategory soundGroup = switch (this) { -+ case HumanEntity humanEntity -> org.bukkit.SoundCategory.PLAYERS; -+ case Ambient ambient -> org.bukkit.SoundCategory.AMBIENT; -+ case Monster monster -> org.bukkit.SoundCategory.HOSTILE; -+ default -> org.bukkit.SoundCategory.NEUTRAL; -+ }; -+ emitSound(sound, soundGroup, volume, pitch); -+ } -+ -+ /** -+ * Plays a sound at the location of the block -+ * -+ * @param sound sound to play -+ * @param category category of the sound -+ * @param volume volume of the sound -+ * @param pitch pitch of the sound -+ */ -+ default void emitSound(@NotNull org.bukkit.Sound sound, @NotNull org.bukkit.SoundCategory category, float volume, float pitch) { -+ getWorld().playSound(this, sound, category, volume, pitch); -+ } -+ // DivineMC end - Extend Sound API - } diff --git a/divinemc-api/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfo.java.patch b/divinemc-api/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfo.java.patch deleted file mode 100644 index a20507f..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/io/papermc/paper/ServerBuildInfo.java.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- a/src/main/java/io/papermc/paper/ServerBuildInfo.java -+++ b/src/main/java/io/papermc/paper/ServerBuildInfo.java -@@ -25,6 +_,14 @@ - */ - Key BRAND_PURPUR_ID = Key.key("purpurmc", "purpur"); - // Purpur end -+ -+ // DivineMC start -+ /** -+ * The brand id for DivineMC. -+ */ -+ Key BRAND_DIVINEMC_ID = Key.key("bxteam", "divinemc"); -+ // DivineMC end -+ - /** - * Gets the {@code ServerBuildInfo}. - * diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/Note.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/Note.java.patch deleted file mode 100644 index 45db7c3..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/Note.java.patch +++ /dev/null @@ -1,73 +0,0 @@ ---- a/src/main/java/org/bukkit/Note.java -+++ b/src/main/java/org/bukkit/Note.java -@@ -127,6 +_,7 @@ - } - - private final byte note; -+ private final net.kyori.adventure.text.format.TextColor color; // DivineMC - Note Color API - - /** - * Creates a new note. -@@ -138,6 +_,7 @@ - Preconditions.checkArgument(note >= 0 && note <= 24, "The note value has to be between 0 and 24."); - - this.note = (byte) note; -+ this.color = getColor(note); // DivineMC - Note Color API - } - - /** -@@ -158,6 +_,7 @@ - } - - this.note = (byte) (octave * Tone.TONES_COUNT + tone.getId(sharped)); -+ this.color = getColor(note); // DivineMC - Note Color API - } - - /** -@@ -298,4 +_,46 @@ - public String toString() { - return "Note{" + getTone().toString() + (isSharped() ? "#" : "") + "}"; - } -+ -+ // DivineMC start - Note Color API -+ /** -+ * Get color of the played note. -+ * -+ * @return the color of the note -+ */ -+ @NotNull -+ public net.kyori.adventure.text.format.TextColor getColor() { -+ return color; -+ } -+ -+ private static @NotNull net.kyori.adventure.text.format.TextColor getColor(int note) { -+ return switch (note) { -+ case 0 -> net.kyori.adventure.text.format.TextColor.fromHexString("#77D700"); -+ case 1 -> net.kyori.adventure.text.format.TextColor.fromHexString("#95C000"); -+ case 2 -> net.kyori.adventure.text.format.TextColor.fromHexString("#B2A500"); -+ case 3 -> net.kyori.adventure.text.format.TextColor.fromHexString("#CC8600"); -+ case 4 -> net.kyori.adventure.text.format.TextColor.fromHexString("#E26500"); -+ case 5 -> net.kyori.adventure.text.format.TextColor.fromHexString("#F34100"); -+ case 6 -> net.kyori.adventure.text.format.TextColor.fromHexString("#FC1E00"); -+ case 7 -> net.kyori.adventure.text.format.TextColor.fromHexString("#FE000F"); -+ case 8 -> net.kyori.adventure.text.format.TextColor.fromHexString("#F70033"); -+ case 9 -> net.kyori.adventure.text.format.TextColor.fromHexString("#E8005A"); -+ case 10 -> net.kyori.adventure.text.format.TextColor.fromHexString("#CF0083"); -+ case 11 -> net.kyori.adventure.text.format.TextColor.fromHexString("#AE00A9"); -+ case 12 -> net.kyori.adventure.text.format.TextColor.fromHexString("#8600CC"); -+ case 13 -> net.kyori.adventure.text.format.TextColor.fromHexString("#5B00E7"); -+ case 14 -> net.kyori.adventure.text.format.TextColor.fromHexString("#2D00F9"); -+ case 15 -> net.kyori.adventure.text.format.TextColor.fromHexString("#020AFE"); -+ case 16 -> net.kyori.adventure.text.format.TextColor.fromHexString("#0037F6"); -+ case 17 -> net.kyori.adventure.text.format.TextColor.fromHexString("#0068E0"); -+ case 18 -> net.kyori.adventure.text.format.TextColor.fromHexString("#009ABC"); -+ case 19 -> net.kyori.adventure.text.format.TextColor.fromHexString("#00C68D"); -+ case 20 -> net.kyori.adventure.text.format.TextColor.fromHexString("#00E958"); -+ case 21 -> net.kyori.adventure.text.format.TextColor.fromHexString("#00FC21"); -+ case 22 -> net.kyori.adventure.text.format.TextColor.fromHexString("#1FFC00"); -+ case 23 -> net.kyori.adventure.text.format.TextColor.fromHexString("#59E800"); -+ default -> net.kyori.adventure.text.format.TextColor.fromHexString("#94C100"); -+ }; -+ } -+ // DivineMC end - Note Color API - } diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch deleted file mode 100644 index a593e52..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/Server.java.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -2346,6 +_,13 @@ - } - // Purpur end - -+ // DivineMC start -+ @NotNull -+ public org.bukkit.configuration.file.YamlConfiguration getDivineConfig() { -+ throw new UnsupportedOperationException("Not supported yet"); -+ } -+ // DivineMC end -+ - /** - * Sends the component to the player - * diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/Command.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/Command.java.patch deleted file mode 100644 index f95e9f7..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/Command.java.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- a/src/main/java/org/bukkit/command/Command.java -+++ b/src/main/java/org/bukkit/command/Command.java -@@ -33,16 +_,6 @@ - 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()); diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/FormattedCommandAlias.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/FormattedCommandAlias.java.patch deleted file mode 100644 index bc49ff4..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/FormattedCommandAlias.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/src/main/java/org/bukkit/command/FormattedCommandAlias.java -+++ b/src/main/java/org/bukkit/command/FormattedCommandAlias.java -@@ -12,7 +_,6 @@ - - public FormattedCommandAlias(@NotNull String alias, @NotNull String[] formatStrings) { - super(alias); -- timings = co.aikar.timings.TimingsManager.getCommandTiming("minecraft", this); // Spigot - this.formatStrings = formatStrings; - } - -@@ -119,10 +_,6 @@ - - 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/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch deleted file mode 100644 index ca83d8c..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/SimpleCommandMap.java.patch +++ /dev/null @@ -1,31 +0,0 @@ ---- a/src/main/java/org/bukkit/command/SimpleCommandMap.java -+++ b/src/main/java/org/bukkit/command/SimpleCommandMap.java -@@ -39,7 +_,6 @@ - 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 +_,6 @@ - */ - @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); -@@ -165,12 +_,6 @@ - sentCommandLabel = event.getLabel(); - 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 diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch deleted file mode 100644 index 33e6aa3..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/command/defaults/VersionCommand.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/src/main/java/org/bukkit/command/defaults/VersionCommand.java -+++ b/src/main/java/org/bukkit/command/defaults/VersionCommand.java -@@ -259,7 +_,7 @@ - // Purpur start - int distance = getVersionFetcher().distance(); - final Component message = Component.join(net.kyori.adventure.text.JoinConfiguration.separator(Component.newline()), -- ChatColor.parseMM("Current Purpur Version: %s%s*", distance == 0 ? "" : distance > 0 ? "" : "", Bukkit.getVersion()), -+ ChatColor.parseMM("Current DivineMC Version: %s%s*", distance == 0 ? "" : distance > 0 ? "" : "", Bukkit.getVersion()), // DivineMC - Rebrand - // Purpur end - msg - ); diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/entity/AbstractArrow.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/entity/AbstractArrow.java.patch deleted file mode 100644 index f4b31b8..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/entity/AbstractArrow.java.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/src/main/java/org/bukkit/entity/AbstractArrow.java -+++ b/src/main/java/org/bukkit/entity/AbstractArrow.java -@@ -297,4 +_,11 @@ - */ - void setShooter(@Nullable org.bukkit.projectiles.ProjectileSource source, boolean resetPickupStatus); - // Paper end - Fix PickupStatus getting reset -+ -+ // DivineMC start - Add startFalling method to AbstractArrow -+ /** -+ * Asks projectile to start falling if possible -+ */ -+ void startFalling(); -+ // DivineMC end - Add startFalling method to AbstractArrow - } diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch deleted file mode 100644 index 320b6d1..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/entity/Player.java.patch +++ /dev/null @@ -1,17 +0,0 @@ ---- a/src/main/java/org/bukkit/entity/Player.java -+++ b/src/main/java/org/bukkit/entity/Player.java -@@ -4021,4 +_,14 @@ - sendDeathScreen(message); - } - // Purpur end -+ -+ // DivineMC start - Open Ender Chest API -+ /** -+ * Opens ender chest for the player -+ * -+ * @param enderChest ender chest -+ * @return whether the chest was opened -+ */ -+ boolean openEnderChest(org.bukkit.block.EnderChest enderChest); -+ // DivineMC end - Open Ender Chest API - } diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/event/block/NotePlayEvent.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/event/block/NotePlayEvent.java.patch deleted file mode 100644 index 0caf824..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/event/block/NotePlayEvent.java.patch +++ /dev/null @@ -1,43 +0,0 @@ ---- a/src/main/java/org/bukkit/event/block/NotePlayEvent.java -+++ b/src/main/java/org/bukkit/event/block/NotePlayEvent.java -@@ -16,13 +_,21 @@ - private static HandlerList handlers = new HandlerList(); - private Instrument instrument; - private Note note; -+ private final @org.jetbrains.annotations.Nullable org.bukkit.entity.Player player; // DivineMC - Add player to NotePlayEvent - private boolean cancelled = false; - -+ // DivineMC start - Add player to NotePlayEvent - public NotePlayEvent(@NotNull Block block, @NotNull Instrument instrument, @NotNull Note note) { -+ this(block, instrument, note, null); -+ } -+ -+ public NotePlayEvent(@NotNull Block block, @NotNull Instrument instrument, @NotNull Note note, @org.jetbrains.annotations.Nullable org.bukkit.entity.Player player) { - super(block); - this.instrument = instrument; - this.note = note; -+ this.player = player; - } -+ // DivineMC end - Add player to NotePlayEvent - - @Override - public boolean isCancelled() { -@@ -53,6 +_,18 @@ - public Note getNote() { - return note; - } -+ -+ // DivineMC start - Add player to NotePlayEvent -+ /** -+ * Gets the {@link org.bukkit.entity.Player} who played the note -+ * -+ * @return player who played the note, if present -+ */ -+ @org.jetbrains.annotations.Nullable -+ public org.bukkit.entity.Player getPlayer() { -+ return this.player; -+ } -+ // DivineMC end - Add player to NotePlayEvent - - /** - * Overrides the {@link Instrument} to be used. diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/plugin/SimplePluginManager.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/plugin/SimplePluginManager.java.patch deleted file mode 100644 index e1e854a..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/plugin/SimplePluginManager.java.patch +++ /dev/null @@ -1,35 +0,0 @@ ---- a/src/main/java/org/bukkit/plugin/SimplePluginManager.java -+++ b/src/main/java/org/bukkit/plugin/SimplePluginManager.java -@@ -720,12 +_,7 @@ - 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)); - } - - @NotNull -@@ -955,8 +_,7 @@ - - @Override - public boolean useTimings() { -- if (true) {return this.paperPluginManager.useTimings();} // Paper -- return co.aikar.timings.Timings.isTimingsEnabled(); // Spigot -+ return false; - } - - /** -@@ -966,7 +_,7 @@ - */ - @Deprecated(forRemoval = true) - public void useTimings(boolean use) { -- co.aikar.timings.Timings.setTimingsEnabled(use); // Paper -+ // DivineMC - Delete timings - } - - // Paper start diff --git a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch b/divinemc-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch deleted file mode 100644 index ded8bdb..0000000 --- a/divinemc-api/paper-patches/files/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- a/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -+++ b/src/main/java/org/bukkit/plugin/java/JavaPluginLoader.java -@@ -43,7 +_,6 @@ - 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 +_,7 @@ - } - } - -- EventExecutor executor = new co.aikar.timings.TimedEventExecutor(new EventExecutor() { // Paper -+ EventExecutor executor = new EventExecutor() { // Paper - @Override - public void execute(@NotNull Listener listener, @NotNull Event event) throws EventException { // Paper - try { -@@ -308,7 +_,7 @@ - throw new EventException(t); - } - } -- }, plugin, method, eventClass); // 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/divinemc-server/minecraft-patches/features/0004-lithium-fast_util.patch b/divinemc-server/minecraft-patches/features/0004-lithium-fast_util.patch deleted file mode 100644 index 7abdd99..0000000 --- a/divinemc-server/minecraft-patches/features/0004-lithium-fast_util.patch +++ /dev/null @@ -1,84 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 12 Jan 2025 15:27:57 +0300 -Subject: [PATCH] lithium: fast_util - - -diff --git a/net/minecraft/core/Direction.java b/net/minecraft/core/Direction.java -index 216f97207dac88cc1dc3df59c6ee8a62c7614b4a..05c7de5729466786a0196fa5f91eccc3cfffc675 100644 ---- a/net/minecraft/core/Direction.java -+++ b/net/minecraft/core/Direction.java -@@ -217,7 +217,7 @@ public enum Direction implements StringRepresentable, ca.spottedleaf.moonrise.pa - } - - public Direction getOpposite() { -- return this.opposite; // Paper - optimise collisions -+ return VALUES[this.oppositeIndex]; // DivineMC - lithium: fast_util - } - - public Direction getClockWise(Direction.Axis axis) { -@@ -350,7 +350,7 @@ public enum Direction implements StringRepresentable, ca.spottedleaf.moonrise.pa - } - - public static Direction getRandom(RandomSource random) { -- return Util.getRandom(VALUES, random); -+ return VALUES[random.nextInt(VALUES.length)]; // DivineMC - lithium: fast_util - } - - public static Direction getApproximateNearest(double x, double y, double z) { -diff --git a/net/minecraft/world/phys/AABB.java b/net/minecraft/world/phys/AABB.java -index c9c6e4e460ad8435f12761704bb9b0284d6aa708..9581e7d51edaa6c51538a5267f421b034f4bfff0 100644 ---- a/net/minecraft/world/phys/AABB.java -+++ b/net/minecraft/world/phys/AABB.java -@@ -18,6 +18,15 @@ public class AABB { - public final double maxY; - public final double maxZ; - -+ // DivineMC start - lithium: fast_util -+ static { -+ assert Direction.Axis.X.ordinal() == 0; -+ assert Direction.Axis.Y.ordinal() == 1; -+ assert Direction.Axis.Z.ordinal() == 2; -+ assert Direction.Axis.values().length == 3; -+ } -+ // DivineMC end - lithium: fast_util -+ - public AABB(double x1, double y1, double z1, double x2, double y2, double z2) { - this.minX = Math.min(x1, x2); - this.minY = Math.min(y1, y2); -@@ -79,11 +88,33 @@ public class AABB { - } - - public double min(Direction.Axis axis) { -- return axis.choose(this.minX, this.minY, this.minZ); -+ // DivineMC start - lithium: fast_util -+ switch (axis.ordinal()) { -+ case 0: // X -+ return this.minX; -+ case 1: // Y -+ return this.minY; -+ case 2: // Z -+ return this.minZ; -+ } -+ -+ throw new IllegalArgumentException(); -+ // DivineMC end - lithium: fast_util - } - - public double max(Direction.Axis axis) { -- return axis.choose(this.maxX, this.maxY, this.maxZ); -+ // DivineMC start - lithium: fast_util -+ switch (axis.ordinal()) { -+ case 0: //X -+ return this.maxX; -+ case 1: //Y -+ return this.maxY; -+ case 2: //Z -+ return this.maxZ; -+ } -+ -+ throw new IllegalArgumentException(); -+ // DivineMC end - lithium: fast_util - } - - @Override diff --git a/divinemc-server/minecraft-patches/features/0005-Petal-Reduce-work-done-by-game-event-system.patch b/divinemc-server/minecraft-patches/features/0005-Petal-Reduce-work-done-by-game-event-system.patch deleted file mode 100644 index 08ce160..0000000 --- a/divinemc-server/minecraft-patches/features/0005-Petal-Reduce-work-done-by-game-event-system.patch +++ /dev/null @@ -1,196 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 12 Jan 2025 20:57:25 +0300 -Subject: [PATCH] Petal: Reduce work done by game event system - -Original code by Bloom-host, licensed under GPL v3 -You can find the original code on https://github.com/Bloom-host/Petal - -diff --git a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -index 1638eccef431fb68775af624110f1968f0c6dabd..2799db1223c9f279322869bdd19605e6d835af2e 100644 ---- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -+++ b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -@@ -65,7 +65,7 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi - return this.catalystListener; - } - -- public static class CatalystListener implements GameEventListener { -+ public class CatalystListener implements GameEventListener { // DivineMC - static -> non-static - public static final int PULSE_TICKS = 8; - final SculkSpreader sculkSpreader; - private final BlockState blockState; -@@ -127,6 +127,13 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi - level.playSound(null, pos, SoundEvents.SCULK_CATALYST_BLOOM, SoundSource.BLOCKS, 2.0F, 0.6F + random.nextFloat() * 0.4F); - } - -+ // DivineMC start - Petal: Reduce work done by game event system -+ @Override -+ public boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { -+ return !SculkCatalystBlockEntity.this.isRemoved() && gameEvent == GameEvent.ENTITY_DIE.value() && context.sourceEntity() instanceof LivingEntity; -+ } -+ // DivineMC end - Petal: Reduce work done by game event system -+ - private void tryAwardItSpreadsAdvancement(Level level, LivingEntity entity) { - if (entity.getLastHurtByMob() instanceof ServerPlayer serverPlayer) { - DamageSource damageSource = entity.getLastDamageSource() == null -diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java -index 761fdcd4a4e18f45547afd8edff44f61c6eeacb4..03264d2b170002c640cec34530909ebb34c7e54e 100644 ---- a/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/net/minecraft/world/level/chunk/LevelChunk.java -@@ -81,7 +81,18 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - private Supplier fullStatus; - @Nullable - private LevelChunk.PostLoadProcessor postLoad; -- private final Int2ObjectMap gameEventListenerRegistrySections; -+ // DivineMC start - Petal: Reduce work done by game event system -+ private final GameEventListenerRegistry[] gameEventListenerRegistrySections; -+ private static final int GAME_EVENT_DISPATCHER_RADIUS = 2; -+ -+ private static int getGameEventSectionIndex(int sectionIndex) { -+ return sectionIndex + GAME_EVENT_DISPATCHER_RADIUS; -+ } -+ -+ private static int getGameEventSectionLength(int sectionCount) { -+ return sectionCount + (GAME_EVENT_DISPATCHER_RADIUS * 2); -+ } -+ // DivineMC end - Petal: Reduce work done by game event system - private final LevelChunkTicks blockTicks; - private final LevelChunkTicks fluidTicks; - private LevelChunk.UnsavedListener unsavedListener = chunkPos -> {}; -@@ -144,7 +155,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - ) { - super(pos, data, level, net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry - this.level = (ServerLevel) level; // CraftBukkit - type -- this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>(); -+ this.gameEventListenerRegistrySections = new GameEventListenerRegistry[getGameEventSectionLength(this.getSectionsCount())]; // DivineMC - Petal: Reduce work done by game event system - - for (Heightmap.Types types : Heightmap.Types.values()) { - if (ChunkStatus.FULL.heightmapsAfter().contains(types)) { -@@ -254,10 +265,29 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - - @Override - public GameEventListenerRegistry getListenerRegistry(int sectionY) { -- return this.level instanceof ServerLevel serverLevel -- ? this.gameEventListenerRegistrySections -- .computeIfAbsent(sectionY, i -> new EuclideanGameEventListenerRegistry(serverLevel, sectionY, this::removeGameEventListenerRegistry)) -- : super.getListenerRegistry(sectionY); -+ Level world = this.level; -+ -+ if (world instanceof ServerLevel worldserver) { -+ // DivineMC start - Petal: Reduce work done by game event system -+ int sectionIndex = getGameEventSectionIndex(this.getSectionIndexFromSectionY(sectionY)); -+ -+ // drop game events that are too far away (32 blocks) from loaded sections -+ // this matches the highest radius of game events in the game -+ if (sectionIndex < 0 || sectionIndex >= this.gameEventListenerRegistrySections.length) { -+ return GameEventListenerRegistry.NOOP; -+ } -+ -+ var dispatcher = this.gameEventListenerRegistrySections[sectionIndex]; -+ -+ if (dispatcher == null) { -+ dispatcher = this.gameEventListenerRegistrySections[sectionIndex] = new EuclideanGameEventListenerRegistry(worldserver, sectionY, this::removeGameEventListenerRegistry); -+ } -+ -+ return dispatcher; -+ // DivineMC end - Petal: Reduce work done by game event system -+ } else { -+ return super.getListenerRegistry(sectionY); -+ } - } - - // Paper start - Perf: Reduce instructions and provide final method -@@ -601,7 +631,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p - } - - private void removeGameEventListenerRegistry(int sectionY) { -- this.gameEventListenerRegistrySections.remove(sectionY); -+ this.gameEventListenerRegistrySections[getGameEventSectionIndex(this.getSectionIndexFromSectionY(sectionY))] = null; // DivineMC - Petal: Reduce work done by game event system - } - - private void removeBlockEntityTicker(BlockPos pos) { -diff --git a/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java b/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java -index 5175fc90a1fc61c832c6697997a97ae199b195ac..f40511b5be6cf72298d30188fd550d1d768d875a 100644 ---- a/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java -+++ b/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java -@@ -14,8 +14,8 @@ import net.minecraft.world.phys.Vec3; - - public class EuclideanGameEventListenerRegistry implements GameEventListenerRegistry { - private final List listeners = Lists.newArrayList(); -- private final Set listenersToRemove = Sets.newHashSet(); -- private final List listenersToAdd = Lists.newArrayList(); -+ //private final Set listenersToRemove = Sets.newHashSet(); // DivineMC - Commented out -+ //private final List listenersToAdd = Lists.newArrayList(); // DivineMC - Commented out - private boolean processing; - private final ServerLevel level; - private final int sectionY; -@@ -35,7 +35,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi - @Override - public void register(GameEventListener listener) { - if (this.processing) { -- this.listenersToAdd.add(listener); -+ throw new java.util.ConcurrentModificationException(); // DivineMC - Disallow concurrent modification - } else { - this.listeners.add(listener); - } -@@ -46,7 +46,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi - @Override - public void unregister(GameEventListener listener) { - if (this.processing) { -- this.listenersToRemove.add(listener); -+ throw new java.util.ConcurrentModificationException(); // DivineMC - Disallow concurrent modification - } else { - this.listeners.remove(listener); - } -@@ -66,7 +66,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi - - while (iterator.hasNext()) { - GameEventListener gameEventListener = iterator.next(); -- if (this.listenersToRemove.remove(gameEventListener)) { -+ if (false) { // DivineMC - Disallow concurrent modification - iterator.remove(); - } else { - Optional postableListenerPosition = getPostableListenerPosition(this.level, pos, gameEventListener); -@@ -80,6 +80,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi - this.processing = false; - } - -+ /* // DivineMC start - Petal: Reduce work done by game event system - if (!this.listenersToAdd.isEmpty()) { - this.listeners.addAll(this.listenersToAdd); - this.listenersToAdd.clear(); -@@ -89,6 +90,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi - this.listeners.removeAll(this.listenersToRemove); - this.listenersToRemove.clear(); - } -+ */ // DivineMC end - Petal: Reduce work done by game event system - - return flag; - } -diff --git a/net/minecraft/world/level/gameevent/GameEventDispatcher.java b/net/minecraft/world/level/gameevent/GameEventDispatcher.java -index 1e9b066ef468ae840eda3c1f6c4b68111a5e862c..cf31dadc73c66e4d4fcca9d81d587480d1c530c5 100644 ---- a/net/minecraft/world/level/gameevent/GameEventDispatcher.java -+++ b/net/minecraft/world/level/gameevent/GameEventDispatcher.java -@@ -44,6 +44,7 @@ public class GameEventDispatcher { - int sectionPosCoord5 = SectionPos.blockToSectionCoord(blockPos.getZ() + notificationRadius); - List list = new ArrayList<>(); - GameEventListenerRegistry.ListenerVisitor listenerVisitor = (listener, pos1) -> { -+ if (!listener.listensToEvent(gameEvent.value(), context)) return; // DivineMC - If they don't listen, ignore - if (listener.getDeliveryMode() == GameEventListener.DeliveryMode.BY_DISTANCE) { - list.add(new GameEvent.ListenerInfo(gameEvent, pos, context, listener, pos1)); - } else { -diff --git a/net/minecraft/world/level/gameevent/GameEventListener.java b/net/minecraft/world/level/gameevent/GameEventListener.java -index 5a31b5f1e75dd7b412ab577ea6621b7e87fc0590..32a79d5a247ddf953d18594897c5e9565353593a 100644 ---- a/net/minecraft/world/level/gameevent/GameEventListener.java -+++ b/net/minecraft/world/level/gameevent/GameEventListener.java -@@ -23,4 +23,10 @@ public interface GameEventListener { - public interface Provider { - T getListener(); - } -+ -+ // DivineMC start - Add check for seeing if this listener cares about an event -+ default boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { -+ return true; -+ } -+ // DivineMC end - Add check for seeing if this listener cares about an event - } diff --git a/divinemc-server/minecraft-patches/features/0006-Fix-MC-65198.patch b/divinemc-server/minecraft-patches/features/0006-Fix-MC-65198.patch deleted file mode 100644 index e6dd975..0000000 --- a/divinemc-server/minecraft-patches/features/0006-Fix-MC-65198.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 12 Jan 2025 21:03:27 +0300 -Subject: [PATCH] Fix MC-65198 - -Original post on Mojira: https://bugs.mojang.com/browse/MC-65198 - -diff --git a/net/minecraft/world/inventory/ItemCombinerMenu.java b/net/minecraft/world/inventory/ItemCombinerMenu.java -index c605bd700fd9f5a6596a2bf9648492786306b025..ae594513799defffa3d3c29ef753fa01337e0df2 100644 ---- a/net/minecraft/world/inventory/ItemCombinerMenu.java -+++ b/net/minecraft/world/inventory/ItemCombinerMenu.java -@@ -120,6 +120,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - if (slot != null && slot.hasItem()) { - ItemStack item = slot.getItem(); - itemStack = item.copy(); -+ ItemStack itemStack2 = itemStack.copy(); // DivineMC - Fix MC-65198 - int inventorySlotStart = this.getInventorySlotStart(); - int useRowEnd = this.getUseRowEnd(); - if (index == this.getResultSlot()) { -@@ -157,7 +158,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - } - - this.activeQuickItem = itemStack; // Purpur - Anvil API -- slot.onTake(player, item); -+ slot.onTake(player, itemStack2); // DivineMC - Fix MC-65198 - this.activeQuickItem = null; // Purpur - Anvil API - } - -diff --git a/net/minecraft/world/inventory/ResultSlot.java b/net/minecraft/world/inventory/ResultSlot.java -index 01b8d73b1be9b41d6f51d11a0bead37a7bd9023f..d3865b375293e29162f08aa447bd91f90ef27513 100644 ---- a/net/minecraft/world/inventory/ResultSlot.java -+++ b/net/minecraft/world/inventory/ResultSlot.java -@@ -49,7 +49,7 @@ public class ResultSlot extends Slot { - @Override - protected void checkTakeAchievements(ItemStack stack) { - if (this.removeCount > 0) { -- stack.onCraftedBy(this.player.level(), this.player, this.removeCount); -+ stack.onCraftedBy(this.player.level(), this.player, stack.getCount()); // DivineMC - Fix MC-65198 - } - - if (this.container instanceof RecipeCraftingHolder recipeCraftingHolder) { -diff --git a/net/minecraft/world/inventory/StonecutterMenu.java b/net/minecraft/world/inventory/StonecutterMenu.java -index d6854d0ebe5cb4205963e879d71eb3940d54de1f..39d00670c4fbfd6646af34cbd598117f07fc41ac 100644 ---- a/net/minecraft/world/inventory/StonecutterMenu.java -+++ b/net/minecraft/world/inventory/StonecutterMenu.java -@@ -238,6 +238,7 @@ public class StonecutterMenu extends AbstractContainerMenu { - ItemStack item = slot.getItem(); - Item item1 = item.getItem(); - itemStack = item.copy(); -+ ItemStack itemStack2 = itemStack.copy(); // DivineMC - Fix MC-65198 - if (index == 1) { - item1.onCraftedBy(item, player.level(), player); - if (!this.moveItemStackTo(item, 2, 38, true)) { -@@ -270,7 +271,7 @@ public class StonecutterMenu extends AbstractContainerMenu { - return ItemStack.EMPTY; - } - -- slot.onTake(player, item); -+ slot.onTake(player, itemStack2); // DivineMC - Fix MC-65198 - if (index == 1) { - player.drop(item, false); - } diff --git a/divinemc-server/minecraft-patches/features/0007-C2ME-Optimize-world-gen-math.patch b/divinemc-server/minecraft-patches/features/0007-C2ME-Optimize-world-gen-math.patch deleted file mode 100644 index ee7030c..0000000 --- a/divinemc-server/minecraft-patches/features/0007-C2ME-Optimize-world-gen-math.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 12 Jan 2025 21:07:52 +0300 -Subject: [PATCH] C2ME: Optimize world gen math - - -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/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java -index 131923282c9ecbcb1d7f45a826da907c02bd2716..e7c0de38ef689510860dc0b626f744617a694956 100644 ---- a/net/minecraft/world/level/levelgen/Beardifier.java -+++ b/net/minecraft/world/level/levelgen/Beardifier.java -@@ -132,8 +132,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 - Optimize method for beardifier -+ 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 - Optimize method for beardifier - } - - private static double getBeardContribution(int x, int y, int z, int height) { -diff --git a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -index 65728ef17e63d71833677fdcbd5bb90794b4822b..832a26760a777fe2d62f2f5f7a885bae63f67517 100644 ---- a/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -+++ b/net/minecraft/world/level/levelgen/NoiseBasedChunkGenerator.java -@@ -68,8 +68,10 @@ public final class NoiseBasedChunkGenerator extends ChunkGenerator { - Aquifer.FluidStatus fluidStatus = new Aquifer.FluidStatus(-54, Blocks.LAVA.defaultBlockState()); - int seaLevel = settings.seaLevel(); - Aquifer.FluidStatus fluidStatus1 = new Aquifer.FluidStatus(seaLevel, settings.defaultFluid()); -- Aquifer.FluidStatus fluidStatus2 = new Aquifer.FluidStatus(DimensionType.MIN_Y * 2, Blocks.AIR.defaultBlockState()); -- return (x, y, z) -> y < Math.min(-54, seaLevel) ? fluidStatus : fluidStatus1; -+ // DivineMC start - Optimize world gen -+ final int min = Math.min(-54, seaLevel); -+ return (j, k, l) -> k < min ? fluidStatus : fluidStatus1; -+ // DivineMC end - Optimize world gen - } - - @Override -diff --git a/net/minecraft/world/level/levelgen/synth/PerlinNoise.java b/net/minecraft/world/level/levelgen/synth/PerlinNoise.java -index da3c26fbad32d75d71f7e59c8c3341316a754756..6e1ebd6110da183a8f97abd81ced16cd89df725f 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() { diff --git a/divinemc-server/minecraft-patches/features/0008-Carpet-Fixes-RecipeManager-Optimize.patch b/divinemc-server/minecraft-patches/features/0008-Carpet-Fixes-RecipeManager-Optimize.patch deleted file mode 100644 index 78ff764..0000000 --- a/divinemc-server/minecraft-patches/features/0008-Carpet-Fixes-RecipeManager-Optimize.patch +++ /dev/null @@ -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 21:10:42 +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 imp - - public > Optional> getRecipeFor(RecipeType recipeType, I input, Level level) { - // CraftBukkit start -- List> list = this.recipes.getRecipesFor(recipeType, input, level).toList(); -+ List> 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 > Stream> getRecipesFor(RecipeType 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 > java.util.List> getRecipesForList(RecipeType type, I input, Level world) { -+ java.util.List> list; -+ -+ if (input.isEmpty()) { -+ return java.util.List.of(); -+ } else { -+ list = new java.util.ArrayList<>(); -+ } -+ -+ for (RecipeHolder recipeholder : this.byType(type)) { -+ if (recipeholder.value().matches(input, world)) { -+ list.add(recipeholder); -+ } -+ } -+ -+ return list; -+ } -+ // DivineMC end - Carpet-Fixes - Remove streams to be faster - } diff --git a/divinemc-server/minecraft-patches/features/0009-No-chat-sign.patch b/divinemc-server/minecraft-patches/features/0009-No-chat-sign.patch deleted file mode 100644 index 44947f4..0000000 --- a/divinemc-server/minecraft-patches/features/0009-No-chat-sign.patch +++ /dev/null @@ -1,149 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Mon, 13 Jan 2025 19:35:57 +0300 -Subject: [PATCH] No chat sign - - -diff --git a/net/minecraft/commands/arguments/ArgumentSignatures.java b/net/minecraft/commands/arguments/ArgumentSignatures.java -index 47cb25aa9c37bd84d156288c397321009f1d9ae2..7837b1cc37f70949dd0931fb93d2399763e4705e 100644 ---- a/net/minecraft/commands/arguments/ArgumentSignatures.java -+++ b/net/minecraft/commands/arguments/ArgumentSignatures.java -@@ -14,9 +14,16 @@ public record ArgumentSignatures(List entries) { - private static final int MAX_ARGUMENT_NAME_LENGTH = 16; - - public ArgumentSignatures(FriendlyByteBuf buffer) { -- this(buffer.readCollection(FriendlyByteBuf.>limitValue(ArrayList::new, 8), ArgumentSignatures.Entry::new)); -+ this(readSign(buffer)); // DivineMC - No chat sign - } - -+ // DivineMC start - No chat sign -+ private static List readSign(FriendlyByteBuf buf) { -+ var entries = buf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 8), Entry::new); -+ return org.bxteam.divinemc.configuration.DivineConfig.noChatSign ? List.of() : entries; -+ } -+ // DivineMC end - No chat sign -+ - public void write(FriendlyByteBuf buffer) { - buffer.writeCollection(this.entries, (buffer1, entry) -> entry.write(buffer1)); - } -diff --git a/net/minecraft/network/FriendlyByteBuf.java b/net/minecraft/network/FriendlyByteBuf.java -index e5e5d9bc095ccd9fbf1c8aaa09e5c4ebb1d1c920..d1676b16db0b0d1b0a92e0279da54ae199c63324 100644 ---- a/net/minecraft/network/FriendlyByteBuf.java -+++ b/net/minecraft/network/FriendlyByteBuf.java -@@ -114,6 +114,17 @@ public class FriendlyByteBuf extends ByteBuf { - public void writeJsonWithCodec(Codec codec, T value, int maxLength) { - // Paper end - Adventure; add max length parameter - DataResult dataResult = codec.encodeStart(JsonOps.INSTANCE, value); -+ -+ // DivineMC start - No chat sign -+ if (codec == net.minecraft.network.protocol.status.ServerStatus.CODEC) { -+ JsonElement element = dataResult.getOrThrow(string -> new EncoderException("Failed to encode: " + string + " " + value)); -+ element.getAsJsonObject().addProperty("preventsChatReports", org.bxteam.divinemc.configuration.DivineConfig.noChatSign); -+ -+ this.writeUtf(GSON.toJson(element)); -+ return; -+ } -+ // DivineMC end - No chat sign -+ - 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/ServerboundChatPacket.java b/net/minecraft/network/protocol/game/ServerboundChatPacket.java -index b5afc05924ae899e020c303c8b86398e1d4ab8a0..6b22c80fdb4be44fc0c879edc1a82eba8f7dcca7 100644 ---- a/net/minecraft/network/protocol/game/ServerboundChatPacket.java -+++ b/net/minecraft/network/protocol/game/ServerboundChatPacket.java -@@ -16,7 +16,7 @@ public record ServerboundChatPacket(String message, Instant timeStamp, long salt - ); - - private ServerboundChatPacket(FriendlyByteBuf buffer) { -- this(buffer.readUtf(256), buffer.readInstant(), buffer.readLong(), buffer.readNullable(MessageSignature::read), new LastSeenMessages.Update(buffer)); -+ this(buffer.readUtf(256), buffer.readInstant(), buffer.readLong(), buffer.readNullable(ServerboundChatPacket::readSign), new LastSeenMessages.Update(buffer)); // DivineMC - No chat sign - } - - private void write(FriendlyByteBuf buffer) { -@@ -27,6 +27,14 @@ public record ServerboundChatPacket(String message, Instant timeStamp, long salt - this.lastSeenMessages.write(buffer); - } - -+ // DivineMC start - No chat sign -+ private static MessageSignature readSign(FriendlyByteBuf buf) { -+ byte[] bs = new byte[256]; -+ buf.readBytes(bs); -+ return org.bxteam.divinemc.configuration.DivineConfig.noChatSign ? null : new MessageSignature(bs); -+ } -+ // DivineMC end - No chat sign -+ - @Override - public PacketType type() { - return GamePacketTypes.SERVERBOUND_CHAT; -diff --git a/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java b/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java -index 1df628ac0b414511aaed6e09d78f884c4170f730..fc10d813e72322d185378453bc25546e68a21711 100644 ---- a/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java -+++ b/net/minecraft/network/protocol/game/ServerboundChatSessionUpdatePacket.java -@@ -26,6 +26,11 @@ public record ServerboundChatSessionUpdatePacket(RemoteChatSession.Data chatSess - - @Override - public void handle(ServerGamePacketListener handler) { -+ // DivineMC start - No chat sign -+ if (org.bxteam.divinemc.configuration.DivineConfig.noChatSign) { -+ return; -+ } -+ // DivineMC end - No chat sign - handler.handleChatSessionUpdate(this); - } - } -diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java -index 0eecc41b02f205022a717691a18114d5c091bc3d..481d56d6c43e04c0b180c7008329d8e8316b0d0c 100644 ---- a/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -668,7 +668,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - // Paper start - Add setting for proxy online mode status - return properties.enforceSecureProfile - && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() -- && this.services.canValidateProfileKeys(); -+ && this.services.canValidateProfileKeys() && !org.bxteam.divinemc.configuration.DivineConfig.noChatSign; // DivineMC - No chat sign - // Paper end - Add setting for proxy online mode status - } - -diff --git a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 398c1733824b689520170de0be94006731afa5cd..4b5d729fd627fdf636ece5339fd0a1e7fe637d66 100644 ---- a/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -+++ b/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -@@ -312,10 +312,24 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack - } - - public void send(Packet packet) { -+ // DivineMC start - No chat sign -+ if (org.bxteam.divinemc.configuration.DivineConfig.noChatSign) { -+ if (this instanceof ServerGamePacketListenerImpl && 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); -+ } -+ } -+ // DivineMC end - No chat sign - this.send(packet, null); - } - - public void send(Packet packet, @Nullable PacketSendListener listener) { -+ // DivineMC start - No chat sign -+ if (org.bxteam.divinemc.configuration.DivineConfig.noChatSign) { -+ if (packet instanceof net.minecraft.network.protocol.game.ClientboundPlayerChatPacket chat && listener != null) { -+ listener = null; -+ } -+ } -+ // DivineMC end - No chat sign - // 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 e8ff6e79ce7ba0ec8b2a90bcb81283f52106c535..94fbf2231752f12c4497fc868cd5b2d9c8bffe66 100644 ---- a/net/minecraft/server/players/PlayerList.java -+++ b/net/minecraft/server/players/PlayerList.java -@@ -1319,7 +1319,7 @@ public abstract class PlayerList { - } - - public boolean verifyChatTrusted(PlayerChatMessage message) { // Paper - private -> public -- return message.hasSignature() && !message.hasExpiredServer(Instant.now()); -+ return org.bxteam.divinemc.configuration.DivineConfig.noChatSign || (message.hasSignature() && !message.hasExpiredServer(Instant.now())); // DivineMC - No chat sign - } - - // CraftBukkit start diff --git a/divinemc-server/minecraft-patches/features/0010-Petal-Async-Pathfinding.patch b/divinemc-server/minecraft-patches/features/0010-Petal-Async-Pathfinding.patch deleted file mode 100644 index 70dec92..0000000 --- a/divinemc-server/minecraft-patches/features/0010-Petal-Async-Pathfinding.patch +++ /dev/null @@ -1,810 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Wed, 15 Jan 2025 18:12:55 +0300 -Subject: [PATCH] Petal: Async Pathfinding - -Original code by Bloom-host, licensed under GPL v3 -You can find the original code on https://github.com/Bloom-host/Petal - -Makes most pathfinding-related work happen asynchronously - -diff --git a/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index 67cbf9f5760fae5db6f31e64095cd1b6be6ade8e..31107c97cf0e98f7f51f28c394f3d3f0778a80e0 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.configuration.DivineConfig.asyncPathfinding) { -+ // await on path async -+ Path possiblePath = findPathToPois(mob, set); -+ -+ // wait on the path to be processed -+ org.bxteam.divinemc.pathfinding.AsyncPathProcessor.awaitProcessing(possiblePath, path -> { -+ // read canReach check -+ if (path == null || !path.canReach()) { -+ for (Pair, 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, 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, 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..f650cda95e9a448149f7f40ba8b4e6ed43cbcead 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 { - 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 { - 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.configuration.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.configuration.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 { - - @Override - protected boolean canStillUse(ServerLevel level, Mob entity, long gameTime) { -+ if (org.bxteam.divinemc.configuration.DivineConfig.asyncPathfinding && !this.finishedProcessing) return true; // DivineMC - wait for processing - if (this.path != null && this.lastTargetPos != null) { - Optional memory = entity.getBrain().getMemory(MemoryModuleType.WALK_TARGET); - boolean flag = memory.map(MoveToTargetSink::isWalkTargetSpectator).orElse(false); -@@ -95,27 +99,98 @@ public class MoveToTargetSink extends Behavior { - - @Override - protected void start(ServerLevel level, Mob entity, long gameTime) { -+ // DivineMC start - start processing -+ if (org.bxteam.divinemc.configuration.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.configuration.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 = 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..0066ca68968f54ba9e27b13123bca908635cf923 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> 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.configuration.DivineConfig.asyncPathfinding) { -+ // await on path async -+ Path possiblePath = AcquirePoi.findPathToPois(mob, set); -+ -+ // wait on the path to be processed -+ org.bxteam.divinemc.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> 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> 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..182bdef3be7bb17339fdc80f5e321d78cd8a398a 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.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.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.configuration.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..991e203e47285c3b3f3788410b0cd950909a73e8 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.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.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.configuration.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..cfe00ac1d65523a811a66fa75a4348a9fe700ace 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.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.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.configuration.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..f6141289024f1d42648dafcffe1212e4651edcca 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.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.configuration.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.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..26cbc17f9727d8494b6b49904df24d7db44d1e6a 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.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.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.configuration.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..089f5e560440f384c347cd8b85da67bba61d3363 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 { - java.util.List, 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> type = poiManager.getType(target); -- if (type.isPresent()) { -- entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, target); -+ // DivineMC start - async pathfinding -+ if (org.bxteam.divinemc.configuration.DivineConfig.asyncPathfinding) { -+ Path possiblePath = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes)); -+ org.bxteam.divinemc.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> 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> 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 87d21e142c3f1522a60bc3e8a0ff3b4954cf5ec9..32a994ccd220927e2523e7b4a5b242248bafa5e2 100644 ---- a/net/minecraft/world/entity/animal/frog/Frog.java -+++ b/net/minecraft/world/entity/animal/frog/Frog.java -@@ -497,6 +497,17 @@ public class Frog extends Animal implements VariantHolder> { - super(mob, level); - } - -+ // DivineMC start - async path processing -+ private static final org.bxteam.divinemc.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.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); -@@ -505,6 +516,11 @@ public class Frog extends Animal implements VariantHolder> { - @Override - protected PathFinder createPathFinder(int maxVisitedNodes) { - this.nodeEvaluator = new Frog.FrogNodeEvaluator(true); -+ // DivineMC start - async path processing -+ if (org.bxteam.divinemc.configuration.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..9ed3076747556aaae2ada4b5cfa2591dec0881c6 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.pathfinding.NodeEvaluatorGenerator nodeEvaluatorGenerator = (org.bxteam.divinemc.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.configuration.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 f74c784906208034f51b31bd9aba45733c3ebebe..48e3e16ee711533e9f9c7007aa97ccf740135ff0 100644 ---- a/net/minecraft/world/entity/monster/warden/Warden.java -+++ b/net/minecraft/world/entity/monster/warden/Warden.java -@@ -619,6 +619,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.configuration.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..710009b887109f3d25ec310a4fe738536ece43b1 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.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.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 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.configuration.DivineConfig.asyncPathfinding) -+ this.openSet.clear(); // it's always cleared in processPath -+ NodeEvaluator nodeEvaluator = this.nodeEvaluatorGenerator == null -+ ? this.nodeEvaluator -+ : org.bxteam.divinemc.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.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); // DivineMC - handle nodeEvaluatorGenerator - return null; - } else { - // Paper start - Perf: remove streams and optimize collection - List> 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.pathfinding.NodeEvaluatorCache.removeNodeEvaluator(nodeEvaluator); -+ return this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier); -+ } -+ -+ return new org.bxteam.divinemc.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.pathfinding.NodeEvaluatorCache.returnNodeEvaluator(nodeEvaluator); -+ } -+ }); -+ // DivineMC end - async path processing - } - } - - @Nullable - private Path findPath(Node node, List> 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> 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]; diff --git a/divinemc-server/minecraft-patches/features/0011-Implement-Secure-Seed.patch b/divinemc-server/minecraft-patches/features/0011-Implement-Secure-Seed.patch deleted file mode 100644 index 7389159..0000000 --- a/divinemc-server/minecraft-patches/features/0011-Implement-Secure-Seed.patch +++ /dev/null @@ -1,433 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 20 Jul 2024 22:04:52 +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..610bf730709351183bc3ccabfd9dd8d73a60e363 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.configuration.DivineConfig.enableSecureSeed) { -+ org.bxteam.divinemc.seed.Globals.setupGlobals(context.getSource().getLevel()); -+ String seedStr = org.bxteam.divinemc.seed.Globals.seedToString(org.bxteam.divinemc.seed.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..6dca8112f74c924a9ec57ca5c80993e440b3a840 100644 ---- a/net/minecraft/server/dedicated/DedicatedServerProperties.java -+++ b/net/minecraft/server/dedicated/DedicatedServerProperties.java -@@ -114,7 +114,17 @@ public class DedicatedServerProperties extends Settings 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..ba81e47190aebe3f90642fe12d447464d150abf9 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() { -+ org.bxteam.divinemc.seed.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 3770dc90d9412c6378c0bd57a651b9c3e62b9a72..28f84d1200ba75d72ea94f831178b9d4e1fc61d2 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 -+ org.bxteam.divinemc.seed.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..c4d77ac76f057fd11f514ee3e2a562ca830c551a 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.configuration.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..80c8834a2f0e92268e8c8037be5246ebca1b168c 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 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 = org.bxteam.divinemc.seed.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..6f365c7ba147445026327df14e3109178e575d33 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 registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE); - Map> map = registry.stream().collect(Collectors.groupingBy(structure1 -> structure1.step().ordinal())); - List list = this.featuresPerStep.get(); -- WorldgenRandom worldgenRandom = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed())); -+ // DivineMC start - Implement Secure Seed -+ WorldgenRandom worldgenRandom = org.bxteam.divinemc.configuration.DivineConfig.enableSecureSeed -+ ? new org.bxteam.divinemc.seed.WorldgenCryptoRandom(blockPos.getX(), blockPos.getZ(), org.bxteam.divinemc.seed.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> set = new ObjectArraySet<>(); - ChunkPos.rangeClosed(sectionPos.chunk(), 1).forEach(chunkPos -> { -@@ -556,8 +560,18 @@ public abstract class ChunkGenerator { - } else { - ArrayList 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.configuration.DivineConfig.enableSecureSeed) { -+ worldgenRandom = new org.bxteam.divinemc.seed.WorldgenCryptoRandom( -+ pos.x, pos.z, org.bxteam.divinemc.seed.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..e9a1fd3ef36355d71254f5a86da7a4430c4b3150 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> list = new ArrayList<>(count); - int spread = placement.spread(); - HolderSet 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.configuration.DivineConfig.enableSecureSeed -+ ? new org.bxteam.divinemc.seed.WorldgenCryptoRandom(0, 0, org.bxteam.divinemc.seed.Globals.Salt.STRONGHOLDS, 0) -+ : RandomSource.create(); -+ -+ if (!org.bxteam.divinemc.configuration.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..9225701f05f583809541ced2c676b9da05ed1a3b 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 apply(WorldGenContext worldGenContext, StaticCache2D cache, ChunkAccess chunk) { -+ org.bxteam.divinemc.seed.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..1acd5946064cafdec498cdf7f876cc2c33f872b4 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.configuration.DivineConfig.enableSecureSeed; - public static final MapCodec 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(), org.bxteam.divinemc.seed.Globals.createRandomWorldSeed(), true, true) -+ : new WorldOptions("North Carolina".hashCode(), true, true); -+ // DivineMC end - Implement Secure Seed - private final long seed; -+ private long[] featureSeed = org.bxteam.divinemc.seed.Globals.createRandomWorldSeed(); // DivineMC - Implement Secure Seed - private final boolean generateStructures; - private final boolean generateBonusChest; - private final Optional 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(), org.bxteam.divinemc.seed.Globals.createRandomWorldSeed(), true, false) -+ : new WorldOptions(randomSeed(), true, false); -+ } -+ -+ private WorldOptions(long seed, java.util.stream.LongStream featureSeed, boolean generateStructures, boolean bonusChest, Optional 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 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()), org.bxteam.divinemc.seed.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..bd486c5d1899ffd1c7ec68cfe1498e9d89f80261 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 { - int i1 = geodeConfiguration.maxGenOffset; - List> 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.configuration.DivineConfig.enableSecureSeed -+ ? new org.bxteam.divinemc.seed.WorldgenCryptoRandom(0, 0, org.bxteam.divinemc.seed.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 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..43b89a497e3e204169ff5ebd4893b4ba1aab45f6 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.configuration.DivineConfig.enableSecureSeed) { -+ return new org.bxteam.divinemc.seed.WorldgenCryptoRandom( -+ chunkPos.x, chunkPos.z, org.bxteam.divinemc.seed.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..c1a4227698b40d75b4dba1f677eef00194327f98 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.configuration.DivineConfig.enableSecureSeed) { -+ worldgenRandom = new org.bxteam.divinemc.seed.WorldgenCryptoRandom( -+ i, i1, org.bxteam.divinemc.seed.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..b6d64950dc865eb0e315947902bac22162fd3a30 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.configuration.DivineConfig.enableSecureSeed) { -+ worldgenRandom = new org.bxteam.divinemc.seed.WorldgenCryptoRandom( -+ regionX, regionZ, org.bxteam.divinemc.seed.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..a0695a3fa1004c6fddfafe3b89f90cc3efc584e8 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.configuration.DivineConfig.enableSecureSeed -+ ? new org.bxteam.divinemc.seed.WorldgenCryptoRandom(context.chunkPos().x, context.chunkPos().z, org.bxteam.divinemc.seed.Globals.Salt.JIGSAW_PLACEMENT, 0) -+ : context.random(); -+ // DivineMC end - Implement Secure Seed - Registry registry = registryAccess.lookupOrThrow(Registries.TEMPLATE_POOL); - Rotation random = Rotation.getRandom(worldgenRandom); - StructureTemplatePool structureTemplatePool = startPool.unwrapKey() diff --git a/divinemc-server/minecraft-patches/features/0012-Multithreaded-Tracker.patch b/divinemc-server/minecraft-patches/features/0012-Multithreaded-Tracker.patch deleted file mode 100644 index b95bb8a..0000000 --- a/divinemc-server/minecraft-patches/features/0012-Multithreaded-Tracker.patch +++ /dev/null @@ -1,335 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Wed, 15 Jan 2025 19:48:24 +0300 -Subject: [PATCH] Multithreaded Tracker - - -diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 94da5ce57b27047443859503f6dcc01d0493021a..c29b476916c3c0a0d8ed97ac432e545f3ecfdaaf 100644 ---- a/net/minecraft/server/level/ChunkMap.java -+++ b/net/minecraft/server/level/ChunkMap.java -@@ -250,9 +250,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.configuration.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 -@@ -936,6 +946,21 @@ 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 trackerMainThreadTasks = new java.util.concurrent.ConcurrentLinkedQueue<>(); -+ private boolean tracking = false; -+ -+ public void runOnTrackerMainThread(final Runnable runnable) { -+ //final boolean isOnMain = ca.spottedleaf.moonrise.common.util.TickThread.isTickThread(); -+ //System.out.println(isOnMain); -+ 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();; -@@ -958,6 +983,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.configuration.DivineConfig.multithreadedEnabled) { -+ final ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel level = this.level; -+ org.bxteam.divinemc.tracker.MultithreadedTracker.tick(level); -+ return; -+ } -+ // DivineMC end - Multithreaded tracker - // Paper start - optimise entity tracker - if (true) { - this.newTrackerTick(); -@@ -1080,7 +1112,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - final Entity entity; - private final int range; - SectionPos lastSectionPos; -- public final Set seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl -+ // DivineMC start - Multithreaded tracker -+ public final Set seenBy = org.bxteam.divinemc.configuration.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; -@@ -1107,21 +1143,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.configuration.DivineConfig.multithreadedEnabled && org.bxteam.divinemc.configuration.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.tracker.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 -@@ -1183,9 +1253,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) { -@@ -1196,9 +1268,11 @@ 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) { -@@ -1209,8 +1283,9 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public void updatePlayer(ServerPlayer player) { -- org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot -+ //org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // DivineMC - Multithreaded tracker - we don't need this - if (player != this.entity) { -+ if (org.bxteam.divinemc.configuration.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..b9f3414da5337c3675d9564f132497d311c0ca9c 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 players = Sets.newHashSet(); -+ // DivineMC start - Multithreaded tracker - players can be removed in async tracking -+ private final Set players = org.bxteam.divinemc.configuration.DivineConfig.multithreadedEnabled -+ ? Sets.newConcurrentHashSet() -+ : Sets.newHashSet(); -+ // DivineMC end - Multithreaded tracker - private final Set 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 6d2c892207c2299c64f59630fb7740d6407e76a7..2d40583089b5b627cf5ed9570469398590931ccc 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.configuration.DivineConfig.multithreadedEnabled && Thread.currentThread() instanceof org.bxteam.divinemc.tracker.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,7 +413,11 @@ public class ServerEntity { - List> 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) { -@@ -413,12 +426,17 @@ public class ServerEntity { - final Set attributesToSync = this.level.divinemcConfig.suppressErrorsFromDirtyAttributes ? Collections.synchronizedSet(attributes) : attributes; - // DivineMC end - Suppress errors from dirty attributes - 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 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 - } - - attributes.clear(); -diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 893d3f96dc31f67e38991b4cd7ea112fc9bcd50a..783fe6551a6d3c532a3eef9f22bd4612bafd31d0 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 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 747b246422cebcfe118cf898dec0451b303466a7..9601b4bafcf066eabead4dffb15e519aee74ca55 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 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..61ea771f6a63d9f773451775736539d9c6da9623 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> modifiersByOperation = Maps.newEnumMap( - AttributeModifier.Operation.class - ); -- private final Map modifierById = new Object2ObjectArrayMap<>(); -- private final Map permanentModifiers = new Object2ObjectArrayMap<>(); -+ // DivineMC start - Multithreaded tracker -+ private final boolean multiThreadedTrackingEnabled = org.bxteam.divinemc.configuration.DivineConfig.multithreadedEnabled; -+ private final Map modifierById = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new Object2ObjectArrayMap<>(); -+ private final Map 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..16ff02f17904c64276cbd64e8891ac64b51c3bc6 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, AttributeInstance> attributes = new Object2ObjectOpenHashMap<>(); -- private final Set attributesToSync = new ObjectOpenHashSet<>(); -- private final Set attributesToUpdate = new ObjectOpenHashSet<>(); -+ // DivineMC start - Multithreaded tracker -+ private final boolean multiThreadedTrackingEnabled = org.bxteam.divinemc.configuration.DivineConfig.multithreadedEnabled; -+ private final Map, AttributeInstance> attributes = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0); -+ private final Set attributesToSync = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0); -+ private final Set attributesToUpdate = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0); -+ // DivineMC end - Multithreaded tracker - private final AttributeSupplier supplier; - private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables - diff --git a/divinemc-server/minecraft-patches/features/0013-Implement-Linear-region-format.patch b/divinemc-server/minecraft-patches/features/0013-Implement-Linear-region-format.patch deleted file mode 100644 index 94ec4a8..0000000 --- a/divinemc-server/minecraft-patches/features/0013-Implement-Linear-region-format.patch +++ /dev/null @@ -1,374 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 18 Jan 2025 01:00:23 +0300 -Subject: [PATCH] Implement Linear region format - -Linear is a region file format that uses ZSTD compression instead of ZLIB. This format saves about 50% of disk space. -Documentation: https://github.com/xymb-endcrystalme/LinearRegionFileFormatTools - -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java -index a814512fcfb85312474ae2c2c21443843bf57831..f2a1b0f703c08bcea85a8e946ff4ebbb0ee59e01 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/ChunkSystemRegionFileStorage.java -@@ -8,9 +8,9 @@ public interface ChunkSystemRegionFileStorage { - - public boolean moonrise$doesRegionFileNotExistNoIO(final int chunkX, final int chunkZ); - -- public RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); -+ public org.bxteam.divinemc.region.AbstractRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ); // DivineMC - linear region format - -- public RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; -+ public org.bxteam.divinemc.region.AbstractRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException; // DivineMC - linear region format - - public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite( - final int chunkX, final int chunkZ, final CompoundTag compound -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java -index 98fbc5c8044bd945d64569f13412a6e7e49a4e7f..60a08ca6aac19b3f205ae7543afc342b17425ec1 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/io/MoonriseRegionFileIO.java -@@ -1260,7 +1260,7 @@ public final class MoonriseRegionFileIO { - this.regionDataController.finishWrite(this.chunkX, this.chunkZ, writeData); - // Paper start - flush regionfiles on save - if (this.world.paperConfig().chunks.flushRegionsOnSave) { -- final RegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); -+ final org.bxteam.divinemc.region.AbstractRegionFile regionFile = this.regionDataController.getCache().moonrise$getRegionFileIfLoaded(this.chunkX, this.chunkZ); // DivineMC - linear region format - if (regionFile != null) { - regionFile.flush(); - } // else: evicted from cache, which should have called flush -@@ -1470,7 +1470,7 @@ public final class MoonriseRegionFileIO { - - public static interface IORunnable { - -- public void run(final RegionFile regionFile) throws IOException; -+ public void run(final org.bxteam.divinemc.region.AbstractRegionFile regionFile) throws IOException; // DivineMC - linear region format - - } - } -diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java -index 51c126735ace8fdde89ad97b5cab62f244212db0..cea71a1de9ac2d391e67407e7f479e877f00ccc9 100644 ---- a/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java -+++ b/ca/spottedleaf/moonrise/patches/chunk_system/storage/ChunkSystemChunkBuffer.java -@@ -8,5 +8,5 @@ public interface ChunkSystemChunkBuffer { - - public void moonrise$setWriteOnClose(final boolean value); - -- public void moonrise$write(final RegionFile regionFile) throws IOException; -+ public void moonrise$write(final org.bxteam.divinemc.region.AbstractRegionFile regionFile) throws IOException; // DivineMC - linear region format - } -diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 989be9b9ea224efecb1bb5998fdf6ceeed2850ae..836224638eca453cd7c83f393c08f3fc86c3da2b 100644 ---- a/net/minecraft/server/MinecraftServer.java -+++ b/net/minecraft/server/MinecraftServer.java -@@ -951,10 +951,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> progressMap = Reference2FloatMaps.synchronize(new Reference2FloatOpenHashMap<>()); - volatile Component status = Component.translatable("optimizeWorld.stage.counting"); -- static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$"); -+ static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.(linear | mca)$"); // DivineMC - linear region format - final DimensionDataStorage overworldDataStorage; - - public WorldUpgrader( -@@ -261,7 +261,7 @@ public class WorldUpgrader implements AutoCloseable { - } - - private static List getAllChunkPositions(RegionStorageInfo regionStorageInfo, Path path) { -- File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(".mca")); -+ File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(".linear") || filename.endsWith(".mca")); // DivineMC - linear region format - if (files == null) { - return List.of(); - } else { -@@ -274,7 +274,7 @@ public class WorldUpgrader implements AutoCloseable { - int i1 = Integer.parseInt(matcher.group(2)) << 5; - List list1 = Lists.newArrayList(); - -- try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) { -+ try (org.bxteam.divinemc.region.AbstractRegionFile regionFile = org.bxteam.divinemc.region.AbstractRegionFileFactory.getAbstractRegionFile(regionStorageInfo, file.toPath(), path, true)) { // DivineMC - linear region format - for (int i2 = 0; i2 < 32; i2++) { - for (int i3 = 0; i3 < 32; i3++) { - ChunkPos chunkPos = new ChunkPos(i2 + i, i3 + i1); -@@ -322,7 +322,7 @@ public class WorldUpgrader implements AutoCloseable { - - protected abstract boolean tryProcessOnePosition(T chunkStorage, ChunkPos chunkPos, ResourceKey dimension); - -- private void onFileFinished(RegionFile regionFile) { -+ private void onFileFinished(org.bxteam.divinemc.region.AbstractRegionFile regionFile) { // DivineMC - linear region format - if (WorldUpgrader.this.recreateRegionFiles) { - if (this.previousWriteFuture != null) { - this.previousWriteFuture.join(); -@@ -424,7 +424,7 @@ public class WorldUpgrader implements AutoCloseable { - } - } - -- record FileToUpgrade(RegionFile file, List chunksToUpgrade) { -+ record FileToUpgrade(org.bxteam.divinemc.region.AbstractRegionFile file, List chunksToUpgrade) { // DivineMC - linear region format - } - - class PoiUpgrader extends WorldUpgrader.SimpleRegionStorageUpgrader { -diff --git a/net/minecraft/world/level/chunk/storage/RegionFile.java b/net/minecraft/world/level/chunk/storage/RegionFile.java -index c72494e757a9dc50e053dbc873f7b30e83d5cb8c..7bfe510a8cd94b130abb674a606c1ae578e3b0e8 100644 ---- a/net/minecraft/world/level/chunk/storage/RegionFile.java -+++ b/net/minecraft/world/level/chunk/storage/RegionFile.java -@@ -22,7 +22,7 @@ import net.minecraft.util.profiling.jfr.JvmProfiler; - import net.minecraft.world.level.ChunkPos; - import org.slf4j.Logger; - --public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile { // Paper - rewrite chunk system -+public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile, org.bxteam.divinemc.region.AbstractRegionFile { // Paper - rewrite chunk system // DivineMC - linear region format - private static final Logger LOGGER = LogUtils.getLogger(); - public static final int MAX_CHUNK_SIZE = 500 * 1024 * 1024; // Paper - don't write garbage data to disk if writing serialization fails - private static final int SECTOR_BYTES = 4096; -@@ -904,7 +904,7 @@ public class RegionFile implements AutoCloseable, ca.spottedleaf.moonrise.patche - } - - @Override -- public final void moonrise$write(final RegionFile regionFile) throws IOException { -+ public final void moonrise$write(final org.bxteam.divinemc.region.AbstractRegionFile regionFile) throws IOException { // DivineMC - linear region format - regionFile.write(this.pos, ByteBuffer.wrap(this.buf, 0, this.count)); - } - // Paper end - rewrite chunk system -diff --git a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -index 6ebd1300c2561116b83cb2472ac7939ead36d576..ca288e45e039ce06ddfda358f32fa843508e614a 100644 ---- a/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -+++ b/net/minecraft/world/level/chunk/storage/RegionFileStorage.java -@@ -18,7 +18,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - private static final org.slf4j.Logger LOGGER = com.mojang.logging.LogUtils.getLogger(); // Paper - public static final String ANVIL_EXTENSION = ".mca"; - private static final int MAX_CACHE_SIZE = 256; -- public final Long2ObjectLinkedOpenHashMap regionCache = new Long2ObjectLinkedOpenHashMap<>(); -+ public final Long2ObjectLinkedOpenHashMap regionCache = new Long2ObjectLinkedOpenHashMap<>(); // DivineMC - linear region format - private final RegionStorageInfo info; - private final Path folder; - private final boolean sync; -@@ -33,7 +33,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - @Nullable - public static ChunkPos getRegionFileCoordinates(Path file) { - String fileName = file.getFileName().toString(); -- if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) { -+ if (!fileName.startsWith("r.") || !fileName.endsWith(".mca") || !fileName.endsWith(".linear")) { // DivineMC - linear region format - return null; - } - -@@ -57,9 +57,14 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - private static final int REGION_SHIFT = 5; - private static final int MAX_NON_EXISTING_CACHE = 1024 * 4; - private final it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet nonExistingRegionFiles = new it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet(); -- private static String getRegionFileName(final int chunkX, final int chunkZ) { -+ // DivineMC start - Linear region format -+ private static String getRegionFileName(final RegionStorageInfo info, final int chunkX, final int chunkZ) { -+ if (info.regionFormat().equals(org.bxteam.divinemc.region.RegionFileFormat.LINEAR)) { -+ return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".linear"; -+ } - return "r." + (chunkX >> REGION_SHIFT) + "." + (chunkZ >> REGION_SHIFT) + ".mca"; - } -+ // DivineMC end - Linear region format - - private boolean doesRegionFilePossiblyExist(final long position) { - synchronized (this.nonExistingRegionFiles) { -@@ -93,15 +98,15 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - } - - @Override -- public synchronized final RegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { -+ public synchronized final org.bxteam.divinemc.region.AbstractRegionFile moonrise$getRegionFileIfLoaded(final int chunkX, final int chunkZ) { // DivineMC - linear region format - return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT)); - } - - @Override -- public synchronized final RegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { -+ public synchronized final org.bxteam.divinemc.region.AbstractRegionFile moonrise$getRegionFileIfExists(final int chunkX, final int chunkZ) throws IOException { // DivineMC - linear region format - final long key = ChunkPos.asLong(chunkX >> REGION_SHIFT, chunkZ >> REGION_SHIFT); - -- RegionFile ret = this.regionCache.getAndMoveToFirst(key); -+ org.bxteam.divinemc.region.AbstractRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - linear region format - if (ret != null) { - return ret; - } -@@ -114,7 +119,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - this.regionCache.removeLast().close(); - } - -- final Path regionPath = this.folder.resolve(getRegionFileName(chunkX, chunkZ)); -+ final Path regionPath = this.folder.resolve(getRegionFileName(this.info, chunkX, chunkZ)); // DivineMC - linear region format - - if (!java.nio.file.Files.exists(regionPath)) { - this.markNonExisting(key); -@@ -125,7 +130,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - - FileUtil.createDirectoriesSafe(this.folder); - -- ret = new RegionFile(this.info, regionPath, this.folder, this.sync); -+ ret = org.bxteam.divinemc.region.AbstractRegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - linear region format - - this.regionCache.putAndMoveToFirst(key, ret); - -@@ -144,11 +149,11 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - } - - final ChunkPos pos = new ChunkPos(chunkX, chunkZ); -- final RegionFile regionFile = this.getRegionFile(pos); -+ final org.bxteam.divinemc.region.AbstractRegionFile regionFile = this.getRegionFile(pos); // DivineMC - linear region format - - // note: not required to keep regionfile loaded after this call, as the write param takes a regionfile as input - // (and, the regionfile parameter is unused for writing until the write call) -- final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = ((ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile)regionFile).moonrise$startWrite(compound, pos); -+ final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData writeData = regionFile.moonrise$startWrite(compound, pos); // DivineMC - linear region format - - try { // Paper - implement RegionFileSizeException - try { -@@ -178,7 +183,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - ) throws IOException { - final ChunkPos pos = new ChunkPos(chunkX, chunkZ); - if (writeData.result() == ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.DELETE) { -- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); -+ final org.bxteam.divinemc.region.AbstractRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - linear region format - if (regionFile != null) { - regionFile.clear(pos); - } // else: didn't exist -@@ -193,7 +198,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - public final ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.ReadData moonrise$readData( - final int chunkX, final int chunkZ - ) throws IOException { -- final RegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); -+ final org.bxteam.divinemc.region.AbstractRegionFile regionFile = this.moonrise$getRegionFileIfExists(chunkX, chunkZ); // DivineMC - linear region format - - final DataInputStream input = regionFile == null ? null : regionFile.getChunkDataInputStream(new ChunkPos(chunkX, chunkZ)); - -@@ -237,7 +242,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - } - // Paper end - rewrite chunk system - // Paper start - rewrite chunk system -- public RegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { -+ public org.bxteam.divinemc.region.AbstractRegionFile getRegionFile(ChunkPos chunkcoordintpair) throws IOException { // DivineMC - linear region format - return this.getRegionFile(chunkcoordintpair, false); - } - // Paper end - rewrite chunk system -@@ -249,7 +254,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - this.isChunkData = isChunkDataFolder(this.folder); // Paper - recalculate region file headers - } - -- @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private RegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit -+ @org.jetbrains.annotations.Contract("_, false -> !null") @Nullable private org.bxteam.divinemc.region.AbstractRegionFile getRegionFile(ChunkPos chunkPos, boolean existingOnly) throws IOException { // CraftBukkit // DivineMC - linear region format - // Paper start - rewrite chunk system - if (existingOnly) { - return this.moonrise$getRegionFileIfExists(chunkPos.x, chunkPos.z); -@@ -257,7 +262,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - synchronized (this) { - final long key = ChunkPos.asLong(chunkPos.x >> REGION_SHIFT, chunkPos.z >> REGION_SHIFT); - -- RegionFile ret = this.regionCache.getAndMoveToFirst(key); -+ org.bxteam.divinemc.region.AbstractRegionFile ret = this.regionCache.getAndMoveToFirst(key); // DivineMC - linear region format - if (ret != null) { - return ret; - } -@@ -266,13 +271,13 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - this.regionCache.removeLast().close(); - } - -- final Path regionPath = this.folder.resolve(getRegionFileName(chunkPos.x, chunkPos.z)); -+ final Path regionPath = this.folder.resolve(getRegionFileName(this.info, chunkPos.x, chunkPos.z)); // DivineMC - linear region format - - this.createRegionFile(key); - - FileUtil.createDirectoriesSafe(this.folder); - -- ret = new RegionFile(this.info, regionPath, this.folder, this.sync); -+ ret = org.bxteam.divinemc.region.AbstractRegionFileFactory.getAbstractRegionFile(this.info, regionPath, this.folder, this.sync); // DivineMC - linear region format - - this.regionCache.putAndMoveToFirst(key, ret); - -@@ -286,7 +291,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO DIVINEMC - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); // DivineMC - Rebrand - } - -- private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { -+ private static CompoundTag readOversizedChunk(org.bxteam.divinemc.region.AbstractRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { - synchronized (regionfile) { - try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { - CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); -@@ -321,7 +326,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - @Nullable - public CompoundTag read(ChunkPos chunkPos) throws IOException { - // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing -- RegionFile regionFile = this.getRegionFile(chunkPos, true); -+ org.bxteam.divinemc.region.AbstractRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - linear region format - if (regionFile == null) { - return null; - } -@@ -360,7 +365,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - - public void scanChunk(ChunkPos chunkPos, StreamTagVisitor visitor) throws IOException { - // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing -- RegionFile regionFile = this.getRegionFile(chunkPos, true); -+ org.bxteam.divinemc.region.AbstractRegionFile regionFile = this.getRegionFile(chunkPos, true); // DivineMC - linear region format - if (regionFile == null) { - return; - } -@@ -374,7 +379,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - } - - public void write(ChunkPos chunkPos, @Nullable CompoundTag chunkData) throws IOException { // Paper - rewrite chunk system - public -- RegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system -+ org.bxteam.divinemc.region.AbstractRegionFile regionFile = this.getRegionFile(chunkPos, chunkData == null); // CraftBukkit // Paper - rewrite chunk system // DivineMC - linear region format - // Paper start - rewrite chunk system - if (regionFile == null) { - // if the RegionFile doesn't exist, no point in deleting from it -@@ -404,7 +409,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - // Paper start - rewrite chunk system - synchronized (this) { - final ExceptionCollector exceptionCollector = new ExceptionCollector<>(); -- for (final RegionFile regionFile : this.regionCache.values()) { -+ for (final org.bxteam.divinemc.region.AbstractRegionFile regionFile : this.regionCache.values()) { // DivineMC - linear region format - try { - regionFile.close(); - } catch (final IOException ex) { -@@ -420,7 +425,7 @@ public class RegionFileStorage implements AutoCloseable, ca.spottedleaf.moonrise - // Paper start - rewrite chunk system - synchronized (this) { - final ExceptionCollector exceptionCollector = new ExceptionCollector<>(); -- for (final RegionFile regionFile : this.regionCache.values()) { -+ for (final org.bxteam.divinemc.region.AbstractRegionFile regionFile : this.regionCache.values()) { // DivineMC - linear region format - try { - regionFile.flush(); - } catch (final IOException ex) { -diff --git a/net/minecraft/world/level/chunk/storage/RegionStorageInfo.java b/net/minecraft/world/level/chunk/storage/RegionStorageInfo.java -index 6111631c6673948b266286894603cc5e30451b02..e843c568d99cb1a65cb584f12c1f86542c4c6eaf 100644 ---- a/net/minecraft/world/level/chunk/storage/RegionStorageInfo.java -+++ b/net/minecraft/world/level/chunk/storage/RegionStorageInfo.java -@@ -7,4 +7,20 @@ public record RegionStorageInfo(String level, ResourceKey dimension, Stri - public RegionStorageInfo withTypeSuffix(String suffix) { - return new RegionStorageInfo(this.level, this.dimension, this.type + suffix); - } -+ -+ // DivineMC start - Linear Region format -+ public org.bxteam.divinemc.region.RegionFileFormat regionFormat() { -+ return ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(level)) -+ .getHandle() -+ .divinemcConfig -+ .regionFormatName; -+ } -+ -+ public int linearCompressionLevel() { -+ return ((org.bukkit.craftbukkit.CraftWorld) org.bukkit.Bukkit.getWorld(level)) -+ .getHandle() -+ .divinemcConfig -+ .linearCompressionLevel; -+ } -+ // DivineMC end - Linear Region format - } diff --git a/divinemc-server/minecraft-patches/features/0014-Snowball-and-Egg-knockback.patch b/divinemc-server/minecraft-patches/features/0014-Snowball-and-Egg-knockback.patch deleted file mode 100644 index eba2da4..0000000 --- a/divinemc-server/minecraft-patches/features/0014-Snowball-and-Egg-knockback.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 18 Jan 2025 15:44:29 +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..9e9afd77ba50c2ab06e97f1c80b1290fb8f91715 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().divinemcConfig.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..7165bad72f761a0a3b2168d6df5f154b4a82d74e 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().divinemcConfig.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 diff --git a/divinemc-server/minecraft-patches/features/0015-Lag-Compensation.patch b/divinemc-server/minecraft-patches/features/0015-Lag-Compensation.patch deleted file mode 100644 index 19fcbce..0000000 --- a/divinemc-server/minecraft-patches/features/0015-Lag-Compensation.patch +++ /dev/null @@ -1,56 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 19 Jan 2025 02:48:59 +0300 -Subject: [PATCH] Lag Compensation - - -diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 836224638eca453cd7c83f393c08f3fc86c3da2b..ded121ea23494874f75f2720a967b94a79dcc136 100644 ---- a/net/minecraft/server/MinecraftServer.java -+++ b/net/minecraft/server/MinecraftServer.java -@@ -1571,6 +1571,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Sun, 19 Jan 2025 18:01:27 +0300 -Subject: [PATCH] Async data saving - - -diff --git a/net/minecraft/world/level/storage/LevelStorageSource.java b/net/minecraft/world/level/storage/LevelStorageSource.java -index de43e54698125ce9f319d4889dd49f7029fe95e0..cdc5ad5ba3a3c4d48609fe80bbe657da90da29fd 100644 ---- a/net/minecraft/world/level/storage/LevelStorageSource.java -+++ b/net/minecraft/world/level/storage/LevelStorageSource.java -@@ -514,7 +514,10 @@ public class LevelStorageSource { - CompoundTag compoundTag = serverConfiguration.createTag(registries, hostPlayerNBT); - CompoundTag compoundTag1 = new CompoundTag(); - compoundTag1.put("Data", compoundTag); -- this.saveLevelData(compoundTag1); -+ // DivineMC start - Async data saving -+ Runnable runnable = () -> this.saveLevelData(compoundTag1); -+ org.bxteam.divinemc.util.AsyncDataSaving.saveAsync(runnable); -+ // DivineMC end - Async data saving - } - - private void saveLevelData(CompoundTag tag) { -@@ -601,7 +604,10 @@ public class LevelStorageSource { - this.checkLock(); - CompoundTag levelDataTagRaw = LevelStorageSource.readLevelDataTagRaw(this.levelDirectory.dataFile()); - modifier.accept(levelDataTagRaw.getCompound("Data")); -- this.saveLevelData(levelDataTagRaw); -+ // DivineMC start - Async data saving -+ Runnable runnable = () -> this.saveLevelData(levelDataTagRaw); -+ org.bxteam.divinemc.util.AsyncDataSaving.saveAsync(runnable); -+ // DivineMC end - Async data saving - } - - public long makeWorldBackup() throws IOException { -diff --git a/net/minecraft/world/level/storage/PlayerDataStorage.java b/net/minecraft/world/level/storage/PlayerDataStorage.java -index c44110b123ba5912af18faf0065e9ded780da9b7..c8dd87faf9a2bdc9fe7c0b9f2076dbed4a339021 100644 ---- a/net/minecraft/world/level/storage/PlayerDataStorage.java -+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java -@@ -32,7 +32,14 @@ public class PlayerDataStorage { - this.playerDir.mkdirs(); - } - -+ // DivineMC start - Async playerdata save - public void save(Player player) { -+ Runnable runnable = () -> saveInternal(player); -+ org.bxteam.divinemc.util.AsyncDataSaving.saveAsync(runnable); -+ } -+ -+ private void saveInternal(Player player) { -+ // DivineMC end - Async playerdata save - if (org.spigotmc.SpigotConfig.disablePlayerDataSaving) return; // Spigot - try { - CompoundTag compoundTag = player.saveWithoutId(new CompoundTag()); diff --git a/divinemc-server/minecraft-patches/features/0017-MSPT-Tracking-for-each-world.patch b/divinemc-server/minecraft-patches/features/0017-MSPT-Tracking-for-each-world.patch deleted file mode 100644 index 723d300..0000000 --- a/divinemc-server/minecraft-patches/features/0017-MSPT-Tracking-for-each-world.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 26 Jan 2025 16:18:37 +0300 -Subject: [PATCH] MSPT Tracking for each world - - -diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index e7491104c5510dcd2d9732ac3809d80b53c3a9e8..0c4deecde0fb1f35dc39cf66449eda9f60f9421a 100644 ---- a/net/minecraft/server/MinecraftServer.java -+++ b/net/minecraft/server/MinecraftServer.java -@@ -1771,7 +1771,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { - ++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(); - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch deleted file mode 100644 index 793efa8..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/core/BlockPos.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/net/minecraft/core/BlockPos.java -+++ b/net/minecraft/core/BlockPos.java -@@ -347,7 +_,18 @@ - }; - } - -+ // DivineMC start - lithium: cached iterate outwards -+ private static final org.bxteam.divinemc.util.lithium.IterateOutwardsCache ITERATE_OUTWARDS_CACHE = new org.bxteam.divinemc.util.lithium.IterateOutwardsCache(50); -+ private static final it.unimi.dsi.fastutil.longs.LongList HOGLIN_PIGLIN_CACHE = ITERATE_OUTWARDS_CACHE.getOrCompute(8, 4, 8); -+ // DivineMC end - lithium: cached iterate outwards -+ - public static Iterable withinManhattan(BlockPos pos, int xSize, int ySize, int zSize) { -+ // DivineMC start - lithium: cached iterate outwards -+ if (pos != org.bxteam.divinemc.util.lithium.IterateOutwardsCache.POS_ZERO) { -+ final it.unimi.dsi.fastutil.longs.LongList positions = xSize == 8 && ySize == 4 && zSize == 8 ? HOGLIN_PIGLIN_CACHE : ITERATE_OUTWARDS_CACHE.getOrCompute(xSize, ySize, zSize); -+ return new org.bxteam.divinemc.util.lithium.LongList2BlockPosMutableIterable(pos, positions); -+ } -+ // DivineMC end - lithium: cached iterate outwards - int i = xSize + ySize + zSize; - int x1 = pos.getX(); - int y1 = pos.getY(); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch deleted file mode 100644 index 792fe29..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/MinecraftServer.java.patch +++ /dev/null @@ -1,40 +0,0 @@ ---- a/net/minecraft/server/MinecraftServer.java -+++ b/net/minecraft/server/MinecraftServer.java -@@ -306,6 +_,7 @@ - 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 final Set entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run - - public static S spin(Function threadFunction) { - ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system -@@ -1705,17 +_,18 @@ - 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"); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch deleted file mode 100644 index f049cdd..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/dedicated/DedicatedServer.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/net/minecraft/server/dedicated/DedicatedServer.java -@@ -326,7 +_,7 @@ - String proxyFlavor = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "Velocity" : "BungeeCord"; - String proxyLink = (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.velocity.enabled) ? "https://docs.papermc.io/velocity/security" : "http://www.spigotmc.org/wiki/firewall-guide/"; - // Paper end - Add Velocity IP Forwarding Support -- if (!this.usesAuthentication()) { -+ if (!io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode()) { // DivineMC - if server uses proxy (velocity or bungee), disable offline warning - LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); - LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); - // Spigot start diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch deleted file mode 100644 index 84d9934..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ChunkMap.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/server/level/ChunkMap.java -+++ b/net/minecraft/server/level/ChunkMap.java -@@ -129,7 +_,7 @@ - public final AtomicInteger tickingGenerated = new AtomicInteger(); // Paper - public - private final String storageName; - private final PlayerMap playerMap = new PlayerMap(); -- public final Int2ObjectMap entityMap = new Int2ObjectOpenHashMap<>(); -+ public final Int2ObjectMap entityMap = new it.unimi.dsi.fastutil.ints.Int2ObjectLinkedOpenHashMap<>(); // DivineMC - vmp: use linked map for entity trackers for faster iteration - private final Long2ByteMap chunkTypeCache = new Long2ByteOpenHashMap(); - // Paper - rewrite chunk system - public int serverViewDistance; -@@ -1232,7 +_,7 @@ - flag = flag && this.entity.broadcastToPlayer(player) && ChunkMap.this.isChunkTracked(player, this.entity.chunkPosition().x, this.entity.chunkPosition().z); - // Paper end - Configurable entity tracking range by Y - // CraftBukkit start - respect vanish API -- 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 diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerEntity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerEntity.java.patch deleted file mode 100644 index 4404eed..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerEntity.java.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/net/minecraft/server/level/ServerEntity.java -+++ b/net/minecraft/server/level/ServerEntity.java -@@ -408,7 +_,10 @@ - } - - if (this.entity instanceof LivingEntity) { -- Set attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync(); -+ // DivineMC start - Suppress errors from dirty attributes -+ Set attributes = ((LivingEntity) this.entity).getAttributes().getAttributesToSync(); -+ final Set attributesToSync = this.level.divinemcConfig.suppressErrorsFromDirtyAttributes ? Collections.synchronizedSet(attributes) : attributes; -+ // DivineMC end - Suppress errors from dirty attributes - if (!attributesToSync.isEmpty()) { - // CraftBukkit start - Send scaled max health - if (this.entity instanceof ServerPlayer serverPlayer) { -@@ -418,7 +_,7 @@ - this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), attributesToSync)); - } - -- attributesToSync.clear(); -+ attributes.clear(); - } - } - diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch deleted file mode 100644 index f759c2f..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/level/ServerPlayer.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- 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 { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch deleted file mode 100644 index 3eefd4b..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerGamePacketListenerImpl.java.patch +++ /dev/null @@ -1,44 +0,0 @@ ---- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -572,7 +_,7 @@ - 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.configuration.DivineConfig.disableMovedWronglyThreshold && d7 - d6 > Math.max(100.0, Math.pow((double) (org.spigotmc.SpigotConfig.movedTooQuicklyMultiplier * (float) i * speed), 2)) && !this.isSingleplayerOwner()) { // DivineMC - Option to disable moved wrongly threshold - // CraftBukkit end - LOGGER.warn( - "{} (vehicle of {}) moved too quickly! {},{},{}", rootVehicle.getName().getString(), this.player.getName().getString(), d3, d4, d5 -@@ -602,7 +_,7 @@ - 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.configuration.DivineConfig.disableMovedWronglyThreshold && d7 > org.spigotmc.SpigotConfig.movedWronglyThreshold) { // Spigot // DivineMC - Option to disable moved wrongly threshold - 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)); - } -@@ -2404,6 +_,7 @@ - } - - 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 -@@ -2431,6 +_,15 @@ - return optional; - } - } -+ -+ // 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++) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch deleted file mode 100644 index 6a59e79..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/network/ServerLoginPacketListenerImpl.java.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -172,7 +_,8 @@ - public void handleHello(ServerboundHelloPacket packet) { - Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet"); - // Paper start - Validate usernames -- if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() -+ if (!org.bxteam.divinemc.configuration.DivineConfig.removeVanillaUsernameCheck // DivineMC - Remove vanilla username check -+ && io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() - && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation - && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation) { - Validate.validState(StringUtil.isReasonablePlayerName(packet.name()), "Invalid characters in username"); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/StoredUserList.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/StoredUserList.java.patch deleted file mode 100644 index a19a24d..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/players/StoredUserList.java.patch +++ /dev/null @@ -1,29 +0,0 @@ ---- a/net/minecraft/server/players/StoredUserList.java -+++ b/net/minecraft/server/players/StoredUserList.java -@@ -97,13 +_,20 @@ - } - - public void save() throws IOException { -- this.removeExpired(); // Paper - remove expired values before saving -- JsonArray jsonArray = new JsonArray(); -- this.map.values().stream().map(storedEntry -> Util.make(new JsonObject(), storedEntry::serialize)).forEach(jsonArray::add); -+ // DivineMC start - Save json list async -+ Runnable saveTask = () -> { -+ this.removeExpired(); // Paper - remove expired values before saving -+ JsonArray jsonArray = new JsonArray(); -+ this.map.values().stream().map(storedEntry -> Util.make(new JsonObject(), storedEntry::serialize)).forEach(jsonArray::add); - -- try (BufferedWriter writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) { -- GSON.toJson(jsonArray, GSON.newJsonWriter(writer)); -- } -+ try (BufferedWriter writer = Files.newWriter(this.file, StandardCharsets.UTF_8)) { -+ GSON.toJson(jsonArray, GSON.newJsonWriter(writer)); -+ } catch (java.io.IOException e) { -+ StoredUserList.LOGGER.warn("Failed to async save " + this.file, e); -+ } -+ }; -+ io.papermc.paper.util.MCUtil.scheduleAsyncTask(saveTask); -+ // DivineMC end - Save json list async - } - - public void load() throws IOException { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch deleted file mode 100644 index 8711080..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/server/rcon/RconConsoleSource.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/server/rcon/RconConsoleSource.java -+++ b/net/minecraft/server/rcon/RconConsoleSource.java -@@ -51,7 +_,7 @@ - - @Override - public void sendSystemMessage(Component component) { -- this.buffer.append(component.getString()); -+ this.buffer.append(component.getString()).append(System.lineSeparator()); // DivineMC - Fix MC-7569 - } - - @Override diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/util/ClassInstanceMultiMap.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/util/ClassInstanceMultiMap.java.patch deleted file mode 100644 index ddce835..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/util/ClassInstanceMultiMap.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/util/ClassInstanceMultiMap.java -+++ b/net/minecraft/util/ClassInstanceMultiMap.java -@@ -14,7 +_,7 @@ - import net.minecraft.Util; - - public class ClassInstanceMultiMap extends AbstractCollection { -- private final Map, List> byClass = Maps.newHashMap(); -+ private final Map, List> byClass = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(); // DivineMC - lithium: collections.entity_by_type - private final Class baseClass; - private final List allInstances = Lists.newArrayList(); - diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/util/Mth.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/util/Mth.java.patch deleted file mode 100644 index e4efe4c..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/util/Mth.java.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- a/net/minecraft/util/Mth.java -+++ b/net/minecraft/util/Mth.java -@@ -29,7 +_,7 @@ - public static final Vector3f Y_AXIS = new Vector3f(0.0F, 1.0F, 0.0F); - public static final Vector3f X_AXIS = new Vector3f(1.0F, 0.0F, 0.0F); - public static final Vector3f Z_AXIS = new Vector3f(0.0F, 0.0F, 1.0F); -- private static final float[] SIN = Util.make(new float[65536], floats -> { -+ public static final float[] SIN = Util.make(new float[65536], floats -> { // DivineMC - lithium: math.sine_lut - for (int i1 = 0; i1 < floats.length; i1++) { - floats[i1] = (float)Math.sin(i1 * Math.PI * 2.0 / 65536.0); - } -@@ -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 org.bxteam.divinemc.util.lithium.CompactSineLUT.sin(value); // DivineMC - lithium: math.sine_lut - } - - public static float cos(float value) { -- return SIN[(int)(value * 10430.378F + 16384.0F) & 65535]; -+ return org.bxteam.divinemc.util.lithium.CompactSineLUT.cos(value); // DivineMC - lithium: math.sine_lut - } - - public static float sqrt(float value) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/util/thread/BlockableEventLoop.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/util/thread/BlockableEventLoop.java.patch deleted file mode 100644 index e8a5a70..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/util/thread/BlockableEventLoop.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- 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 implements ProfilerMeasured, TaskScheduler, 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 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) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch deleted file mode 100644 index a31635f..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/Entity.java.patch +++ /dev/null @@ -1,88 +0,0 @@ ---- a/net/minecraft/world/entity/Entity.java -+++ b/net/minecraft/world/entity/Entity.java -@@ -235,6 +_,7 @@ - public float yRotO; - public float xRotO; - private AABB bb = INITIAL_AABB; -+ private boolean boundingBoxChanged = false; // DivineMC - vmp: skip entity move if movement is zero - public boolean onGround; - public boolean horizontalCollision; - public boolean verticalCollision; -@@ -1117,6 +_,12 @@ - // Paper end - detailed watchdog information - - public void move(MoverType type, Vec3 movement) { -+ // DivineMC start - vmp: skip entity move if movement is zero -+ if (!boundingBoxChanged && movement.equals(Vec3.ZERO)) { -+ boundingBoxChanged = false; -+ return; -+ } -+ // DivineMC end - vmp: skip entity move if movement is zero - final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity - // Paper start - detailed watchdog information - ca.spottedleaf.moonrise.common.util.TickThread.ensureTickThread("Cannot move an entity off-main"); -@@ -2158,30 +_,42 @@ - return new Vec3(this.xOld, this.yOld, this.zOld); - } - -- public float distanceTo(Entity entity) { -- float f = (float)(this.getX() - entity.getX()); -- float f1 = (float)(this.getY() - entity.getY()); -- float f2 = (float)(this.getZ() - entity.getZ()); -- return Mth.sqrt(f * f + f1 * f1 + f2 * f2); -+ // DivineMC start - Optimize distanceTo -+ public final float distanceTo(Entity entity) { -+ final double dx = this.getX() - entity.getX(); -+ final double dy = this.getY() - entity.getY(); -+ final double dz = this.getZ() - entity.getZ(); -+ return (float) Math.sqrt(Boolean.parseBoolean(System.getProperty("DivineMC.enableFMA")) -+ ? Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)) -+ : dx * dx + dy * dy + dz * dz); - } -+ // DivineMC end - Optimize distanceTo - -- public double distanceToSqr(double x, double y, double z) { -- double d = this.getX() - x; -- double d1 = this.getY() - y; -- double d2 = this.getZ() - z; -- return d * d + d1 * d1 + d2 * d2; -+ // DivineMC start - Optimize distanceToSqr -+ public final double distanceToSqr(final double x, final double y, final double z) { -+ final double dx = this.getX() - x; -+ final double dy = this.getY() - y; -+ final double dz = this.getZ() - z; -+ return Boolean.parseBoolean(System.getProperty("DivineMC.enableFMA")) -+ ? Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)) -+ : dx * dx + dy * dy + dz * dz; - } -+ // DivineMC end - Optimize distanceToSqr - - public double distanceToSqr(Entity entity) { - return this.distanceToSqr(entity.position()); - } - -+ // DivineMC start - Optimize distanceToSqr - public double distanceToSqr(Vec3 vec) { -- double d = this.getX() - vec.x; -- double d1 = this.getY() - vec.y; -- double d2 = this.getZ() - vec.z; -- return d * d + d1 * d1 + d2 * d2; -+ final double dx = this.getX() - vec.x; -+ final double dy = this.getY() - vec.y; -+ final double dz = this.getZ() - vec.z; -+ return Boolean.parseBoolean(System.getProperty("DivineMC.enableFMA")) -+ ? Math.fma(dx, dx, Math.fma(dy, dy, dz * dz)) -+ : dx * dx + dy * dy + dz * dz; - } -+ // DivineMC end - Optimize distanceToSqr - - public void playerTouch(Player player) { - } -@@ -4248,6 +_,7 @@ - } - - public final void setBoundingBox(AABB bb) { -+ if (!this.bb.equals(bb)) boundingBoxChanged = true; // DivineMC - vmp: skip entity move if movement is zero - // CraftBukkit start - block invalid bounding boxes - double minX = bb.minX, - minY = bb.minY, diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch deleted file mode 100644 index 36105dd..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/LivingEntity.java.patch +++ /dev/null @@ -1,42 +0,0 @@ ---- 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++; -@@ -3150,7 +_,13 @@ - } - - protected float getFlyingSpeed() { -- return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : 0.02F; -+ // DivineMC start - Fix MC-172801 -+ float flyingSpeed = 0.02F; -+ if (this.getAttributes().hasAttribute(Attributes.FLYING_SPEED)) { -+ flyingSpeed = (float) (this.getAttribute(Attributes.FLYING_SPEED).getValue() * 0.049999999254942D); -+ } -+ return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : flyingSpeed; -+ // DivineMC end - Fix MC-172801 - } - - public float getSpeed() { -@@ -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); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch deleted file mode 100644 index 494bacd..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/ai/goal/target/HurtByTargetGoal.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- 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 - } - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch deleted file mode 100644 index bb1eb0d..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/animal/Animal.java.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/net/minecraft/world/entity/animal/Animal.java -+++ b/net/minecraft/world/entity/animal/Animal.java -@@ -41,6 +_,7 @@ - public UUID loveCause; - public ItemStack breedItem; // CraftBukkit - Add breedItem variable - public abstract int getPurpurBreedTime(); // Purpur - Make entity breeding times configurable -+ private Object level; // DivineMC - Add level variable - - protected Animal(EntityType entityType, Level level) { - super(entityType, level); -@@ -74,7 +_,11 @@ - double d = this.random.nextGaussian() * 0.02; - double d1 = this.random.nextGaussian() * 0.02; - double d2 = this.random.nextGaussian() * 0.02; -- this.level().addParticle(ParticleTypes.HEART, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), d, d1, d2); -+ // DivineMC start - Fix MC-93826 -+ if (this.level instanceof ServerLevel serverLevel) { -+ serverLevel.sendParticles(ParticleTypes.HEART, this.getRandomX(1.0D), this.getRandomY() + 0.5D, this.getRandomZ(1.0D), 1, d, d1, d2, 0); -+ } -+ // DivineMC end - Fix MC-93826 - } - } - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch deleted file mode 100644 index 2837559..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- 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 - ); diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch deleted file mode 100644 index b431131..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/player/Player.java.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- 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) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch deleted file mode 100644 index 707c8b7..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/FireworkRocketEntity.java.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -+++ b/net/minecraft/world/entity/projectile/FireworkRocketEntity.java -@@ -354,6 +_,13 @@ - return false; - } - -+ // DivineMC start - Don't save Fireworks -+ @Override -+ public boolean shouldBeSaved() { -+ return this.level().divinemcConfig.saveFireworks; -+ } -+ // DivineMC end - Don't save Fireworks -+ - public static ItemStack getDefaultItem() { - return new ItemStack(Items.FIREWORK_ROCKET); - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch deleted file mode 100644 index dfe8585..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/projectile/ShulkerBullet.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/entity/projectile/ShulkerBullet.java -+++ b/net/minecraft/world/entity/projectile/ShulkerBullet.java -@@ -215,6 +_,17 @@ - super.tick(); - HitResult hitResult = null; - if (!this.level().isClientSide) { -+ // DivineMC start - despawn shulker bullets on owner death -+ if (this.level().divinemcConfig.despawnShulkerBulletsOnOwnerDeath) { -+ if (!isInvulnerable()) { -+ var owner = getOwner(); -+ if (owner == null || !owner.isAlive()) { -+ discard(); -+ return; -+ } -+ } -+ } -+ // DivineMC end - despawn shulker bullets on owner death - if (this.finalTarget == null && this.targetId != null) { - this.finalTarget = ((ServerLevel)this.level()).getEntity(this.targetId); - if (this.finalTarget == null) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/raid/Raid.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/raid/Raid.java.patch deleted file mode 100644 index 43de7f4..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/raid/Raid.java.patch +++ /dev/null @@ -1,39 +0,0 @@ ---- a/net/minecraft/world/entity/raid/Raid.java -+++ b/net/minecraft/world/entity/raid/Raid.java -@@ -104,6 +_,7 @@ - private Raid.RaidStatus status; - private int celebrationTicks; - private Optional waveSpawnPos = Optional.empty(); -+ private boolean isBarDirty; // DivineMC - lithium: ai.raid - // Paper start - private static final String PDC_NBT_KEY = "BukkitValues"; - private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry PDC_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry(); -@@ -264,6 +_,12 @@ - - public void tick() { - if (!this.isStopped()) { -+ // DivineMC start - lithium: ai.raid -+ if (this.isBarDirty) { -+ this.updateBossbarInternal(); -+ this.isBarDirty = false; -+ } -+ // DivineMC end - lithium: ai.raid - if (this.status == Raid.RaidStatus.ONGOING) { - boolean flag = this.active; - this.active = this.level.hasChunkAt(this.center); -@@ -580,9 +_,15 @@ - } - } - -+ // DivineMC start - lithium: ai.raid - public void updateBossbar() { -+ this.isBarDirty = true; -+ } -+ -+ private void updateBossbarInternal() { - this.raidEvent.setProgress(Mth.clamp(this.getHealthOfLivingRaiders() / this.totalHealth, 0.0F, 1.0F)); - } -+ // DivineMC end - lithium: ai.raid - - public float getHealthOfLivingRaiders() { - float f = 0.0F; diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/MinecartHopper.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/MinecartHopper.java.patch deleted file mode 100644 index d158030..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/entity/vehicle/MinecartHopper.java.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/net/minecraft/world/entity/vehicle/MinecartHopper.java -+++ b/net/minecraft/world/entity/vehicle/MinecartHopper.java -@@ -99,6 +_,13 @@ - } - } - -+ // DivineMC start - tick minecart hopper without players -+ @Override -+ public void inactiveTick() { -+ this.tick(); -+ } -+ // DivineMC end - tick minecart hopper without players -+ - public boolean suckInItems() { - if (HopperBlockEntity.suckInItems(this.level(), this)) { - this.immunize(); // Paper diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/GameRules.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/GameRules.java.patch deleted file mode 100644 index 56a0ade..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/GameRules.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/level/GameRules.java -+++ b/net/minecraft/world/level/GameRules.java -@@ -249,7 +_,7 @@ - } - - private GameRules(Map, GameRules.Value> rules, FeatureFlagSet enabledFeatures) { -- this.rules = rules; -+ this.rules = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(rules); // DivineMC - lithium: collections.gamerules - this.enabledFeatures = enabledFeatures; - - // Paper start - Perf: Use array for gamerule storage diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch deleted file mode 100644 index 2df8ac2..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/Level.java.patch +++ /dev/null @@ -1,47 +0,0 @@ ---- a/net/minecraft/world/level/Level.java -+++ b/net/minecraft/world/level/Level.java -@@ -115,7 +_,7 @@ - public static final int TICKS_PER_DAY = 24000; - public static final int MAX_ENTITY_SPAWN_Y = 20000000; - public static final int MIN_ENTITY_SPAWN_Y = -20000000; -- public final List blockEntityTickers = Lists.newArrayList(); // Paper - public -+ public final org.bxteam.divinemc.util.BlockEntityTickersList blockEntityTickers = new org.bxteam.divinemc.util.BlockEntityTickersList(); // DivineMC - optimize block entity removal - protected final NeighborUpdater neighborUpdater; - private final List pendingBlockEntityTickers = Lists.newArrayList(); - private boolean tickingBlockEntities; -@@ -172,8 +_,6 @@ - public final io.papermc.paper.antixray.ChunkPacketBlockController chunkPacketBlockController; // Paper - Anti-Xray - public final org.purpurmc.purpur.PurpurWorldConfig purpurConfig; // Purpur - Purpur config files - public static BlockPos lastPhysicsProblem; // Spigot -- private org.spigotmc.TickLimiter entityLimiter; -- private org.spigotmc.TickLimiter tileLimiter; - private int tileTickPosition; - public final Map explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions - public java.util.ArrayDeque redstoneUpdateInfos; // Paper - Faster redstone torch rapid clock removal; Move from Map in BlockRedstoneTorch to here -@@ -974,8 +_,6 @@ - public void onBorderSetDamageSafeZOne(WorldBorder border, double safeZoneRadius) {} - }); - // CraftBukkit end -- this.entityLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.entityMaxTickTime); -- this.tileLimiter = new org.spigotmc.TickLimiter(this.spigotConfig.tileMaxTickTime); - this.chunkPacketBlockController = this.paperConfig().anticheat.antiXray.enabled ? new io.papermc.paper.antixray.ChunkPacketBlockControllerAntiXray(this, executor) : io.papermc.paper.antixray.ChunkPacketBlockController.NO_OPERATION_INSTANCE; // Paper - Anti-Xray - this.entityLookup = new ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup(this); // Paper - rewrite chunk system - } -@@ -1523,7 +_,8 @@ - TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition); - // Spigot end - if (tickingBlockEntity.isRemoved()) { -- toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll -+ //toRemove.add(tickingBlockEntity); // Paper - Fix MC-117075; use removeAll -+ this.blockEntityTickers.markAsRemoved(this.tileTickPosition); // Paper - Fix MC-117075 // DivineMC - optimize block entity removal - } else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) { - tickingBlockEntity.tick(); - // Paper start - rewrite chunk system -@@ -1535,6 +_,7 @@ - } - this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075 - -+ this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removal - this.tickingBlockEntities = false; - profilerFiller.pop(); - this.spigotConfig.currentPrimedTnt = 0; // Spigot diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/LocalMobCapCalculator.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/LocalMobCapCalculator.java.patch deleted file mode 100644 index ddedc73..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/LocalMobCapCalculator.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/level/LocalMobCapCalculator.java -+++ b/net/minecraft/world/level/LocalMobCapCalculator.java -@@ -42,14 +_,14 @@ - } - - static class MobCounts { -- private final Object2IntMap counts = new Object2IntOpenHashMap<>(MobCategory.values().length); -+ private final int[] spawnGroupDensities = new int[MobCategory.values().length]; // DivineMC - vmp: spawn_density_cap - - public void add(MobCategory category) { -- this.counts.computeInt(category, (key, value) -> value == null ? 1 : value + 1); -+ this.spawnGroupDensities[category.ordinal()]++; // DivineMC - vmp: spawn_density_cap - } - - public boolean canSpawn(MobCategory category) { -- return this.counts.getOrDefault(category, 0) < category.getMaxInstancesPerChunk(); -+ return this.spawnGroupDensities[category.ordinal()] < category.getMaxInstancesPerChunk(); // DivineMC - vmp: spawn_density_cap - } - } - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/biome/BiomeManager.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/biome/BiomeManager.java.patch deleted file mode 100644 index bc0c686..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/biome/BiomeManager.java.patch +++ /dev/null @@ -1,108 +0,0 @@ ---- a/net/minecraft/world/level/biome/BiomeManager.java -+++ b/net/minecraft/world/level/biome/BiomeManager.java -@@ -14,6 +_,7 @@ - private static final int ZOOM_MASK = 3; - private final BiomeManager.NoiseBiomeSource noiseBiomeSource; - private final long biomeZoomSeed; -+ private static final double maxOffset = 0.4500000001D; // DivineMC - Optimize BiomeManager#getBiome - - public BiomeManager(BiomeManager.NoiseBiomeSource noiseBiomeSource, long biomeZoomSeed) { - this.noiseBiomeSource = noiseBiomeSource; -@@ -29,39 +_,66 @@ - } - - public Holder getBiome(BlockPos pos) { -- int i = pos.getX() - 2; -- int i1 = pos.getY() - 2; -- int i2 = pos.getZ() - 2; -- int i3 = i >> 2; -- int i4 = i1 >> 2; -- int i5 = i2 >> 2; -- double d = (i & 3) / 4.0; -- double d1 = (i1 & 3) / 4.0; -- double d2 = (i2 & 3) / 4.0; -- int i6 = 0; -- double d3 = Double.POSITIVE_INFINITY; -- -- for (int i7 = 0; i7 < 8; i7++) { -- boolean flag = (i7 & 4) == 0; -- boolean flag1 = (i7 & 2) == 0; -- boolean flag2 = (i7 & 1) == 0; -- int i8 = flag ? i3 : i3 + 1; -- int i9 = flag1 ? i4 : i4 + 1; -- int i10 = flag2 ? i5 : i5 + 1; -- double d4 = flag ? d : d - 1.0; -- double d5 = flag1 ? d1 : d1 - 1.0; -- double d6 = flag2 ? d2 : d2 - 1.0; -- double fiddledDistance = getFiddledDistance(this.biomeZoomSeed, i8, i9, i10, d4, d5, d6); -- if (d3 > fiddledDistance) { -- i6 = i7; -- d3 = fiddledDistance; -+ // DivineMC start - Optimize BiomeManager#getBiome -+ int xMinus2 = pos.getX() - 2; -+ int yMinus2 = pos.getY() - 2; -+ int zMinus2 = pos.getZ() - 2; -+ int x = xMinus2 >> 2; -+ int y = yMinus2 >> 2; -+ int z = zMinus2 >> 2; -+ double quartX = (double) (xMinus2 & 3) / 4.0; // quartLocal divided by 4 -+ double quartY = (double) (yMinus2 & 3) / 4.0; // 0/4, 1/4, 2/4, 3/4 -+ double quartZ = (double) (zMinus2 & 3) / 4.0; // [0, 0.25, 0.5, 0.75] -+ int smallestX = 0; -+ double smallestDist = Double.POSITIVE_INFINITY; -+ for (int biomeX = 0; biomeX < 8; ++biomeX) { -+ boolean everyOtherQuad = (biomeX & 4) == 0; // 1 1 1 1 0 0 0 0 -+ boolean everyOtherPair = (biomeX & 2) == 0; // 1 1 0 0 1 1 0 0 -+ boolean everyOther = (biomeX & 1) == 0; // 1 0 1 0 1 0 1 0 -+ double quartXX = everyOtherQuad ? quartX : quartX - 1.0; //[-1.0,-0.75,-0.5,-0.25,0.0,0.25,0.5,0.75] -+ double quartYY = everyOtherPair ? quartY : quartY - 1.0; -+ double quartZZ = everyOther ? quartZ : quartZ - 1.0; -+ -+ double maxQuartYY = 0.0, maxQuartZZ = 0.0; -+ if (biomeX != 0) { -+ maxQuartYY = Mth.square(Math.max(quartYY + maxOffset, Math.abs(quartYY - maxOffset))); -+ maxQuartZZ = Mth.square(Math.max(quartZZ + maxOffset, Math.abs(quartZZ - maxOffset))); -+ double maxQuartXX = Mth.square(Math.max(quartXX + maxOffset, Math.abs(quartXX - maxOffset))); -+ if (smallestDist < maxQuartXX + maxQuartYY + maxQuartZZ) continue; -+ } -+ -+ int xx = everyOtherQuad ? x : x + 1; -+ int yy = everyOtherPair ? y : y + 1; -+ int zz = everyOther ? z : z + 1; -+ -+ long seed = LinearCongruentialGenerator.next(this.biomeZoomSeed, xx); -+ seed = LinearCongruentialGenerator.next(seed, yy); -+ seed = LinearCongruentialGenerator.next(seed, zz); -+ seed = LinearCongruentialGenerator.next(seed, xx); -+ seed = LinearCongruentialGenerator.next(seed, yy); -+ seed = LinearCongruentialGenerator.next(seed, zz); -+ double offsetX = getFiddle(seed); -+ double sqrX = Mth.square(quartXX + offsetX); -+ if (biomeX != 0 && smallestDist < sqrX + maxQuartYY + maxQuartZZ) continue; -+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); -+ double offsetY = getFiddle(seed); -+ double sqrY = Mth.square(quartYY + offsetY); -+ if (biomeX != 0 && smallestDist < sqrX + sqrY + maxQuartZZ) continue; -+ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); -+ double offsetZ = getFiddle(seed); -+ double biomeDist = sqrX + sqrY + Mth.square(quartZZ + offsetZ); -+ -+ if (smallestDist > biomeDist) { -+ smallestX = biomeX; -+ smallestDist = biomeDist; - } - } -- -- int i7x = (i6 & 4) == 0 ? i3 : i3 + 1; -- int i11 = (i6 & 2) == 0 ? i4 : i4 + 1; -- int i12 = (i6 & 1) == 0 ? i5 : i5 + 1; -- return this.noiseBiomeSource.getNoiseBiome(i7x, i11, i12); -+ return this.noiseBiomeSource.getNoiseBiome( -+ (smallestX & 4) == 0 ? x : x + 1, -+ (smallestX & 2) == 0 ? y : y + 1, -+ (smallestX & 1) == 0 ? z : z + 1 -+ ); -+ // DivineMC end - Optimize BiomeManager#getBiome - } - - public Holder getNoiseBiomeAtPosition(double x, double y, double z) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch deleted file mode 100644 index 4cd6154..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/Blocks.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- 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( diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch deleted file mode 100644 index dc0218d..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/EnderChestBlock.java.patch +++ /dev/null @@ -1,20 +0,0 @@ ---- a/net/minecraft/world/level/block/EnderChestBlock.java -+++ b/net/minecraft/world/level/block/EnderChestBlock.java -@@ -43,7 +_,7 @@ - public static final EnumProperty FACING = HorizontalDirectionalBlock.FACING; - public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; - protected static final VoxelShape SHAPE = Block.box(1.0, 0.0, 1.0, 15.0, 14.0, 15.0); -- private static final Component CONTAINER_TITLE = Component.translatable("container.enderchest"); -+ public static final Component CONTAINER_TITLE = Component.translatable("container.enderchest"); // DivineMC - private -> public - Open Ender Chest API - - @Override - public MapCodec codec() { -@@ -101,7 +_,7 @@ - } - - // Purpur start - Barrels and enderchests 6 rows -- private ChestMenu getEnderChestSixRows(int syncId, net.minecraft.world.entity.player.Inventory inventory, Player player, PlayerEnderChestContainer playerEnderChestContainer) { -+ public static ChestMenu getEnderChestSixRows(int syncId, net.minecraft.world.entity.player.Inventory inventory, Player player, PlayerEnderChestContainer playerEnderChestContainer) { // DivineMC - private -> public static - Open Ender Chest API - if (org.purpurmc.purpur.PurpurConfig.enderChestPermissionRows) { - org.bukkit.craftbukkit.entity.CraftHumanEntity bukkitPlayer = player.getBukkitEntity(); - if (bukkitPlayer.hasPermission("purpur.enderchest.rows.six")) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch deleted file mode 100644 index de4c77a..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/NoteBlock.java.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- a/net/minecraft/world/level/block/NoteBlock.java -+++ b/net/minecraft/world/level/block/NoteBlock.java -@@ -40,6 +_,7 @@ - public static final BooleanProperty POWERED = BlockStateProperties.POWERED; - public static final IntegerProperty NOTE = BlockStateProperties.NOTE; - public static final int NOTE_VOLUME = 3; -+ private @Nullable Player lastPlayedBy = null; // DivineMC - Add player to NotePlayEvent - - @Override - public MapCodec codec() { -@@ -108,6 +_,7 @@ - - private void playNote(@Nullable Entity entity, BlockState state, Level level, BlockPos pos) { - if (level.purpurConfig.noteBlockIgnoreAbove || state.getValue(INSTRUMENT).worksAboveNoteBlock() || level.getBlockState(pos.above()).isAir()) { // Purpur - Config to allow Note Block sounds when blocked -+ if (entity instanceof Player player) this.lastPlayedBy = player; // DivineMC - Add player to NotePlayEvent - level.blockEvent(pos, this, 0, 0); - level.gameEvent(entity, GameEvent.NOTE_BLOCK_PLAY, pos); - } -@@ -150,7 +_,8 @@ - protected boolean triggerEvent(BlockState state, Level level, BlockPos pos, int id, int param) { - NoteBlockInstrument noteBlockInstrument = state.getValue(INSTRUMENT); - // Paper start - move NotePlayEvent call to fix instrument/note changes -- org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(level, pos, noteBlockInstrument, state.getValue(NOTE)); -+ org.bukkit.event.block.NotePlayEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callNotePlayEvent(level, pos, noteBlockInstrument, state.getValue(NOTE), this.lastPlayedBy); // DivineMC - Add player to NotePlayEvent -+ this.lastPlayedBy = null; // DivineMC - Add player to NotePlayEvent - if (event.isCancelled()) return false; - // Paper end - move NotePlayEvent call to fix instrument/note changes - float pitchFromNote; diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch deleted file mode 100644 index 97043d1..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/block/entity/SignBlockEntity.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/level/block/entity/SignBlockEntity.java -+++ b/net/minecraft/world/level/block/entity/SignBlockEntity.java -@@ -152,7 +_,7 @@ - this.setAllowedPlayerEditor(null); - this.level.sendBlockUpdated(this.getBlockPos(), this.getBlockState(), this.getBlockState(), 3); - } else { -- LOGGER.warn("Player {} just tried to change non-editable sign", player.getName().getString()); -+ if (!org.bxteam.divinemc.configuration.DivineConfig.disableNonEditableSignWarning) LOGGER.warn("Player {} just tried to change non-editable sign", player.getName().getString()); // DivineMC - Option to disable warning - if (player.distanceToSqr(this.getBlockPos().getX(), this.getBlockPos().getY(), this.getBlockPos().getZ()) < Mth.square(32)) // Paper - Don't send far away sign update - ((net.minecraft.server.level.ServerPlayer) player).connection.send(this.getUpdatePacket()); // CraftBukkit - } diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch deleted file mode 100644 index c14bd50..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/dimension/end/EndDragonFight.java.patch +++ /dev/null @@ -1,82 +0,0 @@ ---- a/net/minecraft/world/level/dimension/end/EndDragonFight.java -+++ b/net/minecraft/world/level/dimension/end/EndDragonFight.java -@@ -274,8 +_,67 @@ - return false; - } - -+ // DivineMC start - Optimized dragon respawn -+ private int cachePortalChunkIteratorX = -8; -+ private int cachePortalChunkIteratorZ = -8; -+ private int cachePortalOriginIteratorY = -1; -+ - @Nullable - public BlockPattern.BlockPatternMatch findExitPortal() { -+ if (org.bxteam.divinemc.configuration.DivineConfig.optimizedDragonRespawn) { -+ int i, j; -+ for (i = cachePortalChunkIteratorX; i <= 8; ++i) { -+ for (j = cachePortalChunkIteratorZ; j <= 8; ++j) { -+ LevelChunk worldChunk = this.level.getChunk(i, j); -+ for (BlockEntity blockEntity : worldChunk.getBlockEntities().values()) { -+ if (blockEntity instanceof net.minecraft.world.level.block.entity.TheEndGatewayBlockEntity) { -+ continue; -+ } -+ if (blockEntity instanceof TheEndPortalBlockEntity) { -+ BlockPattern.BlockPatternMatch blockPatternMatch = this.exitPortalPattern.find(this.level, blockEntity.getBlockPos()); -+ if (blockPatternMatch != null) { -+ BlockPos blockPos = blockPatternMatch.getBlock(3, 3, 3).getPos(); -+ if (this.portalLocation == null) { -+ this.portalLocation = blockPos; -+ } -+ //No need to judge whether optimizing option is open -+ cachePortalChunkIteratorX = i; -+ cachePortalChunkIteratorZ = j; -+ return blockPatternMatch; -+ } -+ } -+ } -+ } -+ } -+ -+ if (this.needsStateScanning || this.portalLocation == null) { -+ if (cachePortalOriginIteratorY != -1) { -+ i = cachePortalOriginIteratorY; -+ } else { -+ i = this.level.getHeightmapPos(Heightmap.Types.MOTION_BLOCKING, EndPodiumFeature.getLocation(BlockPos.ZERO)).getY(); -+ } -+ boolean notFirstSearch = false; -+ for (j = i; j >= 0; --j) { -+ BlockPattern.BlockPatternMatch result2 = null; -+ if (notFirstSearch) { -+ result2 = org.bxteam.divinemc.util.carpetams.BlockPatternHelper.partialSearchAround(this.exitPortalPattern, this.level, new BlockPos(EndPodiumFeature.getLocation(BlockPos.ZERO).getY(), j, EndPodiumFeature.getLocation(BlockPos.ZERO).getZ())); -+ } else { -+ result2 = this.exitPortalPattern.find(this.level, new BlockPos(EndPodiumFeature.getLocation(BlockPos.ZERO).getX(), j, EndPodiumFeature.getLocation(BlockPos.ZERO).getZ())); -+ } -+ if (result2 != null) { -+ if (this.portalLocation == null) { -+ this.portalLocation = result2.getBlock(3, 3, 3).getPos(); -+ } -+ cachePortalOriginIteratorY = j; -+ return result2; -+ } -+ notFirstSearch = true; -+ } -+ } -+ -+ return null; -+ } -+ // DivineMC end - Optimized dragon respawn - ChunkPos chunkPos = new ChunkPos(this.origin); - - for (int i = -8 + chunkPos.x; i <= 8 + chunkPos.x; i++) { -@@ -571,6 +_,11 @@ - } - - public boolean respawnDragon(List crystals) { // CraftBukkit - return boolean -+ // DivineMC start - Optimized dragon respawn -+ cachePortalChunkIteratorX = -8; -+ cachePortalChunkIteratorZ = -8; -+ cachePortalOriginIteratorY = -1; -+ // DivineMC end - Optimized dragon respawn - if (this.dragonKilled && this.respawnStage == null) { - for (BlockPattern.BlockPatternMatch blockPatternMatch = this.findExitPortal(); blockPatternMatch != null; blockPatternMatch = this.findExitPortal()) { - for (int i = 0; i < this.exitPortalPattern.getWidth(); i++) { diff --git a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/feature/OreFeature.java.patch b/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/feature/OreFeature.java.patch deleted file mode 100644 index d90d525..0000000 --- a/divinemc-server/minecraft-patches/sources/net/minecraft/world/level/levelgen/feature/OreFeature.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/level/levelgen/feature/OreFeature.java -+++ b/net/minecraft/world/level/levelgen/feature/OreFeature.java -@@ -69,7 +_,7 @@ - int height - ) { - int i = 0; -- BitSet bitSet = new BitSet(width * height * width); -+ BitSet bitSet = org.bxteam.divinemc.util.c2me.ObjectCachingUtils.getCachedOrNewBitSet(width * height * width); // DivineMC - C2ME: reduce_allocs - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); - int i1 = config.size; - double[] doubles = new double[i1 * 4]; diff --git a/divinemc-server/paper-patches/features/0005-Implement-Secure-Seed.patch b/divinemc-server/paper-patches/features/0005-Implement-Secure-Seed.patch deleted file mode 100644 index 853f44a..0000000 --- a/divinemc-server/paper-patches/features/0005-Implement-Secure-Seed.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sat, 20 Jul 2024 22:04:52 +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..c245a30f8bef4dc9ac980bdc0b39b5e0344a524b 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.configuration.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 0c03829de02f31a15b5f2686d03bf3977e3710cb..0a1465b03e41da4cf4721ae1c06c2ff0f26c374d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -1405,7 +1405,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.configuration.DivineConfig.enableSecureSeed -+ ? new WorldOptions(creator.seed(), org.bxteam.divinemc.seed.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)); diff --git a/divinemc-server/paper-patches/features/0006-Skip-EntityScheduler-s-executeTick-checks-if-there-i.patch b/divinemc-server/paper-patches/features/0006-Skip-EntityScheduler-s-executeTick-checks-if-there-i.patch deleted file mode 100644 index 4e02765..0000000 --- a/divinemc-server/paper-patches/features/0006-Skip-EntityScheduler-s-executeTick-checks-if-there-i.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> -Date: Sun, 26 Jan 2025 16:13: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 run, Consumer retired) {} - -@@ -46,7 +47,8 @@ public final class EntityScheduler { - - private final ArrayDeque 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 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 dca2761fe4765c6e95b5db0d0cb5c818eb8697b4..62efcf81ca48f2f1125f64b489ca9521c6e0f287 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 diff --git a/divinemc-server/paper-patches/files/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java.patch b/divinemc-server/paper-patches/files/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java.patch deleted file mode 100644 index f33bd34..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java -+++ b/src/main/java/com/destroystokyo/paper/profile/CraftPlayerProfile.java -@@ -295,7 +_,7 @@ - - private static GameProfile createAuthLibProfile(UUID uniqueId, String name) { - Preconditions.checkArgument(name == null || name.length() <= 16, "Name cannot be longer than 16 characters"); -- Preconditions.checkArgument(name == null || StringUtil.isValidPlayerName(name), "The name of the profile contains invalid characters: %s", name); -+ Preconditions.checkArgument(name == null || org.bxteam.divinemc.configuration.DivineConfig.removeVanillaUsernameCheck || StringUtil.isValidPlayerName(name), "The name of the profile contains invalid characters: %s", name); // DivineMC - Remove vanilla username check - return new GameProfile( - uniqueId != null ? uniqueId : Util.NIL_UUID, - name != null ? name : "" diff --git a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/adventure/ChatProcessor.java.patch b/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/adventure/ChatProcessor.java.patch deleted file mode 100644 index efda179..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/adventure/ChatProcessor.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/src/main/java/io/papermc/paper/adventure/ChatProcessor.java -+++ b/src/main/java/io/papermc/paper/adventure/ChatProcessor.java -@@ -317,7 +_,7 @@ - - private void sendToServer(final ChatType.Bound chatType, final @Nullable Function msgFunction) { - final PlayerChatMessage toConsoleMessage = msgFunction == null ? ChatProcessor.this.message : ChatProcessor.this.message.withUnsignedContent(msgFunction.apply(ChatProcessor.this.server.console)); -- ChatProcessor.this.server.logChatMessage(toConsoleMessage.decoratedContent(), chatType, ChatProcessor.this.server.getPlayerList().verifyChatTrusted(toConsoleMessage) ? null : "Not Secure"); -+ ChatProcessor.this.server.logChatMessage(toConsoleMessage.decoratedContent(), chatType, ChatProcessor.this.server.getPlayerList().verifyChatTrusted(toConsoleMessage) || org.bxteam.divinemc.configuration.DivineConfig.noChatSign ? null : "Not Secure"); // DivineMC - No chat sign - } - } - diff --git a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/command/MSPTCommand.java.patch b/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/command/MSPTCommand.java.patch deleted file mode 100644 index 9b55c68..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/command/MSPTCommand.java.patch +++ /dev/null @@ -1,50 +0,0 @@ ---- 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 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; - } - diff --git a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch b/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch deleted file mode 100644 index 48ae1ca..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java.patch +++ /dev/null @@ -1,52 +0,0 @@ ---- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java -+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java -@@ -1,6 +_,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; -@@ -36,15 +_,22 @@ - - // 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.configuration.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()) { - continue; -@@ -95,7 +_,6 @@ - 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)); - } - -@@ -182,7 +_,7 @@ - } - } - -- EventExecutor executor = new TimedEventExecutor(EventExecutor.create(method, eventClass), plugin, method, eventClass); -+ EventExecutor executor = EventExecutor.create(method, eventClass); - eventSet.add(new RegisteredListener(listener, executor, eh.priority(), plugin, eh.ignoreCancelled())); - } - return ret; diff --git a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java.patch b/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java.patch deleted file mode 100644 index 1e596c9..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java -+++ b/src/main/java/io/papermc/paper/plugin/manager/PaperPluginManagerImpl.java -@@ -232,7 +_,7 @@ - - @Override - public boolean useTimings() { -- return co.aikar.timings.Timings.isTimingsEnabled(); -+ return false; - } - - @Override diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch deleted file mode 100644 index 315be15..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/CraftServer.java.patch +++ /dev/null @@ -1,43 +0,0 @@ ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -287,6 +_,7 @@ - protected final DedicatedPlayerList playerList; - private final Map worlds = new LinkedHashMap(); - // private final Map, Registry> registries = new HashMap<>(); // Paper - replace with RegistryAccess -+ private final Map worldsByUUID = new it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap<>(); // DivineMC - MultiPaper - optimize getWorld(UUID) - private YamlConfiguration configuration; - private YamlConfiguration commandsConfiguration; - private final Yaml yaml = new Yaml(new SafeConstructor(new LoaderOptions())); -@@ -989,7 +_,7 @@ - - @Override - public List getWorlds() { -- return new ArrayList(this.worlds.values()); -+ return new it.unimi.dsi.fastutil.objects.ObjectArrayList(this.worlds.values()); // DivineMC - optimize getWorlds - } - - @Override -@@ -1537,6 +_,7 @@ - this.getLogger().log(Level.SEVERE, null, ex); - } - -+ this.worldsByUUID.remove(world.getUID()); // DivineMC - MultiPaper - optimize getWorld(UUID) - this.worlds.remove(world.getName().toLowerCase(Locale.ROOT)); - this.console.removeLevel(handle); - return true; -@@ -1555,6 +_,7 @@ - - @Override - public World getWorld(UUID uid) { -+ if (true) return this.worldsByUUID.get(uid); // DivineMC - MultiPaper - optimize getWorld(UUID) - for (World world : this.worlds.values()) { - if (world.getUID().equals(uid)) { - return world; -@@ -1578,6 +_,7 @@ - System.out.println("World " + world.getName() + " is a duplicate of another world and has been prevented from loading. Please delete the uid.dat file from " + world.getName() + "'s world directory if you want to be able to load the duplicate world."); - return; - } -+ this.worldsByUUID.put(world.getUID(), world); // DivineMC - MultiPaper - optimize getWorld(UUID) - this.worlds.put(world.getName().toLowerCase(Locale.ROOT), world); - } - diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java.patch deleted file mode 100644 index 60bfdcb..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java.patch +++ /dev/null @@ -1,14 +0,0 @@ ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAbstractArrow.java -@@ -194,4 +_,11 @@ - this.getHandle().projectileSource = shooter; - } - // Paper end - Fix PickupStatus getting reset -+ -+ // DivineMC start - Add startFalling method to AbstractArrow -+ @Override -+ public void startFalling() { -+ this.getHandle().startFalling(); -+ } -+ // DivineMC end - Add startFalling method to AbstractArrow - } diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch deleted file mode 100644 index 69c2107..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java.patch +++ /dev/null @@ -1,48 +0,0 @@ ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -214,7 +_,7 @@ - private boolean hasPlayedBefore = false; - private final ConversationTracker conversationTracker = new ConversationTracker(); - private final Set channels = new HashSet(); -- private final Map>> invertedVisibilityEntities = new HashMap<>(); -+ private final Map>> invertedVisibilityEntities = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // DivineMC - optimize canSee checks - private final Set unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player - private static final WeakHashMap> pluginWeakReferences = new WeakHashMap<>(); - private int hash = 0; -@@ -2270,8 +_,14 @@ - - @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())); -+ } -+ // DivineMC end - optimize canSee checks - - public boolean canSeePlayer(UUID uuid) { - org.bukkit.entity.Entity entity = this.getServer().getPlayer(uuid); -@@ -3700,4 +_,19 @@ - this.getHandle().connection.send(new net.minecraft.network.protocol.game.ClientboundPlayerCombatKillPacket(getEntityId(), io.papermc.paper.adventure.PaperAdventure.asVanilla(message))); - } - // Purpur end - Death screen API -+ -+ // DivineMC start - Open Ender Chest API -+ /** -+ * Opens ender chest for the player -+ * -+ * @param enderChest ender chest -+ */ -+ @Override -+ public boolean openEnderChest(@NotNull org.bukkit.block.EnderChest enderChest) { -+ net.minecraft.world.inventory.PlayerEnderChestContainer playerEnderChestContainer = this.getHandle().getEnderChestInventory(); -+ net.minecraft.world.level.block.entity.EnderChestBlockEntity blockEntity = ((org.bukkit.craftbukkit.block.CraftEnderChest) enderChest).getTileEntity(); -+ playerEnderChestContainer.setActiveChest(blockEntity); -+ return this.getHandle().openMenu(new net.minecraft.world.SimpleMenuProvider((i, inventory, playerx) -> org.purpurmc.purpur.PurpurConfig.enderChestSixRows ? net.minecraft.world.level.block.EnderChestBlock.getEnderChestSixRows(i, inventory, this.getHandle(), playerEnderChestContainer) : net.minecraft.world.inventory.ChestMenu.threeRows(i, inventory, playerEnderChestContainer), net.minecraft.world.level.block.EnderChestBlock.CONTAINER_TITLE)).isPresent(); -+ } -+ // DivineMC end - Open Ender Chest API - } diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java.patch deleted file mode 100644 index 24a3016..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java.patch +++ /dev/null @@ -1,16 +0,0 @@ ---- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -+++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java -@@ -1568,7 +_,12 @@ - } - - public static NotePlayEvent callNotePlayEvent(Level world, BlockPos pos, NoteBlockInstrument instrument, int note) { -- NotePlayEvent event = new NotePlayEvent(world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()), org.bukkit.Instrument.getByType((byte) instrument.ordinal()), new org.bukkit.Note(note)); -+ // DivineMC start - Add player to NotePlayEvent -+ return callNotePlayEvent(world, pos, instrument, note, null); -+ } -+ public static NotePlayEvent callNotePlayEvent(Level world, BlockPos pos, NoteBlockInstrument instrument, int note, @Nullable net.minecraft.world.entity.player.Player player) { -+ NotePlayEvent event = new NotePlayEvent(world.getWorld().getBlockAt(pos.getX(), pos.getY(), pos.getZ()), org.bukkit.Instrument.getByType((byte) instrument.ordinal()), new org.bukkit.Note(note), player instanceof ServerPlayer serverPlayer ? serverPlayer.getBukkitEntity() : null); -+ // DivineMC end - Add player to NotePlayEvent - world.getCraftServer().getPluginManager().callEvent(event); - return event; - } diff --git a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java.patch b/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java.patch deleted file mode 100644 index 48afc6a..0000000 --- a/divinemc-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- a/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java -+++ b/src/main/java/org/bukkit/craftbukkit/util/permissions/CraftDefaultPermissions.java -@@ -5,6 +_,7 @@ - - public final class CraftDefaultPermissions { - private static final String ROOT = "minecraft"; -+ public static final String DIVINEMC_ROOT = "divinemc"; // DivineMC - permission root for commands - - private CraftDefaultPermissions() {} - diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPath.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPath.java deleted file mode 100644 index 06ed485..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPath.java +++ /dev/null @@ -1,284 +0,0 @@ -package org.bxteam.divinemc.pathfinding; - -import net.minecraft.core.BlockPos; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.pathfinder.Node; -import net.minecraft.world.level.pathfinder.Path; -import net.minecraft.world.phys.Vec3; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.function.Supplier; - -public class AsyncPath extends Path { - /** - * marks whether this async path has been processed - */ - private volatile PathProcessState processState = PathProcessState.WAITING; - - /** - * runnables waiting for this to be processed - */ - private final List postProcessing = new ArrayList<>(0); - - /** - * a list of positions that this path could path towards - */ - private final Set positions; - - /** - * the supplier of the real processed path - */ - private final Supplier pathSupplier; - - /* - * Processed values - */ - - /** - * this is a reference to the nodes list in the parent `Path` object - */ - private final List nodes; - /** - * the block we're trying to path to - *

- * while processing, we have no idea where this is so consumers of `Path` should check that the path is processed before checking the target block - */ - private @Nullable BlockPos target; - /** - * how far we are to the target - *

- * while processing, the target could be anywhere but theoretically we're always "close" to a theoretical target so default is 0 - */ - private float distToTarget = 0; - /** - * whether we can reach the target - *

- * while processing, we can always theoretically reach the target so default is true - */ - private boolean canReach = true; - - public AsyncPath(@NotNull List emptyNodeList, @NotNull Set positions, @NotNull Supplier pathSupplier) { - //noinspection ConstantConditions - super(emptyNodeList, null, false); - - this.nodes = emptyNodeList; - this.positions = positions; - this.pathSupplier = pathSupplier; - - AsyncPathProcessor.queue(this); - } - - @Override - public boolean isProcessed() { - return this.processState == PathProcessState.COMPLETED; - } - - /** - * returns the future representing the processing state of this path - */ - public synchronized void postProcessing(@NotNull Runnable runnable) { - if (isProcessed()) { - runnable.run(); - } else { - this.postProcessing.add(runnable); - } - } - - /** - * an easy way to check if this processing path is the same as an attempted new path - * - * @param positions - the positions to compare against - * @return true if we are processing the same positions - */ - public boolean hasSameProcessingPositions(final Set positions) { - if (this.positions.size() != positions.size()) { - return false; - } - - return this.positions.containsAll(positions); - } - - /** - * starts processing this path - */ - public synchronized void process() { - if (this.processState == PathProcessState.COMPLETED || - this.processState == PathProcessState.PROCESSING) { - return; - } - - processState = PathProcessState.PROCESSING; - - final Path bestPath = this.pathSupplier.get(); - - this.nodes.addAll(bestPath.nodes); // we mutate this list to reuse the logic in Path - this.target = bestPath.getTarget(); - this.distToTarget = bestPath.getDistToTarget(); - this.canReach = bestPath.canReach(); - - processState = PathProcessState.COMPLETED; - - for (Runnable runnable : this.postProcessing) { - runnable.run(); - } // Run tasks after processing - } - - /** - * if this path is accessed while it hasn't processed, just process it in-place - */ - private void checkProcessed() { - if (this.processState == PathProcessState.WAITING || - this.processState == PathProcessState.PROCESSING) { // Block if we are on processing - this.process(); - } - } - - /* - * overrides we need for final fields that we cannot modify after processing - */ - - @Override - public @NotNull BlockPos getTarget() { - this.checkProcessed(); - - return this.target; - } - - @Override - public float getDistToTarget() { - this.checkProcessed(); - - return this.distToTarget; - } - - @Override - public boolean canReach() { - this.checkProcessed(); - - return this.canReach; - } - - /* - * overrides to ensure we're processed first - */ - - @Override - public boolean isDone() { - return this.processState == PathProcessState.COMPLETED && super.isDone(); - } - - @Override - public void advance() { - this.checkProcessed(); - - super.advance(); - } - - @Override - public boolean notStarted() { - this.checkProcessed(); - - return super.notStarted(); - } - - @Nullable - @Override - public Node getEndNode() { - this.checkProcessed(); - - return super.getEndNode(); - } - - @Override - public Node getNode(int index) { - this.checkProcessed(); - - return super.getNode(index); - } - - @Override - public void truncateNodes(int length) { - this.checkProcessed(); - - super.truncateNodes(length); - } - - @Override - public void replaceNode(int index, Node node) { - this.checkProcessed(); - - super.replaceNode(index, node); - } - - @Override - public int getNodeCount() { - this.checkProcessed(); - - return super.getNodeCount(); - } - - @Override - public int getNextNodeIndex() { - this.checkProcessed(); - - return super.getNextNodeIndex(); - } - - @Override - public void setNextNodeIndex(int nodeIndex) { - this.checkProcessed(); - - super.setNextNodeIndex(nodeIndex); - } - - @Override - public Vec3 getEntityPosAtNode(Entity entity, int index) { - this.checkProcessed(); - - return super.getEntityPosAtNode(entity, index); - } - - @Override - public BlockPos getNodePos(int index) { - this.checkProcessed(); - - return super.getNodePos(index); - } - - @Override - public Vec3 getNextEntityPos(Entity entity) { - this.checkProcessed(); - - return super.getNextEntityPos(entity); - } - - @Override - public BlockPos getNextNodePos() { - this.checkProcessed(); - - return super.getNextNodePos(); - } - - @Override - public Node getNextNode() { - this.checkProcessed(); - - return super.getNextNode(); - } - - @Nullable - @Override - public Node getPreviousNode() { - this.checkProcessed(); - - return super.getPreviousNode(); - } - - public PathProcessState getProcessState() { - return processState; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPathProcessor.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPathProcessor.java deleted file mode 100644 index 1403a01..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/AsyncPathProcessor.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.bxteam.divinemc.pathfinding; - -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import net.minecraft.server.MinecraftServer; -import net.minecraft.world.level.pathfinder.Path; -import org.bxteam.divinemc.configuration.DivineConfig; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.concurrent.*; -import java.util.function.Consumer; - -/** - * used to handle the scheduling of async path processing - */ -public class AsyncPathProcessor { - private static final Executor pathProcessingExecutor = new ThreadPoolExecutor( - 1, - DivineConfig.asyncPathfindingMaxThreads, - DivineConfig.asyncPathfindingKeepalive, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), - new ThreadFactoryBuilder() - .setNameFormat("DivineMC Async Pathfinding Thread - %d") - .setPriority(Thread.NORM_PRIORITY - 2) - .build() - ); - - protected static CompletableFuture queue(@NotNull AsyncPath path) { - return CompletableFuture.runAsync(path::process, pathProcessingExecutor); - } - - /** - * takes a possibly unprocessed path, and waits until it is completed - * the consumer will be immediately invoked if the path is already processed - * the consumer will always be called on the main thread - * - * @param path a path to wait on - * @param afterProcessing a consumer to be called - */ - public static void awaitProcessing(@Nullable Path path, Consumer<@Nullable Path> afterProcessing) { - if (path != null && !path.isProcessed() && path instanceof AsyncPath asyncPath) { - asyncPath.postProcessing(() -> - MinecraftServer.getServer().scheduleOnMain(() -> afterProcessing.accept(path)) - ); - } else { - afterProcessing.accept(path); - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorCache.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorCache.java deleted file mode 100644 index add2e3e..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorCache.java +++ /dev/null @@ -1,44 +0,0 @@ -package org.bxteam.divinemc.pathfinding; - -import net.minecraft.world.level.pathfinder.NodeEvaluator; -import org.apache.commons.lang.Validate; -import org.jetbrains.annotations.NotNull; - -import java.util.Map; -import java.util.Queue; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; - -public class NodeEvaluatorCache { - private static final Map> threadLocalNodeEvaluators = new ConcurrentHashMap<>(); - private static final Map nodeEvaluatorToGenerator = new ConcurrentHashMap<>(); - - private static @NotNull Queue getQueueForFeatures(@NotNull NodeEvaluatorFeatures nodeEvaluatorFeatures) { - return threadLocalNodeEvaluators.computeIfAbsent(nodeEvaluatorFeatures, key -> new ConcurrentLinkedQueue<>()); - } - - public static @NotNull NodeEvaluator takeNodeEvaluator(@NotNull NodeEvaluatorGenerator generator, @NotNull NodeEvaluator localNodeEvaluator) { - final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(localNodeEvaluator); - NodeEvaluator nodeEvaluator = getQueueForFeatures(nodeEvaluatorFeatures).poll(); - - if (nodeEvaluator == null) { - nodeEvaluator = generator.generate(nodeEvaluatorFeatures); - } - - nodeEvaluatorToGenerator.put(nodeEvaluator, generator); - - return nodeEvaluator; - } - - public static void returnNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) { - final NodeEvaluatorGenerator generator = nodeEvaluatorToGenerator.remove(nodeEvaluator); - Validate.notNull(generator, "NodeEvaluator already returned"); - - final NodeEvaluatorFeatures nodeEvaluatorFeatures = NodeEvaluatorFeatures.fromNodeEvaluator(nodeEvaluator); - getQueueForFeatures(nodeEvaluatorFeatures).offer(nodeEvaluator); - } - - public static void removeNodeEvaluator(@NotNull NodeEvaluator nodeEvaluator) { - nodeEvaluatorToGenerator.remove(nodeEvaluator); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorFeatures.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorFeatures.java deleted file mode 100644 index 9ee6f0f..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorFeatures.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bxteam.divinemc.pathfinding; - -import net.minecraft.world.level.pathfinder.NodeEvaluator; -import net.minecraft.world.level.pathfinder.SwimNodeEvaluator; - -public record NodeEvaluatorFeatures( - NodeEvaluatorType type, - boolean canPassDoors, - boolean canFloat, - boolean canWalkOverFences, - boolean canOpenDoors, - boolean allowBreaching -) { - public static NodeEvaluatorFeatures fromNodeEvaluator(NodeEvaluator nodeEvaluator) { - NodeEvaluatorType type = NodeEvaluatorType.fromNodeEvaluator(nodeEvaluator); - boolean canPassDoors = nodeEvaluator.canPassDoors(); - boolean canFloat = nodeEvaluator.canFloat(); - boolean canWalkOverFences = nodeEvaluator.canWalkOverFences(); - boolean canOpenDoors = nodeEvaluator.canOpenDoors(); - boolean allowBreaching = nodeEvaluator instanceof SwimNodeEvaluator swimNodeEvaluator && swimNodeEvaluator.allowBreaching; - return new NodeEvaluatorFeatures(type, canPassDoors, canFloat, canWalkOverFences, canOpenDoors, allowBreaching); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorGenerator.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorGenerator.java deleted file mode 100644 index de13612..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorGenerator.java +++ /dev/null @@ -1,8 +0,0 @@ -package org.bxteam.divinemc.pathfinding; - -import net.minecraft.world.level.pathfinder.NodeEvaluator; -import org.jetbrains.annotations.NotNull; - -public interface NodeEvaluatorGenerator { - @NotNull NodeEvaluator generate(NodeEvaluatorFeatures nodeEvaluatorFeatures); -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorType.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorType.java deleted file mode 100644 index 6657aac..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/NodeEvaluatorType.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.bxteam.divinemc.pathfinding; - -import net.minecraft.world.level.pathfinder.*; - -public enum NodeEvaluatorType { - WALK, - SWIM, - AMPHIBIOUS, - FLY; - - public static NodeEvaluatorType fromNodeEvaluator(NodeEvaluator nodeEvaluator) { - if (nodeEvaluator instanceof SwimNodeEvaluator) return SWIM; - if (nodeEvaluator instanceof FlyNodeEvaluator) return FLY; - if (nodeEvaluator instanceof AmphibiousNodeEvaluator) return AMPHIBIOUS; - return WALK; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/PathProcessState.java b/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/PathProcessState.java deleted file mode 100644 index 76f8a7a..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/pathfinding/PathProcessState.java +++ /dev/null @@ -1,7 +0,0 @@ -package org.bxteam.divinemc.pathfinding; - -public enum PathProcessState { - WAITING, - PROCESSING, - COMPLETED -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFile.java deleted file mode 100644 index e1e48b1..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFile.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.bxteam.divinemc.region; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.file.Path; -import ca.spottedleaf.moonrise.patches.chunk_system.storage.ChunkSystemRegionFile; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.ChunkPos; - -public interface AbstractRegionFile extends AutoCloseable, ChunkSystemRegionFile { - Path getPath(); - void flush() throws IOException; - void clear(ChunkPos pos) throws IOException; - void close() throws IOException; - void setOversized(int x, int z, boolean b) throws IOException; - void write(ChunkPos pos, ByteBuffer buffer) throws IOException; - - boolean hasChunk(ChunkPos pos); - boolean doesChunkExist(ChunkPos pos) throws Exception; - boolean isOversized(int x, int z); - boolean recalculateHeader() throws IOException; - - DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; - DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; - CompoundTag getOversizedData(int x, int z) throws IOException; -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFileFactory.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFileFactory.java deleted file mode 100644 index 8ed0888..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/AbstractRegionFileFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.bxteam.divinemc.region; - -import java.io.IOException; -import java.nio.file.Path; -import net.minecraft.world.level.chunk.storage.RegionFile; -import net.minecraft.world.level.chunk.storage.RegionFileVersion; -import net.minecraft.world.level.chunk.storage.RegionStorageInfo; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import org.bxteam.divinemc.configuration.DivineConfig; - -public class AbstractRegionFileFactory { - @Contract("_, _, _, _ -> new") - public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { - return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); - } - - @Contract("_, _, _, _, _ -> new") - public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync, boolean canRecalcHeader) throws IOException { - return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync, canRecalcHeader); - } - - @Contract("_, _, _, _, _ -> new") - public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { - return getAbstractRegionFile(storageKey, path, directory, compressionFormat, dsync, true); - } - - @Contract("_, _, _, _, _, _ -> new") - public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, boolean canRecalcHeader) throws IOException { - final String fullFileName = path.getFileName().toString(); - final String[] fullNameSplit = fullFileName.split("\\."); - final String extensionName = fullNameSplit[fullNameSplit.length - 1]; - switch (RegionFileFormat.fromExtension(extensionName)) { - case UNKNOWN -> { - if (DivineConfig.throwOnUnknownExtension) { - throw new IllegalArgumentException("Unknown region file extension for file: " + fullFileName + "!"); - } - - return new RegionFile(storageKey, path, directory, compressionFormat, dsync); - } - - case LINEAR -> { - return new LinearRegionFile(path, storageKey.linearCompressionLevel()); - } - - default -> { - return new RegionFile(storageKey, path, directory, compressionFormat, dsync); - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java deleted file mode 100644 index 643aee5..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/LinearRegionFile.java +++ /dev/null @@ -1,309 +0,0 @@ -package org.bxteam.divinemc.region; - -import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO; -import com.github.luben.zstd.ZstdInputStream; -import com.github.luben.zstd.ZstdOutputStream; -import com.mojang.logging.LogUtils; -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.nio.ByteBuffer; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardCopyOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.TimeUnit; -import javax.annotation.Nullable; - -import net.jpountz.lz4.LZ4Compressor; -import net.jpountz.lz4.LZ4Factory; -import net.jpountz.lz4.LZ4FastDecompressor; -import net.minecraft.nbt.CompoundTag; -import net.minecraft.world.level.ChunkPos; -import org.slf4j.Logger; -import org.bxteam.divinemc.configuration.DivineConfig; - -public class LinearRegionFile implements AbstractRegionFile { - private static final long SUPERBLOCK = -4323716122432332390L; - private static final byte VERSION = 2; - private static final int HEADER_SIZE = 32; - private static final int FOOTER_SIZE = 8; - private static final Logger LOGGER = LogUtils.getLogger(); - private static final List SUPPORTED_VERSIONS = Arrays.asList((byte) 1, (byte) 2); - private final byte[][] buffer = new byte[1024][]; - private final int[] bufferUncompressedSize = new int[1024]; - private final int[] chunkTimestamps = new int[1024]; - private final LZ4Compressor compressor; - private final LZ4FastDecompressor decompressor; - private final int compressionLevel; - public boolean closed = false; - public Path path; - private volatile long lastFlushed = System.nanoTime(); - - public LinearRegionFile(Path file, int compression) throws IOException { - this.path = file; - this.compressionLevel = compression; - this.compressor = LZ4Factory.fastestInstance().fastCompressor(); - this.decompressor = LZ4Factory.fastestInstance().fastDecompressor(); - - File regionFile = new File(this.path.toString()); - - Arrays.fill(this.bufferUncompressedSize, 0); - - if (!regionFile.canRead()) return; - - try (FileInputStream fileStream = new FileInputStream(regionFile); - DataInputStream rawDataStream = new DataInputStream(fileStream)) { - - long superBlock = rawDataStream.readLong(); - if (superBlock != SUPERBLOCK) - throw new RuntimeException("Invalid superblock: " + superBlock + " in " + file); - - byte version = rawDataStream.readByte(); - if (!SUPPORTED_VERSIONS.contains(version)) - throw new RuntimeException("Invalid version: " + version + " in " + file); - - // Skip newestTimestamp (Long) + Compression level (Byte) + Chunk count (Short): Unused. - rawDataStream.skipBytes(11); - - int dataCount = rawDataStream.readInt(); - long fileLength = file.toFile().length(); - if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) - throw new IOException("Invalid file length: " + this.path + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE)); - - rawDataStream.skipBytes(8); // Skip data hash (Long): Unused. - - byte[] rawCompressed = new byte[dataCount]; - rawDataStream.readFully(rawCompressed, 0, dataCount); - - superBlock = rawDataStream.readLong(); - if (superBlock != SUPERBLOCK) - throw new IOException("Footer superblock invalid " + this.path); - - try (DataInputStream dataStream = new DataInputStream(new ZstdInputStream(new ByteArrayInputStream(rawCompressed)))) { - - int[] starts = new int[1024]; - for (int i = 0; i < 1024; i++) { - starts[i] = dataStream.readInt(); - dataStream.skipBytes(4); // Skip timestamps (Int): Unused. - } - - for (int i = 0; i < 1024; i++) { - if (starts[i] > 0) { - int size = starts[i]; - byte[] b = new byte[size]; - dataStream.readFully(b, 0, size); - - int maxCompressedLength = this.compressor.maxCompressedLength(size); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = this.compressor.compress(b, 0, size, compressed, 0, maxCompressedLength); - b = new byte[compressedLength]; - System.arraycopy(compressed, 0, b, 0, compressedLength); - - this.buffer[i] = b; - this.bufferUncompressedSize[i] = size; - } - } - } - } - } - - private static int getChunkIndex(int x, int z) { - return (x & 31) + ((z & 31) << 5); - } - - private static int getTimestamp() { - return (int) (System.currentTimeMillis() / 1000L); - } - - public void flush() throws IOException { - flushWrapper(); // sync - } - - public void flushWrapper() { - try { - save(); - } catch (IOException e) { - LOGGER.error("Failed to flush region file {}", path.toAbsolutePath(), e); - } - } - - public boolean doesChunkExist(ChunkPos pos) throws Exception { - throw new Exception("doesChunkExist is a stub"); - } - - private synchronized void save() throws IOException { - long timestamp = getTimestamp(); - short chunkCount = 0; - - File tempFile = new File(path.toString() + ".tmp"); - - try (FileOutputStream fileStream = new FileOutputStream(tempFile); - ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream(); - ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, this.compressionLevel); - DataOutputStream zstdDataStream = new DataOutputStream(zstdStream); - DataOutputStream dataStream = new DataOutputStream(fileStream)) { - - dataStream.writeLong(SUPERBLOCK); - dataStream.writeByte(VERSION); - dataStream.writeLong(timestamp); - dataStream.writeByte(this.compressionLevel); - - ArrayList byteBuffers = new ArrayList<>(); - for (int i = 0; i < 1024; i++) { - if (this.bufferUncompressedSize[i] != 0) { - chunkCount += 1; - byte[] content = new byte[bufferUncompressedSize[i]]; - this.decompressor.decompress(buffer[i], 0, content, 0, bufferUncompressedSize[i]); - - byteBuffers.add(content); - } else byteBuffers.add(null); - } - for (int i = 0; i < 1024; i++) { - zstdDataStream.writeInt(this.bufferUncompressedSize[i]); // Write uncompressed size - zstdDataStream.writeInt(this.chunkTimestamps[i]); // Write timestamp - } - for (int i = 0; i < 1024; i++) { - if (byteBuffers.get(i) != null) - zstdDataStream.write(byteBuffers.get(i), 0, byteBuffers.get(i).length); - } - zstdDataStream.close(); - - dataStream.writeShort(chunkCount); - - byte[] compressed = zstdByteArray.toByteArray(); - - dataStream.writeInt(compressed.length); - dataStream.writeLong(0); - - dataStream.write(compressed, 0, compressed.length); - dataStream.writeLong(SUPERBLOCK); - - dataStream.flush(); - fileStream.getFD().sync(); - fileStream.getChannel().force(true); // Ensure atomicity on Btrfs - } - Files.move(tempFile.toPath(), this.path, StandardCopyOption.REPLACE_EXISTING); - this.lastFlushed = System.nanoTime(); - } - - public synchronized void write(ChunkPos pos, ByteBuffer buffer) { - try { - byte[] b = toByteArray(new ByteArrayInputStream(buffer.array())); - int uncompressedSize = b.length; - - int maxCompressedLength = this.compressor.maxCompressedLength(b.length); - byte[] compressed = new byte[maxCompressedLength]; - int compressedLength = this.compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength); - b = new byte[compressedLength]; - System.arraycopy(compressed, 0, b, 0, compressedLength); - - int index = getChunkIndex(pos.x, pos.z); - this.buffer[index] = b; - this.chunkTimestamps[index] = getTimestamp(); - this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize; - } catch (IOException e) { - LOGGER.error("Chunk write IOException {} {}", e, this.path); - } - - if ((System.nanoTime() - this.lastFlushed) >= TimeUnit.NANOSECONDS.toSeconds(DivineConfig.linearFlushFrequency)) { - this.flushWrapper(); - } - } - - public DataOutputStream getChunkDataOutputStream(ChunkPos pos) { - return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos))); - } - - @Override - public MoonriseRegionFileIO.RegionDataController.WriteData moonrise$startWrite(CompoundTag data, ChunkPos pos) throws IOException { - final DataOutputStream out = this.getChunkDataOutputStream(pos); - - return new ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData( - data, ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO.RegionDataController.WriteData.WriteResult.WRITE, - out, regionFile -> out.close() - ); - } - - private byte[] toByteArray(InputStream in) throws IOException { - ByteArrayOutputStream out = new ByteArrayOutputStream(); - byte[] tempBuffer = new byte[4096]; - - int length; - while ((length = in.read(tempBuffer)) >= 0) { - out.write(tempBuffer, 0, length); - } - - return out.toByteArray(); - } - - @Nullable - public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) { - if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) { - byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]]; - this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]); - return new DataInputStream(new ByteArrayInputStream(content)); - } - return null; - } - - public void clear(ChunkPos pos) { - int i = getChunkIndex(pos.x, pos.z); - this.buffer[i] = null; - this.bufferUncompressedSize[i] = 0; - this.chunkTimestamps[i] = getTimestamp(); - this.flushWrapper(); - } - - public Path getPath() { - return this.path; - } - - public boolean hasChunk(ChunkPos pos) { - return this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] > 0; - } - - public void close() throws IOException { - if (closed) return; - closed = true; - flush(); // sync - } - - public boolean recalculateHeader() { - return false; - } - - public void setOversized(int x, int z, boolean something) { - } - - public CompoundTag getOversizedData(int x, int z) throws IOException { - throw new IOException("getOversizedData is a stub " + this.path); - } - - public boolean isOversized(int x, int z) { - return false; - } - - private class ChunkBuffer extends ByteArrayOutputStream { - private final ChunkPos pos; - - public ChunkBuffer(ChunkPos chunkcoordintpair) { - super(); - this.pos = chunkcoordintpair; - } - - public void close() { - ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); - LinearRegionFile.this.write(this.pos, bytebuffer); - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java b/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java deleted file mode 100644 index c7f10dc..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/region/RegionFileFormat.java +++ /dev/null @@ -1,55 +0,0 @@ -package org.bxteam.divinemc.region; - -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.NotNull; -import java.util.Locale; - -public enum RegionFileFormat { - LINEAR(".linear"), - MCA(".mca"), - UNKNOWN(null); - - private final String extensionName; - - RegionFileFormat(String extensionName) { - this.extensionName = extensionName; - } - - public String getExtensionName() { - return this.extensionName; - } - - @Contract(pure = true) - public static RegionFileFormat fromName(@NotNull String name) { - switch (name.toUpperCase(Locale.ROOT)) { - default -> { - return UNKNOWN; - } - - case "MCA" -> { - return MCA; - } - - case "LINEAR" -> { - return LINEAR; - } - } - } - - @Contract(pure = true) - public static RegionFileFormat fromExtension(@NotNull String name) { - switch (name.toLowerCase()) { - case "mca" -> { - return MCA; - } - - case "linear" -> { - return LINEAR; - } - - default -> { - return UNKNOWN; - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Globals.java b/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Globals.java deleted file mode 100644 index 7fb6008..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Globals.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.bxteam.divinemc.seed; - -import com.google.common.collect.Iterables; -import net.minecraft.server.level.ServerLevel; -import org.bxteam.divinemc.configuration.DivineConfig; - -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.Optional; - -public class Globals { - public static final int WORLD_SEED_LONGS = 16; - public static final int WORLD_SEED_BITS = WORLD_SEED_LONGS * 64; - - public static final long[] worldSeed = new long[WORLD_SEED_LONGS]; - public static final ThreadLocal dimension = ThreadLocal.withInitial(() -> 0); - - public enum Salt { - UNDEFINED, - BASTION_FEATURE, - WOODLAND_MANSION_FEATURE, - MINESHAFT_FEATURE, - BURIED_TREASURE_FEATURE, - NETHER_FORTRESS_FEATURE, - PILLAGER_OUTPOST_FEATURE, - GEODE_FEATURE, - NETHER_FOSSIL_FEATURE, - OCEAN_MONUMENT_FEATURE, - RUINED_PORTAL_FEATURE, - POTENTIONAL_FEATURE, - GENERATE_FEATURE, - JIGSAW_PLACEMENT, - STRONGHOLDS, - POPULATION, - DECORATION, - SLIME_CHUNK - } - - public static void setupGlobals(ServerLevel world) { - if (!DivineConfig.enableSecureSeed) return; - - long[] seed = world.getServer().getWorldData().worldGenOptions().featureSeed(); - System.arraycopy(seed, 0, worldSeed, 0, WORLD_SEED_LONGS); - int worldIndex = Iterables.indexOf(world.getServer().levelKeys(), it -> it == world.dimension()); - if (worldIndex == -1) - worldIndex = world.getServer().levelKeys().size(); // if we are in world construction it may not have been added to the map yet - dimension.set(worldIndex); - } - - public static long[] createRandomWorldSeed() { - long[] seed = new long[WORLD_SEED_LONGS]; - SecureRandom rand = new SecureRandom(); - for (int i = 0; i < WORLD_SEED_LONGS; i++) { - seed[i] = rand.nextLong(); - } - return seed; - } - - // 1024-bit string -> 16 * 64 long[] - public static Optional parseSeed(String seedStr) { - if (seedStr.isEmpty()) return Optional.empty(); - - if (seedStr.length() != WORLD_SEED_BITS) { - throw new IllegalArgumentException("Secure seed length must be " + WORLD_SEED_BITS + "-bit but found " + seedStr.length() + "-bit."); - } - - long[] seed = new long[WORLD_SEED_LONGS]; - - for (int i = 0; i < WORLD_SEED_LONGS; i++) { - int start = i * 64; - int end = start + 64; - String seedSection = seedStr.substring(start, end); - - BigInteger seedInDecimal = new BigInteger(seedSection, 2); - seed[i] = seedInDecimal.longValue(); - } - - return Optional.of(seed); - } - - // 16 * 64 long[] -> 1024-bit string - public static String seedToString(long[] seed) { - StringBuilder sb = new StringBuilder(); - - for (long longV : seed) { - // Convert to 64-bit binary string per long - // Use format to keep 64-bit length, and use 0 to complete space - String binaryStr = String.format("%64s", Long.toBinaryString(longV)).replace(' ', '0'); - - sb.append(binaryStr); - } - - return sb.toString(); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Hashing.java b/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Hashing.java deleted file mode 100644 index 930ddc1..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/Hashing.java +++ /dev/null @@ -1,73 +0,0 @@ -package org.bxteam.divinemc.seed; - -public class Hashing { - // https://en.wikipedia.org/wiki/BLAKE_(hash_function) - // https://github.com/bcgit/bc-java/blob/master/core/src/main/java/org/bouncycastle/crypto/digests/Blake2bDigest.java - - private final static long[] blake2b_IV = { - 0x6a09e667f3bcc908L, 0xbb67ae8584caa73bL, 0x3c6ef372fe94f82bL, - 0xa54ff53a5f1d36f1L, 0x510e527fade682d1L, 0x9b05688c2b3e6c1fL, - 0x1f83d9abfb41bd6bL, 0x5be0cd19137e2179L - }; - - private final static byte[][] blake2b_sigma = { - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3}, - {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4}, - {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8}, - {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13}, - {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9}, - {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11}, - {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10}, - {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5}, - {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0}, - {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, - {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3} - }; - - public static long[] hashWorldSeed(long[] worldSeed) { - long[] result = blake2b_IV.clone(); - result[0] ^= 0x01010040; - hash(worldSeed, result, new long[16], 0, false); - return result; - } - - public static void hash(long[] message, long[] chainValue, long[] internalState, long messageOffset, boolean isFinal) { - assert message.length == 16; - assert chainValue.length == 8; - assert internalState.length == 16; - - System.arraycopy(chainValue, 0, internalState, 0, chainValue.length); - System.arraycopy(blake2b_IV, 0, internalState, chainValue.length, 4); - internalState[12] = messageOffset ^ blake2b_IV[4]; - internalState[13] = blake2b_IV[5]; - if (isFinal) internalState[14] = ~blake2b_IV[6]; - internalState[15] = blake2b_IV[7]; - - for (int round = 0; round < 12; round++) { - G(message[blake2b_sigma[round][0]], message[blake2b_sigma[round][1]], 0, 4, 8, 12, internalState); - G(message[blake2b_sigma[round][2]], message[blake2b_sigma[round][3]], 1, 5, 9, 13, internalState); - G(message[blake2b_sigma[round][4]], message[blake2b_sigma[round][5]], 2, 6, 10, 14, internalState); - G(message[blake2b_sigma[round][6]], message[blake2b_sigma[round][7]], 3, 7, 11, 15, internalState); - G(message[blake2b_sigma[round][8]], message[blake2b_sigma[round][9]], 0, 5, 10, 15, internalState); - G(message[blake2b_sigma[round][10]], message[blake2b_sigma[round][11]], 1, 6, 11, 12, internalState); - G(message[blake2b_sigma[round][12]], message[blake2b_sigma[round][13]], 2, 7, 8, 13, internalState); - G(message[blake2b_sigma[round][14]], message[blake2b_sigma[round][15]], 3, 4, 9, 14, internalState); - } - - for (int i = 0; i < 8; i++) { - chainValue[i] ^= internalState[i] ^ internalState[i + 8]; - } - } - - private static void G(long m1, long m2, int posA, int posB, int posC, int posD, long[] internalState) { - internalState[posA] = internalState[posA] + internalState[posB] + m1; - internalState[posD] = Long.rotateRight(internalState[posD] ^ internalState[posA], 32); - internalState[posC] = internalState[posC] + internalState[posD]; - internalState[posB] = Long.rotateRight(internalState[posB] ^ internalState[posC], 24); // replaces 25 of BLAKE - internalState[posA] = internalState[posA] + internalState[posB] + m2; - internalState[posD] = Long.rotateRight(internalState[posD] ^ internalState[posA], 16); - internalState[posC] = internalState[posC] + internalState[posD]; - internalState[posB] = Long.rotateRight(internalState[posB] ^ internalState[posC], 63); // replaces 11 of BLAKE - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/WorldgenCryptoRandom.java b/divinemc-server/src/main/java/org/bxteam/divinemc/seed/WorldgenCryptoRandom.java deleted file mode 100644 index d30487c..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/seed/WorldgenCryptoRandom.java +++ /dev/null @@ -1,159 +0,0 @@ -package org.bxteam.divinemc.seed; - -import net.minecraft.util.Mth; -import net.minecraft.util.RandomSource; -import net.minecraft.world.level.levelgen.LegacyRandomSource; -import net.minecraft.world.level.levelgen.WorldgenRandom; -import org.jetbrains.annotations.NotNull; - -import java.util.Arrays; - -public class WorldgenCryptoRandom extends WorldgenRandom { - // hash the world seed to guard against badly chosen world seeds - private static final long[] HASHED_ZERO_SEED = Hashing.hashWorldSeed(new long[Globals.WORLD_SEED_LONGS]); - private static final ThreadLocal LAST_SEEN_WORLD_SEED = ThreadLocal.withInitial(() -> new long[Globals.WORLD_SEED_LONGS]); - private static final ThreadLocal HASHED_WORLD_SEED = ThreadLocal.withInitial(() -> HASHED_ZERO_SEED); - - private final long[] worldSeed = new long[Globals.WORLD_SEED_LONGS]; - private final long[] randomBits = new long[8]; - private int randomBitIndex; - private static final int MAX_RANDOM_BIT_INDEX = 64 * 8; - private static final int LOG2_MAX_RANDOM_BIT_INDEX = 9; - private long counter; - private final long[] message = new long[16]; - private final long[] cachedInternalState = new long[16]; - - public WorldgenCryptoRandom(int x, int z, Globals.Salt typeSalt, long salt) { - super(new LegacyRandomSource(0L)); - if (typeSalt != null) { - this.setSecureSeed(x, z, typeSalt, salt); - } - } - - public void setSecureSeed(int x, int z, Globals.Salt typeSalt, long salt) { - System.arraycopy(Globals.worldSeed, 0, this.worldSeed, 0, Globals.WORLD_SEED_LONGS); - message[0] = ((long) x << 32) | ((long) z & 0xffffffffL); - message[1] = ((long) Globals.dimension.get() << 32) | ((long) salt & 0xffffffffL); - message[2] = typeSalt.ordinal(); - message[3] = counter = 0; - randomBitIndex = MAX_RANDOM_BIT_INDEX; - } - - private long[] getHashedWorldSeed() { - if (!Arrays.equals(worldSeed, LAST_SEEN_WORLD_SEED.get())) { - HASHED_WORLD_SEED.set(Hashing.hashWorldSeed(worldSeed)); - System.arraycopy(worldSeed, 0, LAST_SEEN_WORLD_SEED.get(), 0, Globals.WORLD_SEED_LONGS); - } - return HASHED_WORLD_SEED.get(); - } - - private void moreRandomBits() { - message[3] = counter++; - System.arraycopy(getHashedWorldSeed(), 0, randomBits, 0, 8); - Hashing.hash(message, randomBits, cachedInternalState, 64, true); - } - - private long getBits(int count) { - if (randomBitIndex >= MAX_RANDOM_BIT_INDEX) { - moreRandomBits(); - randomBitIndex -= MAX_RANDOM_BIT_INDEX; - } - - int alignment = randomBitIndex & 63; - if ((randomBitIndex >>> 6) == ((randomBitIndex + count) >>> 6)) { - long result = (randomBits[randomBitIndex >>> 6] >>> alignment) & ((1L << count) - 1); - randomBitIndex += count; - return result; - } else { - long result = (randomBits[randomBitIndex >>> 6] >>> alignment) & ((1L << (64 - alignment)) - 1); - randomBitIndex += count; - if (randomBitIndex >= MAX_RANDOM_BIT_INDEX) { - moreRandomBits(); - randomBitIndex -= MAX_RANDOM_BIT_INDEX; - } - alignment = randomBitIndex & 63; - result <<= alignment; - result |= (randomBits[randomBitIndex >>> 6] >>> (64 - alignment)) & ((1L << alignment) - 1); - - return result; - } - } - - @Override - public @NotNull RandomSource fork() { - WorldgenCryptoRandom fork = new WorldgenCryptoRandom(0, 0, null, 0); - - System.arraycopy(Globals.worldSeed, 0, fork.worldSeed, 0, Globals.WORLD_SEED_LONGS); - fork.message[0] = this.message[0]; - fork.message[1] = this.message[1]; - fork.message[2] = this.message[2]; - fork.message[3] = this.message[3]; - fork.randomBitIndex = this.randomBitIndex; - fork.counter = this.counter; - fork.nextLong(); - - return fork; - } - - @Override - public int next(int bits) { - return (int) getBits(bits); - } - - @Override - public void consumeCount(int count) { - randomBitIndex += count; - if (randomBitIndex >= MAX_RANDOM_BIT_INDEX * 2) { - randomBitIndex -= MAX_RANDOM_BIT_INDEX; - counter += randomBitIndex >>> LOG2_MAX_RANDOM_BIT_INDEX; - randomBitIndex &= MAX_RANDOM_BIT_INDEX - 1; - randomBitIndex += MAX_RANDOM_BIT_INDEX; - } - } - - @Override - public int nextInt(int bound) { - int bits = Mth.ceillog2(bound); - int result; - do { - result = (int) getBits(bits); - } while (result >= bound); - - return result; - } - - @Override - public long nextLong() { - return getBits(64); - } - - @Override - public double nextDouble() { - return getBits(53) * 0x1.0p-53; - } - - @Override - public long setDecorationSeed(long worldSeed, int blockX, int blockZ) { - setSecureSeed(blockX, blockZ, Globals.Salt.POPULATION, 0); - return ((long) blockX << 32) | ((long) blockZ & 0xffffffffL); - } - - @Override - public void setFeatureSeed(long populationSeed, int index, int step) { - setSecureSeed((int) (populationSeed >> 32), (int) populationSeed, Globals.Salt.DECORATION, index + 10000L * step); - } - - @Override - public void setLargeFeatureSeed(long worldSeed, int chunkX, int chunkZ) { - super.setLargeFeatureSeed(worldSeed, chunkX, chunkZ); - } - - @Override - public void setLargeFeatureWithSalt(long worldSeed, int regionX, int regionZ, int salt) { - super.setLargeFeatureWithSalt(worldSeed, regionX, regionZ, salt); - } - - public static RandomSource seedSlimeChunk(int chunkX, int chunkZ) { - return new WorldgenCryptoRandom(chunkX, chunkZ, Globals.Salt.SLIME_CHUNK, 0); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/tracker/MultithreadedTracker.java b/divinemc-server/src/main/java/org/bxteam/divinemc/tracker/MultithreadedTracker.java deleted file mode 100644 index 454d852..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/tracker/MultithreadedTracker.java +++ /dev/null @@ -1,142 +0,0 @@ -package org.bxteam.divinemc.tracker; - -import ca.spottedleaf.moonrise.common.list.ReferenceList; -import ca.spottedleaf.moonrise.common.misc.NearbyPlayers; -import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel; -import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup; -import ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity; -import ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity; -import com.google.common.util.concurrent.ThreadFactoryBuilder; -import net.minecraft.server.level.ChunkMap; -import net.minecraft.server.level.FullChunkStatus; -import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.entity.Entity; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.bxteam.divinemc.configuration.DivineConfig; - -import java.util.concurrent.Executor; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class MultithreadedTracker { - private static final Logger LOGGER = LogManager.getLogger("MultithreadedTracker"); - - public static class MultithreadedTrackerThread extends Thread { - @Override - public void run() { - super.run(); - } - } - - private static final Executor trackerExecutor = new ThreadPoolExecutor( - 1, - DivineConfig.asyncEntityTrackerMaxThreads, - DivineConfig.asyncEntityTrackerKeepalive, TimeUnit.SECONDS, - new LinkedBlockingQueue<>(), - new ThreadFactoryBuilder() - .setThreadFactory( - r -> new MultithreadedTrackerThread() { - @Override - public void run() { - r.run(); - } - } - ) - .setNameFormat("DivineMC Async Tracker Thread - %d") - .setPriority(Thread.NORM_PRIORITY - 2) - .build()); - - private MultithreadedTracker() { } - - public static Executor getTrackerExecutor() { - return trackerExecutor; - } - - public static void tick(ChunkSystemServerLevel level) { - try { - if (!DivineConfig.multithreadedCompatModeEnabled) { - tickAsync(level); - } else { - tickAsyncWithCompatMode(level); - } - } catch (Exception e) { - LOGGER.error("Error occurred while executing async task.", e); - } - } - - private static void tickAsync(ChunkSystemServerLevel level) { - final NearbyPlayers nearbyPlayers = level.moonrise$getNearbyPlayers(); - final ServerEntityLookup entityLookup = (ServerEntityLookup) level.moonrise$getEntityLookup(); - - final ReferenceList trackerEntities = entityLookup.trackerEntities; - final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked(); - - // Move tracking to off-main - trackerExecutor.execute(() -> { - for (final Entity entity : trackerEntitiesRaw) { - if (entity == null) continue; - - final ChunkMap.TrackedEntity tracker = ((EntityTrackerEntity) entity).moonrise$getTrackedEntity(); - - if (tracker == null) continue; - - ((EntityTrackerTrackedEntity) tracker).moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition())); - tracker.serverEntity.sendChanges(); - } - }); - } - - private static void tickAsyncWithCompatMode(ChunkSystemServerLevel level) { - final NearbyPlayers nearbyPlayers = level.moonrise$getNearbyPlayers(); - final ServerEntityLookup entityLookup = (ServerEntityLookup) level.moonrise$getEntityLookup(); - - final ReferenceList trackerEntities = entityLookup.trackerEntities; - final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked(); - final Runnable[] sendChangesTasks = new Runnable[trackerEntitiesRaw.length]; - int index = 0; - - for (final Entity entity : trackerEntitiesRaw) { - if (entity == null) continue; - - final ChunkMap.TrackedEntity tracker = ((EntityTrackerEntity) entity).moonrise$getTrackedEntity(); - - if (tracker == null) continue; - - ((EntityTrackerTrackedEntity) tracker).moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition())); - sendChangesTasks[index++] = () -> tracker.serverEntity.sendChanges(); // Collect send changes to task array - } - - // batch submit tasks - trackerExecutor.execute(() -> { - for (final Runnable sendChanges : sendChangesTasks) { - if (sendChanges == null) continue; - - sendChanges.run(); - } - }); - } - - // Original ChunkMap#newTrackerTick of Paper - // Just for diff usage for future update - @SuppressWarnings("DuplicatedCode") - private static void tickOriginal(ServerLevel level) { - 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) level).moonrise$getEntityLookup(); - - final ca.spottedleaf.moonrise.common.list.ReferenceList trackerEntities = entityLookup.trackerEntities; - final Entity[] trackerEntitiesRaw = trackerEntities.getRawDataUnchecked(); - for (int i = 0, len = trackerEntities.size(); i < len; ++i) { - final Entity entity = trackerEntitiesRaw[i]; - final ChunkMap.TrackedEntity tracker = ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerEntity) entity).moonrise$getTrackedEntity(); - if (tracker == null) { - continue; - } - ((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity) tracker).moonrise$tick(((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity) entity).moonrise$getChunkData().nearbyPlayers); - if (((ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity) tracker).moonrise$hasPlayers() - || ((ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity) entity).moonrise$getChunkStatus().isOrAfter(FullChunkStatus.ENTITY_TICKING)) { - tracker.serverEntity.sendChanges(); - } - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncDataSaving.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncDataSaving.java deleted file mode 100644 index 274c7c6..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/AsyncDataSaving.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bxteam.divinemc.util; - -import net.minecraft.Util; -import org.bxteam.divinemc.configuration.DivineConfig; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutorService; - -public class AsyncDataSaving { - private AsyncDataSaving() { - throw new IllegalStateException("This class cannot be instantiated"); - } - - public static void saveAsync(Runnable runnable) { - if (!DivineConfig.asyncPlayerDataSaveEnabled) { - runnable.run(); - return; - } - - ExecutorService ioExecutor = Util.backgroundExecutor().service(); - CompletableFuture.runAsync(runnable, ioExecutor); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/BlockEntityTickersList.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/BlockEntityTickersList.java deleted file mode 100644 index 6a934c8..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/BlockEntityTickersList.java +++ /dev/null @@ -1,90 +0,0 @@ -package org.bxteam.divinemc.util; - -import it.unimi.dsi.fastutil.ints.IntOpenHashSet; -import it.unimi.dsi.fastutil.objects.ObjectArrayList; -import net.minecraft.world.level.block.entity.TickingBlockEntity; - -import java.util.Arrays; -import java.util.Collection; - -/** - * A list for ServerLevel's blockEntityTickers - *

- * This list is behaving identically to ObjectArrayList, but it has an additional method, `removeAllByIndex`, that allows a list of integers to be passed indicating what - * indexes should be deleted from the list - *

- * This is faster than using removeAll, since we don't need to compare the identity of each block entity, and faster than looping through each index manually and deleting with remove, - * since we don't need to resize the array every single remove. - */ -public final class BlockEntityTickersList extends ObjectArrayList { - private final IntOpenHashSet toRemove = new IntOpenHashSet(); - private int startSearchFromIndex = -1; - - /** Creates a new array list with {@link #DEFAULT_INITIAL_CAPACITY} capacity. */ - public BlockEntityTickersList() { - super(); - } - - /** - * Creates a new array list and fills it with a given collection. - * - * @param c a collection that will be used to fill the array list. - */ - public BlockEntityTickersList(final Collection c) { - super(c); - } - - /** - * Marks an entry as removed - * - * @param index the index of the item on the list to be marked as removed - */ - public void markAsRemoved(final int index) { - // The block entities list always loop starting from 0, so we only need to check if the startSearchFromIndex is -1 and that's it - if (this.startSearchFromIndex == -1) - this.startSearchFromIndex = index; - this.toRemove.add(index); - } - - /** - * Removes elements that have been marked as removed. - */ - public void removeMarkedEntries() { - if (this.startSearchFromIndex == -1) // No entries in the list, skip - return; - - removeAllByIndex(startSearchFromIndex, toRemove); - toRemove.clear(); - this.startSearchFromIndex = -1; // Reset the start search index - } - - /** - * Removes elements by their index. - */ - private void removeAllByIndex(final int startSearchFromIndex, final IntOpenHashSet c) { // can't use Set because we want to avoid autoboxing when using contains - final int requiredMatches = c.size(); - if (requiredMatches == 0) - return; // exit early, we don't need to do anything - - final Object[] a = this.a; - int j = startSearchFromIndex; - int matches = 0; - for (int i = startSearchFromIndex; i < size; i++) { // If the user knows the first index to be removed, we can skip a lot of unnecessary comparsions - if (!c.contains(i)) { - a[j++] = a[i]; - } else { - matches++; - } - - if (matches == requiredMatches) { // Exit the loop if we already removed everything, we don't need to check anything else - if (i != (size - 1)) { // If it isn't the last index... - System.arraycopy(a, i + 1, a, j, size - i - 1); - } - j = size - requiredMatches; - break; - } - } - Arrays.fill(a, j, size, null); - size = j; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/LagCompensation.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/LagCompensation.java deleted file mode 100644 index c0739dc..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/LagCompensation.java +++ /dev/null @@ -1,113 +0,0 @@ -package org.bxteam.divinemc.util; - -import it.unimi.dsi.fastutil.doubles.DoubleArrayList; - -import java.util.Collections; -import java.util.List; - -public class LagCompensation { - public static float tt20(float ticks, boolean limitZero) { - float newTicks = (float) rawTT20(ticks); - - if (limitZero) return newTicks > 0 ? newTicks : 1; - else return newTicks; - } - - public static int tt20(int ticks, boolean limitZero) { - int newTicks = (int) Math.ceil(rawTT20(ticks)); - - if (limitZero) return newTicks > 0 ? newTicks : 1; - else return newTicks; - } - - public static double tt20(double ticks, boolean limitZero) { - double newTicks = rawTT20(ticks); - - if (limitZero) return newTicks > 0 ? newTicks : 1; - else return newTicks; - } - - public static double rawTT20(double ticks) { - return ticks == 0 ? 0 : ticks * TPSCalculator.getMostAccurateTPS() / TPSCalculator.MAX_TPS; - } - - public static class TPSCalculator { - public static Long lastTick; - public static Long currentTick; - private static double allMissedTicks = 0; - private static final List tpsHistory = Collections.synchronizedList(new DoubleArrayList()); - private static final int historyLimit = 40; - - public static final int MAX_TPS = 20; - public static final int FULL_TICK = 50; - - private TPSCalculator() {} - - public static void onTick() { - if (currentTick != null) { - lastTick = currentTick; - } - - currentTick = System.currentTimeMillis(); - addToHistory(getTPS()); - clearMissedTicks(); - missedTick(); - } - - private static void addToHistory(double tps) { - if (tpsHistory.size() >= historyLimit) { - tpsHistory.removeFirst(); - } - - tpsHistory.add(tps); - } - - public static long getMSPT() { - return currentTick - lastTick; - } - - public static double getAverageTPS() { - double sum = 0.0; - for (double value : tpsHistory) { - sum += value; - } - return tpsHistory.isEmpty() ? 0.1 : sum / tpsHistory.size(); - } - - public static double getTPS() { - if (lastTick == null) return -1; - if (getMSPT() <= 0) return 0.1; - - double tps = 1000 / (double) getMSPT(); - return tps > MAX_TPS ? MAX_TPS : tps; - } - - public static void missedTick() { - if (lastTick == null) return; - - long mspt = getMSPT() <= 0 ? 50 : getMSPT(); - double missedTicks = (mspt / (double) FULL_TICK) - 1; - allMissedTicks += missedTicks <= 0 ? 0 : missedTicks; - } - - public static double getMostAccurateTPS() { - return Math.min(getTPS(), getAverageTPS()); - } - - public double getAllMissedTicks() { - return allMissedTicks; - } - - public static int applicableMissedTicks() { - return (int) Math.floor(allMissedTicks); - } - - public static void clearMissedTicks() { - allMissedTicks -= applicableMissedTicks(); - } - - public void resetMissedTicks() { - allMissedTicks = 0; - } - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/c2me/ObjectCachingUtils.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/c2me/ObjectCachingUtils.java deleted file mode 100644 index d5f3ad9..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/c2me/ObjectCachingUtils.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.bxteam.divinemc.util.c2me; - -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; - -import java.util.BitSet; -import java.util.function.IntFunction; - -public class ObjectCachingUtils { - private static final IntFunction bitSetConstructor = BitSet::new; - - public static ThreadLocal> BITSETS = ThreadLocal.withInitial(Int2ObjectOpenHashMap::new); - - private ObjectCachingUtils() {} - - public static BitSet getCachedOrNewBitSet(int bits) { - final BitSet bitSet = BITSETS.get().computeIfAbsent(bits, bitSetConstructor); - bitSet.clear(); - return bitSet; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/carpetams/BlockPatternHelper.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/carpetams/BlockPatternHelper.java deleted file mode 100644 index 44b8a70..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/carpetams/BlockPatternHelper.java +++ /dev/null @@ -1,32 +0,0 @@ -package org.bxteam.divinemc.util.carpetams; - -import com.google.common.cache.LoadingCache; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.pattern.BlockInWorld; -import net.minecraft.world.level.block.state.pattern.BlockPattern; - -/** - * Original here - * - * @author 1024-byteeeee - */ -public class BlockPatternHelper { - public static BlockPattern.BlockPatternMatch partialSearchAround(BlockPattern pattern, Level world, BlockPos pos) { - LoadingCache loadingCache = BlockPattern.createLevelCache(world, false); - int i = Math.max(Math.max(pattern.getWidth(), pattern.getHeight()), pattern.getDepth()); - - for (BlockPos blockPos : BlockPos.betweenClosed(pos, pos.offset(i - 1, 0, i - 1))) { - for (Direction direction : Direction.values()) { - for (Direction direction2 : Direction.values()) { - BlockPattern.BlockPatternMatch result; - if (direction2 == direction || direction2 == direction.getOpposite() || (result = pattern.matches(blockPos, direction, direction2, loadingCache)) == null) - continue; - return result; - } - } - } - return null; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/CompactSineLUT.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/CompactSineLUT.java deleted file mode 100644 index e372330..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/CompactSineLUT.java +++ /dev/null @@ -1,88 +0,0 @@ -package org.bxteam.divinemc.util.lithium; - -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. - *

- * sin(-x) = -sin(x) - * ... to eliminate negative angles from the LUT. - *

- * sin(x) = sin(pi/2 - x) - * ... to eliminate supplementary angles from the LUT. - *

- * 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. - *

- * 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. - *

- * 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 Rust - * @author jellysquid3 Additional optimizations, port to Java - */ -public class CompactSineLUT { - private static final int[] SIN_INT = new int[16384 + 1]; - private static final float SIN_MIDPOINT; - - static { - // Copy the sine table, covering to raw int bits - for (int i = 0; i < SIN_INT.length; i++) { - SIN_INT[i] = Float.floatToRawIntBits(Mth.SIN[i]); - } - - SIN_MIDPOINT = Mth.SIN[Mth.SIN.length / 2]; - - // Test that the lookup table is correct during runtime - for (int i = 0; i < Mth.SIN.length; i++) { - float expected = Mth.SIN[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] Mth#sin(float) - public static float sin(float f) { - return lookup((int) (f * 10430.378f) & 0xFFFF); - } - - // [VanillaCopy] Mth#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 SIN_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(SIN_INT[pos] ^ neg); - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/IterateOutwardsCache.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/IterateOutwardsCache.java deleted file mode 100644 index 5a9febc..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/IterateOutwardsCache.java +++ /dev/null @@ -1,69 +0,0 @@ -package org.bxteam.divinemc.util.lithium; - -import it.unimi.dsi.fastutil.longs.LongArrayList; -import it.unimi.dsi.fastutil.longs.LongList; -import java.util.Iterator; -import java.util.Random; -import java.util.concurrent.ConcurrentHashMap; -import net.minecraft.core.BlockPos; - -/** - * @author 2No2Name, original implemenation by SuperCoder7979 and Gegy1000 - */ -public class IterateOutwardsCache { - // POS_ZERO must not be replaced with BlockPos.ORIGIN, otherwise iterateOutwards at BlockPos.ORIGIN will not use the cache - public static final BlockPos POS_ZERO = new BlockPos(0,0,0); - - private final ConcurrentHashMap table; - private final int capacity; - private final Random random; - - public IterateOutwardsCache(int capacity) { - this.capacity = capacity; - this.table = new ConcurrentHashMap<>(31); - this.random = new Random(); - } - - private void fillPositionsWithIterateOutwards(LongList entry, int xRange, int yRange, int zRange) { - // Add all positions to the cached list - for (BlockPos pos : BlockPos.withinManhattan(POS_ZERO, xRange, yRange, zRange)) { - entry.add(pos.asLong()); - } - } - - public LongList getOrCompute(int xRange, int yRange, int zRange) { - long key = BlockPos.asLong(xRange, yRange, zRange); - - LongArrayList entry = this.table.get(key); - if (entry != null) { - return entry; - } - - // Cache miss: compute and store - entry = new LongArrayList(128); - - this.fillPositionsWithIterateOutwards(entry, xRange, yRange, zRange); - - // decrease the array size, as of now it won't be modified anymore anyways - entry.trim(); - - // this might overwrite an entry as the same entry could have been computed and added during this thread's computation - // we do not use computeIfAbsent, as it can delay other threads for too long - Object previousEntry = this.table.put(key, entry); - - if (previousEntry == null && this.table.size() > this.capacity) { - // prevent a memory leak by randomly removing about 1/8th of the elements when the exceed the desired capacity is exceeded - final Iterator iterator = this.table.keySet().iterator(); - // prevent an unlikely infinite loop caused by another thread filling the table concurrently using counting - for (int i = -this.capacity; iterator.hasNext() && i < 5; i++) { - Long key2 = iterator.next(); - // random is not threadsafe, but it doesn't matter here, because we don't need quality random numbers - if (this.random.nextInt(8) == 0 && key2 != key) { - iterator.remove(); - } - } - } - - return entry; - } -} diff --git a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/LongList2BlockPosMutableIterable.java b/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/LongList2BlockPosMutableIterable.java deleted file mode 100644 index 2f0ad27..0000000 --- a/divinemc-server/src/main/java/org/bxteam/divinemc/util/lithium/LongList2BlockPosMutableIterable.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.bxteam.divinemc.util.lithium; - -import it.unimi.dsi.fastutil.longs.LongIterator; -import it.unimi.dsi.fastutil.longs.LongList; -import java.util.Iterator; -import net.minecraft.core.BlockPos; - -/** - * @author 2No2Name - */ -public class LongList2BlockPosMutableIterable implements Iterable { - private final LongList positions; - private final int xOffset, yOffset, zOffset; - - public LongList2BlockPosMutableIterable(BlockPos offset, LongList posList) { - this.xOffset = offset.getX(); - this.yOffset = offset.getY(); - this.zOffset = offset.getZ(); - this.positions = posList; - } - - @Override - public Iterator iterator() { - return new Iterator() { - private final LongIterator it = LongList2BlockPosMutableIterable.this.positions.iterator(); - private final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); - - @Override - public boolean hasNext() { - return it.hasNext(); - } - - @Override - public net.minecraft.core.BlockPos next() { - long nextPos = this.it.nextLong(); - return this.pos.set( - LongList2BlockPosMutableIterable.this.xOffset + BlockPos.getX(nextPos), - LongList2BlockPosMutableIterable.this.yOffset + BlockPos.getY(nextPos), - LongList2BlockPosMutableIterable.this.zOffset + BlockPos.getZ(nextPos)); - } - }; - } -}