9
0
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:
NONPLAYT
2025-02-21 22:26:06 +03:00
parent 33526c57ec
commit b90c03f48d
98 changed files with 0 additions and 6588 deletions

View File

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

View File

@@ -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
}

View File

@@ -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
}

View File

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

View File

@@ -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
}

View File

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

View File

@@ -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>());

View File

@@ -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;

View File

@@ -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

View File

@@ -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
);

View File

@@ -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
}

View File

@@ -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
}

View File

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

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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
}

View File

@@ -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);
}

View File

@@ -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() {

View File

@@ -1,52 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sun, 12 Jan 2025 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
}

View File

@@ -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

View File

@@ -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];

View File

@@ -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()

View File

@@ -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

View File

@@ -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
}

View File

@@ -1,42 +0,0 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 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

View File

@@ -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

View File

@@ -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());

View File

@@ -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,

View File

@@ -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();
}

View File

@@ -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();

View File

@@ -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");

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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 {

View File

@@ -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++) {

View File

@@ -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");

View File

@@ -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 {

View File

@@ -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

View File

@@ -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();

View File

@@ -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) {

View File

@@ -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) {

View File

@@ -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,

View File

@@ -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);

View File

@@ -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
}
}

View File

@@ -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
}
}
}

View File

@@ -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
);

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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) {

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
}
}
}

View File

@@ -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) {

View File

@@ -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(

View File

@@ -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")) {

View File

@@ -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;

View File

@@ -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
}

View File

@@ -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++) {

View File

@@ -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];

View File

@@ -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));

View File

@@ -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

View File

@@ -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 : ""

View File

@@ -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
}
}

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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;
}

View File

@@ -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() {}

View File

@@ -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;
}
}

View File

@@ -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);
}
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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;
}
}

View File

@@ -1,7 +0,0 @@
package org.bxteam.divinemc.pathfinding;
public enum PathProcessState {
WAITING,
PROCESSING,
COMPLETED
}

View File

@@ -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;
}

View File

@@ -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);
}
}
}
}

View File

@@ -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);
}
}
}

View File

@@ -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;
}
}
}
}

View File

@@ -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();
}
}

View File

@@ -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
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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;
}
}

View File

@@ -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));
}
};
}
}