mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
cleanup patches for rework
This commit is contained in:
@@ -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.
|
||||
*
|
||||
@@ -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.
|
||||
+ * <ul>
|
||||
+ * <li>A yaw of 0 or 360 represents the positive z direction.
|
||||
+ * <li>A yaw of 180 represents the negative z direction.
|
||||
+ * <li>A yaw of 90 represents the negative x direction.
|
||||
+ * <li>A yaw of 270 represents the positive x direction.
|
||||
+ * </ul>
|
||||
+ * 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.
|
||||
+ * <ul>
|
||||
+ * <li>A pitch of 0 represents level forward facing.
|
||||
+ * <li>A pitch of 90 represents downward facing, or negative y
|
||||
+ * direction.
|
||||
+ * <li>A pitch of -90 represents upward facing, or positive y direction.
|
||||
+ * </ul>
|
||||
+ * 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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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}.
|
||||
*
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
*
|
||||
@@ -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<String>());
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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("<grey>Current Purpur Version: %s%s*", distance == 0 ? "<green>" : distance > 0 ? "<yellow>" : "<red>", Bukkit.getVersion()),
|
||||
+ ChatColor.parseMM("<grey>Current DivineMC Version: %s%s*", distance == 0 ? "<green>" : distance > 0 ? "<yellow>" : "<red>", Bukkit.getVersion()), // DivineMC - Rebrand
|
||||
// Purpur end
|
||||
msg
|
||||
);
|
||||
@@ -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
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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
|
||||
@@ -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 {
|
||||
@@ -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
|
||||
@@ -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<FullChunkStatus> fullStatus;
|
||||
@Nullable
|
||||
private LevelChunk.PostLoadProcessor postLoad;
|
||||
- private final Int2ObjectMap<GameEventListenerRegistry> 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<Block> blockTicks;
|
||||
private final LevelChunkTicks<Fluid> 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<GameEventListener> listeners = Lists.newArrayList();
|
||||
- private final Set<GameEventListener> listenersToRemove = Sets.newHashSet();
|
||||
- private final List<GameEventListener> listenersToAdd = Lists.newArrayList();
|
||||
+ //private final Set<GameEventListener> listenersToRemove = Sets.newHashSet(); // DivineMC - Commented out
|
||||
+ //private final List<GameEventListener> 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<Vec3> 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<GameEvent.ListenerInfo> 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 extends GameEventListener> {
|
||||
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
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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() {
|
||||
@@ -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<RecipeMap> imp
|
||||
|
||||
public <I extends RecipeInput, T extends Recipe<I>> Optional<RecipeHolder<T>> getRecipeFor(RecipeType<T> recipeType, I input, Level level) {
|
||||
// CraftBukkit start
|
||||
- List<RecipeHolder<T>> list = this.recipes.getRecipesFor(recipeType, input, level).toList();
|
||||
+ List<RecipeHolder<T>> list = this.recipes.getRecipesForList(recipeType, input, level); // DivineMC - Carpet-Fixes - Remove streams to be faster
|
||||
return (list.isEmpty()) ? Optional.empty() : Optional.of(list.getLast()); // CraftBukkit - SPIGOT-4638: last recipe gets priority
|
||||
// CraftBukkit end
|
||||
}
|
||||
diff --git a/net/minecraft/world/item/crafting/RecipeMap.java b/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
index 098753ddd215b6ef5915fac71d8c4f0b19cf4142..1778e58dca9430756d59d07bf017ebe4cc1f4ed4 100644
|
||||
--- a/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
+++ b/net/minecraft/world/item/crafting/RecipeMap.java
|
||||
@@ -75,4 +75,24 @@ public class RecipeMap {
|
||||
public <I extends RecipeInput, T extends Recipe<I>> Stream<RecipeHolder<T>> getRecipesFor(RecipeType<T> type, I input, Level level) {
|
||||
return input.isEmpty() ? Stream.empty() : this.byType(type).stream().filter(recipeHolder -> recipeHolder.value().matches(input, level));
|
||||
}
|
||||
+
|
||||
+ // DivineMC start - Carpet-Fixes - Remove streams to be faster
|
||||
+ public <I extends RecipeInput, T extends Recipe<I>> java.util.List<RecipeHolder<T>> getRecipesForList(RecipeType<T> type, I input, Level world) {
|
||||
+ java.util.List<RecipeHolder<T>> list;
|
||||
+
|
||||
+ if (input.isEmpty()) {
|
||||
+ return java.util.List.of();
|
||||
+ } else {
|
||||
+ list = new java.util.ArrayList<>();
|
||||
+ }
|
||||
+
|
||||
+ for (RecipeHolder<T> recipeholder : this.byType(type)) {
|
||||
+ if (recipeholder.value().matches(input, world)) {
|
||||
+ list.add(recipeholder);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return list;
|
||||
+ }
|
||||
+ // DivineMC end - Carpet-Fixes - Remove streams to be faster
|
||||
}
|
||||
@@ -1,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<ArgumentSignatures.Entry> entries) {
|
||||
private static final int MAX_ARGUMENT_NAME_LENGTH = 16;
|
||||
|
||||
public ArgumentSignatures(FriendlyByteBuf buffer) {
|
||||
- this(buffer.readCollection(FriendlyByteBuf.<List<ArgumentSignatures.Entry>>limitValue(ArrayList::new, 8), ArgumentSignatures.Entry::new));
|
||||
+ this(readSign(buffer)); // DivineMC - No chat sign
|
||||
}
|
||||
|
||||
+ // DivineMC start - No chat sign
|
||||
+ private static List<ArgumentSignatures.Entry> 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 <T> void writeJsonWithCodec(Codec<T> codec, T value, int maxLength) {
|
||||
// Paper end - Adventure; add max length parameter
|
||||
DataResult<JsonElement> 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<ServerboundChatPacket> 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
|
||||
@@ -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<Holder<PoiType>, BlockPos> pair : set) {
|
||||
+ map.computeIfAbsent(
|
||||
+ pair.getSecond().asLong(),
|
||||
+ m -> new JitteredLinearRetry(mob.level().random, time)
|
||||
+ );
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
+ BlockPos blockPos = path.getTarget();
|
||||
+ poiManager.getType(blockPos).ifPresent(poiType -> {
|
||||
+ poiManager.take(acquirablePois,
|
||||
+ (holder, blockPos2) -> blockPos2.equals(blockPos),
|
||||
+ blockPos,
|
||||
+ 1
|
||||
+ );
|
||||
+ memoryAccessor.set(GlobalPos.of(level.dimension(), blockPos));
|
||||
+ entityEventId.ifPresent(status -> level.broadcastEntityEvent(mob, status));
|
||||
+ map.clear();
|
||||
+ DebugPackets.sendPoiTicketCountPacket(level, blockPos);
|
||||
+ });
|
||||
});
|
||||
} else {
|
||||
- for (Pair<Holder<PoiType>, BlockPos> pair : set) {
|
||||
- map.computeIfAbsent(pair.getSecond().asLong(), l -> new AcquirePoi.JitteredLinearRetry(level.random, time));
|
||||
+ Path path = findPathToPois(mob, set);
|
||||
+ if (path != null && path.canReach()) {
|
||||
+ BlockPos target = path.getTarget();
|
||||
+ poiManager.getType(target).ifPresent(holder -> {
|
||||
+ poiManager.take(acquirablePois, (holder1, blockPos) -> blockPos.equals(target), target, 1);
|
||||
+ memoryAccessor.set(GlobalPos.of(level.dimension(), target));
|
||||
+ entityEventId.ifPresent(id -> level.broadcastEntityEvent(mob, id));
|
||||
+ map.clear();
|
||||
+ DebugPackets.sendPoiTicketCountPacket(level, target);
|
||||
+ });
|
||||
+ } else {
|
||||
+ for (Pair<Holder<PoiType>, BlockPos> pair : set) {
|
||||
+ map.computeIfAbsent(pair.getSecond().asLong(), l -> new AcquirePoi.JitteredLinearRetry(level.random, time));
|
||||
+ }
|
||||
}
|
||||
}
|
||||
+ // DivineMC end - Async path processing
|
||||
|
||||
return true;
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java b/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java
|
||||
index 621ba76784f2b92790eca62be4d0688834335ab6..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<Mob> {
|
||||
private int remainingCooldown;
|
||||
@Nullable
|
||||
private Path path;
|
||||
+ private boolean finishedProcessing; // DivineMC - async path processing
|
||||
@Nullable
|
||||
private BlockPos lastTargetPos;
|
||||
private float speedModifier;
|
||||
@@ -53,9 +54,11 @@ public class MoveToTargetSink extends Behavior<Mob> {
|
||||
Brain<?> brain = owner.getBrain();
|
||||
WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get();
|
||||
boolean flag = this.reachedTarget(owner, walkTarget);
|
||||
- if (!flag && this.tryComputePath(owner, walkTarget, level.getGameTime())) {
|
||||
+ if (!org.bxteam.divinemc.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<Mob> {
|
||||
|
||||
@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<WalkTarget> memory = entity.getBrain().getMemory(MemoryModuleType.WALK_TARGET);
|
||||
boolean flag = memory.map(MoveToTargetSink::isWalkTargetSpectator).orElse(false);
|
||||
@@ -95,27 +99,98 @@ public class MoveToTargetSink extends Behavior<Mob> {
|
||||
|
||||
@Override
|
||||
protected void start(ServerLevel level, Mob entity, long gameTime) {
|
||||
+ // DivineMC start - start processing
|
||||
+ if (org.bxteam.divinemc.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> 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<Holder<PoiType>> type = poiManager.getType(target);
|
||||
- if (type.isPresent()) {
|
||||
- walkTarget.set(new WalkTarget(target, speedModifier, 1));
|
||||
- DebugPackets.sendPoiTicketCountPacket(level, target);
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (org.bxteam.divinemc.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<Holder<PoiType>> optional2 = poiManager.getType(blockPos);
|
||||
+ if (optional2.isPresent()) {
|
||||
+ walkTarget.set(new WalkTarget(blockPos, speedModifier, 1));
|
||||
+ DebugPackets.sendPoiTicketCountPacket(level, blockPos);
|
||||
+ }
|
||||
+ });
|
||||
+ } else {
|
||||
+ Path path = AcquirePoi.findPathToPois(mob, set);
|
||||
+ if (path != null && path.canReach()) {
|
||||
+ BlockPos target = path.getTarget();
|
||||
+ Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
+ if (type.isPresent()) {
|
||||
+ walkTarget.set(new WalkTarget(target, speedModifier, 1));
|
||||
+ DebugPackets.sendPoiTicketCountPacket(level, target);
|
||||
+ }
|
||||
+ } else if (mutableInt.getValue() < 5) {
|
||||
+ map.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < mutableLong.getValue());
|
||||
}
|
||||
- } else if (mutableInt.getValue() < 5) {
|
||||
- map.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < mutableLong.getValue());
|
||||
}
|
||||
+ // DivineMC end - async path processing
|
||||
|
||||
return true;
|
||||
} else {
|
||||
diff --git a/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java b/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
|
||||
index d8f532c5e68ff4dff933556c4f981e9474c044e6..37f3d3888ea2a862d006cf2b201f9715bcb8ce1e 100644
|
||||
--- a/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
|
||||
+++ b/net/minecraft/world/entity/ai/goal/DoorInteractGoal.java
|
||||
@@ -56,7 +56,7 @@ public abstract class DoorInteractGoal extends Goal {
|
||||
} else {
|
||||
GroundPathNavigation groundPathNavigation = (GroundPathNavigation)this.mob.getNavigation();
|
||||
Path path = groundPathNavigation.getPath();
|
||||
- if (path != null && !path.isDone()) {
|
||||
+ if (path != null && path.isProcessed() && !path.isDone()) { // DivineMC - async path processing
|
||||
for (int i = 0; i < Math.min(path.getNextNodeIndex() + 2, path.getNodeCount()); i++) {
|
||||
Node node = path.getNode(i);
|
||||
this.doorPos = new BlockPos(node.x, node.y + 1, node.z);
|
||||
diff --git a/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java b/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java
|
||||
index 66a02fe7594522ef391d67e09856bf3f70fe597d..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<Mob> {
|
||||
java.util.List<Pair<Holder<PoiType>, BlockPos>> poiposes = new java.util.ArrayList<>();
|
||||
// don't ask me why it's unbounded. ask mojang.
|
||||
io.papermc.paper.util.PoiAccess.findAnyPoiPositions(poiManager, type -> type.is(PoiTypes.HOME), predicate, entity.blockPosition(), level.purpurConfig.villagerNearestBedSensorSearchRadius, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); // Purpur - Configurable villager search radius
|
||||
- Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
||||
// Paper end - optimise POI access
|
||||
- if (path != null && path.canReach()) {
|
||||
- BlockPos target = path.getTarget();
|
||||
- Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
- if (type.isPresent()) {
|
||||
- entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, target);
|
||||
+ // DivineMC start - async pathfinding
|
||||
+ if (org.bxteam.divinemc.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<Holder<PoiType>> optional = poiManager.getType(blockPos);
|
||||
+ if (optional.isPresent()) {
|
||||
+ entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, blockPos);
|
||||
+ }
|
||||
+ });
|
||||
+ } else {
|
||||
+ Path path = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes));
|
||||
+ if (path != null && path.canReach()) {
|
||||
+ BlockPos target = path.getTarget();
|
||||
+ Optional<Holder<PoiType>> type = poiManager.getType(target);
|
||||
+ if (type.isPresent()) {
|
||||
+ entity.getBrain().setMemory(MemoryModuleType.NEAREST_BED, target);
|
||||
+ }
|
||||
+ } else if (this.triedCount < 5) {
|
||||
+ this.batchCache.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < this.lastUpdate);
|
||||
}
|
||||
- } else if (this.triedCount < 5) {
|
||||
- this.batchCache.long2LongEntrySet().removeIf(entry -> entry.getLongValue() < this.lastUpdate);
|
||||
}
|
||||
+ // DivineMC end - async pathfinding
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/Bee.java b/net/minecraft/world/entity/animal/Bee.java
|
||||
index d5727999eb67ff30dbf47865d59452483338e170..ddbee0f0f42fae0a26321bb324d22f5e7520ae72 100644
|
||||
--- a/net/minecraft/world/entity/animal/Bee.java
|
||||
+++ b/net/minecraft/world/entity/animal/Bee.java
|
||||
@@ -936,7 +936,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
} else {
|
||||
Bee.this.pathfindRandomlyTowards(Bee.this.hivePos);
|
||||
}
|
||||
- } else {
|
||||
+ } else if (navigation.getPath() != null && navigation.getPath().isProcessed()) { // DivineMC - check processing
|
||||
boolean flag = this.pathfindDirectlyTowards(Bee.this.hivePos);
|
||||
if (!flag) {
|
||||
this.dropAndBlacklistHive();
|
||||
@@ -990,7 +990,7 @@ public class Bee extends Animal implements NeutralMob, FlyingAnimal {
|
||||
return true;
|
||||
} else {
|
||||
Path path = Bee.this.navigation.getPath();
|
||||
- return path != null && path.getTarget().equals(pos) && path.canReach() && path.isDone();
|
||||
+ return path != null && path.isProcessed() && path.getTarget().equals(pos) && path.canReach() && path.isDone(); // DivineMC - ensure path is processed
|
||||
}
|
||||
}
|
||||
}
|
||||
diff --git a/net/minecraft/world/entity/animal/frog/Frog.java b/net/minecraft/world/entity/animal/frog/Frog.java
|
||||
index 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<Holder<FrogVariant>> {
|
||||
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<Holder<FrogVariant>> {
|
||||
@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<BlockPos> targetPositions, float maxRange, int accuracy, float searchDepthMultiplier) {
|
||||
- this.openSet.clear();
|
||||
- this.nodeEvaluator.prepare(region, mob);
|
||||
- Node start = this.nodeEvaluator.getStart();
|
||||
+ // DivineMC start - use a generated evaluator if we have one otherwise run sync
|
||||
+ if (!org.bxteam.divinemc.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.Entry<Target, BlockPos>> map = Lists.newArrayList();
|
||||
for (BlockPos pos : targetPositions) {
|
||||
- map.add(new java.util.AbstractMap.SimpleEntry<>(this.nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos));
|
||||
+ map.add(new java.util.AbstractMap.SimpleEntry<>(nodeEvaluator.getTarget(pos.getX(), pos.getY(), pos.getZ()), pos)); // DivineMC - handle nodeEvaluatorGenerator
|
||||
}
|
||||
// Paper end - Perf: remove streams and optimize collection
|
||||
- Path path = this.findPath(start, map, maxRange, accuracy, searchDepthMultiplier);
|
||||
- this.nodeEvaluator.done();
|
||||
- return path;
|
||||
+ // DivineMC start - async path processing
|
||||
+ if (this.nodeEvaluatorGenerator == null) {
|
||||
+ // run sync :(
|
||||
+ org.bxteam.divinemc.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<Map.Entry<Target, BlockPos>> positions, float maxRange, int accuracy, float searchDepthMultiplier) { // Paper - optimize collection
|
||||
+ // DivineMC start - split pathfinding into the original sync method for compat and processing for delaying
|
||||
+ try {
|
||||
+ return this.processPath(this.nodeEvaluator, node, positions, maxRange, accuracy, searchDepthMultiplier);
|
||||
+ } catch (Exception e) {
|
||||
+ e.printStackTrace();
|
||||
+ return null;
|
||||
+ } finally {
|
||||
+ this.nodeEvaluator.done();
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ private synchronized @org.jetbrains.annotations.NotNull Path processPath(NodeEvaluator nodeEvaluator, Node node, List<Map.Entry<Target, BlockPos>> positions, float maxRange, int accuracy, float searchDepthMultiplier) { // sync to only use the caching functions in this class on a single thread
|
||||
+ org.apache.commons.lang3.Validate.isTrue(!positions.isEmpty()); // ensure that we have at least one position, which means we'll always return a path
|
||||
+ // DivineMC end - split pathfinding into the original sync method for compat and processing for delaying
|
||||
ProfilerFiller profilerFiller = Profiler.get();
|
||||
profilerFiller.push("find_path");
|
||||
profilerFiller.markForCharting(MetricCategory.PATH_FINDING);
|
||||
@@ -95,7 +140,7 @@ public class PathFinder {
|
||||
}
|
||||
|
||||
if (!(node1.distanceTo(node) >= maxRange)) {
|
||||
- int neighbors = this.nodeEvaluator.getNeighbors(this.neighbors, node1);
|
||||
+ int neighbors = nodeEvaluator.getNeighbors(this.neighbors, node1); // DivineMC - use provided nodeEvaluator
|
||||
|
||||
for (int i2 = 0; i2 < neighbors; i2++) {
|
||||
Node node2 = this.neighbors[i2];
|
||||
@@ -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<DedicatedServerPropertie
|
||||
String string = this.get("level-seed", "");
|
||||
boolean flag = this.get("generate-structures", true);
|
||||
long l = WorldOptions.parseSeed(string).orElse(WorldOptions.randomSeed());
|
||||
- this.worldOptions = new WorldOptions(l, flag, false);
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ if (org.bxteam.divinemc.configuration.DivineConfig.enableSecureSeed) {
|
||||
+ String featureSeedStr = this.get("feature-level-seed", "");
|
||||
+ long[] featureSeed = org.bxteam.divinemc.seed.Globals.parseSeed(featureSeedStr)
|
||||
+ .orElse(org.bxteam.divinemc.seed.Globals.createRandomWorldSeed());
|
||||
+
|
||||
+ this.worldOptions = new WorldOptions(l, featureSeed, flag, false);
|
||||
+ } else {
|
||||
+ this.worldOptions = new WorldOptions(l, flag, false);
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
this.worldDimensionData = new DedicatedServerProperties.WorldDimensionData(
|
||||
this.get("generator-settings", property -> GsonHelper.parse(!property.isEmpty() ? property : "{}"), new JsonObject()),
|
||||
this.get("level-type", property -> property.toLowerCase(Locale.ROOT), WorldPresets.NORMAL.location().toString())
|
||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||
index 6540b2d6a1062d883811ce240c49d30d1925b291..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<BlockPos, BlockEntity> blockEntities = new Object2ObjectOpenHashMap<>();
|
||||
protected final LevelHeightAccessor levelHeightAccessor;
|
||||
protected final LevelChunkSection[] sections;
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ private boolean slimeChunk;
|
||||
+ private boolean hasComputedSlimeChunk;
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
// CraftBukkit start - SPIGOT-6814: move to IChunkAccess to account for 1.17 to 1.18 chunk upgrading.
|
||||
private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
||||
public org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.DirtyCraftPersistentDataContainer(ChunkAccess.DATA_TYPE_REGISTRY);
|
||||
@@ -191,6 +195,17 @@ public abstract class ChunkAccess implements BiomeManager.NoiseBiomeSource, Ligh
|
||||
return GameEventListenerRegistry.NOOP;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ public boolean isSlimeChunk() {
|
||||
+ if (!hasComputedSlimeChunk) {
|
||||
+ hasComputedSlimeChunk = true;
|
||||
+ slimeChunk = 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<Structure> registry = level.registryAccess().lookupOrThrow(Registries.STRUCTURE);
|
||||
Map<Integer, List<Structure>> map = registry.stream().collect(Collectors.groupingBy(structure1 -> structure1.step().ordinal()));
|
||||
List<FeatureSorter.StepFeatureData> list = this.featuresPerStep.get();
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new XoroshiroRandomSource(RandomSupport.generateUniqueSeed()));
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom = org.bxteam.divinemc.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<Holder<Biome>> set = new ObjectArraySet<>();
|
||||
ChunkPos.rangeClosed(sectionPos.chunk(), 1).forEach(chunkPos -> {
|
||||
@@ -556,8 +560,18 @@ public abstract class ChunkGenerator {
|
||||
} else {
|
||||
ArrayList<StructureSet.StructureSelectionEntry> list1 = new ArrayList<>(list.size());
|
||||
list1.addAll(list);
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(0L));
|
||||
- worldgenRandom.setLargeFeatureSeed(structureState.getLevelSeed(), pos.x, pos.z);
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom;
|
||||
+ if (org.bxteam.divinemc.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<CompletableFuture<ChunkPos>> list = new ArrayList<>(count);
|
||||
int spread = placement.spread();
|
||||
HolderSet<Biome> holderSet = placement.preferredBiomes();
|
||||
- RandomSource randomSource = RandomSource.create();
|
||||
- // Paper start - Add missing structure set seed configs
|
||||
- if (this.conf.strongholdSeed != null && structureSet.is(net.minecraft.world.level.levelgen.structure.BuiltinStructureSets.STRONGHOLDS)) {
|
||||
- randomSource.setSeed(this.conf.strongholdSeed);
|
||||
- } else {
|
||||
- // Paper end - Add missing structure set seed configs
|
||||
- randomSource.setSeed(this.concentricRingsSeed);
|
||||
- } // Paper - Add missing structure set seed configs
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ RandomSource randomSource = org.bxteam.divinemc.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<ChunkAccess> apply(WorldGenContext worldGenContext, StaticCache2D<GenerationChunkHolder> 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<WorldOptions> CODEC = RecordCodecBuilder.mapCodec(
|
||||
- instance -> instance.group(
|
||||
+ instance -> isSecureSeedEnabled
|
||||
+ ? instance.group(
|
||||
Codec.LONG.fieldOf("seed").stable().forGetter(WorldOptions::seed),
|
||||
+ Codec.LONG_STREAM.fieldOf("feature_seed").stable().forGetter(WorldOptions::featureSeedStream),
|
||||
Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldOptions::generateStructures),
|
||||
Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldOptions::generateBonusChest),
|
||||
- Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(worldOptions -> worldOptions.legacyCustomOptions)
|
||||
- )
|
||||
- .apply(instance, instance.stable(WorldOptions::new))
|
||||
+ Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(generatorOptions -> generatorOptions.legacyCustomOptions)).apply(instance, instance.stable(WorldOptions::new))
|
||||
+ : instance.group(
|
||||
+ Codec.LONG.fieldOf("seed").stable().forGetter(WorldOptions::seed),
|
||||
+ Codec.BOOL.fieldOf("generate_features").orElse(true).stable().forGetter(WorldOptions::generateStructures),
|
||||
+ Codec.BOOL.fieldOf("bonus_chest").orElse(false).stable().forGetter(WorldOptions::generateBonusChest),
|
||||
+ Codec.STRING.lenientOptionalFieldOf("legacy_custom_options").stable().forGetter(worldOptions -> worldOptions.legacyCustomOptions)).apply(instance, instance.stable(WorldOptions::new))
|
||||
);
|
||||
- public static final WorldOptions DEMO_OPTIONS = new WorldOptions("North Carolina".hashCode(), true, true);
|
||||
+ public static final WorldOptions DEMO_OPTIONS = isSecureSeedEnabled
|
||||
+ ? new WorldOptions("North Carolina".hashCode(), 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<String> legacyCustomOptions;
|
||||
@@ -28,9 +39,21 @@ public class WorldOptions {
|
||||
this(seed, generateStructures, generateBonusChest, Optional.empty());
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ public WorldOptions(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest) {
|
||||
+ this(seed, featureSeed, generateStructures, bonusChest, Optional.empty());
|
||||
+ }
|
||||
+
|
||||
public static WorldOptions defaultWithRandomSeed() {
|
||||
- return new WorldOptions(randomSeed(), true, false);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(randomSeed(), 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<String> legacyCustomOptions) {
|
||||
+ this(seed, featureSeed.toArray(), generateStructures, bonusChest, legacyCustomOptions);
|
||||
}
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
|
||||
public static WorldOptions testWorldWithRandomSeed() {
|
||||
return new WorldOptions(randomSeed(), false, false);
|
||||
@@ -43,10 +66,27 @@ public class WorldOptions {
|
||||
this.legacyCustomOptions = legacyCustomOptions;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ private WorldOptions(long seed, long[] featureSeed, boolean generateStructures, boolean bonusChest, Optional<String> legacyCustomOptions) {
|
||||
+ this(seed, generateStructures, bonusChest, legacyCustomOptions);
|
||||
+ this.featureSeed = featureSeed;
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
+
|
||||
public long seed() {
|
||||
return this.seed;
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ public long[] featureSeed() {
|
||||
+ return this.featureSeed;
|
||||
+ }
|
||||
+
|
||||
+ public java.util.stream.LongStream featureSeedStream() {
|
||||
+ return java.util.stream.LongStream.of(this.featureSeed);
|
||||
+ }
|
||||
+ // DivineMC end - Implement Secure Seed
|
||||
+
|
||||
public boolean generateStructures() {
|
||||
return this.generateStructures;
|
||||
}
|
||||
@@ -59,17 +99,25 @@ public class WorldOptions {
|
||||
return this.legacyCustomOptions.isPresent();
|
||||
}
|
||||
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
public WorldOptions withBonusChest(boolean generateBonusChest) {
|
||||
- return new WorldOptions(this.seed, this.generateStructures, generateBonusChest, this.legacyCustomOptions);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(this.seed, this.featureSeed, this.generateStructures, generateBonusChest, this.legacyCustomOptions)
|
||||
+ : new WorldOptions(this.seed, this.generateStructures, generateBonusChest, this.legacyCustomOptions);
|
||||
}
|
||||
|
||||
public WorldOptions withStructures(boolean generateStructures) {
|
||||
- return new WorldOptions(this.seed, generateStructures, this.generateBonusChest, this.legacyCustomOptions);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(this.seed, this.featureSeed, generateStructures, this.generateBonusChest, this.legacyCustomOptions)
|
||||
+ : new WorldOptions(this.seed, generateStructures, this.generateBonusChest, this.legacyCustomOptions);
|
||||
}
|
||||
|
||||
public WorldOptions withSeed(OptionalLong seed) {
|
||||
- return new WorldOptions(seed.orElse(randomSeed()), this.generateStructures, this.generateBonusChest, this.legacyCustomOptions);
|
||||
+ return isSecureSeedEnabled
|
||||
+ ? new WorldOptions(seed.orElse(randomSeed()), 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<GeodeConfiguration> {
|
||||
int i1 = geodeConfiguration.maxGenOffset;
|
||||
List<Pair<BlockPos, Integer>> list = Lists.newLinkedList();
|
||||
int i2 = geodeConfiguration.distributionPoints.sample(randomSource);
|
||||
- WorldgenRandom worldgenRandom = new WorldgenRandom(new LegacyRandomSource(worldGenLevel.getSeed()));
|
||||
+ // DivineMC start - Implement Secure Seed
|
||||
+ WorldgenRandom worldgenRandom = org.bxteam.divinemc.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<BlockPos> list1 = Lists.newLinkedList();
|
||||
double d = (double)i2 / geodeConfiguration.outerWallDistance.getMaxValue();
|
||||
diff --git a/net/minecraft/world/level/levelgen/structure/Structure.java b/net/minecraft/world/level/levelgen/structure/Structure.java
|
||||
index 8328e864c72b7a358d6bb1f33459b8c4df2ecb1a..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<StructureTemplatePool> registry = registryAccess.lookupOrThrow(Registries.TEMPLATE_POOL);
|
||||
Rotation random = Rotation.getRandom(worldgenRandom);
|
||||
StructureTemplatePool structureTemplatePool = startPool.unwrapKey()
|
||||
@@ -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<Runnable> 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<ServerPlayerConnection> seenBy = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(); // Paper - Perf: optimise map impl
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ public final Set<ServerPlayerConnection> seenBy = org.bxteam.divinemc.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<ServerPlayer> players = Sets.newHashSet();
|
||||
+ // DivineMC start - Multithreaded tracker - players can be removed in async tracking
|
||||
+ private final Set<ServerPlayer> players = org.bxteam.divinemc.configuration.DivineConfig.multithreadedEnabled
|
||||
+ ? Sets.newConcurrentHashSet()
|
||||
+ : Sets.newHashSet();
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
private final Set<ServerPlayer> unmodifiablePlayers = Collections.unmodifiableSet(this.players);
|
||||
public boolean visible = true;
|
||||
|
||||
diff --git a/net/minecraft/server/level/ServerEntity.java b/net/minecraft/server/level/ServerEntity.java
|
||||
index 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<SynchedEntityData.DataValue<?>> list = entityData.packDirty();
|
||||
if (list != null) {
|
||||
this.trackedDataValues = entityData.getNonDefaultValues();
|
||||
- this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list));
|
||||
+ // DivineMC start - Multithreaded tracker - send in main thread
|
||||
+ ((ServerLevel) this.entity.level()).chunkSource.chunkMap.runOnTrackerMainThread(() ->
|
||||
+ this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), list))
|
||||
+ );
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
}
|
||||
|
||||
if (this.entity instanceof LivingEntity) {
|
||||
@@ -413,12 +426,17 @@ public class ServerEntity {
|
||||
final Set<AttributeInstance> 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<AttributeInstance> copy = new it.unimi.dsi.fastutil.objects.ObjectOpenHashSet<>(attributesToSync);
|
||||
+ ((ServerLevel) this.entity.level()).chunkSource.chunkMap.runOnTrackerMainThread(() -> {
|
||||
+ // CraftBukkit start - Send scaled max health
|
||||
+ if (this.entity instanceof ServerPlayer serverPlayer) {
|
||||
+ serverPlayer.getBukkitEntity().injectScaledMaxHealth(copy, false);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
+ this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy));
|
||||
+ });
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
}
|
||||
|
||||
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<Entity> getEntities() {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // Spigot
|
||||
+ //org.spigotmc.AsyncCatcher.catchOp("Chunk getEntities call"); // DivineMC - Multithreaded tracker
|
||||
return this.moonrise$getEntityLookup(); // Paper - rewrite chunk system
|
||||
}
|
||||
|
||||
diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java
|
||||
index 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<Relative> relatives) {
|
||||
- org.spigotmc.AsyncCatcher.catchOp("teleport"); // Paper
|
||||
+ //org.spigotmc.AsyncCatcher.catchOp("teleport"); // DivineMC - Multithreaded tracker
|
||||
// Paper start - Prevent teleporting dead entities
|
||||
if (this.player.isRemoved()) {
|
||||
LOGGER.info("Attempt to teleport removed player {} restricted", player.getScoreboardName());
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeInstance.java b/net/minecraft/world/entity/ai/attributes/AttributeInstance.java
|
||||
index 8013594bb4844e7a8abf28123958e7f632d39341..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<AttributeModifier.Operation, Map<ResourceLocation, AttributeModifier>> modifiersByOperation = Maps.newEnumMap(
|
||||
AttributeModifier.Operation.class
|
||||
);
|
||||
- private final Map<ResourceLocation, AttributeModifier> modifierById = new Object2ObjectArrayMap<>();
|
||||
- private final Map<ResourceLocation, AttributeModifier> permanentModifiers = new Object2ObjectArrayMap<>();
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ private final boolean multiThreadedTrackingEnabled = org.bxteam.divinemc.configuration.DivineConfig.multithreadedEnabled;
|
||||
+ private final Map<ResourceLocation, AttributeModifier> modifierById = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new Object2ObjectArrayMap<>();
|
||||
+ private final Map<ResourceLocation, AttributeModifier> permanentModifiers = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new Object2ObjectArrayMap<>();
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
private double baseValue;
|
||||
private boolean dirty = true;
|
||||
private double cachedValue;
|
||||
diff --git a/net/minecraft/world/entity/ai/attributes/AttributeMap.java b/net/minecraft/world/entity/ai/attributes/AttributeMap.java
|
||||
index a25d74592e89e3d6339479c6dc2b6f45d1932cfc..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<Holder<Attribute>, AttributeInstance> attributes = new Object2ObjectOpenHashMap<>();
|
||||
- private final Set<AttributeInstance> attributesToSync = new ObjectOpenHashSet<>();
|
||||
- private final Set<AttributeInstance> attributesToUpdate = new ObjectOpenHashSet<>();
|
||||
+ // DivineMC start - Multithreaded tracker
|
||||
+ private final boolean multiThreadedTrackingEnabled = org.bxteam.divinemc.configuration.DivineConfig.multithreadedEnabled;
|
||||
+ private final Map<Holder<Attribute>, AttributeInstance> attributes = multiThreadedTrackingEnabled ? new java.util.concurrent.ConcurrentHashMap<>() : new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(0);
|
||||
+ private final Set<AttributeInstance> attributesToSync = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
+ private final Set<AttributeInstance> attributesToUpdate = multiThreadedTrackingEnabled ? com.google.common.collect.Sets.newConcurrentHashSet() : new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<>(0);
|
||||
+ // DivineMC end - Multithreaded tracker
|
||||
private final AttributeSupplier supplier;
|
||||
private final net.minecraft.world.entity.LivingEntity entity; // Purpur - Ridables
|
||||
|
||||
@@ -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<TickTa
|
||||
// CraftBukkit end
|
||||
if (flush) {
|
||||
for (ServerLevel serverLevel2 : this.getAllLevels()) {
|
||||
- LOGGER.info("ThreadedAnvilChunkStorage ({}): All chunks are saved", serverLevel2.getChunkSource().chunkMap.getStorageName());
|
||||
+ LOGGER.info("ThreadedChunkStorage ({}): All chunks are saved", serverLevel2.getChunkSource().chunkMap.getStorageName()); // DivineMC - linear region format
|
||||
}
|
||||
|
||||
- LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved");
|
||||
+ LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // DivineMC - linear region format
|
||||
}
|
||||
|
||||
return flag;
|
||||
diff --git a/net/minecraft/util/worldupdate/WorldUpgrader.java b/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
index e0bcda2ddea0d6633445a7440fbf0d18e50a7653..7daa1fbdad6ed24dd874cf7b62a86d7e1a9636ea 100644
|
||||
--- a/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
+++ b/net/minecraft/util/worldupdate/WorldUpgrader.java
|
||||
@@ -72,7 +72,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
volatile int skipped;
|
||||
final Reference2FloatMap<ResourceKey<Level>> progressMap = Reference2FloatMaps.synchronize(new Reference2FloatOpenHashMap<>());
|
||||
volatile Component status = Component.translatable("optimizeWorld.stage.counting");
|
||||
- static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$");
|
||||
+ static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.(linear | mca)$"); // DivineMC - linear region format
|
||||
final DimensionDataStorage overworldDataStorage;
|
||||
|
||||
public WorldUpgrader(
|
||||
@@ -261,7 +261,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
}
|
||||
|
||||
private static List<WorldUpgrader.FileToUpgrade> getAllChunkPositions(RegionStorageInfo regionStorageInfo, Path path) {
|
||||
- File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(".mca"));
|
||||
+ File[] files = path.toFile().listFiles((directory, filename) -> filename.endsWith(".linear") || filename.endsWith(".mca")); // DivineMC - linear region format
|
||||
if (files == null) {
|
||||
return List.of();
|
||||
} else {
|
||||
@@ -274,7 +274,7 @@ public class WorldUpgrader implements AutoCloseable {
|
||||
int i1 = Integer.parseInt(matcher.group(2)) << 5;
|
||||
List<ChunkPos> list1 = Lists.newArrayList();
|
||||
|
||||
- try (RegionFile regionFile = new RegionFile(regionStorageInfo, file.toPath(), path, true)) {
|
||||
+ try (org.bxteam.divinemc.region.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<Level> 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<ChunkPos> chunksToUpgrade) {
|
||||
+ record FileToUpgrade(org.bxteam.divinemc.region.AbstractRegionFile file, List<ChunkPos> 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<RegionFile> regionCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
+ public final Long2ObjectLinkedOpenHashMap<org.bxteam.divinemc.region.AbstractRegionFile> 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<IOException> 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<IOException> 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<Level> 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
|
||||
}
|
||||
@@ -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
|
||||
@@ -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<TickTa
|
||||
|
||||
this.server.spark.tickStart(); // Paper - spark
|
||||
new com.destroystokyo.paper.event.server.ServerTickStartEvent(this.tickCount+1).callEvent(); // Paper - Server Tick Events
|
||||
+ if (org.bxteam.divinemc.configuration.DivineConfig.lagCompensationEnabled) org.bxteam.divinemc.util.LagCompensation.TPSCalculator.onTick(); // DivineMC - Lag Compensation
|
||||
this.tickCount++;
|
||||
this.tickRateManager.tick();
|
||||
this.tickChildren(hasTimeLeft);
|
||||
diff --git a/net/minecraft/world/level/material/LavaFluid.java b/net/minecraft/world/level/material/LavaFluid.java
|
||||
index 85629a43f5469a89dd6078d879f475e8212438ec..5e3d508b0ef80b20782ee6ed87389105031d42ea 100644
|
||||
--- a/net/minecraft/world/level/material/LavaFluid.java
|
||||
+++ b/net/minecraft/world/level/material/LavaFluid.java
|
||||
@@ -177,7 +177,13 @@ public abstract class LavaFluid extends FlowingFluid {
|
||||
|
||||
@Override
|
||||
public int getTickDelay(LevelReader level) {
|
||||
- return level.dimensionType().ultraWarm() ? level.getWorldBorder().world.purpurConfig.lavaSpeedNether : level.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur - Make lava flow speed configurable
|
||||
+ // DivineMC start - Lag Compensation
|
||||
+ if (org.bxteam.divinemc.configuration.DivineConfig.lagCompensationEnabled && org.bxteam.divinemc.configuration.DivineConfig.lagCompensationEnableForLava) {
|
||||
+ return level.dimensionType().ultraWarm() ? org.bxteam.divinemc.util.LagCompensation.tt20(level.getWorldBorder().world.purpurConfig.lavaSpeedNether, true) : org.bxteam.divinemc.util.LagCompensation.tt20(level.getWorldBorder().world.purpurConfig.lavaSpeedNotNether, true); // Purpur - Make lava flow speed configurable
|
||||
+ } else {
|
||||
+ return level.dimensionType().ultraWarm() ? level.getWorldBorder().world.purpurConfig.lavaSpeedNether : level.getWorldBorder().world.purpurConfig.lavaSpeedNotNether; // Purpur - Make lava flow speed configurable
|
||||
+ }
|
||||
+ // DivineMC end - Lag Compensation
|
||||
}
|
||||
|
||||
@Override
|
||||
diff --git a/net/minecraft/world/level/material/WaterFluid.java b/net/minecraft/world/level/material/WaterFluid.java
|
||||
index 2e4fed7c27910b6c886f710f33b0841c2a175837..22c205a11c6ec0e3c40bdb93235b70932c78b9be 100644
|
||||
--- a/net/minecraft/world/level/material/WaterFluid.java
|
||||
+++ b/net/minecraft/world/level/material/WaterFluid.java
|
||||
@@ -115,7 +115,13 @@ public abstract class WaterFluid extends FlowingFluid {
|
||||
|
||||
@Override
|
||||
public int getTickDelay(LevelReader level) {
|
||||
- return 5;
|
||||
+ // DivineMC start - Lag Compensation
|
||||
+ if (org.bxteam.divinemc.configuration.DivineConfig.lagCompensationEnabled && org.bxteam.divinemc.configuration.DivineConfig.lagCompensationEnableForWater) {
|
||||
+ return org.bxteam.divinemc.util.LagCompensation.tt20(5, true);
|
||||
+ } else {
|
||||
+ return 5;
|
||||
+ }
|
||||
+ // DivineMC end - Lag Compensation
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1,53 +0,0 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
||||
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());
|
||||
@@ -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<TickTa
|
||||
profilerFiller.push("tick");
|
||||
|
||||
try {
|
||||
+ // DivineMC start - MSPT Tracking for each world
|
||||
+ long i = Util.getNanos();
|
||||
serverLevel.tick(hasTimeLeft);
|
||||
+ long j = Util.getNanos() - i;
|
||||
+
|
||||
+ serverLevel.tickTimes5s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes10s.add(this.tickCount, j);
|
||||
+ serverLevel.tickTimes60s.add(this.tickCount, j);
|
||||
+ // DivineMC end - MSPT Tracking for each world
|
||||
} catch (Throwable var7) {
|
||||
CrashReport crashReport = CrashReport.forThrowable(var7, "Exception ticking world");
|
||||
serverLevel.fillReportDetails(crashReport);
|
||||
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
||||
index e6a55f6fa9f4b827d14ae29c82cb7e30cfa5d56a..b1cba7f14220f5bf2f2bbfeca34580de9ba0896e 100644
|
||||
--- a/net/minecraft/server/level/ServerLevel.java
|
||||
+++ b/net/minecraft/server/level/ServerLevel.java
|
||||
@@ -573,6 +573,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
|
||||
}
|
||||
// Paper end - chunk tick iteration
|
||||
|
||||
+ // DivineMC start - MSPT Tracking for each world
|
||||
+ public final MinecraftServer.TickTimes tickTimes5s = new MinecraftServer.TickTimes(100);
|
||||
+ public final MinecraftServer.TickTimes tickTimes10s = new MinecraftServer.TickTimes(200);
|
||||
+ public final MinecraftServer.TickTimes tickTimes60s = new MinecraftServer.TickTimes(1200);
|
||||
+ // DivineMC end - MSPT Tracking for each world
|
||||
+
|
||||
public ServerLevel(
|
||||
MinecraftServer server,
|
||||
Executor dispatcher,
|
||||
@@ -1,32 +0,0 @@
|
||||
--- a/io/papermc/paper/command/subcommands/FixLightCommand.java
|
||||
+++ b/io/papermc/paper/command/subcommands/FixLightCommand.java
|
||||
@@ -95,17 +_,22 @@
|
||||
((StarLightLightingProvider)lightengine).starlight$serverRelightChunks(chunks,
|
||||
(final ChunkPos chunkPos) -> {
|
||||
++relitChunks[0];
|
||||
- sender.getBukkitEntity().sendMessage(text().color(DARK_AQUA).append(
|
||||
- text("Relit chunk ", BLUE), text(chunkPos.toString()),
|
||||
- text(", progress: ", BLUE), text(ONE_DECIMAL_PLACES.get().format(100.0 * (double) (relitChunks[0]) / (double) pending[0]) + "%")
|
||||
- ));
|
||||
+ // DivineMC start - Make FixLight use action bar
|
||||
+ sender.getBukkitEntity().sendActionBar(text().color(DARK_AQUA).append(
|
||||
+ text("Relighting Chunks: ", DARK_AQUA), text(chunkPos.toString()),
|
||||
+ text(" " + relitChunks[0], net.kyori.adventure.text.format.NamedTextColor.YELLOW),
|
||||
+ text("/", DARK_AQUA),
|
||||
+ text(pending[0] + " ", net.kyori.adventure.text.format.NamedTextColor.YELLOW),
|
||||
+ text("(" + (int) (Math.round(100.0 * (double) (relitChunks[0]) / (double) pending[0])) + "%)", net.kyori.adventure.text.format.NamedTextColor.YELLOW)
|
||||
+ )); // DivineMC end - Make FixLight use action bar
|
||||
},
|
||||
(final int totalRelit) -> {
|
||||
final long end = System.nanoTime();
|
||||
sender.getBukkitEntity().sendMessage(text().color(DARK_AQUA).append(
|
||||
- text("Relit ", BLUE), text(totalRelit),
|
||||
- text(" chunks. Took ", BLUE), text(ONE_DECIMAL_PLACES.get().format(1.0e-6 * (end - start)) + "ms")
|
||||
- ));
|
||||
+ // DivineMC start - Make FixLight use action bar
|
||||
+ text("Relit ", DARK_AQUA), text(totalRelit, net.kyori.adventure.text.format.NamedTextColor.YELLOW),
|
||||
+ text(" chunks. Took ", DARK_AQUA), text(ONE_DECIMAL_PLACES.get().format(1.0e-6 * (end - start)) + "ms", net.kyori.adventure.text.format.NamedTextColor.YELLOW)
|
||||
+ )); // DivineMC end - Make FixLight use action bar
|
||||
if (done != null) {
|
||||
done.run();
|
||||
}
|
||||
@@ -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<BlockPos> 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();
|
||||
@@ -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<net.minecraft.world.entity.Entity> entitiesWithScheduledTasks = java.util.concurrent.ConcurrentHashMap.newKeySet(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
|
||||
public static <S extends MinecraftServer> S spin(Function<Thread, S> threadFunction) {
|
||||
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
||||
@@ -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");
|
||||
@@ -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
|
||||
@@ -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<ChunkMap.TrackedEntity> entityMap = new Int2ObjectOpenHashMap<>();
|
||||
+ public final Int2ObjectMap<ChunkMap.TrackedEntity> 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
|
||||
@@ -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<AttributeInstance> attributesToSync = ((LivingEntity)this.entity).getAttributes().getAttributesToSync();
|
||||
+ // DivineMC start - Suppress errors from dirty attributes
|
||||
+ Set<AttributeInstance> attributes = ((LivingEntity) this.entity).getAttributes().getAttributesToSync();
|
||||
+ final Set<AttributeInstance> 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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -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++) {
|
||||
@@ -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");
|
||||
@@ -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 {
|
||||
@@ -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
|
||||
@@ -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<T> extends AbstractCollection<T> {
|
||||
- private final Map<Class<?>, List<T>> byClass = Maps.newHashMap();
|
||||
+ private final Map<Class<?>, List<T>> byClass = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(); // DivineMC - lithium: collections.entity_by_type
|
||||
private final Class<T> baseClass;
|
||||
private final List<T> allInstances = Lists.newArrayList();
|
||||
|
||||
@@ -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) {
|
||||
@@ -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<R extends Runnable> implements ProfilerMeasured, TaskScheduler<R>, Executor {
|
||||
- public static final long BLOCK_TIME_NANOS = 100000L;
|
||||
+ public static final long BLOCK_TIME_NANOS = 2000000L; // DivineMC - Fix MC-183518
|
||||
private final String name;
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
private final Queue<R> pendingRunnables = Queues.newConcurrentLinkedQueue();
|
||||
@@ -146,8 +_,7 @@
|
||||
}
|
||||
|
||||
protected void waitForTasks() {
|
||||
- Thread.yield();
|
||||
- LockSupport.parkNanos("waiting for tasks", 100000L);
|
||||
+ LockSupport.parkNanos("waiting for tasks", 2000000L); // DivineMC - Fix MC-183518
|
||||
}
|
||||
|
||||
protected void doRunTask(R task) {
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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<? extends Animal> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
);
|
||||
@@ -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) {
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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<BlockPos> 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;
|
||||
@@ -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
|
||||
@@ -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.Key<?>, GameRules.Value<?>> rules, FeatureFlagSet enabledFeatures) {
|
||||
- this.rules = rules;
|
||||
+ this.rules = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(rules); // DivineMC - lithium: collections.gamerules
|
||||
this.enabledFeatures = enabledFeatures;
|
||||
|
||||
// Paper start - Perf: Use array for gamerule storage
|
||||
@@ -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<TickingBlockEntity> 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<TickingBlockEntity> 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<ServerExplosion.CacheKey, Float> explosionDensityCache = new HashMap<>(); // Paper - Optimize explosions
|
||||
public java.util.ArrayDeque<net.minecraft.world.level.block.RedstoneTorchBlock.Toggle> 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
|
||||
@@ -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<MobCategory> 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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Biome> getBiome(BlockPos pos) {
|
||||
- int i = pos.getX() - 2;
|
||||
- int i1 = pos.getY() - 2;
|
||||
- int i2 = pos.getZ() - 2;
|
||||
- int i3 = i >> 2;
|
||||
- int i4 = i1 >> 2;
|
||||
- int i5 = i2 >> 2;
|
||||
- double d = (i & 3) / 4.0;
|
||||
- double d1 = (i1 & 3) / 4.0;
|
||||
- double d2 = (i2 & 3) / 4.0;
|
||||
- int i6 = 0;
|
||||
- double d3 = Double.POSITIVE_INFINITY;
|
||||
-
|
||||
- for (int i7 = 0; i7 < 8; i7++) {
|
||||
- boolean flag = (i7 & 4) == 0;
|
||||
- boolean flag1 = (i7 & 2) == 0;
|
||||
- boolean flag2 = (i7 & 1) == 0;
|
||||
- int i8 = flag ? i3 : i3 + 1;
|
||||
- int i9 = flag1 ? i4 : i4 + 1;
|
||||
- int i10 = flag2 ? i5 : i5 + 1;
|
||||
- double d4 = flag ? d : d - 1.0;
|
||||
- double d5 = flag1 ? d1 : d1 - 1.0;
|
||||
- double d6 = flag2 ? d2 : d2 - 1.0;
|
||||
- double fiddledDistance = getFiddledDistance(this.biomeZoomSeed, i8, i9, i10, d4, d5, d6);
|
||||
- if (d3 > fiddledDistance) {
|
||||
- i6 = i7;
|
||||
- d3 = fiddledDistance;
|
||||
+ // DivineMC start - 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<Biome> getNoiseBiomeAtPosition(double x, double y, double z) {
|
||||
@@ -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(
|
||||
@@ -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<Direction> 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<EnderChestBlock> 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")) {
|
||||
@@ -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<NoteBlock> 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;
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<EndCrystal> 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++) {
|
||||
@@ -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];
|
||||
@@ -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));
|
||||
@@ -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<? extends Entity> run, Consumer<? extends Entity> retired) {}
|
||||
|
||||
@@ -46,7 +47,8 @@ public final class EntityScheduler {
|
||||
|
||||
private final ArrayDeque<ScheduledTask> currentlyExecuting = new ArrayDeque<>();
|
||||
|
||||
- public EntityScheduler(final CraftEntity entity) {
|
||||
+ public EntityScheduler(final net.minecraft.server.MinecraftServer server, final CraftEntity entity) { // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
+ this.server = Validate.notNull(server);
|
||||
this.entity = Validate.notNull(entity);
|
||||
}
|
||||
|
||||
@@ -61,15 +63,15 @@ public final class EntityScheduler {
|
||||
* @throws IllegalStateException If the scheduler is already retired.
|
||||
*/
|
||||
public void retire() {
|
||||
+ final Entity thisEntity = this.entity.getHandleRaw(); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
synchronized (this.stateLock) {
|
||||
if (this.tickCount == RETIRED_TICK_COUNT) {
|
||||
throw new IllegalStateException("Already retired");
|
||||
}
|
||||
this.tickCount = RETIRED_TICK_COUNT;
|
||||
+ this.server.entitiesWithScheduledTasks.remove(thisEntity); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
}
|
||||
|
||||
- final Entity thisEntity = this.entity.getHandleRaw();
|
||||
-
|
||||
// correctly handle and order retiring while running executeTick
|
||||
for (int i = 0, len = this.currentlyExecuting.size(); i < len; ++i) {
|
||||
final ScheduledTask task = this.currentlyExecuting.pollFirst();
|
||||
@@ -124,6 +126,7 @@ public final class EntityScheduler {
|
||||
if (this.tickCount == RETIRED_TICK_COUNT) {
|
||||
return false;
|
||||
}
|
||||
+ this.server.entitiesWithScheduledTasks.add(this.entity.getHandleRaw()); // DivineMC - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
this.oneTimeDelayed.computeIfAbsent(this.tickCount + Math.max(1L, delay), (final long keyInMap) -> {
|
||||
return new ArrayList<>();
|
||||
}).add(task);
|
||||
@@ -143,6 +146,12 @@ public final class EntityScheduler {
|
||||
TickThread.ensureTickThread(thisEntity, "May not tick entity scheduler asynchronously");
|
||||
final List<ScheduledTask> toRun;
|
||||
synchronized (this.stateLock) {
|
||||
+ // DivineMC start - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
+ if (this.currentlyExecuting.isEmpty() && this.oneTimeDelayed.isEmpty()) {
|
||||
+ this.server.entitiesWithScheduledTasks.remove(thisEntity);
|
||||
+ return;
|
||||
+ }
|
||||
+ // DivineMC end - Skip EntityScheduler's executeTick checks if there isn't any tasks to be run
|
||||
if (this.tickCount == RETIRED_TICK_COUNT) {
|
||||
throw new IllegalStateException("Ticking retired scheduler");
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
|
||||
index 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
|
||||
@@ -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 : ""
|
||||
@@ -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<Audience, net.minecraft.network.chat.Component> 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Component> worldTimes = new ArrayList<>();
|
||||
+ worldTimes.addAll(eval(serverLevel.tickTimes5s.getTimes()));
|
||||
+ worldTimes.addAll(eval(serverLevel.tickTimes10s.getTimes()));
|
||||
+ worldTimes.addAll(eval(serverLevel.tickTimes60s.getTimes()));
|
||||
+
|
||||
+ sender.sendMessage(text().content("◴ " + serverLevel.getWorld().getName() + ": ").color(GOLD)
|
||||
+ .append(text().color(GRAY)
|
||||
+ .append(
|
||||
+ worldTimes.get(0), SLASH, worldTimes.get(1), SLASH, worldTimes.get(2), text(", ", YELLOW),
|
||||
+ worldTimes.get(3), SLASH, worldTimes.get(4), SLASH, worldTimes.get(5), text(", ", YELLOW),
|
||||
+ worldTimes.get(6), SLASH, worldTimes.get(7), SLASH, worldTimes.get(8)
|
||||
+ )
|
||||
+ )
|
||||
+ );
|
||||
+ }
|
||||
+ // DivineMC end - MSPT Tracking for each world
|
||||
+
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -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<String, World> worlds = new LinkedHashMap<String, World>();
|
||||
// private final Map<Class<?>, Registry<?>> registries = new HashMap<>(); // Paper - replace with RegistryAccess
|
||||
+ private final Map<UUID, World> 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<World> getWorlds() {
|
||||
- return new ArrayList<World>(this.worlds.values());
|
||||
+ return new it.unimi.dsi.fastutil.objects.ObjectArrayList<World>(this.worlds.values()); // DivineMC - optimize getWorlds
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -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<String> channels = new HashSet<String>();
|
||||
- private final Map<UUID, Set<WeakReference<Plugin>>> invertedVisibilityEntities = new HashMap<>();
|
||||
+ private final Map<UUID, Set<WeakReference<Plugin>>> invertedVisibilityEntities = new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(); // DivineMC - optimize canSee checks
|
||||
private final Set<UUID> unlistedEntities = new HashSet<>(); // Paper - Add Listing API for Player
|
||||
private static final WeakHashMap<Plugin, WeakReference<Plugin>> pluginWeakReferences = new WeakHashMap<>();
|
||||
private int hash = 0;
|
||||
@@ -2270,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
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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<Runnable> postProcessing = new ArrayList<>(0);
|
||||
|
||||
/**
|
||||
* a list of positions that this path could path towards
|
||||
*/
|
||||
private final Set<BlockPos> positions;
|
||||
|
||||
/**
|
||||
* the supplier of the real processed path
|
||||
*/
|
||||
private final Supplier<Path> pathSupplier;
|
||||
|
||||
/*
|
||||
* Processed values
|
||||
*/
|
||||
|
||||
/**
|
||||
* this is a reference to the nodes list in the parent `Path` object
|
||||
*/
|
||||
private final List<Node> nodes;
|
||||
/**
|
||||
* the block we're trying to path to
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* while processing, we can always theoretically reach the target so default is true
|
||||
*/
|
||||
private boolean canReach = true;
|
||||
|
||||
public AsyncPath(@NotNull List<Node> emptyNodeList, @NotNull Set<BlockPos> positions, @NotNull Supplier<Path> 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<BlockPos> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<Void> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<NodeEvaluatorFeatures, ConcurrentLinkedQueue<NodeEvaluator>> threadLocalNodeEvaluators = new ConcurrentHashMap<>();
|
||||
private static final Map<NodeEvaluator, NodeEvaluatorGenerator> nodeEvaluatorToGenerator = new ConcurrentHashMap<>();
|
||||
|
||||
private static @NotNull Queue<NodeEvaluator> 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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package org.bxteam.divinemc.pathfinding;
|
||||
|
||||
public enum PathProcessState {
|
||||
WAITING,
|
||||
PROCESSING,
|
||||
COMPLETED
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Byte> 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<byte[]> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Integer> 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<long[]> 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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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<long[]> LAST_SEEN_WORLD_SEED = ThreadLocal.withInitial(() -> new long[Globals.WORLD_SEED_LONGS]);
|
||||
private static final ThreadLocal<long[]> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<Entity> 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<Entity> 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<net.minecraft.world.entity.Entity> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
* <p>
|
||||
* 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
|
||||
* <p>
|
||||
* 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<TickingBlockEntity> {
|
||||
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<? extends TickingBlockEntity> 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<Integer> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<Double> 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<BitSet> bitSetConstructor = BitSet::new;
|
||||
|
||||
public static ThreadLocal<Int2ObjectOpenHashMap<BitSet>> 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;
|
||||
}
|
||||
}
|
||||
@@ -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 <a href="https://github.com/Minecraft-AMS/Carpet-AMS-Addition">here</a>
|
||||
*
|
||||
* @author 1024-byteeeee
|
||||
*/
|
||||
public class BlockPatternHelper {
|
||||
public static BlockPattern.BlockPatternMatch partialSearchAround(BlockPattern pattern, Level world, BlockPos pos) {
|
||||
LoadingCache<BlockPos, BlockInWorld> 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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
* <p>
|
||||
* sin(-x) = -sin(x)
|
||||
* ... to eliminate negative angles from the LUT.
|
||||
* <p>
|
||||
* sin(x) = sin(pi/2 - x)
|
||||
* ... to eliminate supplementary angles from the LUT.
|
||||
* <p>
|
||||
* Using these identities allows us to reduce the LUT from 64K entries (256 KB) to just 16K entries (64 KB), enabling
|
||||
* it to better fit into the CPU's caches at the expense of some cycles on the fast path. The implementation has been
|
||||
* tightly optimized to avoid branching where possible and to use very quick integer operations.
|
||||
* <p>
|
||||
* Generally speaking, reducing the size of a lookup table is always a good optimization, but since we need to spend
|
||||
* extra CPU cycles trying to maintain parity with vanilla, there is the potential risk that this implementation ends
|
||||
* up being slower than vanilla when the lookup table is able to be kept in cache memory.
|
||||
* <p>
|
||||
* Unlike other "fast math" implementations, the values returned by this class are *bit-for-bit identical* with those
|
||||
* from {@link Mth}. Validation is performed during runtime to ensure that the table is correct.
|
||||
*
|
||||
* @author coderbot16 Author of the original (and very clever) <a href="https://gitlab.com/coderbot16/i73/-/tree/master/i73-trig/src">implementation</a> 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);
|
||||
}
|
||||
}
|
||||
@@ -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<Long, LongArrayList> 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<Long> 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;
|
||||
}
|
||||
}
|
||||
@@ -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<BlockPos> {
|
||||
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<BlockPos> iterator() {
|
||||
return new Iterator<BlockPos>() {
|
||||
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));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user