diff --git a/patches/api/0002-Leaves-fakeplayer-API.patch b/patches/api/0002-Leaves-fakeplayer-API.patch deleted file mode 100644 index 64b3391..0000000 --- a/patches/api/0002-Leaves-fakeplayer-API.patch +++ /dev/null @@ -1,563 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Mon, 29 Jan 2024 11:36:39 +0000 -Subject: [PATCH] Leaves fakeplayer API - - -diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java -index 00ed780f190fa1bf3c33fc093a46b4e914131e5f..eb92f582daae270eb1b152106c5ec5f7b854e650 100644 ---- a/src/main/java/org/bukkit/Bukkit.java -+++ b/src/main/java/org/bukkit/Bukkit.java -@@ -58,6 +58,7 @@ import org.jetbrains.annotations.Contract; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; - import io.papermc.paper.util.JarManifests; // Paper -+import top.leavesmc.leaves.entity.BotManager; - - /** - * Represents the Bukkit core, for version and Server singleton handling -@@ -2846,6 +2847,17 @@ public final class Bukkit { - } - // Folia end - region threading API - -+ // Leaves start - Bot API -+ /** -+ * Returns a bot manager. -+ * -+ * @return Bot Manager -+ */ -+ public static @NotNull BotManager getBotManager() { -+ return server.getBotManager(); -+ } -+ // Leaves end - Bot API -+ - @NotNull - public static Server.Spigot spigot() { - return server.spigot(); -diff --git a/src/main/java/org/bukkit/Server.java b/src/main/java/org/bukkit/Server.java -index 8d51301e1a0a2a528353b90e2e2d0e4c69c6a4f5..9a798842b4dd8f26f696160f54a9b86b8bcc628a 100644 ---- a/src/main/java/org/bukkit/Server.java -+++ b/src/main/java/org/bukkit/Server.java -@@ -58,6 +58,7 @@ import org.bukkit.util.CachedServerIcon; - import org.jetbrains.annotations.Contract; - import org.jetbrains.annotations.NotNull; - import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.entity.BotManager; - - /** - * Represents a server implementation. -@@ -2487,4 +2488,14 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi - */ - public boolean isGlobalTickThread(); - // Folia end - region threading API -+ -+ -+ // Leaves start - Bot API -+ /** -+ * Returns a bot manager. -+ * -+ * @return Bot Manager -+ */ -+ @NotNull BotManager getBotManager(); -+ // Leaves end - Bot API - } -diff --git a/src/main/java/top/leavesmc/leaves/entity/Bot.java b/src/main/java/top/leavesmc/leaves/entity/Bot.java -new file mode 100644 -index 0000000000000000000000000000000000000000..02815077dcd6d5c1b155ef3ca5cd6e3a9c45c0b5 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/entity/Bot.java -@@ -0,0 +1,51 @@ -+package top.leavesmc.leaves.entity; -+ -+import org.bukkit.entity.Player; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.entity.botaction.LeavesBotAction; -+ -+import java.util.UUID; -+ -+/** -+ * Represents a fakeplayer -+ */ -+public interface Bot extends Player { -+ -+ /** -+ * Gets the fakeplayer skin -+ * -+ * @return fakeplayer skin name -+ */ -+ @Nullable -+ public String getSkinName(); -+ -+ /** -+ * Gets the fakeplayer name without prefix and suffix -+ * -+ * @return fakeplayer real name -+ */ -+ @NotNull -+ public String getRealName(); -+ -+ @Nullable -+ public UUID getCreatePlayerUUID(); -+ -+ /** -+ * Sets the fakeplayer action with args. -+ * -+ * @param action action name -+ * @param player player who create this action -+ * @param args passed action arguments -+ */ -+ public boolean setBotAction(@NotNull String action, @NotNull Player player, @NotNull String[] args); -+ -+ /** -+ * Sets the fakeplayer action with args. -+ * -+ * @param action leaves bot action -+ * @param player player who create this action -+ * @param args passed action arguments -+ */ -+ public boolean setBotAction(@NotNull LeavesBotAction action, @NotNull Player player, @NotNull String[] args); -+} -diff --git a/src/main/java/top/leavesmc/leaves/entity/BotManager.java b/src/main/java/top/leavesmc/leaves/entity/BotManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f2258027b2ed4bfcf7feda2e9075b1a1a05a85b6 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/entity/BotManager.java -@@ -0,0 +1,107 @@ -+package top.leavesmc.leaves.entity; -+ -+import org.bukkit.Location; -+import org.bukkit.util.Consumer; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.entity.botaction.CustomBotAction; -+ -+import java.util.Collection; -+import java.util.UUID; -+ -+/** -+ * Simple fakeplayer manager -+ */ -+public interface BotManager { -+ -+ /** -+ * Gets a fakeplayer object by the given uuid. -+ * -+ * @param uuid the uuid to look up -+ * @return a fakeplayer if one was found, null otherwise -+ */ -+ @Nullable -+ public Bot getBot(@NotNull UUID uuid); -+ -+ /** -+ * Gets a fakeplayer object by the given name. -+ * -+ * @param name the name to look up -+ * @return a fakeplayer if one was found, null otherwise -+ */ -+ @Nullable -+ public Bot getBot(@NotNull String name); -+ -+ /** -+ * Creates a fakeplayer with given param. -+ *

-+ * prefix and suffix will not be added. -+ * -+ * @param name fakeplayer name -+ * @param realName fakeplayer real name -+ * @param skin fakeplayer skin arr -+ * @param skinName fakeplayer skin name -+ * @param location a location will create fakeplayer -+ * @return a fakeplayer if success, null otherwise -+ */ -+ @Nullable -+ public Bot createBot(@NotNull String name, @NotNull String realName, @Nullable String[] skin, @Nullable String skinName, @NotNull Location location); -+ -+ /** -+ * Creates a fakeplayer with given param. -+ * -+ * @param name fakeplayer name -+ * @param skinName fakeplayer skin name -+ * @param location a location will create fakeplayer -+ * @param consumer a consumer after create fakeplayer success -+ */ -+ public void createBot(@NotNull String name, @Nullable String skinName, @NotNull Location location, @Nullable Consumer consumer); -+ -+ /** -+ * Removes a fakeplayer object by the given name. -+ * -+ * @param name the name to look up -+ */ -+ public void removeBot(@NotNull String name); -+ -+ /** -+ * Removes a fakeplayer object by the given uuid. -+ * -+ * @param uuid the uuid to look up -+ */ -+ public void removeBot(@NotNull UUID uuid); -+ -+ /** -+ * Removes all fakeplayers. -+ */ -+ public void removeAllBots(); -+ -+ /** -+ * Save fakeplayers data if resident-fakeplayer is true, or remove all fakeplayer. -+ */ -+ public void saveOrRemoveAllBots(); -+ -+ /** -+ * Gets a view of all currently logged in fakeplayers. This view is a reused object, making some operations like Collection.size() zero-allocation. -+ * -+ * @return a view of fakeplayers. -+ */ -+ public Collection getBots(); -+ -+ /** -+ * Register a custom bot action. -+ * -+ * @param name action name -+ * @param action action executor -+ * @return true if success, or false -+ */ -+ public boolean registerCustomBotAction(String name, CustomBotAction action); -+ -+ /** -+ * Unregister a custom bot action. -+ * -+ * @param name action name -+ * @return true if success, or false -+ */ -+ public boolean unregisterCustomBotAction(String name); -+} -diff --git a/src/main/java/top/leavesmc/leaves/entity/botaction/CustomBotAction.java b/src/main/java/top/leavesmc/leaves/entity/botaction/CustomBotAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7abf4eef22e40468929e724ebc07a97b0b2a05f3 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/entity/botaction/CustomBotAction.java -@@ -0,0 +1,52 @@ -+package top.leavesmc.leaves.entity.botaction; -+ -+import org.bukkit.entity.Player; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.entity.Bot; -+ -+import java.util.List; -+ -+/** -+ * Represents a class which contains methods for a custom bot action -+ */ -+public interface CustomBotAction { -+ -+ /** -+ * Executes the action, returning its success. -+ * -+ * @param bot bot of the action -+ * @return true if once action finish, otherwise false -+ */ -+ public boolean doTick(Bot bot); -+ -+ /** -+ * Created a new action instance. -+ * -+ * @param player player who create this action -+ * @param args passed action arguments -+ * @return a new action instance with given args -+ */ -+ public @Nullable CustomBotAction getNew(Player player, String[] args); -+ -+ /** -+ * Requests a list of possible completions for a action argument. -+ * -+ * @return A List of a List of possible completions for the argument. -+ */ -+ public @NotNull List> getTabComplete(); -+ -+ /** -+ * Return a ticks to wait between {@link CustomBotAction#doTick(Bot)} -+ * -+ * @return the ticks to wait between runs -+ */ -+ public int getTickDelay(); -+ -+ /** -+ * Return a number of times {@link CustomBotAction#doTick(Bot)} can return true -+ * -+ * @return the number of times an action can be executed -+ */ -+ public int getNumber(); -+} -diff --git a/src/main/java/top/leavesmc/leaves/entity/botaction/LeavesBotAction.java b/src/main/java/top/leavesmc/leaves/entity/botaction/LeavesBotAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e298722319ff0cfd52e531693ea3767e5f9a3d52 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/entity/botaction/LeavesBotAction.java -@@ -0,0 +1,32 @@ -+package top.leavesmc.leaves.entity.botaction; -+ -+/** -+ * A Leaves bot action enum -+ */ -+public enum LeavesBotAction { -+ ATTACK("attack"), -+ ATTACK_SELF("attack_self"), -+ BREAK("break"), -+ DROP("drop"), -+ FISH("fish"), -+ JUMP("jump"), -+ LAY("lay"), -+ LOOK("look"), -+ ROTATE("rotate"), -+ SNEAK("sneak"), -+ STOP("stop"), -+ SWIM("swim"), -+ USE("use"), -+ USE_ON("use_on"), -+ USE_TO("use_to"); -+ -+ private final String name; -+ -+ private LeavesBotAction(String name) { -+ this.name = name; -+ } -+ -+ public String getName() { -+ return name; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/event/bot/BotCreateEvent.java b/src/main/java/top/leavesmc/leaves/event/bot/BotCreateEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7cf1eb4eb3d2fe9310f9272ec53208632b87b49b ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/event/bot/BotCreateEvent.java -@@ -0,0 +1,106 @@ -+package top.leavesmc.leaves.event.bot; -+ -+import org.bukkit.Location; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.Event; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+/** -+ * Call when a fakeplayer creates a server -+ */ -+public class BotCreateEvent extends Event implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private final String bot; -+ private final String skin; -+ private String joinMessage; -+ private Location createLocation; -+ private boolean cancel = false; -+ -+ public BotCreateEvent(@NotNull final String who, @NotNull final String skin, @NotNull final Location createLocation, @Nullable final String joinMessage) { -+ this.bot = who; -+ this.skin = skin; -+ this.joinMessage = joinMessage; -+ this.createLocation = createLocation; -+ } -+ -+ /** -+ * Gets the fakeplayer name -+ * -+ * @return fakeplayer name -+ */ -+ public String getBot() { -+ return bot; -+ } -+ -+ /** -+ * Gets the join message to send to all online players -+ * -+ * @return string join message. Can be null -+ */ -+ @Nullable -+ public String getJoinMessage() { -+ return joinMessage; -+ } -+ -+ /** -+ * Sets the join message to send to all online players -+ * -+ * @param joinMessage join message. If null, no message will be sent -+ */ -+ public void setJoinMessage(@Nullable String joinMessage) { -+ this.joinMessage = joinMessage; -+ } -+ -+ /** -+ * Gets the location to create the fakeplayer -+ * -+ * @return Location to create the fakeplayer -+ */ -+ @NotNull -+ public Location getCreateLocation() { -+ return createLocation; -+ } -+ -+ /** -+ * Sets the location to create the fakeplayer -+ * -+ * @param createLocation location to create the fakeplayer -+ */ -+ public void setCreateLocation(@NotNull Location createLocation) { -+ this.createLocation = createLocation; -+ } -+ -+ /** -+ * Gets the fakeplayer skin -+ * -+ * @return fakeplayer skin name -+ */ -+ @Nullable -+ public String getSkin() { -+ return skin; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/event/bot/BotEvent.java b/src/main/java/top/leavesmc/leaves/event/bot/BotEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4a4fe07ce965d4a97e0d8105a91310dac7d1343c ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/event/bot/BotEvent.java -@@ -0,0 +1,31 @@ -+package top.leavesmc.leaves.event.bot; -+ -+import org.bukkit.event.Event; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.entity.Bot; -+ -+/** -+ * Represents a fakeplayer related event -+ */ -+public abstract class BotEvent extends Event { -+ protected Bot bot; -+ -+ public BotEvent(@NotNull final Bot who) { -+ bot = who; -+ } -+ -+ public BotEvent(@NotNull final Bot who, boolean async) { // Paper - public -+ super(async); -+ bot = who; -+ } -+ -+ /** -+ * Returns the fakeplayer involved in this event -+ * -+ * @return Fakeplayer who is involved in this event -+ */ -+ @NotNull -+ public final Bot getBot() { -+ return bot; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/event/bot/BotInventoryOpenEvent.java b/src/main/java/top/leavesmc/leaves/event/bot/BotInventoryOpenEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..e889f7e98ec9cb6a3b95d8ea865e25fffea662a1 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/event/bot/BotInventoryOpenEvent.java -@@ -0,0 +1,46 @@ -+package top.leavesmc.leaves.event.bot; -+ -+import org.bukkit.entity.Player; -+import org.bukkit.event.Cancellable; -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.entity.Bot; -+ -+public class BotInventoryOpenEvent extends BotEvent implements Cancellable { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ private final Player player; -+ private boolean cancel = false; -+ -+ public BotInventoryOpenEvent(@NotNull Bot who, @Nullable Player player) { -+ super(who); -+ this.player = player; -+ } -+ -+ @Override -+ public boolean isCancelled() { -+ return cancel; -+ } -+ -+ @Override -+ public void setCancelled(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ @Nullable -+ public Player getOpenPlayer() { -+ return player; -+ } -+ -+ -+ @Override -+ public @NotNull HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/event/bot/BotJoinEvent.java b/src/main/java/top/leavesmc/leaves/event/bot/BotJoinEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..10afa5c7fd4ee8a4e72d64f8ca9bf8731ec2ad61 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/event/bot/BotJoinEvent.java -@@ -0,0 +1,27 @@ -+package top.leavesmc.leaves.event.bot; -+ -+import org.bukkit.event.HandlerList; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.entity.Bot; -+ -+/** -+ * Called when a fakeplayer joins a server -+ */ -+public class BotJoinEvent extends BotEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ public BotJoinEvent(@NotNull Bot who) { -+ super(who); -+ } -+ -+ @Override -+ @NotNull -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ @NotNull -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/server/0003-Added-empty-luminol-config.patch b/patches/server/0003-Added-empty-luminol-config.patch deleted file mode 100644 index 30108d4..0000000 --- a/patches/server/0003-Added-empty-luminol-config.patch +++ /dev/null @@ -1,179 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Sat, 27 Jan 2024 07:36:28 +0000 -Subject: [PATCH] Added empty luminol config - - -diff --git a/build.gradle.kts b/build.gradle.kts -index b9c5ef4d15aa97a380419912e3ee09d094ae752e..83660616a26d989ce441e17acab103ab166304d8 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -19,6 +19,7 @@ dependencies { - exclude("io.papermc.paper", "paper-api") - } - // Folia end -+ implementation("com.electronwill.night-config:toml:3.6.0") //Luminol - Night config - // Paper start - implementation("org.jline:jline-terminal-jansi:3.21.0") - implementation("net.minecrell:terminalconsoleappender:1.3.0") -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1f9ff0fc33fa36c90fc4cbbd21b7b790de581632 ---- /dev/null -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -0,0 +1,99 @@ -+package me.earthme.luminol; -+ -+import com.electronwill.nightconfig.core.file.CommentedFileConfig; -+import net.minecraft.server.level.ServerLevel; -+ -+import java.io.File; -+import java.io.IOException; -+ -+public class LuminolConfig { -+ private static final File PARENT_FOLDER = new File("luminol_config"); -+ private static final File MAIN_CONFIG_FILE = new File(PARENT_FOLDER,"luminol_global.toml"); -+ private static CommentedFileConfig MAIN_CONFIG; -+ -+ public static String serverModName = "Luminol"; -+ public static boolean fakeVanillaModeEnabled = false; -+ -+ public static void init() throws IOException { -+ PARENT_FOLDER.mkdir(); -+ -+ if (!MAIN_CONFIG_FILE.exists()){ -+ MAIN_CONFIG_FILE.createNewFile(); -+ } -+ -+ MAIN_CONFIG = CommentedFileConfig.ofConcurrent(MAIN_CONFIG_FILE); -+ -+ MAIN_CONFIG.load(); -+ initValues(); -+ MAIN_CONFIG.save(); -+ } -+ -+ public static void initValues(){ -+ serverModName = get("misc.server_mod_name",serverModName,"The servermod name will be sent to players,and you can see it in F3 or motd responses"); -+ fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server"); -+ } -+ -+ public static T get(String key,T def){ -+ if (MAIN_CONFIG.contains(key)){ -+ return MAIN_CONFIG.get(key); -+ } -+ -+ MAIN_CONFIG.set(key,def); -+ return def; -+ } -+ -+ public static T get(String key,T def,String comment){ -+ MAIN_CONFIG.setComment(key,comment); -+ -+ if (MAIN_CONFIG.contains(key)){ -+ return MAIN_CONFIG.get(key); -+ } -+ -+ MAIN_CONFIG.set(key,def); -+ return def; -+ } -+ -+ public static class LumionalWorldConfig{ -+ private final File configFile; -+ private CommentedFileConfig commentedFileConfig; -+ -+ public LumionalWorldConfig(ServerLevel level) { -+ this.configFile = new File(PARENT_FOLDER,"luminol_world_"+level.getWorld().getName()+".toml"); -+ } -+ -+ public void init() throws IOException { -+ if (!this.configFile.exists()){ -+ this.configFile.createNewFile(); -+ } -+ -+ this.commentedFileConfig = CommentedFileConfig.ofConcurrent(this.configFile); -+ this.commentedFileConfig.load(); -+ this.initValues(); -+ this.commentedFileConfig.save(); -+ } -+ -+ public void initValues(){ -+ -+ } -+ -+ public T get(String key,T def,String comment){ -+ this.commentedFileConfig.setComment(key,comment); -+ -+ if (this.commentedFileConfig.contains(key)){ -+ return this.commentedFileConfig.get(key); -+ } -+ -+ this.commentedFileConfig.set(key,def); -+ return def; -+ } -+ -+ public T get(String key,T def){ -+ if (this.commentedFileConfig.contains(key)){ -+ return this.commentedFileConfig.get(key); -+ } -+ -+ this.commentedFileConfig.set(key,def); -+ return def; -+ } -+ } -+} -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 0f8c868fce0a054a0ba356350baf4c3824c2c958..5a71ee8d50818c5d6e7a6a2fee05a5c16108b50a 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -19,6 +19,8 @@ import java.util.Locale; - import java.util.Optional; - import java.util.function.BooleanSupplier; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.DefaultUncaughtExceptionHandler; - import net.minecraft.DefaultUncaughtExceptionHandlerWithName; - import net.minecraft.SharedConstants; -@@ -205,6 +207,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - org.spigotmc.SpigotConfig.registerCommands(); - // Spigot end - io.papermc.paper.util.ObfHelper.INSTANCE.getClass(); // Paper - load mappings for stacktrace deobf and etc. -+ LuminolConfig.init(); //Luminol - // Paper start - initialize global and world-defaults configuration - this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess()); - this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index a16fc5ba55dbde0cf7f968884da40d70a754a0d8..0a2d50b72506115644af5682d72f8ee04e45796b 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -38,6 +38,8 @@ import java.util.stream.Collectors; - import java.util.stream.Stream; - import javax.annotation.Nonnull; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.CrashReport; - import net.minecraft.CrashReportCategory; - import net.minecraft.Util; -@@ -767,6 +769,8 @@ public class ServerLevel extends Level implements WorldGenLevel { - } - // Folia end - region threading - -+ public final LuminolConfig.LumionalWorldConfig lumionalWorldConfig; //Luminol -+ - // Add env and gen to constructor, IWorldDataServer -> WorldDataServer - public ServerLevel(MinecraftServer minecraftserver, Executor executor, LevelStorageSource.LevelStorageAccess convertable_conversionsession, PrimaryLevelData iworlddataserver, ResourceKey resourcekey, LevelStem worlddimension, ChunkProgressListener worldloadlistener, boolean flag, long i, List list, boolean flag1, @Nullable RandomSequences randomsequences, org.bukkit.World.Environment env, org.bukkit.generator.ChunkGenerator gen, org.bukkit.generator.BiomeProvider biomeProvider) { - // IRegistryCustom.Dimension iregistrycustom_dimension = minecraftserver.registryAccess(); // CraftBukkit - decompile error -@@ -851,6 +855,12 @@ public class ServerLevel extends Level implements WorldGenLevel { - this.chunkTaskScheduler = new io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler(this, io.papermc.paper.chunk.system.scheduling.ChunkTaskScheduler.workerThreads); // Paper - rewrite chunk system - this.entityLookup = new io.papermc.paper.chunk.system.entity.EntityLookup(this, new EntityCallbacks()); // Paper - rewrite chunk system - this.updateTickData(); // Folia - region threading - make sure it is initialised before ticked -+ this.lumionalWorldConfig = new LuminolConfig.LumionalWorldConfig(this); -+ try { -+ this.lumionalWorldConfig.init(); -+ } catch (IOException e) { -+ throw new RuntimeException("Failed to create luminol config for level "+ this.getWorld().getName()+"!",e); -+ } - } - - // Folia start - region threading diff --git a/patches/server/0003-Empty-config-file-base.patch b/patches/server/0003-Empty-config-file-base.patch new file mode 100644 index 0000000..bb9ab1e --- /dev/null +++ b/patches/server/0003-Empty-config-file-base.patch @@ -0,0 +1,312 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrHua269 +Date: Wed, 7 Feb 2024 00:45:19 +0000 +Subject: [PATCH] Empty config file base + + +diff --git a/build.gradle.kts b/build.gradle.kts +index b9c5ef4d15aa97a380419912e3ee09d094ae752e..e837f1f9b444318cbee8719b9dd0eb669478742e 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -19,6 +19,7 @@ dependencies { + exclude("io.papermc.paper", "paper-api") + } + // Folia end ++ implementation("com.electronwill.night-config:toml:3.6.6") //Luminol - Night config + // Paper start + implementation("org.jline:jline-terminal-jansi:3.21.0") + implementation("net.minecrell:terminalconsoleappender:1.3.0") +diff --git a/src/main/java/me/earthme/luminol/config/ConfigInfo.java b/src/main/java/me/earthme/luminol/config/ConfigInfo.java +new file mode 100644 +index 0000000000000000000000000000000000000000..01b64c2cf6b437114337626c242e1da3fbdb8ead +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/ConfigInfo.java +@@ -0,0 +1,11 @@ ++package me.earthme.luminol.config; ++ ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++ ++@Retention(RetentionPolicy.RUNTIME) ++public @interface ConfigInfo { ++ String baseName(); ++ ++ String comments() default ""; ++} +diff --git a/src/main/java/me/earthme/luminol/config/DoNotLoad.java b/src/main/java/me/earthme/luminol/config/DoNotLoad.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fffc5eb4be4b78a886f3c340bd60f3a2b0108a7d +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/DoNotLoad.java +@@ -0,0 +1,8 @@ ++package me.earthme.luminol.config; ++ ++import java.lang.annotation.Retention; ++import java.lang.annotation.RetentionPolicy; ++ ++@Retention(RetentionPolicy.RUNTIME) ++public @interface DoNotLoad { ++} +diff --git a/src/main/java/me/earthme/luminol/config/EnumConfigCategory.java b/src/main/java/me/earthme/luminol/config/EnumConfigCategory.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ac2a92fe0ddbebb71ea4dd8c96f461d06ec29a4c +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/EnumConfigCategory.java +@@ -0,0 +1,18 @@ ++package me.earthme.luminol.config; ++ ++public enum EnumConfigCategory { ++ OPTIMIZATIONS("optimizations"), ++ FIXES("fixes"), ++ MISC("misc"), ++ GAMEPLAY("gameplay"); ++ ++ private final String baseKeyName; ++ ++ EnumConfigCategory(String baseKeyName) { ++ this.baseKeyName = baseKeyName; ++ } ++ ++ public String getBaseKeyName() { ++ return this.baseKeyName; ++ } ++} +diff --git a/src/main/java/me/earthme/luminol/config/IConfigModule.java b/src/main/java/me/earthme/luminol/config/IConfigModule.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9f6896711907ac30fe0c00130207b970007e4bb4 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/IConfigModule.java +@@ -0,0 +1,22 @@ ++package me.earthme.luminol.config; ++ ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import org.jetbrains.annotations.NotNull; ++ ++public interface IConfigModule { ++ ++ EnumConfigCategory getCategory(); ++ ++ String getBaseName(); ++ ++ default void onLoaded(CommentedFileConfig configInstance) {} ++ ++ default T get(String keyName, T defaultValue, @NotNull CommentedFileConfig config){ ++ if (!config.contains(keyName)){ ++ config.set(keyName,defaultValue); ++ return defaultValue; ++ } ++ ++ return config.get(keyName); ++ } ++} +diff --git a/src/main/java/me/earthme/luminol/config/LuminolConfig.java b/src/main/java/me/earthme/luminol/config/LuminolConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..caeb3249c2d99cc920f7a3e6380a263a52b3b8a6 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/LuminolConfig.java +@@ -0,0 +1,184 @@ ++package me.earthme.luminol.config; ++ ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import org.jetbrains.annotations.NotNull; ++ ++import java.io.File; ++import java.io.IOException; ++import java.lang.reflect.Field; ++import java.lang.reflect.InvocationTargetException; ++import java.lang.reflect.Modifier; ++import java.net.JarURLConnection; ++import java.net.URL; ++import java.net.URLDecoder; ++import java.nio.charset.StandardCharsets; ++import java.util.*; ++import java.util.jar.JarEntry; ++import java.util.jar.JarFile; ++ ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; ++ ++public class LuminolConfig { ++ public static final Logger logger = LogManager.getLogger(); ++ private static final File baseConfigFolder = new File("luminol_config"); ++ private static final File baseConfigFile = new File(baseConfigFolder,"luminol_global_config.toml"); ++ private static final Set allInstanced = new HashSet<>(); ++ private static CommentedFileConfig configFileInstance; ++ ++ public static void loadConfig() throws IOException { ++ baseConfigFolder.mkdirs(); ++ ++ if (!baseConfigFile.exists()){ ++ baseConfigFile.createNewFile(); ++ } ++ ++ configFileInstance = CommentedFileConfig.ofConcurrent(baseConfigFile); ++ ++ configFileInstance.load(); ++ ++ try { ++ instanceAllModule(); ++ loadAllModules(); ++ System.out.println(allInstanced.size()); ++ }catch (Exception e){ ++ e.printStackTrace(); ++ } ++ ++ configFileInstance.save(); ++ } ++ ++ private static void loadAllModules() throws IllegalAccessException { ++ for (IConfigModule instanced : allInstanced){ ++ loadForSingle(instanced); ++ } ++ } ++ ++ private static void instanceAllModule() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { ++ for (Class clazz : getClasses("me.earthme.luminol.config.modules")){ ++ if (IConfigModule.class.isAssignableFrom(clazz)){ ++ allInstanced.add((IConfigModule) clazz.getConstructor().newInstance()); ++ } ++ } ++ } ++ ++ private static void loadForSingle(@NotNull IConfigModule singleConfigModule) throws IllegalAccessException { ++ final EnumConfigCategory category = singleConfigModule.getCategory(); ++ ++ Field[] fields = singleConfigModule.getClass().getDeclaredFields(); ++ ++ for (Field field : fields) { ++ int modifiers = field.getModifiers(); ++ if (Modifier.isStatic(modifiers) && !Modifier.isFinal(modifiers)) { ++ boolean skipLoad = field.getAnnotation(DoNotLoad.class) != null; ++ ConfigInfo configInfo = field.getAnnotation(ConfigInfo.class); ++ ++ if (skipLoad || configInfo == null){ ++ continue; ++ } ++ ++ final String fullConfigKeyName = category.getBaseKeyName() + "." + singleConfigModule.getBaseName() + "." + configInfo.baseName(); ++ ++ field.setAccessible(true); ++ final Object currentValue = field.get(null); ++ ++ if (!configFileInstance.contains(fullConfigKeyName)){ ++ if (currentValue == null){ ++ throw new UnsupportedOperationException("Config " + singleConfigModule.getBaseName() + "tried to add an null default value!"); ++ } ++ ++ final String comments = configInfo.comments(); ++ ++ if (!comments.isBlank()){ ++ configFileInstance.setComment(fullConfigKeyName,comments); ++ } ++ ++ configFileInstance.add(fullConfigKeyName,currentValue); ++ continue; ++ } ++ ++ final Object actuallyValue = configFileInstance.get(fullConfigKeyName); ++ field.set(null,actuallyValue); ++ ++ ++ } ++ } ++ ++ singleConfigModule.onLoaded(configFileInstance); ++ } ++ ++ public static Set> getClasses(String pack) { ++ Set> classes = new LinkedHashSet>(); ++ String packageDirName = pack.replace('.', '/'); ++ Enumeration dirs; ++ try { ++ dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName); ++ while (dirs.hasMoreElements()) { ++ URL url = dirs.nextElement(); ++ String protocol = url.getProtocol(); ++ if ("file".equals(protocol)) { ++ String filePath = URLDecoder.decode(url.getFile(), StandardCharsets.UTF_8); ++ findClassesInPackageByFile(pack, filePath, classes); ++ } else if ("jar".equals(protocol)) { ++ JarFile jar; ++ try { ++ jar = ((JarURLConnection) url.openConnection()).getJarFile(); ++ Enumeration entries = jar.entries(); ++ findClassesInPackageByJar(pack, entries, packageDirName, classes); ++ } catch (IOException e) { ++ e.printStackTrace(); ++ } ++ } ++ } ++ } catch (IOException e) { ++ e.printStackTrace(); ++ } ++ return classes; ++ } ++ ++ private static void findClassesInPackageByFile(String packageName, String packagePath, Set> classes) { ++ File dir = new File(packagePath); ++ if (!dir.exists() || !dir.isDirectory()) { ++ return; ++ } ++ File[] dirfiles = dir.listFiles((file) -> file.isDirectory() || file.getName().endsWith(".class")); ++ if (dirfiles != null) { ++ for (File file : dirfiles) { ++ if (file.isDirectory()) { ++ findClassesInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), classes); ++ } else { ++ String className = file.getName().substring(0, file.getName().length() - 6); ++ try { ++ classes.add(Class.forName(packageName + '.' + className)); ++ } catch (ClassNotFoundException e) { ++ e.printStackTrace(); ++ } ++ } ++ } ++ } ++ } ++ ++ private static void findClassesInPackageByJar(String packageName, Enumeration entries, String packageDirName, Set> classes) { ++ while (entries.hasMoreElements()) { ++ JarEntry entry = entries.nextElement(); ++ String name = entry.getName(); ++ if (name.charAt(0) == '/') { ++ name = name.substring(1); ++ } ++ if (name.startsWith(packageDirName)) { ++ int idx = name.lastIndexOf('/'); ++ if (idx != -1) { ++ packageName = name.substring(0, idx).replace('/', '.'); ++ } ++ if (name.endsWith(".class") && !entry.isDirectory()) { ++ String className = name.substring(packageName.length() + 1, name.length() - 6); ++ try { ++ classes.add(Class.forName(packageName + '.' + className)); ++ } catch (ClassNotFoundException e) { ++ e.printStackTrace(); ++ } ++ } ++ } ++ } ++ } ++} +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 0f8c868fce0a054a0ba356350baf4c3824c2c958..d99e0acf0000c566fdb1bffb149ec13a55d7c8dd 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -19,6 +19,8 @@ import java.util.Locale; + import java.util.Optional; + import java.util.function.BooleanSupplier; + import javax.annotation.Nullable; ++ ++import me.earthme.luminol.config.LuminolConfig; + import net.minecraft.DefaultUncaughtExceptionHandler; + import net.minecraft.DefaultUncaughtExceptionHandlerWithName; + import net.minecraft.SharedConstants; +@@ -209,6 +211,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + this.paperConfigurations.initializeGlobalConfiguration(this.registryAccess()); + this.paperConfigurations.initializeWorldDefaultsConfiguration(this.registryAccess()); + // Paper end - initialize global and world-defaults configuration ++ LuminolConfig.loadConfig(); //Luminol - load config file + // Paper start - fix converting txt to json file; convert old users earlier after PlayerList creation but before file load/save + if (this.convertOldUsers()) { + this.getProfileCache().save(false); // Paper diff --git a/patches/server/0004-Add-config-for-server-brand-name.patch b/patches/server/0004-Add-config-for-server-brand-name.patch deleted file mode 100644 index 431c7fe..0000000 --- a/patches/server/0004-Add-config-for-server-brand-name.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 01:44:36 +0000 -Subject: [PATCH] Add config for server brand name - - -diff --git a/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java -index 6ed2114f577ce12d2d493985e798609c7d83f15e..8200391c3177284d2e18b8fc1d532a9a9e4c4ad1 100644 ---- a/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java -+++ b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java -@@ -1,6 +1,7 @@ - package com.destroystokyo.paper.network; - - import com.destroystokyo.paper.event.server.PaperServerListPingEvent; -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.server.MinecraftServer; - import net.minecraft.server.level.ServerPlayer; - import org.bukkit.entity.Player; -@@ -14,7 +15,7 @@ class PaperServerListPingEventImpl extends PaperServerListPingEvent { - - PaperServerListPingEventImpl(MinecraftServer server, StatusClient client, int protocolVersion, @Nullable CachedServerIcon icon) { - super(client, server.motd(), server.getPlayerCount(), server.getMaxPlayers(), -- server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon); -+ LuminolConfig.fakeVanillaModeEnabled ? server.getServerVersion() : server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon);//Luminol - Fake vanilla mode - this.server = server; - } - -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 22aff010859dded150b6e3dd0644fe3c38dbaea9..bf1df7da39dc42bda2e4b54ae3f6856399f5cb10 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -54,6 +54,8 @@ import java.util.stream.Collectors; - import java.util.stream.Stream; - import javax.annotation.Nullable; - import javax.imageio.ImageIO; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.CrashReport; - import net.minecraft.ReportedException; - import net.minecraft.SharedConstants; -@@ -1954,7 +1956,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Wed, 7 Feb 2024 00:49:38 +0000 +Subject: [PATCH] Add config for server mod name + + +diff --git a/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java +index 6ed2114f577ce12d2d493985e798609c7d83f15e..7a5dcf3b7108794b9a224004730eb396a96cce8f 100644 +--- a/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java ++++ b/src/main/java/com/destroystokyo/paper/network/PaperServerListPingEventImpl.java +@@ -14,7 +14,7 @@ class PaperServerListPingEventImpl extends PaperServerListPingEvent { + + PaperServerListPingEventImpl(MinecraftServer server, StatusClient client, int protocolVersion, @Nullable CachedServerIcon icon) { + super(client, server.motd(), server.getPlayerCount(), server.getMaxPlayers(), +- server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon); ++ me.earthme.luminol.config.modules.misc.ServerModNameConfig.fakeVanilla ? server.getServerVersion() : server.getServerModName() + ' ' + server.getServerVersion(), protocolVersion, icon);//Luminol - Fake vanilla mode + this.server = server; + } + +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..94e7c8910e3623163528a844fd7a08b3ffe5826b +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/ServerModNameConfig.java +@@ -0,0 +1,23 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class ServerModNameConfig implements IConfigModule { ++ @ConfigInfo(baseName = "name") ++ public static String serverModName = "Luminol"; ++ ++ @ConfigInfo(baseName = "vanilla_spoof") ++ public static boolean fakeVanilla = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "server_mod_name"; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 22aff010859dded150b6e3dd0644fe3c38dbaea9..4468e6fdbbe527111f4410188f2f2df7f592f81e 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -1954,7 +1954,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop -Date: Sat, 27 Jan 2024 07:40:23 +0000 +Date: Wed, 7 Feb 2024 00:53:03 +0000 Subject: [PATCH] Add config for unsafe teleportation -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 1f9ff0fc33fa36c90fc4cbbd21b7b790de581632..36ca0b94d29d81e5f1f2aff4a38ead0b363dd1c7 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -14,6 +14,8 @@ public class LuminolConfig { - public static String serverModName = "Luminol"; - public static boolean fakeVanillaModeEnabled = false; - -+ public static boolean safeTeleportation = true; +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/UnsafeTeleportationConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/UnsafeTeleportationConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ea10d8d38ecdb791b7b2a748496791c04eff5997 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/UnsafeTeleportationConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.fixes; + - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); - -@@ -31,6 +33,8 @@ public class LuminolConfig { - public static void initValues(){ - serverModName = get("misc.server_mod_name",serverModName,"The servermod name will be sent to players,and you can see it in F3 or motd responses"); - fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server"); ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; + -+ safeTeleportation = get("fixes.enable_safe_teleportation",safeTeleportation,"If this enabled,the end portals will not teleport removed entities."); - } - - public static T get(String key,T def){ ++public class UnsafeTeleportationConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "unsafe_teleportation"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index eade31ea668c171dceafee958e265041a439c54b..4cc0a97c0c3cef23b10930e204039c4450543907 100644 +index eade31ea668c171dceafee958e265041a439c54b..6b560754382936d4889e5729613077a3401d8740 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -24,6 +24,8 @@ import java.util.function.BiConsumer; - import java.util.function.Predicate; - import java.util.stream.Stream; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.BlockUtil; - import net.minecraft.CrashReport; - import net.minecraft.CrashReportCategory; -@@ -4043,6 +4045,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4043,6 +4043,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S protected boolean tryEndPortal() { io.papermc.paper.util.TickThread.ensureTickThread(this, "Cannot portal entity async"); -+ if (!LuminolConfig.safeTeleportation && !(this instanceof Player)) return false; //Luminol - Unsafe teleportation ++ if (me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled && !(this instanceof Player)) return false; //Luminol - Unsafe teleportation BlockPos pos = this.portalBlock; ServerLevel world = this.portalWorld; this.portalBlock = null; diff --git a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -index a0c1db8cfebaa0344012cc0af18d6231cdcdcbb8..96cc3cb8448b58f9ab11558821251996e7560079 100644 +index a0c1db8cfebaa0344012cc0af18d6231cdcdcbb8..cb174f06f9701cc4f0ff479649f39ee9aa63a97a 100644 --- a/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java +++ b/src/main/java/net/minecraft/world/level/block/EndPortalBlock.java -@@ -8,6 +8,7 @@ import net.minecraft.server.level.ServerLevel; - import net.minecraft.server.level.ServerPlayer; - import net.minecraft.util.RandomSource; - import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.player.Player; - import net.minecraft.world.item.ItemStack; - import net.minecraft.world.level.BlockGetter; - import net.minecraft.world.level.Level; -@@ -25,6 +26,7 @@ import net.minecraft.world.phys.shapes.VoxelShape; - import org.bukkit.event.entity.EntityPortalEnterEvent; - import org.bukkit.event.player.PlayerTeleportEvent; - // CraftBukkit end -+import me.earthme.luminol.LuminolConfig; - - public class EndPortalBlock extends BaseEntityBlock { - -@@ -61,6 +63,13 @@ public class EndPortalBlock extends BaseEntityBlock { +@@ -61,6 +61,13 @@ public class EndPortalBlock extends BaseEntityBlock { // return; // CraftBukkit - always fire event in case plugins wish to change it } + //Luminol start - Unsafe teleportation -+ if (!LuminolConfig.safeTeleportation && !(entity instanceof Player)){ ++ if (me.earthme.luminol.config.modules.fixes.UnsafeTeleportationConfig.enabled && !(entity instanceof net.minecraft.world.entity.player.Player)){ + entity.endPortalLogicAsync(); + return; + } diff --git a/patches/server/0006-Add-config-for-sand-duping.patch b/patches/server/0006-Add-config-for-sand-duping.patch index 0716a8a..a047c78 100644 --- a/patches/server/0006-Add-config-for-sand-duping.patch +++ b/patches/server/0006-Add-config-for-sand-duping.patch @@ -1,57 +1,54 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 01:53:06 +0000 +Date: Wed, 7 Feb 2024 00:56:34 +0000 Subject: [PATCH] Add config for sand duping -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 36ca0b94d29d81e5f1f2aff4a38ead0b363dd1c7..9db3bdd7a7d0b2a110e927ee4781eee489d0da9b 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -15,6 +15,7 @@ public class LuminolConfig { - public static boolean fakeVanillaModeEnabled = false; - - public static boolean safeTeleportation = true; -+ public static boolean enableSandDuping = false; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -35,6 +36,7 @@ public class LuminolConfig { - fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server"); - - safeTeleportation = get("fixes.enable_safe_teleportation",safeTeleportation,"If this enabled,the end portals will not teleport removed entities."); -+ enableSandDuping = get("fixes.enable_sand_duping",enableSandDuping,"If this enabled,The value of safe teleportation will always be false and sand duping will be enabled"); - } - - public static T get(String key,T def){ +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/SandDupingFixConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/SandDupingFixConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..cacb1f51a28eaa260aedba8d5b541475605e36ea +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/SandDupingFixConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.fixes; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class SandDupingFixConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "sand_duping"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -index 25b7b85cbd1130c5320e55b3c6b6f81ec228da81..018e4acb2ad6795e6c5059a47023e1b5c8713705 100644 +index 25b7b85cbd1130c5320e55b3c6b6f81ec228da81..c43f710a558cfe887a373a94ee48c4804986186d 100644 --- a/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java +++ b/src/main/java/net/minecraft/world/entity/item/FallingBlockEntity.java -@@ -4,6 +4,8 @@ import com.mojang.logging.LogUtils; - import java.util.Iterator; - import java.util.function.Predicate; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.CrashReportCategory; - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; -@@ -133,7 +135,7 @@ public class FallingBlockEntity extends Entity { +@@ -133,7 +133,7 @@ public class FallingBlockEntity extends Entity { @Override public void tick() { // Paper start - fix sand duping - if (this.isRemoved()) { -+ if (!LuminolConfig.enableSandDuping && this.isRemoved()) { //Luminol - Add config for sand duping ++ if (!me.earthme.luminol.config.modules.fixes.SandDupingFixConfig.enabled && this.isRemoved()) { //Luminol - Add config for sand duping return; } // Paper end - fix sand duping -@@ -149,7 +151,7 @@ public class FallingBlockEntity extends Entity { +@@ -149,7 +149,7 @@ public class FallingBlockEntity extends Entity { this.move(MoverType.SELF, this.getDeltaMovement()); // Paper start - fix sand duping - if (this.isRemoved()) { -+ if (!LuminolConfig.enableSandDuping && this.isRemoved()) { //Luminol - Add config for sand duping ++ if (!me.earthme.luminol.config.modules.fixes.SandDupingFixConfig.enabled && this.isRemoved()) { //Luminol - Add config for sand duping return; } // Paper end - fix sand duping diff --git a/patches/server/0007-Add-config-for-void-trading.patch b/patches/server/0007-Add-config-for-void-trading.patch index ae011a9..df4aa18 100644 --- a/patches/server/0007-Add-config-for-void-trading.patch +++ b/patches/server/0007-Add-config-for-void-trading.patch @@ -1,39 +1,45 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 01:55:03 +0000 +Date: Wed, 7 Feb 2024 00:59:18 +0000 Subject: [PATCH] Add config for void trading -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 9db3bdd7a7d0b2a110e927ee4781eee489d0da9b..dffa9db569fcef2feec75072fe86c9a6ded80aa4 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -16,6 +16,7 @@ public class LuminolConfig { - - public static boolean safeTeleportation = true; - public static boolean enableSandDuping = false; -+ public static boolean enableVoidTrading = false; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -37,6 +38,7 @@ public class LuminolConfig { - - safeTeleportation = get("fixes.enable_safe_teleportation",safeTeleportation,"If this enabled,the end portals will not teleport removed entities."); - enableSandDuping = get("fixes.enable_sand_duping",enableSandDuping,"If this enabled,The value of safe teleportation will always be false and sand duping will be enabled"); -+ enableVoidTrading = get("fixes.enable_void_trading",enableVoidTrading); - } - - public static T get(String key,T def){ +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/VoidTradingFixConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/VoidTradingFixConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a72f3a6cf1580f901b12417cac10303090a3370f +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/VoidTradingFixConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.fixes; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class VoidTradingFixConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "void_trading"; ++ } ++} diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 0a2d50b72506115644af5682d72f8ee04e45796b..00593eadeadc74429a05d83e10964781b6311c54 100644 +index a16fc5ba55dbde0cf7f968884da40d70a754a0d8..9e82dc98ef2d4da39839699f455e0ef20ab4ef65 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -3056,7 +3056,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -3046,7 +3046,7 @@ public class ServerLevel extends Level implements WorldGenLevel { // Spigot Start if (entity.getBukkitEntity() instanceof org.bukkit.inventory.InventoryHolder && (!(entity instanceof ServerPlayer) || entity.getRemovalReason() != Entity.RemovalReason.KILLED)) { // SPIGOT-6876: closeInventory clears death message // Paper start - Fix merchant inventory not closing on entity removal - if (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null) { -+ if (!LuminolConfig.enableVoidTrading && (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null)) { //Luminol - Add config for void trading ++ if (!me.earthme.luminol.config.modules.fixes.VoidTradingFixConfig.enabled && (entity.getBukkitEntity() instanceof org.bukkit.inventory.Merchant merchant && merchant.getTrader() != null)) { //Luminol - Add config for void trading merchant.getTrader().closeInventory(org.bukkit.event.inventory.InventoryCloseEvent.Reason.UNLOADED); } // Paper end - Fix merchant inventory not closing on entity removal diff --git a/patches/server/0008-Add-config-for-incorrect-tripwire-updating-fixing.patch b/patches/server/0008-Add-config-for-incorrect-tripwire-updating-fixing.patch index 8511012..fa07bcc 100644 --- a/patches/server/0008-Add-config-for-incorrect-tripwire-updating-fixing.patch +++ b/patches/server/0008-Add-config-for-incorrect-tripwire-updating-fixing.patch @@ -1,48 +1,45 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 01:56:30 +0000 +Date: Wed, 7 Feb 2024 01:05:57 +0000 Subject: [PATCH] Add config for incorrect tripwire updating fixing -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index dffa9db569fcef2feec75072fe86c9a6ded80aa4..a49da370c91211d4e2274f72d62c911a1912296a 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -17,6 +17,7 @@ public class LuminolConfig { - public static boolean safeTeleportation = true; - public static boolean enableSandDuping = false; - public static boolean enableVoidTrading = false; -+ public static boolean allowIncorrectTripwireUpdating = false; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -39,6 +40,7 @@ public class LuminolConfig { - safeTeleportation = get("fixes.enable_safe_teleportation",safeTeleportation,"If this enabled,the end portals will not teleport removed entities."); - enableSandDuping = get("fixes.enable_sand_duping",enableSandDuping,"If this enabled,The value of safe teleportation will always be false and sand duping will be enabled"); - enableVoidTrading = get("fixes.enable_void_trading",enableVoidTrading); -+ allowIncorrectTripwireUpdating = get("fixes.allow_incorrect_trip_wire_updaing",allowIncorrectTripwireUpdating); - } - - public static T get(String key,T def){ +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/IncorrectTripwireFixConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/IncorrectTripwireFixConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8779c9fba1990c62e010387e32d1923410a043ed +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/IncorrectTripwireFixConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.fixes; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class IncorrectTripwireFixConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "update_incorrect_trip_wire"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java -index 7f2dcf6a9e69779e6f898284b58fb1e32902000c..c9177a8c94cb47ac8082404bbe86cbc121a9e064 100644 +index 7f2dcf6a9e69779e6f898284b58fb1e32902000c..e1a7208b76e4dc7f388923d72edeceb6daefa774 100644 --- a/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java +++ b/src/main/java/net/minecraft/world/level/block/TripWireHookBlock.java -@@ -4,6 +4,8 @@ import com.google.common.base.MoreObjects; - import com.mojang.serialization.MapCodec; - import java.util.Optional; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; - import net.minecraft.server.level.ServerLevel; -@@ -162,7 +164,7 @@ public class TripWireHookBlock extends Block { +@@ -162,7 +162,7 @@ public class TripWireHookBlock extends Block { boolean flag7 = (Boolean) iblockdata2.getValue(TripWireBlock.POWERED); flag5 |= flag6 && flag7; - if (k != i || !tripWireBeingRemoved || !flag6) // Paper - fix tripwire state inconsistency; don't update the tripwire again if being removed and not disarmed -+ if (k != i || !tripWireBeingRemoved || !flag6 || LuminolConfig.allowIncorrectTripwireUpdating) // Paper - don't update the tripwire again if being removed and not disarmed //Luminol - Add config for incorrect tripwire updating fixing ++ if (k != i || !tripWireBeingRemoved || !flag6 || me.earthme.luminol.config.modules.fixes.IncorrectTripwireFixConfig.enabled) // Paper - don't update the tripwire again if being removed and not disarmed //Luminol - Add config for incorrect tripwire updating fixing aiblockdata[k] = iblockdata2; if (k == i) { world.scheduleTick(pos, block, 10); diff --git a/patches/server/0009-Add-config-for-chat-sign.patch b/patches/server/0009-Add-config-for-chat-sign.patch index 270719a..22b1d5c 100644 --- a/patches/server/0009-Add-config-for-chat-sign.patch +++ b/patches/server/0009-Add-config-for-chat-sign.patch @@ -1,91 +1,70 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Sat, 27 Jan 2024 07:55:42 +0000 +Date: Wed, 7 Feb 2024 02:00:50 +0000 Subject: [PATCH] Add config for chat sign -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index a49da370c91211d4e2274f72d62c911a1912296a..8d1ce8eae252fcf05b6a62d2dc467d6d503d3df4 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -13,6 +13,7 @@ public class LuminolConfig { - - public static String serverModName = "Luminol"; - public static boolean fakeVanillaModeEnabled = false; -+ public static boolean disableChatSign = false; - - public static boolean safeTeleportation = true; - public static boolean enableSandDuping = false; -@@ -36,6 +37,7 @@ public class LuminolConfig { - public static void initValues(){ - serverModName = get("misc.server_mod_name",serverModName,"The servermod name will be sent to players,and you can see it in F3 or motd responses"); - fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server"); -+ disableChatSign = get("misc.disable_chat_sign",disableChatSign,"Set this to true to disable mojang's chat sign"); - - safeTeleportation = get("fixes.enable_safe_teleportation",safeTeleportation,"If this enabled,the end portals will not teleport removed entities."); - enableSandDuping = get("fixes.enable_sand_duping",enableSandDuping,"If this enabled,The value of safe teleportation will always be false and sand duping will be enabled"); +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/ChatSignConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/ChatSignConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1e03e51e51f56c38abaad100274e25c9f854f727 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/ChatSignConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class ChatSignConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = true; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "mojang_chat_sign"; ++ } ++} diff --git a/src/main/java/net/minecraft/commands/arguments/ArgumentSignatures.java b/src/main/java/net/minecraft/commands/arguments/ArgumentSignatures.java -index 72a8aa676836fcb3b4578689d16af65e18f55bbe..04653d58f2493d796e61bc97f0481cb628539c37 100644 +index 72a8aa676836fcb3b4578689d16af65e18f55bbe..9408747cb254a99d5cb3fc26fde16ddb80168894 100644 --- a/src/main/java/net/minecraft/commands/arguments/ArgumentSignatures.java +++ b/src/main/java/net/minecraft/commands/arguments/ArgumentSignatures.java -@@ -4,6 +4,8 @@ import java.util.ArrayList; - import java.util.List; - import java.util.Objects; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.network.FriendlyByteBuf; - import net.minecraft.network.chat.MessageSignature; - import net.minecraft.network.chat.SignableCommand; -@@ -14,8 +16,16 @@ public record ArgumentSignatures(List entries) { +@@ -14,9 +14,17 @@ public record ArgumentSignatures(List entries) { private static final int MAX_ARGUMENT_NAME_LENGTH = 16; public ArgumentSignatures(FriendlyByteBuf buf) { - this(buf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 8), ArgumentSignatures.Entry::new)); -+ this(readSign(buf)); -+ } -+ ++ this(readSign(buf)); //Luminol - Fix java compile + } + + //Luminol start - Add config for chat sign + private static List readSign(FriendlyByteBuf buf) { + var entries = buf.readCollection(FriendlyByteBuf.limitValue(ArrayList::new, 8), Entry::new); -+ return LuminolConfig.disableChatSign ? List.of() : entries; - } ++ return me.earthme.luminol.config.modules.misc.ChatSignConfig.enabled ? List.of() : entries; ++ } + //Luminol end + - ++ @Nullable public MessageSignature get(String argumentName) { + for(ArgumentSignatures.Entry entry : this.entries) { diff --git a/src/main/java/net/minecraft/network/FriendlyByteBuf.java b/src/main/java/net/minecraft/network/FriendlyByteBuf.java -index b863249ff7e13cf4939c8961601f0564c62fd661..4e9bfce4fd188e832c15feedebe4d10b6873b764 100644 +index b863249ff7e13cf4939c8961601f0564c62fd661..6ab73b0568c3f9df8090be992736a14d49e0286c 100644 --- a/src/main/java/net/minecraft/network/FriendlyByteBuf.java +++ b/src/main/java/net/minecraft/network/FriendlyByteBuf.java -@@ -48,6 +48,8 @@ import java.util.function.Function; - import java.util.function.IntFunction; - import java.util.function.ToIntFunction; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.Util; - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; -@@ -83,6 +85,8 @@ import org.joml.Vector3f; - - import org.bukkit.craftbukkit.inventory.CraftItemStack; // CraftBukkit - -+import net.minecraft.network.protocol.status.ServerStatus; -+ - public class FriendlyByteBuf extends ByteBuf { - - public static final int DEFAULT_NBT_QUOTA = 2097152; -@@ -143,6 +147,17 @@ public class FriendlyByteBuf extends ByteBuf { +@@ -143,6 +143,16 @@ public class FriendlyByteBuf extends ByteBuf { // Paper end - Adventure; add max length parameter DataResult dataresult = codec.encodeStart(JsonOps.INSTANCE, value); -+ + //Luminol start - Add config for chat sign -+ if (codec == ServerStatus.CODEC) { ++ if (codec == net.minecraft.network.protocol.status.ServerStatus.CODEC) { + JsonElement element = Util.getOrThrow(dataresult, string -> new EncoderException("Failed to encode: " + string + " " + value)); -+ element.getAsJsonObject().addProperty("preventsChatReports", LuminolConfig.disableChatSign); ++ element.getAsJsonObject().addProperty("preventsChatReports", !me.earthme.luminol.config.modules.misc.ChatSignConfig.enabled); + + this.writeUtf(GSON.toJson(element)); + return; diff --git a/patches/server/0010-Add-config-for-vanilla-random.patch b/patches/server/0010-Add-config-for-vanilla-random.patch index 53fc2aa..584ef4d 100644 --- a/patches/server/0010-Add-config-for-vanilla-random.patch +++ b/patches/server/0010-Add-config-for-vanilla-random.patch @@ -1,39 +1,45 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 02:06:42 +0000 +Date: Wed, 7 Feb 2024 02:33:00 +0000 Subject: [PATCH] Add config for vanilla random -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 8d1ce8eae252fcf05b6a62d2dc467d6d503d3df4..89d8ffc947d265e0e81943ad851e868b622de168 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -19,6 +19,7 @@ public class LuminolConfig { - public static boolean enableSandDuping = false; - public static boolean enableVoidTrading = false; - public static boolean allowIncorrectTripwireUpdating = false; -+ public static boolean useVanillaRandomSource = false; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -43,6 +44,7 @@ public class LuminolConfig { - enableSandDuping = get("fixes.enable_sand_duping",enableSandDuping,"If this enabled,The value of safe teleportation will always be false and sand duping will be enabled"); - enableVoidTrading = get("fixes.enable_void_trading",enableVoidTrading); - allowIncorrectTripwireUpdating = get("fixes.allow_incorrect_trip_wire_updaing",allowIncorrectTripwireUpdating); -+ useVanillaRandomSource = get("fixes.use_vanilla_random_source",useVanillaRandomSource,"RNG feature related"); - } - - public static T get(String key,T def){ +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/VanillaRandomSourceConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/VanillaRandomSourceConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8ba66e737d36157b3797c308cb9fca804e396915 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/VanillaRandomSourceConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.fixes; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class VanillaRandomSourceConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enable_for_player_entity") ++ public static boolean useLegacyRandomSourceForPlayers = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "vanilla_random_source"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 4cc0a97c0c3cef23b10930e204039c4450543907..18c9a35624d6d3c94efd5df8e97c4257fd199d0d 100644 +index 6b560754382936d4889e5729613077a3401d8740..865804a16fce714497b2c025a869f972787442e3 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -565,7 +565,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -563,7 +563,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S this.bb = Entity.INITIAL_AABB; this.stuckSpeedMultiplier = Vec3.ZERO; this.nextStep = 1.0F; - this.random = SHARED_RANDOM; // Paper - Share random for entities to make them more random -+ this.random = LuminolConfig.useVanillaRandomSource ? RandomSource.create() : SHARED_RANDOM;//Luminol - Add config for vanilla random SHARED_RANDOM // Paper - Share random for entities to make them more random ++ this.random = me.earthme.luminol.config.modules.fixes.VanillaRandomSourceConfig.useLegacyRandomSourceForPlayers ? RandomSource.create() : SHARED_RANDOM;//Luminol - Add config for vanilla random SHARED_RANDOM // Paper - Share random for entities to make them more random this.remainingFireTicks = -this.getFireImmuneTicks(); this.fluidHeight = new Object2DoubleArrayMap(2); this.fluidOnEyes = new HashSet(); diff --git a/patches/server/0015-Add-a-simple-tpsbar.patch b/patches/server/0011-Add-a-simple-tpsbar.patch similarity index 68% rename from patches/server/0015-Add-a-simple-tpsbar.patch rename to patches/server/0011-Add-a-simple-tpsbar.patch index 83c4baf..1e5b7c8 100644 --- a/patches/server/0015-Add-a-simple-tpsbar.patch +++ b/patches/server/0011-Add-a-simple-tpsbar.patch @@ -1,66 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 03:05:31 +0000 +Date: Wed, 7 Feb 2024 04:39:56 +0000 Subject: [PATCH] Add a simple tpsbar -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 90a6cfd011aaefe66fda79f887380ab2d62a07b1..0657fce8aabb956a400b3cead53c28ef52e67fe9 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -2,11 +2,15 @@ package me.earthme.luminol; - - import dev.kaiijumc.kaiiju.region.RegionFileFormat; - import com.electronwill.nightconfig.core.file.CommentedFileConfig; -+import me.earthme.luminol.commands.TpsBarCommand; -+import me.earthme.luminol.functions.GlobalServerTpsBar; - import net.minecraft.server.level.ServerLevel; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; -+import org.bukkit.Bukkit; - - import java.util.Arrays; -+import java.util.List; - import java.util.logging.Level; - import java.io.File; - import java.io.IOException; -@@ -20,6 +24,10 @@ public class LuminolConfig { - public static String serverModName = "Luminol"; - public static boolean fakeVanillaModeEnabled = false; - public static boolean disableChatSign = false; -+ public static boolean tpsbarEnabled = false; -+ public static String tpsBarFormat = "TPS: MSPT: Ping: ms"; -+ public static String[] tpsColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; -+ public static String[] pingColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; - - public static boolean safeTeleportation = true; - public static boolean enableSandDuping = false; -@@ -46,10 +54,25 @@ public class LuminolConfig { - MAIN_CONFIG.save(); - } - -+ public static void initTpsbar(){ -+ if (tpsbarEnabled){ -+ GlobalServerTpsBar.init(); -+ Bukkit.getCommandMap().register("tpsbar","luminol",new TpsBarCommand("tpsbar")); -+ } -+ } -+ - public static void initValues(){ - serverModName = get("misc.server_mod_name",serverModName,"The servermod name will be sent to players,and you can see it in F3 or motd responses"); - fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server"); - disableChatSign = get("misc.disable_chat_sign",disableChatSign,"Set this to true to disable mojang's chat sign"); -+ tpsbarEnabled = get("misc.enable_tpsbar",tpsbarEnabled,"When this enabled,You or your players can see the tps,mspt and ping through a simple bossbar"); -+ tpsBarFormat = get("misc.tpsbar_title_format",tpsBarFormat,"The format of tpsbar."); -+ tpsColors = get("misc.tpsbar_range_colors", List.of(tpsColors),"The bar and text color of each tps ranges.The last is the color of initial bar's color").toArray(String[]::new); -+ pingColors = get("misc.tpsbar_ping_range_colors",List.of(pingColors),"As same as the tpsColors").toArray(String[]::new); -+ -+ if (tpsbarEnabled){ -+ initTpsbar(); -+ } - - safeTeleportation = get("fixes.enable_safe_teleportation",safeTeleportation,"If this enabled,the end portals will not teleport removed entities."); - enableSandDuping = get("fixes.enable_sand_duping",enableSandDuping,"If this enabled,The value of safe teleportation will always be false and sand duping will be enabled"); diff --git a/src/main/java/me/earthme/luminol/commands/TpsBarCommand.java b/src/main/java/me/earthme/luminol/commands/TpsBarCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..ac8f0e3bf130ba6dfd7202e2f480352218154cdc @@ -107,26 +50,73 @@ index 0000000000000000000000000000000000000000..ac8f0e3bf130ba6dfd7202e2f4803522 + return true; + } +} +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/TpsBarConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/TpsBarConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b370787c3f525b9b978ad14b3e7056d7c92fcae5 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/TpsBarConfig.java +@@ -0,0 +1,40 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import me.earthme.luminol.commands.TpsBarCommand; ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++import me.earthme.luminol.functions.GlobalServerTpsBar; ++import org.bukkit.Bukkit; ++ ++import java.util.List; ++ ++public class TpsBarConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean tpsbarEnabled = false; ++ @ConfigInfo(baseName = "format") ++ public static String tpsBarFormat = "TPS: MSPT: Ping: ms"; ++ @ConfigInfo(baseName = "tps_color_list") ++ public static List tpsColors = List.of("GREEN","YELLOW","RED","PURPLE"); ++ @ConfigInfo(baseName = "ping_color_list") ++ public static List pingColors = List.of("GREEN","YELLOW","RED","PURPLE"); ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "tpsbar"; ++ } ++ ++ @Override ++ public void onLoaded(CommentedFileConfig configInstance){ ++ if (tpsbarEnabled){ ++ GlobalServerTpsBar.init(); ++ Bukkit.getCommandMap().register("tpsbar","luminol",new TpsBarCommand("tpsbar")); ++ } ++ } ++} diff --git a/src/main/java/me/earthme/luminol/functions/GlobalServerTpsBar.java b/src/main/java/me/earthme/luminol/functions/GlobalServerTpsBar.java new file mode 100644 -index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a7420757b +index 0000000000000000000000000000000000000000..7511bc3f6828ab712f644cf4292a5f831e8c8653 --- /dev/null +++ b/src/main/java/me/earthme/luminol/functions/GlobalServerTpsBar.java -@@ -0,0 +1,204 @@ +@@ -0,0 +1,206 @@ +package me.earthme.luminol.functions; + -+import com.google.common.collect.Lists; +import io.papermc.paper.threadedregions.ThreadedRegionizer; +import io.papermc.paper.threadedregions.TickData; +import io.papermc.paper.threadedregions.TickRegions; +import io.papermc.paper.threadedregions.scheduler.ScheduledTask; -+import me.earthme.luminol.LuminolConfig; ++import me.earthme.luminol.config.modules.misc.TpsBarConfig; +import net.kyori.adventure.bossbar.BossBar; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.minimessage.MiniMessage; +import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; ++import org.apache.logging.log4j.LogManager; ++import org.apache.logging.log4j.Logger; +import org.bukkit.Bukkit; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin; @@ -140,6 +130,7 @@ index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a + protected static final MinecraftInternalPlugin NULL_PLUGIN = new MinecraftInternalPlugin(); + protected static final Map uuid2Bossbars = new HashMap<>(); + protected static volatile ScheduledTask tpsbarTask = null; ++ private static final Logger logger = LogManager.getLogger(); + + public static void init(){ + Bukkit.getAsyncScheduler().runAtFixedRate(NULL_PLUGIN,c -> { @@ -147,7 +138,7 @@ index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a + try { + update(); + }catch (Exception e){ -+ e.printStackTrace(); ++ logger.error(e); + } + },1,1, TimeUnit.SECONDS); + } @@ -215,7 +206,7 @@ index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a + BossBar targetBossbar = uuid2Bossbars.get(nmsPlayer.getUUID()); + + if (targetBossbar == null && isPlayerVisible(apiPlayer)){ -+ targetBossbar = BossBar.bossBar(Component.text(""),0.0F, BossBar.Color.valueOf(LuminolConfig.tpsColors[3]), BossBar.Overlay.NOTCHED_20); ++ targetBossbar = BossBar.bossBar(Component.text(""),0.0F, BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(3)), BossBar.Overlay.NOTCHED_20); + uuid2Bossbars.put(nmsPlayer.getUUID(),targetBossbar); + apiPlayer.showBossBar(targetBossbar); + } @@ -230,7 +221,7 @@ index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a + + private static void updateTpsBar(double tps, double mspt, @NotNull BossBar bar, @NotNull Player player){ + bar.name(MiniMessage.miniMessage().deserialize( -+ LuminolConfig.tpsBarFormat, ++ TpsBarConfig.tpsBarFormat, + Placeholder.component("tps",getTpsComponent(tps)), + Placeholder.component("mspt",getMsptComponent(mspt)), + Placeholder.component("ping",getPingComponent(player.getPing())) @@ -251,18 +242,18 @@ index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a + + private static BossBar.Color barColorFromPing(int ping){ + if (ping == -1){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[3]); ++ return BossBar.Color.valueOf(TpsBarConfig.pingColors.get(3)); + } + + if (ping <= 80){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[0]); ++ return BossBar.Color.valueOf(TpsBarConfig.pingColors.get(0)); + } + + if (ping <= 160){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[1]); ++ return BossBar.Color.valueOf(TpsBarConfig.pingColors.get(1)); + } + -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[2]); ++ return BossBar.Color.valueOf(TpsBarConfig.pingColors.get(2)); + } + + private static @NotNull Component getMsptComponent(double mspt){ @@ -277,18 +268,18 @@ index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a + + private static BossBar.Color barColorFromMspt(double mspt){ + if (mspt == -1){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[3]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(3)); + } + + if (mspt <= 25){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[0]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(0)); + } + + if (mspt <= 50){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[1]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(1)); + } + -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[2]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(2)); + } + + private static @NotNull Component getTpsComponent(double tps){ @@ -303,90 +294,65 @@ index 0000000000000000000000000000000000000000..59c39402d896d0ba75a9ca7e6c74a01a + + private static BossBar.Color barColorFromTps(double tps){ + if (tps == -1){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[3]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(3)); + } + + if (tps >= 18){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[0]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(0)); + } + + if (tps >= 15){ -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[1]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(1)); + } + -+ return BossBar.Color.valueOf(LuminolConfig.tpsColors[2]); ++ return BossBar.Color.valueOf(TpsBarConfig.tpsColors.get(2)); + } +} diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 5a71ee8d50818c5d6e7a6a2fee05a5c16108b50a..c16f92ac58bbaac875450e2c019772d13384d1de 100644 +index d99e0acf0000c566fdb1bffb149ec13a55d7c8dd..9c5d4cab2e2ec03f5413cfc9d809f2f148f0ba4d 100644 --- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -1,20 +1,16 @@ - package net.minecraft.server.dedicated; - --import com.google.common.collect.Lists; -+import me.earthme.luminol.functions.GlobalServerTpsBar; - import com.mojang.authlib.GameProfile; - import com.mojang.datafixers.DataFixer; - import com.mojang.logging.LogUtils; --import java.io.BufferedReader; -+ - import java.io.BufferedWriter; - import java.io.IOException; --import java.io.InputStreamReader; - import java.net.InetAddress; - import java.net.Proxy; --import java.nio.charset.StandardCharsets; - import java.nio.file.Files; - import java.nio.file.Path; --import java.util.Collections; --import java.util.List; - import java.util.Locale; - import java.util.Optional; - import java.util.function.BooleanSupplier; -@@ -830,6 +826,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface +@@ -830,6 +830,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface @Override public void stopServer() { -+ GlobalServerTpsBar.cancelBarUpdateTask(); //Luminol - Tpsbar ++ me.earthme.luminol.functions.GlobalServerTpsBar.cancelBarUpdateTask(); //Luminol - Tpsbar super.stopServer(); //Util.shutdownExecutors(); // Paper - moved into super SkullBlockEntity.clear(); diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index c8ee0307fa6c13c34a1db80ddf65d8381fd556be..1e5df8a667dad52aef51e4c22e1e0234548a17f6 100644 +index c8ee0307fa6c13c34a1db80ddf65d8381fd556be..92a2e116f47d1434cc406709c3bcf85fedd2bb86 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java @@ -285,6 +285,7 @@ public class ServerPlayer extends Player { // Paper start - replace player chunk loader private final java.util.concurrent.atomic.AtomicReference viewDistances = new java.util.concurrent.atomic.AtomicReference<>(new io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances(-1, -1, -1)); public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.PlayerChunkLoaderData chunkLoader; -+ public volatile boolean isTpsBarVisible = false; ++ public volatile boolean isTpsBarVisible = false; //Luminol - Tps bar public io.papermc.paper.chunk.system.RegionizedPlayerChunkLoader.ViewDistances getViewDistances() { return this.viewDistances.get(); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index fc301fcf812b79ac7ceae710132a762f101b82b2..91678602a5509b7ee0ff792d1a626e271b7db6b9 100644 +index fc301fcf812b79ac7ceae710132a762f101b82b2..f4b7f2f223964df7533577342d8af158af35363b 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -@@ -2257,6 +2257,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2257,6 +2257,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { handle.expToDrop = data.getInt("expToDrop"); handle.keepLevel = data.getBoolean("keepLevel"); } -+ + //Luminol start - Tpsbar + getHandle().isTpsBarVisible = data.getBoolean("tpsbarVisible"); + //Luminol end } } -@@ -2278,6 +2282,10 @@ public class CraftPlayer extends CraftHumanEntity implements Player { +@@ -2278,6 +2281,9 @@ public class CraftPlayer extends CraftHumanEntity implements Player { data.putLong("lastPlayed", System.currentTimeMillis()); data.putString("lastKnownName", handle.getScoreboardName()); + //Luminol start - Tpsbar + data.putBoolean("tpsbarVisible",handle.isTpsBarVisible); + //Luminol end -+ // Paper start - persist for use in offline save data if (!nbttagcompound.contains("Paper")) { nbttagcompound.put("Paper", new CompoundTag()); diff --git a/patches/server/0012-Add-config-for-username-check.patch b/patches/server/0012-Add-config-for-username-check.patch new file mode 100644 index 0000000..406e2b8 --- /dev/null +++ b/patches/server/0012-Add-config-for-username-check.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrHua269 +Date: Wed, 7 Feb 2024 04:50:10 +0000 +Subject: [PATCH] Add config for username check + + +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/UsernameCheckConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/UsernameCheckConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c7e4724cc4ab8d911bcaf0106c098b266c843bb1 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/UsernameCheckConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class UsernameCheckConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = true; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "username_checks"; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +index aa4b461bbb2c8c4753f7c9057bab1740de2c0284..1ff6c82925417932df856bf1e5866519327f018e 100644 +--- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java ++++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java +@@ -143,7 +143,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, + @Override + public void handleHello(ServerboundHelloPacket packet) { + Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]); +- if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation) Validate.validState(Player.isValidUsername(packet.name()), "Invalid characters in username", new Object[0]); // Paper - config username validation ++ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation && me.earthme.luminol.config.modules.misc.UsernameCheckConfig.enabled) Validate.validState(Player.isValidUsername(packet.name()), "Invalid characters in username", new Object[0]); // Paper - config username validation //Luminol - Add config for username check + this.requestedUsername = packet.name(); + GameProfile gameprofile = this.server.getSingleplayerProfile(); + diff --git a/patches/server/0012-Add-logger-field-to-LuminolConfig.patch b/patches/server/0012-Add-logger-field-to-LuminolConfig.patch deleted file mode 100644 index 863e9bf..0000000 --- a/patches/server/0012-Add-logger-field-to-LuminolConfig.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 02:16:52 +0000 -Subject: [PATCH] Add logger field to LuminolConfig - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 89d8ffc947d265e0e81943ad851e868b622de168..74573c50c903cfbe5f9617be5b75c21647f05a91 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -2,11 +2,14 @@ package me.earthme.luminol; - - import com.electronwill.nightconfig.core.file.CommentedFileConfig; - import net.minecraft.server.level.ServerLevel; -+import org.apache.logging.log4j.LogManager; -+import org.apache.logging.log4j.Logger; - - import java.io.File; - import java.io.IOException; - - public class LuminolConfig { -+ private static final Logger logger = LogManager.getLogger(); - private static final File PARENT_FOLDER = new File("luminol_config"); - private static final File MAIN_CONFIG_FILE = new File(PARENT_FOLDER,"luminol_global.toml"); - private static CommentedFileConfig MAIN_CONFIG; diff --git a/patches/server/0013-Add-config-for-offline-mode-warning.patch b/patches/server/0013-Add-config-for-offline-mode-warning.patch new file mode 100644 index 0000000..a5e016f --- /dev/null +++ b/patches/server/0013-Add-config-for-offline-mode-warning.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrHua269 +Date: Wed, 7 Feb 2024 06:40:44 +0000 +Subject: [PATCH] Add config for offline mode warning + + +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/OfflineModeWarningConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/OfflineModeWarningConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..502b93c7bda9e8577a1901a8777b7cf9b9bdc36b +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/OfflineModeWarningConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class OfflineModeWarningConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = true; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "warn_on_offline_mode"; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +index 9c5d4cab2e2ec03f5413cfc9d809f2f148f0ba4d..f88c42852555461ec6a2e868adbce55227da38f0 100644 +--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java ++++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java +@@ -282,7 +282,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface + 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 (!this.usesAuthentication() && !me.earthme.luminol.config.modules.misc.OfflineModeWarningConfig.enabled) { //Luminol - Add config for offline mod warning + DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); + DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); + // Spigot start diff --git a/patches/server/0013-Kaiiju-region-format-settings.patch b/patches/server/0013-Kaiiju-region-format-settings.patch deleted file mode 100644 index dfc4d1f..0000000 --- a/patches/server/0013-Kaiiju-region-format-settings.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 02:17:20 +0000 -Subject: [PATCH] Kaiiju region format settings - - -diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/RegionFileFormat.java b/src/main/java/dev/kaiijumc/kaiiju/region/RegionFileFormat.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7164d9cd03186f0657783f83de3d6435cda2b17e ---- /dev/null -+++ b/src/main/java/dev/kaiijumc/kaiiju/region/RegionFileFormat.java -@@ -0,0 +1,16 @@ -+package dev.kaiijumc.kaiiju.region; -+ -+public enum RegionFileFormat { -+ ANVIL, -+ LINEAR, -+ INVALID; -+ -+ public static RegionFileFormat fromString(String format) { -+ for (RegionFileFormat rff : values()) { -+ if (rff.name().equalsIgnoreCase(format)) { -+ return rff; -+ } -+ } -+ return RegionFileFormat.INVALID; -+ } -+} -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 74573c50c903cfbe5f9617be5b75c21647f05a91..3d526d7cfb313e419de89be1b275651982be42c7 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -1,10 +1,13 @@ - package me.earthme.luminol; - -+import dev.kaiijumc.kaiiju.region.RegionFileFormat; - import com.electronwill.nightconfig.core.file.CommentedFileConfig; - import net.minecraft.server.level.ServerLevel; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - -+import java.util.Arrays; -+import java.util.logging.Level; - import java.io.File; - import java.io.IOException; - -@@ -24,6 +27,9 @@ public class LuminolConfig { - public static boolean allowIncorrectTripwireUpdating = false; - public static boolean useVanillaRandomSource = false; - -+ public static RegionFileFormat regionFormatName = RegionFileFormat.ANVIL; -+ public static int regionFormatLinearCompressionLevel = 1; -+ - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); - -@@ -48,6 +54,19 @@ public class LuminolConfig { - enableVoidTrading = get("fixes.enable_void_trading",enableVoidTrading); - allowIncorrectTripwireUpdating = get("fixes.allow_incorrect_trip_wire_updaing",allowIncorrectTripwireUpdating); - useVanillaRandomSource = get("fixes.use_vanilla_random_source",useVanillaRandomSource,"RNG feature related"); -+ -+ regionFormatName = RegionFileFormat.fromString(get("save.region-format.format", regionFormatName.name())); -+ if (regionFormatName.equals(RegionFileFormat.INVALID)) { -+ logger.error("Unknown region format in luminol global config: " + regionFormatName); -+ logger.error("Falling back to ANVIL region file format."); -+ regionFormatName = RegionFileFormat.ANVIL; -+ } -+ regionFormatLinearCompressionLevel = get("save.region-format.linear.compression-level", regionFormatLinearCompressionLevel); -+ if (regionFormatLinearCompressionLevel > 23 || regionFormatLinearCompressionLevel < 1) { -+ logger.error("Linear region compression level should be between 1 and 22 in luminol global config: " + regionFormatLinearCompressionLevel); -+ logger.error("Falling back to compression level 1."); -+ regionFormatLinearCompressionLevel = 1; -+ } - } - - public static T get(String key,T def){ -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index bf1df7da39dc42bda2e4b54ae3f6856399f5cb10..76522b9fd7c0aaa17ab6df2183dfb30da2a35a68 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -925,7 +925,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop +Date: Wed, 7 Feb 2024 06:30:03 +0000 +Subject: [PATCH] Try fixing folia spector teleportation + + +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaSpectorTeleportationFixConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaSpectorTeleportationFixConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8487799cdfb776eaca33b57f7c99ae3aeadb890d +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaSpectorTeleportationFixConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.fixes; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class FoliaSpectorTeleportationFixConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean fixSpectorTeleportFolia = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "folia.fix_spector_teleportation"; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java +index 92a2e116f47d1434cc406709c3bcf85fedd2bb86..59f3ea98d0346d5b92053e13fa20048e3a946203 100644 +--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java ++++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java +@@ -17,6 +17,8 @@ import java.util.OptionalInt; + import java.util.Set; + import java.util.stream.Collectors; + import javax.annotation.Nullable; ++ ++import me.earthme.luminol.config.modules.fixes.FoliaSpectorTeleportationFixConfig; + import net.minecraft.BlockUtil; + import net.minecraft.ChatFormatting; + import net.minecraft.CrashReport; +@@ -842,6 +844,11 @@ public class ServerPlayer extends Player { + } + + Entity entity = this.getCamera(); ++ //Luminol start - Fix folia spector teleportation ++ if (!io.papermc.paper.util.TickThread.isTickThreadFor(entity) && FoliaSpectorTeleportationFixConfig.fixSpectorTeleportFolia){ ++ this.setCamera(this); ++ } ++ //Luminol end + + if (entity != this) { + if (entity.isAlive()) { diff --git a/patches/server/0048-Teleport-async-if-the-entity-was-moving-to-another-r.patch b/patches/server/0015-Teleport-async-if-entity-was-moving-to-another-regio.patch similarity index 53% rename from patches/server/0048-Teleport-async-if-the-entity-was-moving-to-another-r.patch rename to patches/server/0015-Teleport-async-if-entity-was-moving-to-another-regio.patch index f0330a4..dd35a4d 100644 --- a/patches/server/0048-Teleport-async-if-the-entity-was-moving-to-another-r.patch +++ b/patches/server/0015-Teleport-async-if-entity-was-moving-to-another-regio.patch @@ -1,33 +1,39 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 04:17:43 +0000 -Subject: [PATCH] Teleport async if the entity was moving to another region +Date: Wed, 7 Feb 2024 06:34:15 +0000 +Subject: [PATCH] Teleport async if entity was moving to another region at once -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index ec372d91ed60534ecbe0d2b28ba3b9abda800683..3f560bd27c5a43c5681b50492e04290dda51f37e 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -40,6 +40,8 @@ public class LuminolConfig { - public static boolean enableVoidTrading = false; - public static boolean allowIncorrectTripwireUpdating = false; - public static boolean useVanillaRandomSource = false; -+ public static boolean fixLargePosMoving = false; -+ public static boolean warnOnLargeMovingDetected = true; - - public static RegionFileFormat regionFormatName = RegionFileFormat.ANVIL; - public static int regionFormatLinearCompressionLevel = 1; -@@ -159,6 +161,8 @@ public class LuminolConfig { - enableVoidTrading = get("fixes.enable_void_trading",enableVoidTrading); - allowIncorrectTripwireUpdating = get("fixes.allow_incorrect_trip_wire_updaing",allowIncorrectTripwireUpdating); - useVanillaRandomSource = get("fixes.use_vanilla_random_source",useVanillaRandomSource,"RNG feature related"); -+ fixLargePosMoving = get("fixes.fix_large_pos_moving", fixLargePosMoving,"Fix an entity moving issue on folia which is not fixed yet"); -+ warnOnLargeMovingDetected = get("fixes.warn_on_large_pos_moving",warnOnLargeMovingDetected); - - regionFormatName = RegionFileFormat.fromString(get("save.region-format.format", regionFormatName.name())); - if (regionFormatName.equals(RegionFileFormat.INVALID)) { +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaEntityMovingFixConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaEntityMovingFixConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..9ccd6a3a07abfce54dccf9b6e01d0050d03279b2 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaEntityMovingFixConfig.java +@@ -0,0 +1,22 @@ ++package me.earthme.luminol.config.modules.fixes; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class FoliaEntityMovingFixConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ @ConfigInfo(baseName = "warnOnDetected") ++ public static boolean warnOnDetected = true; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "folia.fix_high_velocity_issue"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index b1a17c730939f39ba81209a368c215c236f203b0..ea7fe58bd68895dedeed2df1a7f1276d7fe5b70d 100644 +index 865804a16fce714497b2c025a869f972787442e3..7ba9c8677a09d43107ab0d178f4141c44a1d25bc 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -7,6 +7,7 @@ import com.google.common.collect.Lists; @@ -38,7 +44,16 @@ index b1a17c730939f39ba81209a368c215c236f203b0..ea7fe58bd68895dedeed2df1a7f1276d import it.unimi.dsi.fastutil.objects.Object2DoubleArrayMap; import it.unimi.dsi.fastutil.objects.Object2DoubleMap; import java.util.Arrays; -@@ -1084,10 +1085,40 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -24,6 +25,8 @@ import java.util.function.BiConsumer; + import java.util.function.Predicate; + import java.util.stream.Stream; + import javax.annotation.Nullable; ++ ++import me.earthme.luminol.config.modules.fixes.FoliaEntityMovingFixConfig; + import net.minecraft.BlockUtil; + import net.minecraft.CrashReport; + import net.minecraft.CrashReportCategory; +@@ -1071,10 +1074,40 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S } // Paper end - detailed watchdog information @@ -51,7 +66,7 @@ index b1a17c730939f39ba81209a368c215c236f203b0..ea7fe58bd68895dedeed2df1a7f1276d // Paper start - detailed watchdog information io.papermc.paper.util.TickThread.ensureTickThread("Cannot move an entity off-main"); + //Luminol start - Fix high position moving -+ if (LuminolConfig.fixLargePosMoving && TickThread.isTickThread()){ //Except the threads because it may be called by the chunk system worker thread ++ if (me.earthme.luminol.config.modules.fixes.FoliaEntityMovingFixConfig.enabled && TickThread.isTickThread()){ //Except the threads because it may be called by the chunk system worker thread + if (this.preventMoving){ + return; + } @@ -69,7 +84,7 @@ index b1a17c730939f39ba81209a368c215c236f203b0..ea7fe58bd68895dedeed2df1a7f1276d + this.preventMoving = false; + } + ); -+ if (LuminolConfig.warnOnLargeMovingDetected){ ++ if (FoliaEntityMovingFixConfig.warnOnDetected){ + MinecraftServer.LOGGER.warn("Entity {} with entityId {} has tried moving to another region!",this.type.getCategory().getName(),this.getId()); + } + return; diff --git a/patches/server/0016-Petal-Reduce-sensor-work.patch b/patches/server/0016-Petal-Reduce-sensor-work.patch deleted file mode 100644 index 8204c31..0000000 --- a/patches/server/0016-Petal-Reduce-sensor-work.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 03:10:04 +0000 -Subject: [PATCH] Petal Reduce sensor work - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 0657fce8aabb956a400b3cead53c28ef52e67fe9..c3a481cb7bea0619b1af0e3203e9d88514e84c62 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -40,6 +40,8 @@ public class LuminolConfig { - public static int linearFlushFrequency = 10; - public static int linearFlushThreads = 1; - -+ public static boolean reduceSensorWork = true; -+ - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); - -@@ -98,6 +100,8 @@ public class LuminolConfig { - linearFlushThreads = Math.max(Runtime.getRuntime().availableProcessors() + linearFlushThreads, 1); - else - linearFlushThreads = Math.max(linearFlushThreads, 1); -+ -+ reduceSensorWork = get("optimizations.reduce_sensor_work",reduceSensorWork,"This optimization is from petal.You can find out more about it on petal's repository"); - } - - public static T get(String key,T def){ -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index a1a0ac986e2052d3669428a29987630bc226d80f..7ca0057037380b9eac49a6415ec05acbb2b70ec0 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -10,6 +10,8 @@ import java.util.Optional; - import java.util.UUID; - import java.util.function.Predicate; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.core.BlockPos; - import net.minecraft.core.NonNullList; - import net.minecraft.core.Vec3i; -@@ -925,10 +927,11 @@ public abstract class Mob extends LivingEntity implements Targeting { - return; - } - // Paper end - Allow nerfed mobs to jump and float -+ int i = this.tickCount + this.getId(); // Folia - region threading //Luminol - Petal - Move up -+ - this.level().getProfiler().push("sensing"); -- this.sensing.tick(); -+ if (i % 10 == 0 || !LuminolConfig.reduceSensorWork)this.sensing.tick(); //Luminol - Petal - Reduce sensor work - this.level().getProfiler().pop(); -- int i = this.tickCount + this.getId(); // Folia - region threading - - if (i % 2 != 0 && this.tickCount > 1) { - this.level().getProfiler().push("targetSelector"); diff --git a/patches/server/0057-Prevent-teleportAsync-calling-during-moving-event-be.patch b/patches/server/0016-Prevent-teleportAsync-calling-during-moving-event-be.patch similarity index 75% rename from patches/server/0057-Prevent-teleportAsync-calling-during-moving-event-be.patch rename to patches/server/0016-Prevent-teleportAsync-calling-during-moving-event-be.patch index 331f49d..d0b963f 100644 --- a/patches/server/0057-Prevent-teleportAsync-calling-during-moving-event-be.patch +++ b/patches/server/0016-Prevent-teleportAsync-calling-during-moving-event-be.patch @@ -1,37 +1,42 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 04:33:45 +0000 +Date: Wed, 7 Feb 2024 06:58:52 +0000 Subject: [PATCH] Prevent teleportAsync calling during moving event being - handled -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 39b089fa8e347f5efba3be071164d831d4dc95c2..9f0a45c1fba3e14c15bbb33f5f96b8674496de29 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -43,6 +43,8 @@ public class LuminolConfig { - public static boolean useVanillaRandomSource = false; - public static boolean fixLargePosMoving = false; - public static boolean warnOnLargeMovingDetected = true; -+ public static boolean preventTeleportAsyncDuringMovingEvent = false; -+ public static boolean throwOnPreventingTeleportAsync = true; - - public static RegionFileFormat regionFormatName = RegionFileFormat.ANVIL; - public static int regionFormatLinearCompressionLevel = 1; -@@ -192,6 +194,8 @@ public class LuminolConfig { - useVanillaRandomSource = get("fixes.use_vanilla_random_source",useVanillaRandomSource,"RNG feature related"); - fixLargePosMoving = get("fixes.fix_large_pos_moving", fixLargePosMoving,"Fix an entity moving issue on folia which is not fixed yet"); - warnOnLargeMovingDetected = get("fixes.warn_on_large_pos_moving",warnOnLargeMovingDetected); -+ preventTeleportAsyncDuringMovingEvent = get("fixes.prevent_teleportasync_during_moving_event",preventTeleportAsyncDuringMovingEvent); -+ throwOnPreventingTeleportAsync = get("fixes.throw_on_preventing_async_teleport",throwOnPreventingTeleportAsync); - - regionFormatName = RegionFileFormat.fromString(get("save.region-format.format", regionFormatName.name())); - if (regionFormatName.equals(RegionFileFormat.INVALID)) { +diff --git a/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaTeleportAsyncFixConfig.java b/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaTeleportAsyncFixConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b8aceab54bb60000e7c56810140271022f5147a2 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/fixes/FoliaTeleportAsyncFixConfig.java +@@ -0,0 +1,22 @@ ++package me.earthme.luminol.config.modules.fixes; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class FoliaTeleportAsyncFixConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ @ConfigInfo(baseName = "throw_on_detected") ++ public static boolean throwOnDetected = true; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.FIXES; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "folia.prevent_teleportasync_call_during_moving"; ++ } ++} diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 3baf7f920334931dd53cd174c462c2e52d315ced..3dd6f29e55b02939db8b4509967cba685c83ae18 100644 +index 59f3ea98d0346d5b92053e13fa20048e3a946203..4799627301db90734dd891c099ffe5000c8873a0 100644 --- a/src/main/java/net/minecraft/server/level/ServerPlayer.java +++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -334,6 +334,10 @@ public class ServerPlayer extends Player { +@@ -332,6 +332,10 @@ public class ServerPlayer extends Player { public double lastEntitySpawnRadiusSquared = -1.0; // Paper end - optimise chunk tick iteration @@ -43,10 +48,10 @@ index 3baf7f920334931dd53cd174c462c2e52d315ced..3dd6f29e55b02939db8b4509967cba68 super(world, world.getSharedSpawnPos(), world.getSharedSpawnAngle(), profile); this.chatVisibility = ChatVisiblity.FULL; diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index cb4acce1c458331f7e1db423a446f8b337bdfe57..c4521696c589c56f325036db34e1d452a97cb326 100644 +index 095134bb3c07ad8daeaf4b28076d60b96b481458..7d6ac979135c62e35187cb2aed4c25d9137f9c45 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -684,7 +684,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -675,7 +675,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl Location oldTo = to.clone(); PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); @@ -56,7 +61,7 @@ index cb4acce1c458331f7e1db423a446f8b337bdfe57..c4521696c589c56f325036db34e1d452 // If the event is cancelled we move the player back to their old location. if (event.isCancelled()) { -@@ -1634,7 +1636,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl +@@ -1625,7 +1627,9 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl Location oldTo = to.clone(); PlayerMoveEvent event = new PlayerMoveEvent(player, from, to); @@ -67,17 +72,41 @@ index cb4acce1c458331f7e1db423a446f8b337bdfe57..c4521696c589c56f325036db34e1d452 // If the event is cancelled we move the player back to their old location. if (event.isCancelled()) { diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 11e992e88dc9e7a268535d356eab1e60db57b7ac..0b3d1b18b2be65ba662f65687b06771de3bf6e54 100644 +index 7ba9c8677a09d43107ab0d178f4141c44a1d25bc..55c42fa5fb60858af08c98940a2e786038f2ca4e 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -3992,6 +3992,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -27,6 +27,7 @@ import java.util.stream.Stream; + import javax.annotation.Nullable; + + import me.earthme.luminol.config.modules.fixes.FoliaEntityMovingFixConfig; ++import me.earthme.luminol.config.modules.fixes.FoliaTeleportAsyncFixConfig; + import net.minecraft.BlockUtil; + import net.minecraft.CrashReport; + import net.minecraft.CrashReportCategory; +@@ -59,7 +60,6 @@ import net.minecraft.network.syncher.EntityDataSerializers; + import net.minecraft.network.syncher.SynchedEntityData; + import net.minecraft.resources.ResourceKey; + import net.minecraft.resources.ResourceLocation; +-import io.papermc.paper.util.MCUtil; + import net.minecraft.server.MinecraftServer; + import net.minecraft.server.level.ServerLevel; + import net.minecraft.server.level.ServerPlayer; +@@ -132,7 +132,6 @@ import org.joml.Vector3f; + import org.slf4j.Logger; + import org.bukkit.Bukkit; + import org.bukkit.Location; +-import org.bukkit.Server; + import org.bukkit.block.BlockFace; + import org.bukkit.command.CommandSender; + import org.bukkit.craftbukkit.event.CraftPortalEvent; +@@ -3967,6 +3966,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S java.util.function.Consumer teleportComplete) { io.papermc.paper.util.TickThread.ensureTickThread(this, "Cannot teleport entity async"); + //Luminol start - Prevent teleportAsync calling during moving event being handled -+ if (this instanceof ServerPlayer player && LuminolConfig.preventTeleportAsyncDuringMovingEvent){ ++ if (this instanceof ServerPlayer player && FoliaTeleportAsyncFixConfig.enabled){ + if (player.handlingMoveEvent){ -+ if (LuminolConfig.throwOnPreventingTeleportAsync){ ++ if (FoliaTeleportAsyncFixConfig.throwOnDetected){ + throw new IllegalStateException("Player " + player.getScoreboardName() + " is trying to teleport to " + pos + " during move event handling!"); + } + MinecraftServer.LOGGER.warn("Player {} is trying to teleport to {} during move event handling!",player.getScoreboardName(),pos); diff --git a/patches/server/0017-Add-config-for-username-check.patch b/patches/server/0017-Add-config-for-username-check.patch deleted file mode 100644 index 426bf3f..0000000 --- a/patches/server/0017-Add-config-for-username-check.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 03:11:28 +0000 -Subject: [PATCH] Add config for username check - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index c3a481cb7bea0619b1af0e3203e9d88514e84c62..0929a5a167691bde7dedaa1e2812b34ad69913d6 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -28,6 +28,7 @@ public class LuminolConfig { - public static String tpsBarFormat = "TPS: MSPT: Ping: ms"; - public static String[] tpsColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; - public static String[] pingColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; -+ public static boolean disableUsernameCheck = false; - - public static boolean safeTeleportation = true; - public static boolean enableSandDuping = false; -@@ -71,6 +72,7 @@ public class LuminolConfig { - tpsBarFormat = get("misc.tpsbar_title_format",tpsBarFormat,"The format of tpsbar."); - tpsColors = get("misc.tpsbar_range_colors", List.of(tpsColors),"The bar and text color of each tps ranges.The last is the color of initial bar's color").toArray(String[]::new); - pingColors = get("misc.tpsbar_ping_range_colors",List.of(pingColors),"As same as the tpsColors").toArray(String[]::new); -+ disableUsernameCheck = get("misc.disable_username_check",disableUsernameCheck,"Disable username check that can accept usernames with other characters(such as Chinese).Not recommended to use"); - - if (tpsbarEnabled){ - initTpsbar(); -diff --git a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -index aa4b461bbb2c8c4753f7c9057bab1740de2c0284..4801c59cb3604257fb1016726e4c66ade7295f2e 100644 ---- a/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerLoginPacketListenerImpl.java -@@ -44,6 +44,7 @@ import org.bukkit.craftbukkit.util.Waitable; - import org.bukkit.event.player.AsyncPlayerPreLoginEvent; - import org.bukkit.event.player.PlayerPreLoginEvent; - // CraftBukkit end -+import me.earthme.luminol.LuminolConfig; - - public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, TickablePacketListener { - -@@ -143,7 +144,7 @@ public class ServerLoginPacketListenerImpl implements ServerLoginPacketListener, - @Override - public void handleHello(ServerboundHelloPacket packet) { - Validate.validState(this.state == ServerLoginPacketListenerImpl.State.HELLO, "Unexpected hello packet", new Object[0]); -- if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation) Validate.validState(Player.isValidUsername(packet.name()), "Invalid characters in username", new Object[0]); // Paper - config username validation -+ if (io.papermc.paper.configuration.GlobalConfiguration.get().proxies.isProxyOnlineMode() && io.papermc.paper.configuration.GlobalConfiguration.get().unsupportedSettings.performUsernameValidation && !this.iKnowThisMayNotBeTheBestIdeaButPleaseDisableUsernameValidation && !LuminolConfig.disableUsernameCheck) Validate.validState(Player.isValidUsername(packet.name()), "Invalid characters in username", new Object[0]); // Paper - config username validation //Luminol - Add config for username check - this.requestedUsername = packet.name(); - GameProfile gameprofile = this.server.getSingleplayerProfile(); - diff --git a/patches/server/0047-Piston-fixes-from-molean-server.patch b/patches/server/0017-Piston-fixes-from-molean-server.patch similarity index 93% rename from patches/server/0047-Piston-fixes-from-molean-server.patch rename to patches/server/0017-Piston-fixes-from-molean-server.patch index e2e3c39..e8e75be 100644 --- a/patches/server/0047-Piston-fixes-from-molean-server.patch +++ b/patches/server/0017-Piston-fixes-from-molean-server.patch @@ -1,14 +1,14 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Sun, 21 Jan 2024 11:49:38 +0000 +Date: Wed, 7 Feb 2024 07:18:27 +0000 Subject: [PATCH] Piston fixes from molean server diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 03752939200823c8b3df40f1ec602917da725067..b1a17c730939f39ba81209a368c215c236f203b0 100644 +index 55c42fa5fb60858af08c98940a2e786038f2ca4e..539ddfb88a5409b2270b36cf81120d81cffb197d 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1429,7 +1429,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1448,7 +1448,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S if (movement.lengthSqr() <= 1.0E-7D) { return movement; } else { diff --git a/patches/server/0018-Io_uring-channel-type-support.patch b/patches/server/0018-Io_uring-channel-type-support.patch new file mode 100644 index 0000000..8921c0b --- /dev/null +++ b/patches/server/0018-Io_uring-channel-type-support.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrHua269 +Date: Wed, 7 Feb 2024 07:41:47 +0000 +Subject: [PATCH] Io_uring channel type support + + +diff --git a/build.gradle.kts b/build.gradle.kts +index e837f1f9b444318cbee8719b9dd0eb669478742e..3a787b0afa3a34f23f1c18fb5250a5ff4bcd2f96 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -35,6 +35,7 @@ dependencies { + log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins + runtimeOnly(log4jPlugins.output) + alsoShade(log4jPlugins.output) ++ implementation("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.21.Final:linux-x86_64") //Luminol - io_uring Libraries + implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Paper - Add support for proxy protocol + // Paper end + implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/IOUringSupportConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/IOUringSupportConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..313c3908ea406119da4f49db2e4fac6572727c80 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/IOUringSupportConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class IOUringSupportConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "io_uring_support"; ++ } ++} +diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +index 6e95017f4c36208abdf344e3b7d55efe2d5b4e10..bf87a55d78155ea5c303ec28d6a0154e80d7fce3 100644 +--- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java ++++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java +@@ -73,6 +73,10 @@ public class ServerConnectionListener { + } + // Paper end - prevent blocking on adding a new connection while the server is ticking + ++ //Luminol start - io_uring support ++ public static final Supplier SERVER_IO_URING_WORKER_GROUP = Suppliers.memoize(() -> new io.netty.incubator.channel.uring.IOUringEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty IO_URING Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build())); ++ //Luminol end ++ + public ServerConnectionListener(MinecraftServer server) { + this.server = server; + this.running = true; +@@ -90,7 +94,14 @@ public class ServerConnectionListener { + Class oclass; + EventLoopGroup eventloopgroup; + +- if (Epoll.isAvailable() && this.server.isEpollEnabled()) { ++ //Luminol start - io_uring support ++ if (io.netty.incubator.channel.uring.IOUring.isAvailable() && me.earthme.luminol.config.modules.misc.IOUringSupportConfig.enabled){ ++ eventloopgroup = SERVER_IO_URING_WORKER_GROUP.get(); ++ oclass = io.netty.incubator.channel.uring.IOUringServerSocketChannel.class; ++ ServerConnectionListener.LOGGER.info("Using io_uring channel type"); ++ } ++ else if (Epoll.isAvailable() && this.server.isEpollEnabled()) { ++ //Luminol end + // Paper start - Unix domain socket support + if (address instanceof io.netty.channel.unix.DomainSocketAddress) { + oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class; diff --git a/patches/server/0014-Kaiiju-Add-linear-region-format.patch b/patches/server/0019-Kaiiju-linear-region-format-and-settings.patch similarity index 88% rename from patches/server/0014-Kaiiju-Add-linear-region-format.patch rename to patches/server/0019-Kaiiju-linear-region-format-and-settings.patch index fb5d8bb..069fd8a 100644 --- a/patches/server/0014-Kaiiju-Add-linear-region-format.patch +++ b/patches/server/0019-Kaiiju-linear-region-format-and-settings.patch @@ -1,24 +1,24 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 02:43:58 +0000 -Subject: [PATCH] Kaiiju Add linear region format +Date: Wed, 7 Feb 2024 03:11:28 +0000 +Subject: [PATCH] Kaiiju linear region format and settings diff --git a/build.gradle.kts b/build.gradle.kts -index 83660616a26d989ce441e17acab103ab166304d8..1bdeb0e9d0c04509d7ed4003f6b79c806dc55eed 100644 +index 3a787b0afa3a34f23f1c18fb5250a5ff4bcd2f96..18326989bfccea2c6d292b0020aab711438031c8 100644 --- a/build.gradle.kts +++ b/build.gradle.kts -@@ -19,6 +19,10 @@ dependencies { - exclude("io.papermc.paper", "paper-api") +@@ -20,6 +20,10 @@ dependencies { } // Folia end + implementation("com.electronwill.night-config:toml:3.6.6") //Luminol - Night config + // Kaiiju start - Linear format + implementation("com.github.luben:zstd-jni:1.5.4-1") + implementation("org.lz4:lz4-java:1.8.0") + // Kaiiju end - implementation("com.electronwill.night-config:toml:3.6.0") //Luminol - Night config // Paper start implementation("org.jline:jline-terminal-jansi:3.21.0") + implementation("net.minecrell:terminalconsoleappender:1.3.0") diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java b/src/main/java/dev/kaiijumc/kaiiju/region/AbstractRegionFile.java new file mode 100644 index 0000000000000000000000000000000000000000..249303116d3cfadd078ebf0ae6e44bf99eed6a47 @@ -415,16 +415,15 @@ index 0000000000000000000000000000000000000000..e40989889f3821bb7484fc0bae5d94b0 +} diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFileFlusher.java b/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFileFlusher.java new file mode 100644 -index 0000000000000000000000000000000000000000..e800c6103396530efe5acd0b4081a3cd05b62b68 +index 0000000000000000000000000000000000000000..f06d7767c79e465f999b2032086cc224de95152a --- /dev/null +++ b/src/main/java/dev/kaiijumc/kaiiju/region/LinearRegionFileFlusher.java -@@ -0,0 +1,45 @@ +@@ -0,0 +1,44 @@ +package dev.kaiijumc.kaiiju.region; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.Queue; +import java.util.concurrent.*; -+import me.earthme.luminol.LuminolConfig; +import org.bukkit.Bukkit; + +public class LinearRegionFileFlusher { @@ -435,15 +434,15 @@ index 0000000000000000000000000000000000000000..e800c6103396530efe5acd0b4081a3cd + .build() + ); + private final ExecutorService executor = Executors.newFixedThreadPool( -+ LuminolConfig.linearFlushThreads, ++ me.earthme.luminol.config.modules.misc.RegionFormatConfig.linearFlushThreads, + new ThreadFactoryBuilder() + .setNameFormat("linear-flusher-%d") + .build() + ); + + public LinearRegionFileFlusher() { -+ Bukkit.getLogger().info("Using " + LuminolConfig.linearFlushThreads + " threads for linear region flushing."); -+ scheduler.scheduleAtFixedRate(this::pollAndFlush, 0L, LuminolConfig.linearFlushFrequency, TimeUnit.SECONDS); ++ Bukkit.getLogger().info("Using " + me.earthme.luminol.config.modules.misc.RegionFormatConfig.linearFlushThreads + " threads for linear region flushing."); ++ scheduler.scheduleAtFixedRate(this::pollAndFlush, 0L, me.earthme.luminol.config.modules.misc.RegionFormatConfig.linearFlushFrequency, TimeUnit.SECONDS); + } + + public void scheduleSave(LinearRegionFile regionFile) { @@ -464,6 +463,28 @@ index 0000000000000000000000000000000000000000..e800c6103396530efe5acd0b4081a3cd + scheduler.shutdown(); + } +} +diff --git a/src/main/java/dev/kaiijumc/kaiiju/region/RegionFileFormat.java b/src/main/java/dev/kaiijumc/kaiiju/region/RegionFileFormat.java +new file mode 100644 +index 0000000000000000000000000000000000000000..7164d9cd03186f0657783f83de3d6435cda2b17e +--- /dev/null ++++ b/src/main/java/dev/kaiijumc/kaiiju/region/RegionFileFormat.java +@@ -0,0 +1,16 @@ ++package dev.kaiijumc.kaiiju.region; ++ ++public enum RegionFileFormat { ++ ANVIL, ++ LINEAR, ++ INVALID; ++ ++ public static RegionFileFormat fromString(String format) { ++ for (RegionFileFormat rff : values()) { ++ if (rff.name().equalsIgnoreCase(format)) { ++ return rff; ++ } ++ } ++ return RegionFileFormat.INVALID; ++ } ++} diff --git a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java index 2934f0cf0ef09c84739312b00186c2ef0019a165..b46acbc078f3d3bfb0f3ede3f1cc172f4b48c5df 100644 --- a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java @@ -532,7 +553,7 @@ index 2934f0cf0ef09c84739312b00186c2ef0019a165..b46acbc078f3d3bfb0f3ede3f1cc172f } } diff --git a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java -index 9017907c0ec67a37a506f09b7e4499cef7885279..f4ed74401ae574ca3e7867df1e47d0e1af867f10 100644 +index 9017907c0ec67a37a506f09b7e4499cef7885279..8b9ffcaab5d71660291d1c0454d2abd969d8c6ae 100644 --- a/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java +++ b/src/main/java/io/papermc/paper/world/ThreadedWorldUpgrader.java @@ -84,8 +84,13 @@ public class ThreadedWorldUpgrader { @@ -540,8 +561,8 @@ index 9017907c0ec67a37a506f09b7e4499cef7885279..f4ed74401ae574ca3e7867df1e47d0e1 LOGGER.info("Starting conversion now for world " + this.worldName); + // Kaiiju start -+ dev.kaiijumc.kaiiju.region.RegionFileFormat formatName = me.earthme.luminol.LuminolConfig.regionFormatName; -+ int linearCompression = me.earthme.luminol.LuminolConfig.regionFormatLinearCompressionLevel; ++ dev.kaiijumc.kaiiju.region.RegionFileFormat formatName = me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatName; ++ int linearCompression = me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatLinearCompressionLevel; + LOGGER.info("Using format " + formatName + " (" + linearCompression + ")"); + // Kaiiju end final WorldInfo info = new WorldInfo(() -> worldPersistentData, @@ -550,34 +571,86 @@ index 9017907c0ec67a37a506f09b7e4499cef7885279..f4ed74401ae574ca3e7867df1e47d0e1 long expectedChunks = (long)regionFiles.length * (32L * 32L); -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 3d526d7cfb313e419de89be1b275651982be42c7..90a6cfd011aaefe66fda79f887380ab2d62a07b1 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -29,6 +29,8 @@ public class LuminolConfig { - - public static RegionFileFormat regionFormatName = RegionFileFormat.ANVIL; - public static int regionFormatLinearCompressionLevel = 1; -+ public static int linearFlushFrequency = 10; +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..5219ef799585db502a19e79145b971365a736277 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java +@@ -0,0 +1,50 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import dev.kaiijumc.kaiiju.region.RegionFileFormat; ++import me.earthme.luminol.config.*; ++ ++public class RegionFormatConfig implements IConfigModule { ++ @DoNotLoad ++ public static RegionFileFormat regionFormatName = RegionFileFormat.ANVIL; ++ ++ @ConfigInfo(baseName = "formatName") ++ private static String formatName = "ANVIL"; ++ @ConfigInfo(baseName = "linear_compression_level") ++ public static int regionFormatLinearCompressionLevel = 1; ++ @ConfigInfo(baseName = "linear_flusher_thread_count") + public static int linearFlushThreads = 1; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -67,6 +69,12 @@ public class LuminolConfig { - logger.error("Falling back to compression level 1."); - regionFormatLinearCompressionLevel = 1; - } -+ linearFlushFrequency = get("save.region-format.linear.flush-frequency", linearFlushFrequency); -+ linearFlushThreads = get("save.region-format.linear.flush-max-threads", linearFlushThreads); ++ @ConfigInfo(baseName = "linear_flush_frequency") ++ public static int linearFlushFrequency = 10; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "region_format"; ++ } ++ ++ @Override ++ public void onLoaded(CommentedFileConfig configInstance){ ++ regionFormatName = RegionFileFormat.fromString(formatName); ++ if (regionFormatName.equals(RegionFileFormat.INVALID)) { ++ LuminolConfig.logger.error("Unknown region format in luminol global config: {}", formatName); ++ LuminolConfig.logger.error("Falling back to ANVIL region file format."); ++ regionFormatName = RegionFileFormat.ANVIL; ++ } ++ ++ if (regionFormatLinearCompressionLevel > 23 || regionFormatLinearCompressionLevel < 1) { ++ LuminolConfig.logger.error("Linear region compression level should be between 1 and 22 in luminol global config: {}", regionFormatLinearCompressionLevel); ++ LuminolConfig.logger.error("Falling back to compression level 1."); ++ regionFormatLinearCompressionLevel = 1; ++ } ++ + if (linearFlushThreads < 0) + linearFlushThreads = Math.max(Runtime.getRuntime().availableProcessors() + linearFlushThreads, 1); + else + linearFlushThreads = Math.max(linearFlushThreads, 1); - } ++ } ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index 4468e6fdbbe527111f4410188f2f2df7f592f81e..13ad20b3d43cc22ad1046220b24272dd274de997 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -923,7 +923,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop T get(String key,T def){ +- MinecraftServer.LOGGER.info("ThreadedAnvilChunkStorage: All dimensions are saved"); ++ MinecraftServer.LOGGER.info("ThreadedChunkStorage: All dimensions are saved"); // Kaiiju + } + + return flag3; diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 21ec49acb3c1241d9286959c42a7f8363f637e4f..5fc083b58f6f120d234513c7c36999f034e1d869 100644 +index 21ec49acb3c1241d9286959c42a7f8363f637e4f..c212030a24174115a975604b91d03cf8ad4043de 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -211,7 +211,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -585,7 +658,7 @@ index 21ec49acb3c1241d9286959c42a7f8363f637e4f..5fc083b58f6f120d234513c7c36999f0 public ChunkMap(ServerLevel world, LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, StructureTemplateManager structureTemplateManager, Executor executor, BlockableEventLoop mainThreadExecutor, LightChunkGetter chunkProvider, ChunkGenerator chunkGenerator, ChunkProgressListener worldGenerationProgressListener, ChunkStatusUpdateListener chunkStatusChangeListener, Supplier persistentStateManagerFactory, int viewDistance, boolean dsync) { - super(session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); -+ super(me.earthme.luminol.LuminolConfig.regionFormatName, me.earthme.luminol.LuminolConfig.regionFormatLinearCompressionLevel, session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); // Kaiiju ++ super(me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatName, me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatLinearCompressionLevel, session.getDimensionPath(world.dimension()).resolve("region"), dataFixer, dsync); // Kaiiju // Paper - rewrite chunk system this.tickingGenerated = new AtomicInteger(); //this.playerMap = new PlayerMap(); // Folia - region threading @@ -594,7 +667,7 @@ index 21ec49acb3c1241d9286959c42a7f8363f637e4f..5fc083b58f6f120d234513c7c36999f0 this.distanceManager = new ChunkMap.ChunkDistanceManager(executor, mainThreadExecutor); this.overworldDataStorage = persistentStateManagerFactory; - this.poiManager = new PoiManager(path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); -+ this.poiManager = new PoiManager(me.earthme.luminol.LuminolConfig.regionFormatName, me.earthme.luminol.LuminolConfig.regionFormatLinearCompressionLevel, path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); // Kaiiju ++ this.poiManager = new PoiManager(me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatName, me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatLinearCompressionLevel, path.resolve("poi"), dataFixer, dsync, iregistrycustom, world); // Kaiiju this.setServerViewDistance(viewDistance); // Paper start this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new); @@ -624,10 +697,10 @@ index 21ec49acb3c1241d9286959c42a7f8363f637e4f..5fc083b58f6f120d234513c7c36999f0 regionFile.setStatus(chunkPos.x, chunkPos.z, ChunkSerializer.getStatus(compound)); } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 00593eadeadc74429a05d83e10964781b6311c54..b3dde336a8fb38b6ab30019c6d66ef1a47b25d9d 100644 +index 9e82dc98ef2d4da39839699f455e0ef20ab4ef65..c0f8f72d1677d4ef6a15f487262953c5df3b03c0 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -449,8 +449,8 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -447,8 +447,8 @@ public class ServerLevel extends Level implements WorldGenLevel { private static final class EntityRegionFileStorage extends net.minecraft.world.level.chunk.storage.RegionFileStorage { @@ -638,17 +711,17 @@ index 00593eadeadc74429a05d83e10964781b6311c54..b3dde336a8fb38b6ab30019c6d66ef1a } protected void write(ChunkPos pos, net.minecraft.nbt.CompoundTag nbt) throws IOException { -@@ -813,7 +813,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -809,7 +809,7 @@ public class ServerLevel extends Level implements WorldGenLevel { // CraftBukkit end boolean flag2 = minecraftserver.forceSynchronousWrites(); DataFixer datafixer = minecraftserver.getFixerUpper(); - this.entityStorage = new EntityRegionFileStorage(convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); -+ this.entityStorage = new EntityRegionFileStorage(me.earthme.luminol.LuminolConfig.regionFormatName, me.earthme.luminol.LuminolConfig.regionFormatLinearCompressionLevel, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); // Kaiiju ++ this.entityStorage = new EntityRegionFileStorage(me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatName, me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatLinearCompressionLevel, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), flag2); // Paper - rewrite chunk system //EntityPersistentStorage entitypersistentstorage = new EntityStorage(this, convertable_conversionsession.getDimensionPath(resourcekey).resolve("entities"), datafixer, flag2, minecraftserver); // Kaiiju // this.entityManager = new PersistentEntitySectionManager<>(Entity.class, new ServerLevel.EntityCallbacks(), entitypersistentstorage, this.entitySliceManager); // Paper // Paper - rewrite chunk system StructureTemplateManager structuretemplatemanager = minecraftserver.getStructureManager(); diff --git a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java -index 77dd632a266f4abed30b87b7909d77857c01e316..b79f324dcf4256dc9a5824a0a8e27a9e790eb781 100644 +index 77dd632a266f4abed30b87b7909d77857c01e316..97007462c7f3d7231fff18ecf295f2574684bf9f 100644 --- a/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java +++ b/src/main/java/net/minecraft/util/worldupdate/WorldUpgrader.java @@ -61,7 +61,7 @@ public class WorldUpgrader { @@ -667,8 +740,8 @@ index 77dd632a266f4abed30b87b7909d77857c01e316..b79f324dcf4256dc9a5824a0a8e27a9e - builder1.put(resourcekey1, new ChunkStorage(path.resolve("region"), this.dataFixer, true)); + // Kaiiju start + String worldName = this.levelStorage.getLevelId(); -+ dev.kaiijumc.kaiiju.region.RegionFileFormat formatName = me.earthme.luminol.LuminolConfig.regionFormatName; -+ int linearCompression = me.earthme.luminol.LuminolConfig.regionFormatLinearCompressionLevel; ++ dev.kaiijumc.kaiiju.region.RegionFileFormat formatName = me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatName; ++ int linearCompression = me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatLinearCompressionLevel; + builder1.put(resourcekey1, new ChunkStorage(formatName, linearCompression, path.resolve("region"), this.dataFixer, true)); + // Kaiiju end } @@ -690,7 +763,7 @@ index 77dd632a266f4abed30b87b7909d77857c01e316..b79f324dcf4256dc9a5824a0a8e27a9e - RegionFile regionfile = new RegionFile(file2.toPath(), file1.toPath(), true); + // Kaiiju start + String worldName = this.levelStorage.getLevelId(); -+ int linearCompression = me.earthme.luminol.LuminolConfig.regionFormatLinearCompressionLevel; ++ int linearCompression = me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatLinearCompressionLevel; + dev.kaiijumc.kaiiju.region.AbstractRegionFile regionfile = dev.kaiijumc.kaiiju.region.AbstractRegionFileFactory.getAbstractRegionFile(linearCompression, file2.toPath(), file1.toPath(), true); + // Kaiiju end diff --git a/patches/server/0011-Kaiiju-Don-t-pathfind-outside-region.patch b/patches/server/0020-Kaiiju-Don-t-pathfind-outside-region.patch similarity index 100% rename from patches/server/0011-Kaiiju-Don-t-pathfind-outside-region.patch rename to patches/server/0020-Kaiiju-Don-t-pathfind-outside-region.patch diff --git a/patches/server/0035-Kaiiju-Vanilla-end-portal-teleportation.patch b/patches/server/0021-Kaiiju-Vanilla-end-portal-teleportation.patch similarity index 91% rename from patches/server/0035-Kaiiju-Vanilla-end-portal-teleportation.patch rename to patches/server/0021-Kaiiju-Vanilla-end-portal-teleportation.patch index 328a324..acbdc7b 100644 --- a/patches/server/0035-Kaiiju-Vanilla-end-portal-teleportation.patch +++ b/patches/server/0021-Kaiiju-Vanilla-end-portal-teleportation.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Kaiiju Vanilla end portal teleportation diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 50986d5309676b8cff3a02313ee383f1b1300b0f..03752939200823c8b3df40f1ec602917da725067 100644 +index 539ddfb88a5409b2270b36cf81120d81cffb197d..93936213c0ddd3fc1435be15eae09a2cdb1a099e 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -4150,12 +4150,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4173,12 +4173,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S targetPos, 16, // load 16 blocks to be safe from block physics ca.spottedleaf.concurrentutil.executor.standard.PrioritisedExecutor.Priority.HIGH, (chunks) -> { @@ -28,7 +28,7 @@ index 50986d5309676b8cff3a02313ee383f1b1300b0f..03752939200823c8b3df40f1ec602917 ); } ); -@@ -4342,6 +4347,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4365,6 +4370,10 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S if (!this.canPortalAsync(takePassengers)) { return false; } @@ -39,7 +39,7 @@ index 50986d5309676b8cff3a02313ee383f1b1300b0f..03752939200823c8b3df40f1ec602917 Vec3 initialPosition = this.position(); ChunkPos initialPositionChunk = new ChunkPos( -@@ -4400,7 +4409,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4423,7 +4432,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S // place passengerTree.root.placeInAsync( originWorld, destination, Entity.TELEPORT_FLAG_LOAD_CHUNK | (takePassengers ? Entity.TELEPORT_FLAG_TELEPORT_PASSENGERS : 0L), diff --git a/patches/server/0038-Kaiiju-Async-path-processing.patch b/patches/server/0022-Kaiiju-Async-path-processing.patch similarity index 91% rename from patches/server/0038-Kaiiju-Async-path-processing.patch rename to patches/server/0022-Kaiiju-Async-path-processing.patch index 4275f1d..adac318 100644 --- a/patches/server/0038-Kaiiju-Async-path-processing.patch +++ b/patches/server/0022-Kaiiju-Async-path-processing.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 03:58:19 +0000 +Date: Wed, 7 Feb 2024 07:33:03 +0000 Subject: [PATCH] Kaiiju Async path processing @@ -299,15 +299,14 @@ index 0000000000000000000000000000000000000000..6b91852238f80d236fc44f766b115267 +} diff --git a/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java new file mode 100644 -index 0000000000000000000000000000000000000000..b4c27b33dffa8dce19c9db25d15bc57f48e05d4a +index 0000000000000000000000000000000000000000..31f3ae25069f516255263ab50aca8ee6f1268f8f --- /dev/null +++ b/src/main/java/dev/kaiijumc/kaiiju/path/AsyncPathProcessor.java -@@ -0,0 +1,53 @@ +@@ -0,0 +1,52 @@ +package dev.kaiijumc.kaiiju.path; + +import com.google.common.util.concurrent.ThreadFactoryBuilder; + -+import me.earthme.luminol.LuminolConfig; +import net.minecraft.world.level.pathfinder.Path; +import net.minecraft.world.entity.Entity; + @@ -324,8 +323,8 @@ index 0000000000000000000000000000000000000000..b4c27b33dffa8dce19c9db25d15bc57f + + private static final Executor pathProcessingExecutor = new ThreadPoolExecutor( + 1, -+ LuminolConfig.asyncPathProcessingMaxThreads, -+ LuminolConfig.asyncPathProcessingKeepalive, TimeUnit.SECONDS, ++ me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessingMaxThreads, ++ me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessingKeepalive, TimeUnit.SECONDS, + new LinkedBlockingQueue<>(), + new ThreadFactoryBuilder() + .setNameFormat("petal-path-processor-%d") @@ -474,51 +473,52 @@ index 0000000000000000000000000000000000000000..130d61324679c8600faa52255f3ad99f + return WALK; + } +} -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index bfdb0513bf2021fd53910fdfadebb37ebc2f3fef..785dc39724f3fb2e27a9fbbe9ea6b4e489b9e0ec 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -11,6 +11,7 @@ import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - import org.bukkit.Bukkit; - -+import java.lang.Math; - import java.util.*; - import java.io.File; - import java.io.IOException; -@@ -57,7 +58,9 @@ public class LuminolConfig { - public static double entityWakeUpDurationRatioStandardDeviation = 0.2; - public static boolean loadChunksToActiveClimbingEntities = false; - public static int acquirePoiForStuckEntityInterval = 60; -- -+ public static boolean asyncPathProcessing = false; -+ public static int asyncPathProcessingMaxThreads = 0; -+ public static int asyncPathProcessingKeepalive = 60; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -173,6 +176,16 @@ public class LuminolConfig { - entityWakeUpDurationRatioStandardDeviation = get("optimizations.entity_wakeup_duration_ratio_standard_deviation",entityWakeUpDurationRatioStandardDeviation); - loadChunksToActiveClimbingEntities = get("optimizations.load_chunks_to_active_climbing_entities",loadChunksToActiveClimbingEntities); - acquirePoiForStuckEntityInterval = get("optimizations.acquire_poi_for_stuck_entity_interval", acquirePoiForStuckEntityInterval); +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/AsyncPathProcessingConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/AsyncPathProcessingConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..a5472bb9d453bbeee92738c8d1a57ef4fd9bf07e +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/AsyncPathProcessingConfig.java +@@ -0,0 +1,35 @@ ++package me.earthme.luminol.config.modules.optimizations; + -+ asyncPathProcessing = get("optimizations.async_pathfinding.enabled",asyncPathProcessing,"Config to enable the async pathfinder."); -+ asyncPathProcessingMaxThreads = get("optimizations.async_pathfinding.max-threads", asyncPathProcessingMaxThreads,"If it was set to 0(default),the thread count will be auto set(a quarter of the CPU thread count)"); -+ asyncPathProcessingKeepalive = get("optimizations.async_pathfinding.keepalive", asyncPathProcessingKeepalive); ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class AsyncPathProcessingConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean asyncPathProcessing = false; ++ @ConfigInfo(baseName = "max_threads") ++ public static int asyncPathProcessingMaxThreads = 0; ++ @ConfigInfo(baseName = "keep_alive_time") ++ public static int asyncPathProcessingKeepalive = 60; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "async_path_processing"; ++ } ++ ++ @Override ++ public void onLoaded(CommentedFileConfig config){ + if (asyncPathProcessingMaxThreads < 0) + asyncPathProcessingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() + asyncPathProcessingMaxThreads, 1); + else if (asyncPathProcessingMaxThreads == 0) + asyncPathProcessingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() / 4, 1); + if (!asyncPathProcessing) + asyncPathProcessingMaxThreads = 0; - } - - public static T get(String key,T def){ ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index b7970a29eb0626718051cd044a4d6092a3b88538..8a7f94dda9ec72a2c254c01087049ce25bb4da0b 100644 +index a1a0ac986e2052d3669428a29987630bc226d80f..192584ac3b280cef2e76bc510c03ff6e0fd26ce2 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -298,6 +298,7 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -296,6 +296,7 @@ public abstract class Mob extends LivingEntity implements Targeting { @Nullable @Override public LivingEntity getTarget() { @@ -527,15 +527,15 @@ index b7970a29eb0626718051cd044a4d6092a3b88538..8a7f94dda9ec72a2c254c01087049ce2 if (this.target != null && (!io.papermc.paper.util.TickThread.isTickThreadFor(this.target) || this.target.isRemoved())) { this.target = null; diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index 961d3df1ca72d36ed7f0008bac346c95e07a0288..de6ecdbbe2b90f10ea673c3cc4f4a89e30449866 100644 +index abcc3ef59475ac170fd10b4dd4a4f3371faf17e0..e1dc31deeb87d695ddf2308c27e2cf949e48e538 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -79,6 +79,40 @@ public class AcquirePoi { +@@ -68,6 +68,40 @@ public class AcquirePoi { io.papermc.paper.util.PoiAccess.findNearestPoiPositions(poiManager, poiPredicate, predicate2, entity.blockPosition(), 48, 48*48, PoiManager.Occupancy.HAS_SPACE, false, 5, poiposes); Set, BlockPos>> set = new java.util.HashSet<>(poiposes); // Paper end - optimise POI access + // Kaiiju start - petal - Async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) { ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { + // await on path async + Path possiblePath = findPathToPois(entity, set); + @@ -571,7 +571,7 @@ index 961d3df1ca72d36ed7f0008bac346c95e07a0288..de6ecdbbe2b90f10ea673c3cc4f4a89e Path path = findPathToPois(entity, set); if (path != null && path.canReach()) { BlockPos blockPos = path.getTarget(); -@@ -100,6 +134,7 @@ public class AcquirePoi { +@@ -89,6 +123,7 @@ public class AcquirePoi { }); } } @@ -580,7 +580,7 @@ index 961d3df1ca72d36ed7f0008bac346c95e07a0288..de6ecdbbe2b90f10ea673c3cc4f4a89e return true; } diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java b/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java -index 98bf17441da3169d49de55fe89d79ebe250a2b7e..a93457a4c0f4ec8be3a105c6feeb5a189056d8cf 100644 +index 98bf17441da3169d49de55fe89d79ebe250a2b7e..74162661e5757bb2c732361042b5dd2c3ded43ee 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/MoveToTargetSink.java @@ -21,6 +21,7 @@ public class MoveToTargetSink extends Behavior { @@ -596,10 +596,10 @@ index 98bf17441da3169d49de55fe89d79ebe250a2b7e..a93457a4c0f4ec8be3a105c6feeb5a18 WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); boolean bl = this.reachedTarget(entity, walkTarget); - if (!bl && this.tryComputePath(entity, walkTarget, world.getGameTime())) { -+ if (!me.earthme.luminol.LuminolConfig.asyncPathProcessing && !bl && this.tryComputePath(entity, walkTarget, world.getGameTime())) { // Kaiiju - petal - async path processing means we can't know if the path is reachable here ++ if (!me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing && !bl && this.tryComputePath(entity, walkTarget, world.getGameTime())) { // Kaiiju - petal - async path processing means we can't know if the path is reachable here this.lastTargetPos = walkTarget.getTarget().currentBlockPosition(); return true; -+ } else if (me.earthme.luminol.LuminolConfig.asyncPathProcessing && !bl) { return true; // Kaiiju - async pathfinding ++ } else if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing && !bl) { return true; // Kaiiju - async pathfinding } else { brain.eraseMemory(MemoryModuleType.WALK_TARGET); if (bl) { @@ -607,7 +607,7 @@ index 98bf17441da3169d49de55fe89d79ebe250a2b7e..a93457a4c0f4ec8be3a105c6feeb5a18 @Override protected boolean canStillUse(ServerLevel world, Mob entity, long time) { -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing && !this.finishedProcessing) return true; // Kaiiju - petal - wait for processing ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing && !this.finishedProcessing) return true; // Kaiiju - petal - wait for processing if (this.path != null && this.lastTargetPos != null) { Optional optional = entity.getBrain().getMemory(MemoryModuleType.WALK_TARGET); boolean bl = optional.map(MoveToTargetSink::isWalkTargetSpectator).orElse(false); @@ -616,7 +616,7 @@ index 98bf17441da3169d49de55fe89d79ebe250a2b7e..a93457a4c0f4ec8be3a105c6feeb5a18 @Override protected void start(ServerLevel serverLevel, Mob mob, long l) { + // Kaiiju start - petal - start processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) { ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { + Brain brain = mob.getBrain(); + WalkTarget walkTarget = brain.getMemory(MemoryModuleType.WALK_TARGET).get(); + @@ -633,7 +633,7 @@ index 98bf17441da3169d49de55fe89d79ebe250a2b7e..a93457a4c0f4ec8be3a105c6feeb5a18 @Override protected void tick(ServerLevel serverLevel, Mob mob, long l) { + // Kaiiju start - petal - Async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) { ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { + if (this.path != null && !this.path.isProcessed()) return; // wait for processing + + if (!this.finishedProcessing) { @@ -705,7 +705,7 @@ index 98bf17441da3169d49de55fe89d79ebe250a2b7e..a93457a4c0f4ec8be3a105c6feeb5a18 private boolean tryComputePath(Mob entity, WalkTarget walkTarget, long time) { BlockPos blockPos = walkTarget.getTarget().currentBlockPosition(); diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java b/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java -index 271efbb027f6f5d69ac5bc5dc51102a1eb00ab31..a64be68194fb0fa205b3f3cb87406056832d1fe3 100644 +index 271efbb027f6f5d69ac5bc5dc51102a1eb00ab31..cd2a3edc03301286114834e721f5441e7b70474a 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java +++ b/src/main/java/net/minecraft/world/entity/ai/behavior/SetClosestHomeAsWalkTarget.java @@ -57,6 +57,26 @@ public class SetClosestHomeAsWalkTarget { @@ -713,7 +713,7 @@ index 271efbb027f6f5d69ac5bc5dc51102a1eb00ab31..a64be68194fb0fa205b3f3cb87406056 return poiType.is(PoiTypes.HOME); }, predicate, entity.blockPosition(), 48, PoiManager.Occupancy.ANY).collect(Collectors.toSet()); + // Kaiiju start - petal - Async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) { ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { + // await on path async + Path possiblePath = AcquirePoi.findPathToPois(entity, set); + @@ -757,7 +757,7 @@ index 6771f2dc974317b6b152288bf41d1a95bc78a8e4..7a641747b17164b09bb8483cda7f69d1 Node node = path.getNode(i); this.doorPos = new BlockPos(node.x, node.y + 1, node.z); diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java -index 9d3b32c852d660356e0f16d4cc10072b1c603e64..545f578d77398a00fbc626e048eac56626308792 100644 +index 9d3b32c852d660356e0f16d4cc10072b1c603e64..2e64fe17fb3ee1925db1fdb34dedba356aea070b 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/AmphibiousPathNavigation.java @@ -12,10 +12,26 @@ public class AmphibiousPathNavigation extends PathNavigation { @@ -780,7 +780,7 @@ index 9d3b32c852d660356e0f16d4cc10072b1c603e64..545f578d77398a00fbc626e048eac566 this.nodeEvaluator = new AmphibiousNodeEvaluator(false); this.nodeEvaluator.setCanPassDoors(true); + // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) + return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); + else + // Kaiiju end @@ -788,7 +788,7 @@ index 9d3b32c852d660356e0f16d4cc10072b1c603e64..545f578d77398a00fbc626e048eac566 } diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java -index e35c38feb62c3345d82636081decc09db9f061ab..c889494d4bb2a700b00c8cbc85578ceb6c2f5496 100644 +index e35c38feb62c3345d82636081decc09db9f061ab..70f4104f8e49fd6b7df531673f3e1da123783409 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/FlyingPathNavigation.java @@ -16,10 +16,26 @@ public class FlyingPathNavigation extends PathNavigation { @@ -811,7 +811,7 @@ index e35c38feb62c3345d82636081decc09db9f061ab..c889494d4bb2a700b00c8cbc85578ceb this.nodeEvaluator = new FlyNodeEvaluator(); this.nodeEvaluator.setCanPassDoors(true); + // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) + return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); + else + // Kaiiju end @@ -827,7 +827,7 @@ index e35c38feb62c3345d82636081decc09db9f061ab..c889494d4bb2a700b00c8cbc85578ceb if (!this.isDone()) { if (this.canUpdatePath()) { diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java -index b31ba4e2286eaee5028cb4dc236829d1a302a25a..0fae5f72ab584ceb97958bef6d7b7d0629cd88ab 100644 +index b31ba4e2286eaee5028cb4dc236829d1a302a25a..aaa04a4b01575495e6e01f0d83b2bb03acc93822 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/GroundPathNavigation.java @@ -23,10 +23,26 @@ public class GroundPathNavigation extends PathNavigation { @@ -850,7 +850,7 @@ index b31ba4e2286eaee5028cb4dc236829d1a302a25a..0fae5f72ab584ceb97958bef6d7b7d06 this.nodeEvaluator = new WalkNodeEvaluator(); this.nodeEvaluator.setCanPassDoors(true); + // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) + return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); + else + // Kaiiju end @@ -858,7 +858,7 @@ index b31ba4e2286eaee5028cb4dc236829d1a302a25a..0fae5f72ab584ceb97958bef6d7b7d06 } diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java -index 089baec30e0c16149b147a501d68958663519b96..302cc37a7d085028324fae79977657f7e248294f 100644 +index 089baec30e0c16149b147a501d68958663519b96..f6484fefd28a028fbcd1a54d93c8607b65575d00 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/PathNavigation.java @@ -153,6 +153,10 @@ public abstract class PathNavigation { @@ -877,7 +877,7 @@ index 089baec30e0c16149b147a501d68958663519b96..302cc37a7d085028324fae79977657f7 Path path = this.pathFinder.findPath(pathNavigationRegion, this.mob, positions, followRange, distance, this.maxVisitedNodesMultiplier); this.level.getProfiler().pop(); + // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) { ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { + // assign early a target position. most calls will only have 1 position + if (!positions.isEmpty()) this.targetPos = positions.iterator().next(); + @@ -939,7 +939,7 @@ index 089baec30e0c16149b147a501d68958663519b96..302cc37a7d085028324fae79977657f7 Vec3 vec3 = new Vec3(((double)node.x + this.mob.getX()) / 2.0D, ((double)node.y + this.mob.getY()) / 2.0D, ((double)node.z + this.mob.getZ()) / 2.0D); return pos.closerToCenterThan(vec3, (double)(this.path.getNodeCount() - this.path.getNextNodeIndex())); diff --git a/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java b/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java -index ee8543afbbd681bf327a353530a7a635aa5ef592..0e6fd5c6d31e6b39e693866165f3dab3d483c920 100644 +index ee8543afbbd681bf327a353530a7a635aa5ef592..238b5f2dc5487dcf675152b8c19a40a6e16958dc 100644 --- a/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java +++ b/src/main/java/net/minecraft/world/entity/ai/navigation/WaterBoundPathNavigation.java @@ -15,10 +15,26 @@ public class WaterBoundPathNavigation extends PathNavigation { @@ -962,7 +962,7 @@ index ee8543afbbd681bf327a353530a7a635aa5ef592..0e6fd5c6d31e6b39e693866165f3dab3 this.allowBreaching = this.mob.getType() == EntityType.DOLPHIN; this.nodeEvaluator = new SwimNodeEvaluator(this.allowBreaching); + // Kaiiju start - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) + return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); + else + // Kaiiju end @@ -970,7 +970,7 @@ index ee8543afbbd681bf327a353530a7a635aa5ef592..0e6fd5c6d31e6b39e693866165f3dab3 } diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java -index 8db20db72cd51046213625fac46c35854c59ec5d..d40e00a0a8726c920ea43aaa1ed680054cbfd9a3 100644 +index 8db20db72cd51046213625fac46c35854c59ec5d..afa5d36f5f9e6f3a44a1e92f98a1d83c3af4d277 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestBedSensor.java @@ -57,6 +57,25 @@ public class NearestBedSensor extends Sensor { @@ -978,7 +978,7 @@ index 8db20db72cd51046213625fac46c35854c59ec5d..d40e00a0a8726c920ea43aaa1ed68005 // 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(), 48, PoiManager.Occupancy.ANY, false, Integer.MAX_VALUE, poiposes); + // Kaiiju start - await on async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) { ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) { + Path possiblePath = AcquirePoi.findPathToPois(entity, new java.util.HashSet<>(poiposes)); + dev.kaiijumc.kaiiju.path.AsyncPathProcessor.awaitProcessing(entity, possiblePath, path -> { + // read canReach check @@ -1030,10 +1030,10 @@ index 9f1791e60061934fc89a13258f3fab9f67f3a45c..489fab4847118b8ecb92e435d57d2241 } } diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index e88b058c0734e436ef24bab6364b206c13e5a9c2..613c04314d2693af4889a665e17f272b2af01db3 100644 +index 295769d039f2a1e4f48912a60f9dbe267d8992c1..580da502c62ec5d669cb09932d99d1c7d711c965 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -@@ -385,6 +385,17 @@ public class Frog extends Animal implements VariantHolder { +@@ -383,6 +383,17 @@ public class Frog extends Animal implements VariantHolder { super(frog, world); } @@ -1051,12 +1051,12 @@ index e88b058c0734e436ef24bab6364b206c13e5a9c2..613c04314d2693af4889a665e17f272b @Override public boolean canCutCorner(BlockPathTypes nodeType) { return nodeType != BlockPathTypes.WATER_BORDER && super.canCutCorner(nodeType); -@@ -394,6 +405,11 @@ public class Frog extends Animal implements VariantHolder { +@@ -392,6 +403,11 @@ public class Frog extends Animal implements VariantHolder { protected PathFinder createPathFinder(int range) { this.nodeEvaluator = new Frog.FrogNodeEvaluator(true); this.nodeEvaluator.setCanPassDoors(true); + // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) + return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); + else + // Kaiiju end @@ -1085,7 +1085,7 @@ index 01897af1e6253b987734a24c052daf2ce1314092..b2f3f65caa92cfd9a8c65e617fde5585 if (blockposition != null) { diff --git a/src/main/java/net/minecraft/world/entity/monster/Strider.java b/src/main/java/net/minecraft/world/entity/monster/Strider.java -index 61162ecd43dc5e6f7898daecdec49f444e6d869b..26cdfe0dcf16c252648561f83e4d6a6757c0bd38 100644 +index 61162ecd43dc5e6f7898daecdec49f444e6d869b..864215e909224d180b47798e90a3c5846fa03dbd 100644 --- a/src/main/java/net/minecraft/world/entity/monster/Strider.java +++ b/src/main/java/net/minecraft/world/entity/monster/Strider.java @@ -563,10 +563,26 @@ public class Strider extends Animal implements ItemSteerable, Saddleable { @@ -1108,7 +1108,7 @@ index 61162ecd43dc5e6f7898daecdec49f444e6d869b..26cdfe0dcf16c252648561f83e4d6a67 this.nodeEvaluator = new WalkNodeEvaluator(); this.nodeEvaluator.setCanPassDoors(true); + // Kaiiju start - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) + return new PathFinder(this.nodeEvaluator, range, nodeEvaluatorGenerator); + else + // Kaiiju end @@ -1116,15 +1116,15 @@ index 61162ecd43dc5e6f7898daecdec49f444e6d869b..26cdfe0dcf16c252648561f83e4d6a67 } diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 0a151c679b0dc943598180942d6d4b3886211688..af816e10faf7d257f267de6b039f61239a9d453a 100644 +index 937f81a859953498abe73bea560c86e6560e1c33..7aadd36f0fe986635b495ab8c1426644620400cf 100644 --- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -@@ -604,6 +604,16 @@ public class Warden extends Monster implements VibrationSystem { +@@ -602,6 +602,16 @@ public class Warden extends Monster implements VibrationSystem { protected PathFinder createPathFinder(int range) { this.nodeEvaluator = new WalkNodeEvaluator(); this.nodeEvaluator.setCanPassDoors(true); + // Kaiiju start - petal - async path processing -+ if (me.earthme.luminol.LuminolConfig.asyncPathProcessing) ++ if (me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) + return new PathFinder(this.nodeEvaluator, range, GroundPathNavigation.nodeEvaluatorGenerator) { + @Override + protected float distance(Node a, Node b) { @@ -1191,7 +1191,7 @@ index 3049edb5a8b5967e5242a3896b23665888eb3472..0da9acd785cf785d82be7aab0a1e2bfd return false; } else if (o.nodes.size() != this.nodes.size()) { diff --git a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java -index eb18494bd7257fa5eb00dea16cf4d5667b796f2b..b497ea3059f73320c3718db114778a9e32b753e9 100644 +index eb18494bd7257fa5eb00dea16cf4d5667b796f2b..3cbc29fa169350879254a90e198e6247b6ab3037 100644 --- a/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java +++ b/src/main/java/net/minecraft/world/level/pathfinder/PathFinder.java @@ -24,37 +24,80 @@ public class PathFinder { @@ -1218,7 +1218,7 @@ index eb18494bd7257fa5eb00dea16cf4d5667b796f2b..b497ea3059f73320c3718db114778a9e - this.openSet.clear(); - this.nodeEvaluator.prepare(world, mob); - Node node = this.nodeEvaluator.getStart(); -+ if(!me.earthme.luminol.LuminolConfig.asyncPathProcessing) this.openSet.clear(); // Kaiiju - petal - it's always cleared in processPath ++ if(!me.earthme.luminol.config.modules.optimizations.AsyncPathProcessingConfig.asyncPathProcessing) this.openSet.clear(); // Kaiiju - petal - it's always cleared in processPath + // Kaiiju start - petal - use a generated evaluator if we have one otherwise run sync + NodeEvaluator nodeEvaluator = this.nodeEvaluatorGenerator == null + ? this.nodeEvaluator diff --git a/patches/server/0023-Petal-Reduce-sensor-work.patch b/patches/server/0023-Petal-Reduce-sensor-work.patch new file mode 100644 index 0000000..ade4dde --- /dev/null +++ b/patches/server/0023-Petal-Reduce-sensor-work.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrHua269 +Date: Wed, 7 Feb 2024 04:46:30 +0000 +Subject: [PATCH] Petal Reduce sensor work + + +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/PetalReduceSensorWorkConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/PetalReduceSensorWorkConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..dd45cf1fde5ee4cf8347064f106c64b861b77ead +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/PetalReduceSensorWorkConfig.java +@@ -0,0 +1,22 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class PetalReduceSensorWorkConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = true; ++ @ConfigInfo(baseName = "delay_ticks") ++ public static int delayTicks = 10; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "reduce_sensor_work"; ++ } ++} +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index 192584ac3b280cef2e76bc510c03ff6e0fd26ce2..8e2da025ff13abd7f021099b66dc04d1ead64390 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -926,10 +926,11 @@ public abstract class Mob extends LivingEntity implements Targeting { + return; + } + // Paper end - Allow nerfed mobs to jump and float ++ int i = this.tickCount + this.getId(); // Folia - region threading //Luminol - Petal - Move up ++ + this.level().getProfiler().push("sensing"); +- this.sensing.tick(); ++ if (i % me.earthme.luminol.config.modules.optimizations.PetalReduceSensorWorkConfig.delayTicks == 0 || !me.earthme.luminol.config.modules.optimizations.PetalReduceSensorWorkConfig.enabled)this.sensing.tick(); //Luminol - Petal - Reduce sensor work + this.level().getProfiler().pop(); +- int i = this.tickCount + this.getId(); // Folia - region threading + + if (i % 2 != 0 && this.tickCount > 1) { + this.level().getProfiler().push("targetSelector"); diff --git a/patches/server/0018-Pufferfish-Optimize-entity-coordinate-key.patch b/patches/server/0024-Pufferfish-Optimize-entity-coordinate-key.patch similarity index 90% rename from patches/server/0018-Pufferfish-Optimize-entity-coordinate-key.patch rename to patches/server/0024-Pufferfish-Optimize-entity-coordinate-key.patch index 47dcd40..c0801b4 100644 --- a/patches/server/0018-Pufferfish-Optimize-entity-coordinate-key.patch +++ b/patches/server/0024-Pufferfish-Optimize-entity-coordinate-key.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Pufferfish Optimize entity coordinate key diff --git a/src/main/java/io/papermc/paper/util/MCUtil.java b/src/main/java/io/papermc/paper/util/MCUtil.java -index 1f0ec6add54b7503415d5f4141fe2b6046f1ec69..8ec8084195e0400de76460b445012d605fe05724 100644 +index 878306271d4af280c7a086d1839c446a01da1ad6..cb22cac2b8c4eaf705b76fd4a9d8b82fb8eb0140 100644 --- a/src/main/java/io/papermc/paper/util/MCUtil.java +++ b/src/main/java/io/papermc/paper/util/MCUtil.java @@ -212,7 +212,7 @@ public final class MCUtil { diff --git a/patches/server/0019-Pufferfish-Cache-climbing-check-for-activation.patch b/patches/server/0025-Pufferfish-Cache-climbing-check-for-activation.patch similarity index 96% rename from patches/server/0019-Pufferfish-Cache-climbing-check-for-activation.patch rename to patches/server/0025-Pufferfish-Cache-climbing-check-for-activation.patch index a7296d2..e988887 100644 --- a/patches/server/0019-Pufferfish-Cache-climbing-check-for-activation.patch +++ b/patches/server/0025-Pufferfish-Cache-climbing-check-for-activation.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Pufferfish Cache climbing check for activation diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 18c9a35624d6d3c94efd5df8e97c4257fd199d0d..f04517cb4a0c134344481c2779fea5bf49f1482d 100644 +index 93936213c0ddd3fc1435be15eae09a2cdb1a099e..9c80582a02123364eea527bd59ff3cb0e4aad98f 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -310,7 +310,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S diff --git a/patches/server/0020-Pufferfish-Improve-fluid-direction-caching.patch b/patches/server/0026-Pufferfish-Improve-fluid-direction-caching.patch similarity index 100% rename from patches/server/0020-Pufferfish-Improve-fluid-direction-caching.patch rename to patches/server/0026-Pufferfish-Improve-fluid-direction-caching.patch diff --git a/patches/server/0021-Pufferfish-Optimize-suffocation.patch b/patches/server/0027-Pufferfish-Optimize-suffocation.patch similarity index 56% rename from patches/server/0021-Pufferfish-Optimize-suffocation.patch rename to patches/server/0027-Pufferfish-Optimize-suffocation.patch index 41b8d00..076167e 100644 --- a/patches/server/0021-Pufferfish-Optimize-suffocation.patch +++ b/patches/server/0027-Pufferfish-Optimize-suffocation.patch @@ -1,43 +1,40 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: M2ke4U <79621885+MrHua269@users.noreply.github.com> -Date: Sun, 24 Dec 2023 09:52:30 +0800 +From: MrHua269 +Date: Wed, 7 Feb 2024 04:55:43 +0000 Subject: [PATCH] Pufferfish Optimize suffocation -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 0929a5a167691bde7dedaa1e2812b34ad69913d6..de0855656ad3882b182aa5674fd0117288268e71 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -42,6 +42,7 @@ public class LuminolConfig { - public static int linearFlushThreads = 1; - - public static boolean reduceSensorWork = true; -+ public static boolean enableSuffocationOptimization = true; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -104,6 +105,7 @@ public class LuminolConfig { - linearFlushThreads = Math.max(linearFlushThreads, 1); - - reduceSensorWork = get("optimizations.reduce_sensor_work",reduceSensorWork,"This optimization is from petal.You can find out more about it on petal's repository"); -+ enableSuffocationOptimization = get("optimizations.optimize_suffocation_check",enableSuffocationOptimization); - } - - public static T get(String key,T def){ +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/SuffocationOptimizationConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/SuffocationOptimizationConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3e48cd297b4869e5c89b6abc43c726d3a7511e7f +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/SuffocationOptimizationConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class SuffocationOptimizationConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean enabled = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "suffocation_optimization"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index dd50c93283dfce2ed33d3eece48e1829b9cdc9d0..81984f462da4acec1e1a6bcbe52ad0d10d6767f4 100644 +index dd50c93283dfce2ed33d3eece48e1829b9cdc9d0..e304407868a109ea9455112b2003c89d62db1607 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -18,6 +18,8 @@ import java.util.Optional; - import java.util.UUID; - import java.util.function.Predicate; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.BlockUtil; - import net.minecraft.advancements.CriteriaTriggers; - import net.minecraft.commands.arguments.EntityAnchorArgument; -@@ -418,7 +420,7 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -418,7 +418,7 @@ public abstract class LivingEntity extends Entity implements Attackable { boolean flag = this instanceof net.minecraft.world.entity.player.Player; if (!this.level().isClientSide) { @@ -46,7 +43,7 @@ index dd50c93283dfce2ed33d3eece48e1829b9cdc9d0..81984f462da4acec1e1a6bcbe52ad0d1 this.hurt(this.damageSources().inWall(), 1.0F); } else if (flag && !this.level().getWorldBorder().isWithinBounds(this.getBoundingBox())) { double d0 = this.level().getWorldBorder().getDistanceToBorder(this) + this.level().getWorldBorder().getDamageSafeZone(); -@@ -1419,6 +1421,19 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -1419,6 +1419,19 @@ public abstract class LivingEntity extends Entity implements Attackable { return this.getHealth() <= 0.0F; } @@ -59,7 +56,7 @@ index dd50c93283dfce2ed33d3eece48e1829b9cdc9d0..81984f462da4acec1e1a6bcbe52ad0d1 + } + + public boolean shouldCheckForSuffocation() { -+ return !LuminolConfig.enableSuffocationOptimization || (tickCount % 10 == 0 && couldPossiblyBeHurt(1.0F)); ++ return !me.earthme.luminol.config.modules.optimizations.SuffocationOptimizationConfig.enabled || (tickCount % 10 == 0 && couldPossiblyBeHurt(1.0F)); + } + // Pufferfish end + diff --git a/patches/server/0022-Pufferfish-Early-return-optimization-for-target-find.patch b/patches/server/0028-Pufferfish-Early-return-optimization-for-target-find.patch similarity index 100% rename from patches/server/0022-Pufferfish-Early-return-optimization-for-target-find.patch rename to patches/server/0028-Pufferfish-Early-return-optimization-for-target-find.patch diff --git a/patches/server/0023-Pufferfish-Reduce-chunk-loading-lookups.patch b/patches/server/0029-Pufferfish-Reduce-chunk-loading-lookups.patch similarity index 94% rename from patches/server/0023-Pufferfish-Reduce-chunk-loading-lookups.patch rename to patches/server/0029-Pufferfish-Reduce-chunk-loading-lookups.patch index 47a59c0..f8acd09 100644 --- a/patches/server/0023-Pufferfish-Reduce-chunk-loading-lookups.patch +++ b/patches/server/0029-Pufferfish-Reduce-chunk-loading-lookups.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Pufferfish Reduce chunk loading & lookups diff --git a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java -index bd5996eef2d946e9d7765b6b315bc5951158810e..0d51f435f18f3f9d59a3241a0b7fa1c4af841b72 100644 +index f33c03e81b7ff643741f56eea055e6af260de618..6563e625ebae47fc68e5010d36bd4b4d327c07b7 100644 --- a/src/main/java/net/minecraft/world/entity/monster/EnderMan.java +++ b/src/main/java/net/minecraft/world/entity/monster/EnderMan.java @@ -333,11 +333,17 @@ public class EnderMan extends Monster implements NeutralMob { diff --git a/patches/server/0024-Pufferfish-Improve-container-checking-with-a-bitset.patch b/patches/server/0030-Pufferfish-Improve-container-checking-with-a-bitset.patch similarity index 99% rename from patches/server/0024-Pufferfish-Improve-container-checking-with-a-bitset.patch rename to patches/server/0030-Pufferfish-Improve-container-checking-with-a-bitset.patch index f6428ca..4eb59fd 100644 --- a/patches/server/0024-Pufferfish-Improve-container-checking-with-a-bitset.patch +++ b/patches/server/0030-Pufferfish-Improve-container-checking-with-a-bitset.patch @@ -284,7 +284,7 @@ index 6d23c39e4eadf23616080d6d08672e13b5d3c37d..e7115f1635821e0aab32e8aeea691438 } diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -index a71414397bd45ee7bcacfeef0041d80dfa25f114..d66806565770cb03a21794f99e5c4b0f3040b26a 100644 +index 9b1243d96e0694c62fc9e82e9be540bce0d2b3ad..3514022d898a24052c917ebf55dcef3e757d6836 100644 --- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java +++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java @@ -31,7 +31,10 @@ import org.bukkit.entity.HumanEntity; diff --git a/patches/server/0025-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch b/patches/server/0031-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch similarity index 100% rename from patches/server/0025-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch rename to patches/server/0031-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch diff --git a/patches/server/0026-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch b/patches/server/0032-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch similarity index 96% rename from patches/server/0026-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch rename to patches/server/0032-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch index 932879c..0607a9c 100644 --- a/patches/server/0026-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch +++ b/patches/server/0032-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Pufferfish Reduce entity fluid lookups if no fluids diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index f04517cb4a0c134344481c2779fea5bf49f1482d..8a3e11b80d8935b54be2a4a815ee58f5d116424e 100644 +index 9c80582a02123364eea527bd59ff3cb0e4aad98f..e6b90e53b2b539543084ddbfda4ab819656a3179 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -5189,16 +5189,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -5240,16 +5240,18 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S } public boolean updateFluidHeightAndDoFluidPushing(TagKey tag, double speed) { @@ -34,7 +34,7 @@ index f04517cb4a0c134344481c2779fea5bf49f1482d..8a3e11b80d8935b54be2a4a815ee58f5 double d1 = 0.0D; boolean flag = this.isPushedByFluid(); boolean flag1 = false; -@@ -5206,14 +5208,61 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -5257,14 +5259,61 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S int k1 = 0; BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); @@ -102,7 +102,7 @@ index f04517cb4a0c134344481c2779fea5bf49f1482d..8a3e11b80d8935b54be2a4a815ee58f5 if (d2 >= axisalignedbb.minY) { flag1 = true; -@@ -5235,9 +5284,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -5286,9 +5335,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S // CraftBukkit end } } diff --git a/patches/server/0027-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch b/patches/server/0033-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch similarity index 95% rename from patches/server/0027-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch rename to patches/server/0033-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch index f80b3d4..2af622c 100644 --- a/patches/server/0027-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch +++ b/patches/server/0033-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Pufferfish Only check for spooky season once an hour diff --git a/src/main/java/net/minecraft/world/entity/ambient/Bat.java b/src/main/java/net/minecraft/world/entity/ambient/Bat.java -index 6b614818b14ecfc8fc82b523eeb7e21fdf9bf1ba..1029fbda5042373886d0909d348cc39e44c95ab1 100644 +index 44fa2d4f90389f5526746bd94a2450c03340bd0b..864c3c72b6881a2a8223a9aa5a593f1a65bcc857 100644 --- a/src/main/java/net/minecraft/world/entity/ambient/Bat.java +++ b/src/main/java/net/minecraft/world/entity/ambient/Bat.java @@ -3,6 +3,10 @@ package net.minecraft.world.entity.ambient; diff --git a/patches/server/0034-Gale-Reduce-acquire-POI-for-stuck-entities.patch b/patches/server/0034-Gale-Reduce-acquire-POI-for-stuck-entities.patch deleted file mode 100644 index 56967f4..0000000 --- a/patches/server/0034-Gale-Reduce-acquire-POI-for-stuck-entities.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Sat, 27 Jan 2024 12:45:40 +0000 -Subject: [PATCH] Gale Reduce acquire POI for stuck entities - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index fcd532898e099a809969603941b90fdd415b03c3..d032786938db9725e1be72dae63a1387bcb69d79 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -12,14 +12,10 @@ import org.apache.logging.log4j.Logger; - import org.bukkit.Bukkit; - - import java.util.*; --import java.util.logging.Level; - import java.io.File; - import java.io.IOException; - --import net.minecraft.core.registries.BuiltInRegistries; - import net.minecraft.server.MinecraftServer; --import org.bukkit.configuration.ConfigurationSection; --import net.minecraft.world.entity.EntityType; - - public class LuminolConfig { - private static final Logger logger = LogManager.getLogger(); -@@ -58,6 +54,7 @@ public class LuminolConfig { - public static int activationDistanceMod; - public static double entityWakeUpDurationRatioStandardDeviation = 0.2; - public static boolean loadChunksToActiveClimbingEntities = false; -+ public static int acquirePoiForStuckEntityInterval = 60; - - - public static void init() throws IOException { -@@ -171,6 +168,7 @@ public class LuminolConfig { - initDAB(); - entityWakeUpDurationRatioStandardDeviation = get("optimizations.entity_wakeup_duration_ratio_standard_deviation",entityWakeUpDurationRatioStandardDeviation); - loadChunksToActiveClimbingEntities = get("optimizations.load_chunks_to_active_climbing_entities",loadChunksToActiveClimbingEntities); -+ acquirePoiForStuckEntityInterval = get("optimizations.acquire_poi_for_stuck_entity_interval", acquirePoiForStuckEntityInterval); - } - - public static T get(String key,T def){ -diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -index abcc3ef59475ac170fd10b4dd4a4f3371faf17e0..961d3df1ca72d36ed7f0008bac346c95e07a0288 100644 ---- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java -@@ -9,10 +9,13 @@ import java.util.Set; - import java.util.function.Predicate; - import java.util.stream.Collectors; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.core.BlockPos; - import net.minecraft.core.GlobalPos; - import net.minecraft.core.Holder; - import net.minecraft.network.protocol.game.DebugPackets; -+import net.minecraft.server.level.ServerLevel; - import net.minecraft.util.RandomSource; - import net.minecraft.world.entity.Mob; - import net.minecraft.world.entity.PathfinderMob; -@@ -26,6 +29,13 @@ import org.apache.commons.lang3.mutable.MutableLong; - public class AcquirePoi { - public static final int SCAN_RANGE = 48; - -+ // Gale start - Airplane - reduce acquire POI for stuck entities -+ public static void addAdditionalTimeToMutableLongIfEntityIsStuck(MutableLong mutableLong, ServerLevel world, PathfinderMob entity) { -+ long stuckEntityAdditionalWaitTime = LuminolConfig.acquirePoiForStuckEntityInterval; -+ mutableLong.add(stuckEntityAdditionalWaitTime <= 0L ? 0L : entity.getNavigation().isStuck() ? stuckEntityAdditionalWaitTime : 0L); -+ } -+ // Gale end - Airplane - reduce acquire POI for stuck entities -+ - public static BehaviorControl create(Predicate> poiPredicate, MemoryModuleType poiPosModule, boolean onlyRunIfChild, Optional entityStatus) { - return create(poiPredicate, poiPosModule, poiPosModule, onlyRunIfChild, entityStatus); - } -@@ -42,12 +52,13 @@ public class AcquirePoi { - return false; - } else if (mutableLong.getValue() == 0L) { - mutableLong.setValue(world.getGameTime() + (long)world.random.nextInt(20)); -+ addAdditionalTimeToMutableLongIfEntityIsStuck(mutableLong, world, entity); // Gale - Airplane - reduce acquire POI for stuck entities - return false; - } else if (world.getGameTime() < mutableLong.getValue()) { - return false; - } else { - mutableLong.setValue(time + 20L + (long)world.getRandom().nextInt(20)); -- if (entity.getNavigation().isStuck()) mutableLong.add(200); // Paper - Perf: Wait an additional 10s to check again if they're stuck -+ addAdditionalTimeToMutableLongIfEntityIsStuck(mutableLong, world, entity); // Gale - Airplane - reduce acquire POI for stuck entities - PoiManager poiManager = world.getPoiManager(); - long2ObjectMap.long2ObjectEntrySet().removeIf((entry) -> { - return !entry.getValue().isStillValid(time); diff --git a/patches/server/0028-Pufferfish-Entity-TTL.patch b/patches/server/0034-Pufferfish-Entity-TTL.patch similarity index 51% rename from patches/server/0028-Pufferfish-Entity-TTL.patch rename to patches/server/0034-Pufferfish-Entity-TTL.patch index c845236..3a40d0a 100644 --- a/patches/server/0028-Pufferfish-Entity-TTL.patch +++ b/patches/server/0034-Pufferfish-Entity-TTL.patch @@ -1,39 +1,42 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: M2ke4U <79621885+MrHua269@users.noreply.github.com> -Date: Sun, 26 Nov 2023 16:30:24 +0800 +From: MrHua269 +Date: Wed, 7 Feb 2024 05:19:37 +0000 Subject: [PATCH] Pufferfish Entity TTL -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index de0855656ad3882b182aa5674fd0117288268e71..d0c0b4daec59f23a989a8b8f66ea3c704b0e309c 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -4,13 +4,16 @@ import dev.kaiijumc.kaiiju.region.RegionFileFormat; - import com.electronwill.nightconfig.core.file.CommentedFileConfig; - import me.earthme.luminol.commands.TpsBarCommand; - import me.earthme.luminol.functions.GlobalServerTpsBar; +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/EntityTTLOptimizationConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/EntityTTLOptimizationConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..15697d69659b6e1e776acf5094684b5f0c079b57 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/EntityTTLOptimizationConfig.java +@@ -0,0 +1,38 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; +import net.minecraft.core.registries.BuiltInRegistries; - import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.entity.EntityType; - import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - import org.bukkit.Bukkit; - - import java.util.Arrays; - import java.util.List; ++ +import java.util.Locale; - import java.util.logging.Level; - import java.io.File; - import java.io.IOException; -@@ -65,6 +68,22 @@ public class LuminolConfig { - } - } - -+ private static void initEntityTTL() { ++ ++public class EntityTTLOptimizationConfig implements IConfigModule { ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "entity_time_outs"; ++ } ++ ++ @Override ++ public void onLoaded(CommentedFileConfig config) { + // Set some defaults -+ get("optimizations.entity_timeouts.SNOWBALL", -1); -+ get("optimizations.entity_timeouts.LLAMA_SPIT", -1); -+ MAIN_CONFIG.setComment("optimizations.entity_timeouts", ++ this.get("optimizations.entity_timeouts.SNOWBALL", -1,config); ++ this.get("optimizations.entity_timeouts.LLAMA_SPIT", -1,config); ++ config.setComment("optimizations.entity_timeouts", + """ + These values define a entity's maximum lifespan. If an + entity is in this list and it has survived for longer than @@ -41,23 +44,12 @@ index de0855656ad3882b182aa5674fd0117288268e71..d0c0b4daec59f23a989a8b8f66ea3c70 + -1 disables this feature."""); + for (EntityType entityType : BuiltInRegistries.ENTITY_TYPE) { + String type = EntityType.getKey(entityType).getPath().toUpperCase(Locale.ROOT); -+ entityType.ttl = get("optimizations.entity_timeouts." + type, -1); ++ entityType.ttl = this.get("optimizations.entity_timeouts." + type, -1,config); + } + } -+ - public static void initValues(){ - serverModName = get("misc.server_mod_name",serverModName,"The servermod name will be sent to players,and you can see it in F3 or motd responses"); - fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server"); -@@ -106,6 +125,7 @@ public class LuminolConfig { - - reduceSensorWork = get("optimizations.reduce_sensor_work",reduceSensorWork,"This optimization is from petal.You can find out more about it on petal's repository"); - enableSuffocationOptimization = get("optimizations.optimize_suffocation_check",enableSuffocationOptimization); -+ initEntityTTL(); - } - - public static T get(String key,T def){ ++} diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 8a3e11b80d8935b54be2a4a815ee58f5d116424e..3b42af742edbe01a4f8b8d03b5dce86efabeb6ac 100644 +index e6b90e53b2b539543084ddbfda4ab819656a3179..03a6633edd34a34f7c5cfb1a58f4d132e6bd1c12 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -798,6 +798,12 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S diff --git a/patches/server/0029-Pufferfish-Reduce-projectile-chunk-loading.patch b/patches/server/0035-Pufferfish-Reduce-projectile-chunk-loading.patch similarity index 57% rename from patches/server/0029-Pufferfish-Reduce-projectile-chunk-loading.patch rename to patches/server/0035-Pufferfish-Reduce-projectile-chunk-loading.patch index 21c47ce..956e1ce 100644 --- a/patches/server/0029-Pufferfish-Reduce-projectile-chunk-loading.patch +++ b/patches/server/0035-Pufferfish-Reduce-projectile-chunk-loading.patch @@ -1,33 +1,39 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: M2ke4U <79621885+MrHua269@users.noreply.github.com> -Date: Sun, 26 Nov 2023 16:35:37 +0800 +From: MrHua269 +Date: Wed, 7 Feb 2024 05:45:24 +0000 Subject: [PATCH] Pufferfish Reduce projectile chunk loading -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index d0c0b4daec59f23a989a8b8f66ea3c704b0e309c..11c1a367fbc25cb63738a00ad93fb0b0b3500e7d 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -46,6 +46,8 @@ public class LuminolConfig { - - public static boolean reduceSensorWork = true; - public static boolean enableSuffocationOptimization = true; +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/ProjectileChunkReduceConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/ProjectileChunkReduceConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..12683ec5a5102e45b6171fea0b833ba57e5e188c +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/ProjectileChunkReduceConfig.java +@@ -0,0 +1,22 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class ProjectileChunkReduceConfig implements IConfigModule { ++ @ConfigInfo(baseName = "max-loads-per-tick") + public static int maxProjectileLoadsPerTick; ++ @ConfigInfo(baseName = "max-loads-per-projectile") + public static int maxProjectileLoadsPerProjectile; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -126,6 +128,8 @@ public class LuminolConfig { - reduceSensorWork = get("optimizations.reduce_sensor_work",reduceSensorWork,"This optimization is from petal.You can find out more about it on petal's repository"); - enableSuffocationOptimization = get("optimizations.optimize_suffocation_check",enableSuffocationOptimization); - initEntityTTL(); -+ maxProjectileLoadsPerTick = get("optimizations.projectile.max-loads-per-tick", maxProjectileLoadsPerTick, "Controls how many chunks are allowed \nto be sync loaded by projectiles in a tick."); -+ maxProjectileLoadsPerProjectile = get("optimizations.projectile.max-loads-per-projectile", maxProjectileLoadsPerProjectile, "Controls how many chunks a projectile \n can load in its lifetime before it gets \nautomatically removed."); - } - - public static T get(String key,T def){ ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "projectile"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java -index dd204b547ea0981cf82c567cc497364ee221f09b..986ed887a771bc64474412e6c1944e59ae125248 100644 +index 10d7c64fb3a9bafdcdae99f8dc87017722341337..c366da764e2e11018460430595c14b17480c6da7 100644 --- a/src/main/java/net/minecraft/world/entity/projectile/Projectile.java +++ b/src/main/java/net/minecraft/world/entity/projectile/Projectile.java @@ -4,6 +4,8 @@ import com.google.common.base.MoreObjects; @@ -60,8 +66,8 @@ index dd204b547ea0981cf82c567cc497364ee221f09b..986ed887a771bc64474412e6c1944e59 + if (previousX != newX || previousZ != newZ) { + boolean isLoaded = ((net.minecraft.server.level.ServerChunkCache) this.level().getChunkSource()).getChunkAtIfLoadedMainThread(newX, newZ) != null; + if (!isLoaded) { -+ if (Projectile.loadedThisTick > me.earthme.luminol.LuminolConfig.maxProjectileLoadsPerTick) { -+ if (++this.loadedLifetime > me.earthme.luminol.LuminolConfig.maxProjectileLoadsPerProjectile) { ++ if (Projectile.loadedThisTick > me.earthme.luminol.config.modules.optimizations.ProjectileChunkReduceConfig.maxProjectileLoadsPerTick) { ++ if (++this.loadedLifetime > me.earthme.luminol.config.modules.optimizations.ProjectileChunkReduceConfig.maxProjectileLoadsPerProjectile) { + this.discard(); + } + return; diff --git a/patches/server/0030-Pufferfish-Dynamic-Activation-of-Brain.patch b/patches/server/0036-Pufferfish-Dynamic-Activation-of-Brain.patch similarity index 74% rename from patches/server/0030-Pufferfish-Dynamic-Activation-of-Brain.patch rename to patches/server/0036-Pufferfish-Dynamic-Activation-of-Brain.patch index 0768d01..2310e79 100644 --- a/patches/server/0030-Pufferfish-Dynamic-Activation-of-Brain.patch +++ b/patches/server/0036-Pufferfish-Dynamic-Activation-of-Brain.patch @@ -1,93 +1,80 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 03:31:26 +0000 +Date: Wed, 7 Feb 2024 05:56:56 +0000 Subject: [PATCH] Pufferfish Dynamic Activation of Brain -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 11c1a367fbc25cb63738a00ad93fb0b0b3500e7d..fead5b1be39083f3fe28be8c41dc78dcac4b59da 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -11,13 +11,16 @@ import org.apache.logging.log4j.LogManager; - import org.apache.logging.log4j.Logger; - import org.bukkit.Bukkit; - --import java.util.Arrays; --import java.util.List; --import java.util.Locale; -+import java.util.*; - import java.util.logging.Level; - import java.io.File; - import java.io.IOException; - +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/EntityDABConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/EntityDABConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..af5893ba1f738ec9827d7b714682c314229292d9 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/EntityDABConfig.java +@@ -0,0 +1,60 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.DoNotLoad; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.server.MinecraftServer; -+import org.bukkit.configuration.ConfigurationSection; +import net.minecraft.world.entity.EntityType; ++import java.util.Collections; ++import java.util.List; + - public class LuminolConfig { - private static final Logger logger = LogManager.getLogger(); - private static final File PARENT_FOLDER = new File("luminol_config"); -@@ -48,6 +51,12 @@ public class LuminolConfig { - public static boolean enableSuffocationOptimization = true; - public static int maxProjectileLoadsPerTick; - public static int maxProjectileLoadsPerProjectile; -+ public static boolean dearEnabled; -+ public static int startDistance; ++public class EntityDABConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") ++ public static boolean dearEnabled = false; ++ @ConfigInfo(baseName = "start_distance",comments = ++ "This value determines how far away an entity has to be\n" + ++ " from the player to start being effected by DEAR." ++ ) ++ public static int startDistance = 12; ++ @DoNotLoad + public static int startDistanceSquared; -+ public static int maximumActivationPrio; ++ @ConfigInfo(baseName = "max-tick-freq",comments = ++ "This value defines how often in ticks, the furthest entity\n"+ ++ "will get their pathfinders and behaviors ticked. 20 = 1s") ++ public static int maximumActivationPrio = 20; ++ @ConfigInfo(baseName = "activation-dist-mod",comments = ++ """ ++ This value defines how much distance modifies an entity's ++ tick frequency. freq = (distanceToPlayer^2) / (2^value) ++ If you want further away entities to tick less often, use 7. ++ If you want further away entities to tick more often, try 9.""") + public static int activationDistanceMod; ++ @ConfigInfo(baseName = "blacklisted-entities") ++ public static List blackedEntities = Collections.emptyList(); + - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -86,6 +95,33 @@ public class LuminolConfig { - } - } - -+ private static void initDAB(){ -+ dearEnabled = get("optimizations.dab.enabled", false); -+ startDistance = get("optimizations.dab.start-distance", 12, -+ "This value determines how far away an entity has to be\n"+ -+ "from the player to start being effected by DEAR."); -+ startDistanceSquared = startDistance * startDistance; -+ maximumActivationPrio = get("optimizations.dab.max-tick-freq",20, -+ "This value defines how often in ticks, the furthest entity\n"+ -+ "will get their pathfinders and behaviors ticked. 20 = 1s"); -+ activationDistanceMod = get("optimizations.dab.activation-dist-mod",8, -+ """ -+ This value defines how much distance modifies an entity's -+ tick frequency. freq = (distanceToPlayer^2) / (2^value) -+ If you want further away entities to tick less often, use 7. -+ If you want further away entities to tick more often, try 9."""); ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } + ++ @Override ++ public String getBaseName() { ++ return "dab"; ++ } ++ ++ @Override ++ public void onLoaded(CommentedFileConfig config) { + for (EntityType entityType : BuiltInRegistries.ENTITY_TYPE) { + entityType.dabEnabled = true; // reset all, before setting the ones to true + } -+ get("optimizations.dab.blacklisted-entities",Collections.emptyList(), "A list of entities to ignore for activation") -+ .forEach(name -> EntityType.byString(name).ifPresentOrElse(entityType -> { ++ ++ blackedEntities.forEach(name -> EntityType.byString(name).ifPresentOrElse(entityType -> { + entityType.dabEnabled = false; -+ }, () -> MinecraftServer.LOGGER.warn("Unknown entity \"" + name + "\""))); ++ }, () -> MinecraftServer.LOGGER.warn("Unknown entity \"" + name + "\""))); + -+ MAIN_CONFIG.setComment("optimizations.dab", "Optimizes entity brains when\n"+"they're far away from the player"); ++ config.setComment("optimizations.dab", "Optimizes entity brains when\n" + "they're far away from the player"); + } -+ - public static void initValues(){ - serverModName = get("misc.server_mod_name",serverModName,"The servermod name will be sent to players,and you can see it in F3 or motd responses"); - fakeVanillaModeEnabled = get("misc.enable_fake_vanilla_mode",fakeVanillaModeEnabled,"Enable this to make the ping response of your server like a vanilla server"); -@@ -130,6 +166,7 @@ public class LuminolConfig { - initEntityTTL(); - maxProjectileLoadsPerTick = get("optimizations.projectile.max-loads-per-tick", maxProjectileLoadsPerTick, "Controls how many chunks are allowed \nto be sync loaded by projectiles in a tick."); - maxProjectileLoadsPerProjectile = get("optimizations.projectile.max-loads-per-projectile", maxProjectileLoadsPerProjectile, "Controls how many chunks a projectile \n can load in its lifetime before it gets \nautomatically removed."); -+ initDAB(); - } - - public static T get(String key,T def){ ++} diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index b3dde336a8fb38b6ab30019c6d66ef1a47b25d9d..3508eeb5c779e5f955a44ab8d43b3d1433fde099 100644 +index c0f8f72d1677d4ef6a15f487262953c5df3b03c0..33154e89457e3d7331c6d17785544d08f7e6bed8 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -998,6 +998,7 @@ public class ServerLevel extends Level implements WorldGenLevel { +@@ -988,6 +988,7 @@ public class ServerLevel extends Level implements WorldGenLevel { this.timings.entityTick.startTiming(); // Spigot profiler.startTimer(ca.spottedleaf.leafprofiler.LProfilerRegistry.ENTITY_TICK); try { // Folia - profiler regionizedWorldData.forEachTickingEntity((entity) -> { // Folia - regionised ticking @@ -96,7 +83,7 @@ index b3dde336a8fb38b6ab30019c6d66ef1a47b25d9d..3508eeb5c779e5f955a44ab8d43b3d14 if (false && this.shouldDiscardEntity(entity)) { // CraftBukkit - We prevent spawning in general, so this butchering is not needed entity.discard(); diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 3b42af742edbe01a4f8b8d03b5dce86efabeb6ac..874187e6b2c14b11ce63b3b58cf5ddb0f911475d 100644 +index 03a6633edd34a34f7c5cfb1a58f4d132e6bd1c12..f61ac02037ce13bb80b0db0814145fd9ff39bc37 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -482,6 +482,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S @@ -105,7 +92,7 @@ index 3b42af742edbe01a4f8b8d03b5dce86efabeb6ac..874187e6b2c14b11ce63b3b58cf5ddb0 // Paper end - optimise entity tracking + //Pufferfish start + public boolean activatedPriorityReset = false; // DAB -+ public int activatedPriority = LuminolConfig.maximumActivationPrio; // golf score ++ public int activatedPriority = me.earthme.luminol.config.modules.optimizations.EntityDABConfig.maximumActivationPrio; // golf score + // Pufferfish end + public float getBukkitYaw() { @@ -124,10 +111,10 @@ index 8deae3e95a26f4b42b2c2134e22f9649bd7a5391..c09357c1ef84a29d972119cb496b0ae9 private String descriptionId; @Nullable diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 7ca0057037380b9eac49a6415ec05acbb2b70ec0..fcf1f61e3c37ee8d964146f5e33543f5bc478433 100644 +index 8e2da025ff13abd7f021099b66dc04d1ead64390..2f592612ddc39723b76ddc6de3b20681ece5829d 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -235,10 +235,10 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -233,10 +233,10 @@ public abstract class Mob extends LivingEntity implements Targeting { @Override public void inactiveTick() { super.inactiveTick(); @@ -140,7 +127,7 @@ index 7ca0057037380b9eac49a6415ec05acbb2b70ec0..fcf1f61e3c37ee8d964146f5e33543f5 this.targetSelector.tick(); } } -@@ -935,16 +935,20 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -934,16 +934,20 @@ public abstract class Mob extends LivingEntity implements Targeting { if (i % 2 != 0 && this.tickCount > 1) { this.level().getProfiler().push("targetSelector"); @@ -162,25 +149,16 @@ index 7ca0057037380b9eac49a6415ec05acbb2b70ec0..fcf1f61e3c37ee8d964146f5e33543f5 this.level().getProfiler().pop(); } diff --git a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -index 676f5485a4ca9252e911213dcda8d51776b637b6..8a045349f36ad4a5578a3ca48721736405255cdb 100644 +index 676f5485a4ca9252e911213dcda8d51776b637b6..0f53c206b4c0607e2cda5cfa4edeae5209e897bf 100644 --- a/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java +++ b/src/main/java/net/minecraft/world/entity/ai/goal/GoalSelector.java -@@ -11,6 +11,8 @@ import java.util.Set; - import java.util.function.Predicate; - import java.util.function.Supplier; - import java.util.stream.Stream; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.util.profiling.ProfilerFiller; - import org.slf4j.Logger; - -@@ -53,9 +55,12 @@ public class GoalSelector { +@@ -53,9 +53,12 @@ public class GoalSelector { } // Paper start - public boolean inactiveTick() { + public boolean inactiveTick(int tickRate, boolean inactive) { // Pufferfish start -+ if (inactive && !LuminolConfig.dearEnabled) tickRate = 4; // reset to Paper's ++ if (inactive && !me.earthme.luminol.config.modules.optimizations.EntityDABConfig.dearEnabled) tickRate = 4; // reset to Paper's + tickRate = Math.min(tickRate, this.newGoalRate); this.curRate++; - return this.curRate % this.newGoalRate == 0; @@ -222,7 +200,7 @@ index b21e180641d17438997a80e5bcb0ec7998d24a2e..33c160994f70f71446d665e748791343 this.level().getProfiler().pop(); this.level().getProfiler().push("axolotlActivityUpdate"); diff --git a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java -index 295769d039f2a1e4f48912a60f9dbe267d8992c1..e88b058c0734e436ef24bab6364b206c13e5a9c2 100644 +index 580da502c62ec5d669cb09932d99d1c7d711c965..b94d775e366f5cb251e9199ff5022ad53129da76 100644 --- a/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java +++ b/src/main/java/net/minecraft/world/entity/animal/frog/Frog.java @@ -159,9 +159,11 @@ public class Frog extends Animal implements VariantHolder { @@ -302,7 +280,7 @@ index a9813da7f2b248f98f22e0ad2e7842915025ec12..83d83e3f84bb6bd58761671c6cd4c868 this.level().getProfiler().pop(); PiglinAi.updateActivity(this); diff --git a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java -index 937f81a859953498abe73bea560c86e6560e1c33..0a151c679b0dc943598180942d6d4b3886211688 100644 +index 7aadd36f0fe986635b495ab8c1426644620400cf..0c947d7509d66647327bce885ad2c6051f41c56f 100644 --- a/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java +++ b/src/main/java/net/minecraft/world/entity/monster/warden/Warden.java @@ -273,11 +273,13 @@ public class Warden extends Monster implements VibrationSystem { @@ -354,17 +332,10 @@ index 853c777bad19656cd48e9de9015c12e2c078d940..fba0f3725ff3001decdb9efeeab50dd7 if (this.assignProfessionWhenSpawned) { this.assignProfessionWhenSpawned = false; diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index 50fafff765b2494c075784cc5342d086c8dc97b2..bcb21ed7f9d425d94d62822c32ec77a197ce3dd6 100644 +index 50fafff765b2494c075784cc5342d086c8dc97b2..78b495ffbb1ca753714304e2a18035bcfd84b918 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -1,5 +1,6 @@ - package org.spigotmc; - -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.core.BlockPos; - import net.minecraft.server.MinecraftServer; - import net.minecraft.server.level.ServerChunkCache; -@@ -38,6 +39,10 @@ import co.aikar.timings.MinecraftTimings; +@@ -38,6 +38,10 @@ import co.aikar.timings.MinecraftTimings; import net.minecraft.world.entity.schedule.Activity; import net.minecraft.world.level.Level; import net.minecraft.world.phys.AABB; @@ -375,23 +346,23 @@ index 50fafff765b2494c075784cc5342d086c8dc97b2..bcb21ed7f9d425d94d62822c32ec77a1 public class ActivationRange { -@@ -230,6 +235,25 @@ public class ActivationRange +@@ -230,6 +234,25 @@ public class ActivationRange } // Paper end - Configurable marker ticking ActivationRange.activateEntity(entity, bbByType); // Folia - threaded regions + + // Pufferfish start -+ if (LuminolConfig.dearEnabled && entity.getType().dabEnabled) { ++ if (me.earthme.luminol.config.modules.optimizations.EntityDABConfig.dearEnabled && entity.getType().dabEnabled) { + if (!entity.activatedPriorityReset) { + entity.activatedPriorityReset = true; -+ entity.activatedPriority = LuminolConfig.maximumActivationPrio; ++ entity.activatedPriority = me.earthme.luminol.config.modules.optimizations.EntityDABConfig.maximumActivationPrio; + } + Vec3 playerVec = player.position(); + Vec3 entityVec = entity.position(); + double diffX = playerVec.x - entityVec.x, diffY = playerVec.y - entityVec.y, diffZ = playerVec.z - entityVec.z; + int squaredDistance = (int) (diffX * diffX + diffY * diffY + diffZ * diffZ); -+ entity.activatedPriority = squaredDistance > LuminolConfig.startDistanceSquared ? -+ Math.max(1, Math.min(squaredDistance >> LuminolConfig.activationDistanceMod, entity.activatedPriority)) : ++ entity.activatedPriority = squaredDistance > me.earthme.luminol.config.modules.optimizations.EntityDABConfig.startDistanceSquared ? ++ Math.max(1, Math.min(squaredDistance >> me.earthme.luminol.config.modules.optimizations.EntityDABConfig.activationDistanceMod, entity.activatedPriority)) : + 1; + } else { + entity.activatedPriority = 1; @@ -401,7 +372,7 @@ index 50fafff765b2494c075784cc5342d086c8dc97b2..bcb21ed7f9d425d94d62822c32ec77a1 } // Paper end } -@@ -246,12 +270,12 @@ public class ActivationRange +@@ -246,12 +269,12 @@ public class ActivationRange if ( io.papermc.paper.threadedregions.RegionizedServer.getCurrentTick() > entity.activatedTick ) // Folia - threaded regions { if ( entity.defaultActivationState ) diff --git a/patches/server/0036-Try-fixing-folia-spector-teleportation.patch b/patches/server/0036-Try-fixing-folia-spector-teleportation.patch deleted file mode 100644 index fc30c0a..0000000 --- a/patches/server/0036-Try-fixing-folia-spector-teleportation.patch +++ /dev/null @@ -1,99 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: M2ke4U <79621885+MrHua269@users.noreply.github.com> -Date: Sun, 24 Dec 2023 11:24:04 +0800 -Subject: [PATCH] Try fixing folia spector teleportation - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index d032786938db9725e1be72dae63a1387bcb69d79..dcc52141b34b87a67c3d6070b68b58af4a7c4f26 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -31,6 +31,7 @@ public class LuminolConfig { - public static String[] tpsColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; - public static String[] pingColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; - public static boolean disableUsernameCheck = false; -+ public static boolean fixSpectorTeleportFolia = false; - - public static boolean safeTeleportation = true; - public static boolean enableSandDuping = false; -@@ -130,6 +131,7 @@ public class LuminolConfig { - tpsColors = get("misc.tpsbar_range_colors", List.of(tpsColors),"The bar and text color of each tps ranges.The last is the color of initial bar's color").toArray(String[]::new); - pingColors = get("misc.tpsbar_ping_range_colors",List.of(pingColors),"As same as the tpsColors").toArray(String[]::new); - disableUsernameCheck = get("misc.disable_username_check",disableUsernameCheck,"Disable username check that can accept usernames with other characters(such as Chinese).Not recommended to use"); -+ fixSpectorTeleportFolia = get("misc.fix_folia_spector_teleport",fixSpectorTeleportFolia); - - if (tpsbarEnabled){ - initTpsbar(); -diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java -index 90969df697f3f0d6d77d8584924c28a844c1535d..47fbda55317e27d9f5fac583f529ae1215f43052 100644 ---- a/src/main/java/net/minecraft/server/level/ServerPlayer.java -+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java -@@ -17,6 +17,9 @@ import java.util.OptionalInt; - import java.util.Set; - import java.util.stream.Collectors; - import javax.annotation.Nullable; -+ -+import io.papermc.paper.util.TickThread; -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.BlockUtil; - import net.minecraft.ChatFormatting; - import net.minecraft.CrashReport; -@@ -843,18 +846,7 @@ public class ServerPlayer extends Player { - - Entity entity = this.getCamera(); - -- if (entity != this) { -- if (entity.isAlive()) { -- this.absMoveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); -- this.serverLevel().getChunkSource().move(this); -- if (this.wantsToStopRiding()) { -- this.setCamera(this); -- } -- } else { -- this.setCamera(this); -- } -- } -- -+ //Luminol - move up - CriteriaTriggers.TICK.trigger(this); - if (this.levitationStartPos != null) { - CriteriaTriggers.LEVITATION.trigger(this, this.levitationStartPos, this.tickCount - this.levitationStartTime); -@@ -863,6 +855,38 @@ public class ServerPlayer extends Player { - this.trackStartFallingPosition(); - this.trackEnteredOrExitedLavaOnVehicle(); - this.advancements.flushDirty(this); -+ -+ if (entity != this) { -+ if (entity.isAlive()) { -+ //Luminol start - Fix spector camera -+ if (TickThread.isTickThreadFor(entity) || !LuminolConfig.fixSpectorTeleportFolia){ -+ this.absMoveTo(entity.getX(), entity.getY(), entity.getZ(), entity.getYRot(), entity.getXRot()); -+ this.serverLevel().getChunkSource().move(this); -+ if (this.wantsToStopRiding()) { -+ this.setCamera(this); -+ } -+ }else{ -+ this.teleportAsync( -+ ((ServerLevel) entity.level()), -+ entity.position, -+ entity.getYRot(), -+ entity.getXRot(), -+ null, -+ TeleportCause.SPECTATE, -+ Entity.TELEPORT_FLAG_LOAD_CHUNK | Entity.TELEPORT_FLAG_TELEPORT_PASSENGERS, -+ r -> { -+ this.serverLevel().getChunkSource().move(this); -+ if (this.wantsToStopRiding()) { -+ this.setCamera(this); -+ } -+ } -+ ); -+ } -+ //Luminol end -+ } else { -+ this.setCamera(this); -+ } -+ } - } - - public void doTick() { diff --git a/patches/server/0037-Add-config-for-offline-mode-warning.patch b/patches/server/0037-Add-config-for-offline-mode-warning.patch deleted file mode 100644 index 3c3e3d6..0000000 --- a/patches/server/0037-Add-config-for-offline-mode-warning.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Sat, 27 Jan 2024 13:13:12 +0000 -Subject: [PATCH] Add config for offline mode warning - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index dcc52141b34b87a67c3d6070b68b58af4a7c4f26..8bf7a0235ed292d6cb3beca9b786a69148e0b4d9 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -31,6 +31,7 @@ public class LuminolConfig { - public static String[] tpsColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; - public static String[] pingColors = new String[]{"GREEN","YELLOW","RED","PURPLE"}; - public static boolean disableUsernameCheck = false; -+ public static boolean disableOfflineModeWarning = false; - public static boolean fixSpectorTeleportFolia = false; - - public static boolean safeTeleportation = true; -@@ -132,6 +133,7 @@ public class LuminolConfig { - pingColors = get("misc.tpsbar_ping_range_colors",List.of(pingColors),"As same as the tpsColors").toArray(String[]::new); - disableUsernameCheck = get("misc.disable_username_check",disableUsernameCheck,"Disable username check that can accept usernames with other characters(such as Chinese).Not recommended to use"); - fixSpectorTeleportFolia = get("misc.fix_folia_spector_teleport",fixSpectorTeleportFolia); -+ disableOfflineModeWarning = get("misc.disable_offline_mode_warning",disableOfflineModeWarning); - - if (tpsbarEnabled){ - initTpsbar(); -diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -index 59de20edb5a770a380c26f13ba1b830e3c0c1875..551f80fc56fa620ebfab2b80b3e9a32c90b3fff0 100644 ---- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java -@@ -278,7 +278,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface - 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 (!this.usesAuthentication() && !LuminolConfig.disableOfflineModeWarning) { //Luminol - Add config for offline mod warning - DedicatedServer.LOGGER.warn("**** SERVER IS RUNNING IN OFFLINE/INSECURE MODE!"); - DedicatedServer.LOGGER.warn("The server will make no attempt to authenticate usernames. Beware."); - // Spigot start diff --git a/patches/server/0031-Gale-Variable-entity-wake-up-duration.patch b/patches/server/0037-Gale-Variable-entity-wake-up-duration.patch similarity index 67% rename from patches/server/0031-Gale-Variable-entity-wake-up-duration.patch rename to patches/server/0037-Gale-Variable-entity-wake-up-duration.patch index e31b78c..ac7c95e 100644 --- a/patches/server/0031-Gale-Variable-entity-wake-up-duration.patch +++ b/patches/server/0037-Gale-Variable-entity-wake-up-duration.patch @@ -1,34 +1,40 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 03:52:35 +0000 +Date: Wed, 7 Feb 2024 06:00:22 +0000 Subject: [PATCH] Gale Variable entity wake-up duration -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index fead5b1be39083f3fe28be8c41dc78dcac4b59da..aed42e6fa85c8ab5b57e1d09dd840bb49ffe0006 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -56,6 +56,7 @@ public class LuminolConfig { - public static int startDistanceSquared; - public static int maximumActivationPrio; - public static int activationDistanceMod; +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/GaleVariableEntityWakeupConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/GaleVariableEntityWakeupConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..fa30e8dc39a2d4bd1399e41230b307b19eeb716a +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/GaleVariableEntityWakeupConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class GaleVariableEntityWakeupConfig implements IConfigModule { ++ @ConfigInfo(baseName = "entity_wakeup_duration_ratio_standard_deviation") + public static double entityWakeUpDurationRatioStandardDeviation = 0.2; - - - public static void init() throws IOException { -@@ -167,6 +168,7 @@ public class LuminolConfig { - maxProjectileLoadsPerTick = get("optimizations.projectile.max-loads-per-tick", maxProjectileLoadsPerTick, "Controls how many chunks are allowed \nto be sync loaded by projectiles in a tick."); - maxProjectileLoadsPerProjectile = get("optimizations.projectile.max-loads-per-projectile", maxProjectileLoadsPerProjectile, "Controls how many chunks a projectile \n can load in its lifetime before it gets \nautomatically removed."); - initDAB(); -+ entityWakeUpDurationRatioStandardDeviation = get("optimizations.entity_wakeup_duration_ratio_standard_deviation",entityWakeUpDurationRatioStandardDeviation); - } - - public static T get(String key,T def){ ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "variable_entity_waking_up"; ++ } ++} diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java -index bcb21ed7f9d425d94d62822c32ec77a197ce3dd6..9cde36cb62b73b96467033901172b22a3c373081 100644 +index 78b495ffbb1ca753714304e2a18035bcfd84b918..e9331fe4d524215bbab9a410d16e4f1811f5ad31 100644 --- a/src/main/java/org/spigotmc/ActivationRange.java +++ b/src/main/java/org/spigotmc/ActivationRange.java -@@ -76,28 +76,41 @@ public class ActivationRange +@@ -75,28 +75,41 @@ public class ActivationRange if (entity.activationType == ActivationType.VILLAGER) { if (inactiveFor > config.wakeUpInactiveVillagersEvery && worldData.wakeupInactiveRemainingVillagers > 0) { // Folia - threaded regions worldData.wakeupInactiveRemainingVillagers--; // Folia - threaded regions @@ -62,7 +68,7 @@ index bcb21ed7f9d425d94d62822c32ec77a197ce3dd6..9cde36cb62b73b96467033901172b22a + private static final java.util.concurrent.ThreadLocalRandom wakeUpDurationRandom = java.util.concurrent.ThreadLocalRandom.current(); + + private static int getWakeUpDurationWithVariance(Entity entity, int wakeUpDuration) { -+ double deviation = LuminolConfig.entityWakeUpDurationRatioStandardDeviation; ++ double deviation = me.earthme.luminol.config.modules.optimizations.GaleVariableEntityWakeupConfig.entityWakeUpDurationRatioStandardDeviation; + if (deviation <= 0) { + return wakeUpDuration; + } diff --git a/patches/server/0032-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch b/patches/server/0038-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch similarity index 62% rename from patches/server/0032-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch rename to patches/server/0038-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch index 70dc1de..5f7901a 100644 --- a/patches/server/0032-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch +++ b/patches/server/0038-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch @@ -1,34 +1,40 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: M2ke4U <79621885+MrHua269@users.noreply.github.com> -Date: Sun, 26 Nov 2023 17:21:11 +0800 +From: MrHua269 +Date: Wed, 7 Feb 2024 06:03:02 +0000 Subject: [PATCH] Gale Don't load chunks to activate climbing entities -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index aed42e6fa85c8ab5b57e1d09dd840bb49ffe0006..5a5a868a3715db24635ad5531005b022daa28c7d 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -57,6 +57,7 @@ public class LuminolConfig { - public static int maximumActivationPrio; - public static int activationDistanceMod; - public static double entityWakeUpDurationRatioStandardDeviation = 0.2; -+ public static boolean loadChunksToActiveClimbingEntities = false; - - - public static void init() throws IOException { -@@ -169,6 +170,7 @@ public class LuminolConfig { - maxProjectileLoadsPerProjectile = get("optimizations.projectile.max-loads-per-projectile", maxProjectileLoadsPerProjectile, "Controls how many chunks a projectile \n can load in its lifetime before it gets \nautomatically removed."); - initDAB(); - entityWakeUpDurationRatioStandardDeviation = get("optimizations.entity_wakeup_duration_ratio_standard_deviation",entityWakeUpDurationRatioStandardDeviation); -+ loadChunksToActiveClimbingEntities = get("optimizations.load_chunks_to_active_climbing_entities",loadChunksToActiveClimbingEntities); - } - - public static T get(String key,T def){ +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/LoadChunksToActiveClimbingEntitiesConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/LoadChunksToActiveClimbingEntitiesConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..ed62d25d6cd6dfcf8c5db20ced36eb3d3c79dafd +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/LoadChunksToActiveClimbingEntitiesConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class LoadChunksToActiveClimbingEntitiesConfig implements IConfigModule { ++ @ConfigInfo(baseName = "allow") ++ public static boolean allow = false; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "load_chunks_to_active_climbing_entities"; ++ } ++} diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 874187e6b2c14b11ce63b3b58cf5ddb0f911475d..884e4d34ac1cadfb59a65f7e420030b5f1b965c6 100644 +index f61ac02037ce13bb80b0db0814145fd9ff39bc37..0d8dd2d9b038f0694c955e649f7a4ad0039a3d89 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -5387,6 +5387,16 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -5438,6 +5438,16 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S return this.feetBlockState; } @@ -46,17 +52,17 @@ index 874187e6b2c14b11ce63b3b58cf5ddb0f911475d..884e4d34ac1cadfb59a65f7e420030b5 return this.chunkPosition; } diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 81984f462da4acec1e1a6bcbe52ad0d10d6767f4..dc80c44f52bb7acaf7d90e1c6f01c4de981f69b4 100644 +index e304407868a109ea9455112b2003c89d62db1607..aea521bd240db699eabcbe110d9a25b1141d3634 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -2035,19 +2035,43 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -2033,19 +2033,43 @@ public abstract class LivingEntity extends Entity implements Attackable { public boolean onClimableCached() { if (!this.blockPosition().equals(this.lastClimbingPosition)) { - this.cachedOnClimable = this.onClimbable(); - this.lastClimbingPosition = this.blockPosition(); + // Gale start - don't load chunks to activate climbing entities -+ Boolean onClimbableIfLoaded = this.onClimbable(LuminolConfig.loadChunksToActiveClimbingEntities); ++ Boolean onClimbableIfLoaded = this.onClimbable(me.earthme.luminol.config.modules.optimizations.LoadChunksToActiveClimbingEntitiesConfig.allow); + if (onClimbableIfLoaded != null) { + this.cachedOnClimable = onClimbableIfLoaded; + this.lastClimbingPosition = this.blockPosition(); diff --git a/patches/server/0033-Gale-Optimize-sun-burn-tick.patch b/patches/server/0039-Gale-Optimize-sun-burn-tick.patch similarity index 92% rename from patches/server/0033-Gale-Optimize-sun-burn-tick.patch rename to patches/server/0039-Gale-Optimize-sun-burn-tick.patch index de12e84..f7fbcce 100644 --- a/patches/server/0033-Gale-Optimize-sun-burn-tick.patch +++ b/patches/server/0039-Gale-Optimize-sun-burn-tick.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Gale Optimize sun burn tick diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 884e4d34ac1cadfb59a65f7e420030b5f1b965c6..50986d5309676b8cff3a02313ee383f1b1300b0f 100644 +index 0d8dd2d9b038f0694c955e649f7a4ad0039a3d89..d1f31b991a2a10593fa0ae45d10d7761baffdd75 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java @@ -309,7 +309,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S @@ -17,7 +17,7 @@ index 884e4d34ac1cadfb59a65f7e420030b5f1b965c6..50986d5309676b8cff3a02313ee383f1 public BlockPos blockPosition; // Pufferfish - private->public private ChunkPos chunkPosition; private Vec3 deltaMovement; -@@ -2023,9 +2023,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -2053,9 +2053,17 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S /** @deprecated */ @Deprecated public float getLightLevelDependentMagicValue() { @@ -37,10 +37,10 @@ index 884e4d34ac1cadfb59a65f7e420030b5f1b965c6..50986d5309676b8cff3a02313ee383f1 this.absMoveTo(x, y, z); this.setYRot(yaw % 360.0F); diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index fcf1f61e3c37ee8d964146f5e33543f5bc478433..b7970a29eb0626718051cd044a4d6092a3b88538 100644 +index 2f592612ddc39723b76ddc6de3b20681ece5829d..570371a2c903f2dfaee2935e0f845e36e3922a86 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -1741,13 +1741,29 @@ public abstract class Mob extends LivingEntity implements Targeting { +@@ -1740,13 +1740,29 @@ public abstract class Mob extends LivingEntity implements Targeting { } diff --git a/patches/server/0051-Gale-Check-frozen-ticks-before-landing-block.patch b/patches/server/0040-Gale-Check-frozen-ticks-before-landing-block.patch similarity index 85% rename from patches/server/0051-Gale-Check-frozen-ticks-before-landing-block.patch rename to patches/server/0040-Gale-Check-frozen-ticks-before-landing-block.patch index 40a3c08..a050eda 100644 --- a/patches/server/0051-Gale-Check-frozen-ticks-before-landing-block.patch +++ b/patches/server/0040-Gale-Check-frozen-ticks-before-landing-block.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Gale Check frozen ticks before landing block diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index dc80c44f52bb7acaf7d90e1c6f01c4de981f69b4..623304ea71a30d967e5ae3fa4c17f02fe305d37b 100644 +index aea521bd240db699eabcbe110d9a25b1141d3634..64ffefc98ebf19a7541b73332f050692e6d71b3a 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -589,11 +589,10 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -587,11 +587,10 @@ public abstract class LivingEntity extends Entity implements Attackable { } protected void tryAddFrost() { @@ -21,7 +21,7 @@ index dc80c44f52bb7acaf7d90e1c6f01c4de981f69b4..623304ea71a30d967e5ae3fa4c17f02f if (attributemodifiable == null) { return; -@@ -603,7 +602,6 @@ public abstract class LivingEntity extends Entity implements Attackable { +@@ -601,7 +600,6 @@ public abstract class LivingEntity extends Entity implements Attackable { attributemodifiable.addTransientModifier(new AttributeModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID, "Powder snow slow", (double) f, AttributeModifier.Operation.ADDITION)); } diff --git a/patches/server/0052-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch b/patches/server/0041-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch similarity index 100% rename from patches/server/0052-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch rename to patches/server/0041-Gale-Don-t-trigger-lootable-refresh-for-non-player-i.patch diff --git a/patches/server/0041-Leaves-PCA-sync-protocol.patch b/patches/server/0041-Leaves-PCA-sync-protocol.patch deleted file mode 100644 index 792ab4b..0000000 --- a/patches/server/0041-Leaves-PCA-sync-protocol.patch +++ /dev/null @@ -1,709 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 04:05:46 +0000 -Subject: [PATCH] Leaves PCA sync protocol - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index a15bf25fb01fb9cf239ecb8c05d795c61d6a8bb9..da818a35faf396e94192ee9ef18c2e5aaef5077a 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -63,6 +63,10 @@ public class LuminolConfig { - public static int asyncPathProcessingKeepalive = 60; - public static boolean useAlternateKeepAlive = false; - -+ public static boolean pcaSyncProtocol = false; -+ public static String pcaSyncPlayerEntity = "NOBODY"; -+ -+ - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); - -@@ -188,6 +192,9 @@ public class LuminolConfig { - if (!asyncPathProcessing) - asyncPathProcessingMaxThreads = 0; - useAlternateKeepAlive = get("optimizations.enable_alternative_keep_alive_handling",useAlternateKeepAlive,"Enabling this sends a keepalive packet once per second to a player, and only kicks for timeout if none of them were responded to in 30 seconds. Responding to any of them in any order will keep the player connected. AKA, it won't kick your players because one packet gets dropped somewhere along the lines(From purpur)"); -+ -+ pcaSyncProtocol = get("gameplay.enable_pca_sync_protocol",pcaSyncProtocol); -+ pcaSyncPlayerEntity = get("gameplay.pca_sync_player_entity",pcaSyncPlayerEntity,"Available values: NOBODY,EVERYBODY,OPS,OPS_AND_SELF"); - } - - public static T get(String key,T def){ -diff --git a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -index 815eb15086976b8f9e03bf8182d9ed50aec14720..2d8d7eebff351987b4d184afa5b6b32ac524cd78 100644 ---- a/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -+++ b/src/main/java/net/minecraft/world/entity/animal/horse/AbstractHorse.java -@@ -373,6 +373,11 @@ public abstract class AbstractHorse extends Animal implements ContainerListener, - - @Override - public void containerChanged(Container sender) { -+ // Leaves start - pca -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this); -+ } -+ // Leaves end - pca - boolean flag = this.isSaddled(); - - this.updateContainerEquipment(); -diff --git a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -index d2fbeb0e4e3e681b22455b9cf2d125dcb4de0a56..49fcd1d78e97f1e63024ef7d65b47602a0abc0a7 100644 ---- a/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -+++ b/src/main/java/net/minecraft/world/entity/npc/AbstractVillager.java -@@ -64,6 +64,15 @@ public abstract class AbstractVillager extends AgeableMob implements InventoryCa - super(type, world); - this.setPathfindingMalus(BlockPathTypes.DANGER_FIRE, 16.0F); - this.setPathfindingMalus(BlockPathTypes.DAMAGE_FIRE, -1.0F); -+ // Leaves start - pca -+ if (!this.level().isClientSide()) { -+ this.inventory.addListener(inventory -> { -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this); -+ } -+ }); -+ } -+ // Leaves end - pca - } - - @Override -diff --git a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -index e7115f1635821e0aab32e8aeea6914388dc24639..6593ae2dad5d1f7d8e403d08cd425a64d218274e 100644 ---- a/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -+++ b/src/main/java/net/minecraft/world/entity/vehicle/AbstractMinecartContainer.java -@@ -138,7 +138,13 @@ public abstract class AbstractMinecartContainer extends AbstractMinecart impleme - } - - @Override -- public void setChanged() {} -+ public void setChanged() { -+ // Leaves start - pca -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncEntityToClient(this); -+ } -+ // Leaves end - pca -+ } - - @Override - public boolean stillValid(Player player) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -index d04fc84eef11adb5ea64077f48794b6ed7fb3ada..192b81ea4973b1fb478574ee798d68e884e8be3c 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/AbstractFurnaceBlockEntity.java -@@ -570,6 +570,16 @@ public abstract class AbstractFurnaceBlockEntity extends BaseContainerBlockEntit - - } - -+ // Leaves start - pca -+ @Override -+ public void setChanged() { -+ super.setChanged(); -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ } -+ // Leaves end - pca -+ - @Override - public boolean stillValid(net.minecraft.world.entity.player.Player player) { - return Container.stillValidBlockEntity(this, player); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -index 416aa989ebb18a8741cc9d605a1180ab830f6643..b73c3dc28a95279285e911bfed3bc3d3f038e6db 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BarrelBlockEntity.java -@@ -131,6 +131,16 @@ public class BarrelBlockEntity extends RandomizableContainerBlockEntity { - this.items = list; - } - -+ // Leaves start - pca -+ @Override -+ public void setChanged() { -+ super.setChanged(); -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ } -+ // Leaves end - pca -+ - @Override - protected Component getDefaultName() { - return Component.translatable("container.barrel"); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -index 56b328c64bea0ffd51930d8ba15fb87a36e6d8a1..218f697bc075140c62f461870aff3121d671480d 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BeehiveBlockEntity.java -@@ -4,6 +4,7 @@ import com.google.common.collect.Lists; - import java.util.Arrays; - import java.util.Iterator; - import java.util.List; -+import java.util.Objects; - import javax.annotation.Nullable; - import net.minecraft.core.BlockPos; - import net.minecraft.core.Direction; -@@ -127,6 +128,11 @@ public class BeehiveBlockEntity extends BlockEntity { - super.setChanged(); - } - -+ // Leaves start - pca -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ // Leaves end - pca - return list; - } - -@@ -188,6 +194,12 @@ public class BeehiveBlockEntity extends BlockEntity { - this.level.gameEvent(GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entity, this.getBlockState())); - } - -+ // Leaves start - pca -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ // Leaves end - pca -+ - entity.discard(); - super.setChanged(); - } -@@ -334,6 +346,11 @@ public class BeehiveBlockEntity extends BlockEntity { - if (BeehiveBlockEntity.releaseOccupant(world, pos, state, tileentitybeehive_hivebee, (List) null, tileentitybeehive_releasestatus, flowerPos)) { - flag = true; - iterator.remove(); -+ // Leaves start - pca -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(Objects.requireNonNull(world.getBlockEntity(pos))); -+ } -+ // Leaves end - pca - // CraftBukkit start - } else { - tileentitybeehive_hivebee.exitTickCounter = tileentitybeehive_hivebee.minOccupationTicks / 2; // Not strictly Vanilla behaviour in cases where bees cannot spawn but still reasonable // Paper - Fix bees aging inside hives; use exitTickCounter to keep actual bee life -@@ -385,6 +402,11 @@ public class BeehiveBlockEntity extends BlockEntity { - this.maxBees = nbt.getInt("Bukkit.MaxEntities"); - } - // CraftBukkit end -+ // Leaves start - pca -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ // Leaves end - pca - } - - @Override -diff --git a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -index 4a62ac73dd89bc3c2aed1e58152e93c5043c6633..2d5230a001b933337d90972357b8c7b4e6f88bdd 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/BrewingStandBlockEntity.java -@@ -333,6 +333,16 @@ public class BrewingStandBlockEntity extends BaseContainerBlockEntity implements - - } - -+ // Leaves start - pca -+ @Override -+ public void setChanged() { -+ super.setChanged(); -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ } -+ // Leaves end - pca -+ - @Override - public boolean stillValid(Player player) { - return Container.stillValidBlockEntity(this, player); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -index 3514022d898a24052c917ebf55dcef3e757d6836..8a94c9af960a22a1598c7c9ccb7ecad9a311e619 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/ChestBlockEntity.java -@@ -220,6 +220,16 @@ public class ChestBlockEntity extends RandomizableContainerBlockEntity implement - // Pufferfish end - } - -+ // Leaves start - pca -+ @Override -+ public void setChanged() { -+ super.setChanged(); -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ } -+ // Leaves end - pca -+ - @Override - public float getOpenNess(float tickDelta) { - return this.chestLidController.getOpenness(tickDelta); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java -index 881379681c39230a00b3a1f11cd87498984396c7..51fae4d72eed9e4224a8abe1a0b6520835857ba5 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/DispenserBlockEntity.java -@@ -92,6 +92,16 @@ public class DispenserBlockEntity extends RandomizableContainerBlockEntity { - return -1; - } - -+ // Leaves start - pca -+ @Override -+ public void setChanged() { -+ super.setChanged(); -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ } -+ // Leaves end - pca -+ - @Override - protected Component getDefaultName() { - return Component.translatable("container.dispenser"); -diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 009263f6aab41608d7e17bebbed6f962fcb55634..a6bc5d7e848470118d4520962fc9652b9637f799 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java -@@ -155,6 +155,16 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - - } - -+ // Leaves start - pca -+ @Override -+ public void setChanged() { -+ super.setChanged(); -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ } -+ // Leaves end - pca -+ - @Override - protected Component getDefaultName() { - return Component.translatable("container.hopper"); -@@ -234,6 +244,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen - if (flag) { - blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Spigot - setChanged(world, pos, state); -+ // Leaves start - pca -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(blockEntity); -+ } -+ // Leaves end - pca - return true; - } - } -diff --git a/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java -index 1fa22445a4ecc8c08dbcf0cc6bd39dc5003604c4..c1492fce06cdc00a8e82977f0c474a541efa39e8 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/ShulkerBoxBlockEntity.java -@@ -269,6 +269,16 @@ public class ShulkerBoxBlockEntity extends RandomizableContainerBlockEntity impl - this.itemStacks = list; - } - -+ // Leaves start - pca -+ @Override -+ public void setChanged() { -+ super.setChanged(); -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ top.leavesmc.leaves.protocol.PcaSyncProtocol.syncBlockEntityToClient(this); -+ } -+ } -+ // Leaves end - pca -+ - @Override - public int[] getSlotsForFace(Direction side) { - return ShulkerBoxBlockEntity.SLOTS; -diff --git a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -index b00e3b9b628f3d2a2fdbf1d2c77904963c16d3ac..5df29ac0a351a5f29189e548afc52b303031b1a2 100644 ---- a/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -+++ b/src/main/java/org/bukkit/craftbukkit/scheduler/CraftScheduler.java -@@ -47,7 +47,7 @@ import org.bukkit.scheduler.BukkitWorker; - */ - public class CraftScheduler implements BukkitScheduler { - -- static Plugin MINECRAFT = new MinecraftInternalPlugin(); -+ public static Plugin MINECRAFT = new MinecraftInternalPlugin(); - /** - * The start ID for the counter. - */ -diff --git a/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..ebd28033ddf0fe6a354585dc2818a9b481d90ed4 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java -@@ -0,0 +1,384 @@ -+package top.leavesmc.leaves.protocol; -+ -+import net.minecraft.core.BlockPos; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.player.Player; -+import net.minecraft.world.level.Level; -+import net.minecraft.world.level.block.ChestBlock; -+import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.block.state.properties.ChestType; -+import org.apache.commons.lang3.tuple.ImmutablePair; -+import org.apache.commons.lang3.tuple.MutablePair; -+import org.apache.commons.lang3.tuple.Pair; -+import org.apache.logging.log4j.LogManager; -+import org.bukkit.craftbukkit.scheduler.CraftScheduler; -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.protocol.core.LeavesProtocol; -+import top.leavesmc.leaves.protocol.core.ProtocolHandler; -+import top.leavesmc.leaves.protocol.core.ProtocolUtils; -+ -+import java.util.HashMap; -+import java.util.HashSet; -+import java.util.Map; -+import java.util.Set; -+import java.util.concurrent.locks.ReentrantLock; -+ -+import static org.bukkit.craftbukkit.scheduler.CraftScheduler.MINECRAFT; -+import static top.leavesmc.leaves.protocol.core.LeavesProtocolManager.EmptyPayload; -+ -+@LeavesProtocol(namespace = "pca") -+public class PcaSyncProtocol { -+ -+ public static final String PROTOCOL_ID = "pca"; -+ -+ public static final ReentrantLock lock = new ReentrantLock(true); -+ public static final ReentrantLock pairLock = new ReentrantLock(true); -+ -+ // send -+ private static final ResourceLocation ENABLE_PCA_SYNC_PROTOCOL = id("enable_pca_sync_protocol"); -+ private static final ResourceLocation DISABLE_PCA_SYNC_PROTOCOL = id("disable_pca_sync_protocol"); -+ private static final ResourceLocation UPDATE_ENTITY = id("update_entity"); -+ private static final ResourceLocation UPDATE_BLOCK_ENTITY = id("update_block_entity"); -+ -+ private static final Map> playerWatchBlockPos = new HashMap<>(); -+ private static final Map> playerWatchEntity = new HashMap<>(); -+ private static final Map, Set> blockPosWatchPlayerSet = new HashMap<>(); -+ private static final Map, Set> entityWatchPlayerSet = new HashMap<>(); -+ private static final MutablePair ResourceLocationEntityPair = new MutablePair<>(); -+ private static final MutablePair ResourceLocationBlockPosPair = new MutablePair<>(); -+ -+ @Contract("_ -> new") -+ public static @NotNull ResourceLocation id(String path) { -+ return new ResourceLocation(PROTOCOL_ID, path); -+ } -+ -+ @ProtocolHandler.PlayerJoin -+ private static void onJoin(ServerPlayer player) { -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ enablePcaSyncProtocol(player); -+ } -+ } -+ -+ @ProtocolHandler.ReloadServer -+ private static void onServerReload() { -+ if (me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ enablePcaSyncProtocolGlobal(); -+ } else { -+ disablePcaSyncProtocolGlobal(); -+ } -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = EmptyPayload.class, payloadId = "cancel_sync_block_entity") -+ private static void cancelSyncBlockEntityHandler(ServerPlayer player, EmptyPayload payload) { -+ if (!me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ return; -+ } -+ PcaSyncProtocol.clearPlayerWatchBlock(player); -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = EmptyPayload.class, payloadId = "cancel_sync_entity") -+ private static void cancelSyncEntityHandler(ServerPlayer player, EmptyPayload payload) { -+ if (!me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ return; -+ } -+ PcaSyncProtocol.clearPlayerWatchEntity(player); -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = SyncBlockEntityPayload.class, payloadId = "sync_block_entity") -+ private static void syncBlockEntityHandler(ServerPlayer player, SyncBlockEntityPayload payload) { -+ if (!me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ return; -+ } -+ MinecraftServer server = MinecraftServer.getServer(); -+ BlockPos pos = payload.pos; -+ ServerLevel world = player.serverLevel(); -+ -+ player.getBukkitEntity().getScheduler().execute(MINECRAFT,() -> { -+ BlockState blockState = world.getBlockState(pos); -+ clearPlayerWatchData(player); -+ -+ BlockEntity blockEntityAdj = null; -+ if (blockState.getBlock() instanceof ChestBlock) { -+ if (blockState.getValue(ChestBlock.TYPE) != ChestType.SINGLE) { -+ BlockPos posAdj = pos.offset(ChestBlock.getConnectedDirection(blockState).getNormal()); -+ // The method in World now checks that the caller is from the same thread... -+ blockEntityAdj = world.getChunk(posAdj).getBlockEntity(posAdj); -+ } -+ } -+ -+ if (blockEntityAdj != null) { -+ updateBlockEntity(player, blockEntityAdj); -+ } -+ -+ // The method in World now checks that the caller is from the same thread... -+ BlockEntity blockEntity = world.getChunk(pos).getBlockEntity(pos); -+ if (blockEntity != null) { -+ updateBlockEntity(player, blockEntity); -+ } -+ -+ Pair pair = new ImmutablePair<>(player.level().dimension().location(), pos); -+ lock.lock(); -+ playerWatchBlockPos.put(player, pair); -+ if (!blockPosWatchPlayerSet.containsKey(pair)) { -+ blockPosWatchPlayerSet.put(pair, new HashSet<>()); -+ } -+ blockPosWatchPlayerSet.get(pair).add(player); -+ lock.unlock(); -+ },null,1); -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = SyncEntityPayload.class, payloadId = "sync_entity") -+ private static void syncEntityHandler(ServerPlayer player, SyncEntityPayload payload) { -+ if (!me.earthme.luminol.LuminolConfig.pcaSyncProtocol) { -+ return; -+ } -+ MinecraftServer server = MinecraftServer.getServer(); -+ int entityId = payload.entityId; -+ ServerLevel world = player.serverLevel(); -+ player.getBukkitEntity().getScheduler().execute(MINECRAFT,() -> { -+ Entity entity = world.getEntity(entityId); -+ if (entity != null) { -+ clearPlayerWatchData(player); -+ if (entity instanceof Player) { -+ if (me.earthme.luminol.LuminolConfig.pcaSyncPlayerEntity.equals("NOBODY")) { -+ return; -+ }else if (me.earthme.luminol.LuminolConfig.pcaSyncPlayerEntity.equals("OPS")) { -+ if (server.getProfilePermissions(player.getGameProfile()) < 2) { -+ return; -+ } -+ } else if (me.earthme.luminol.LuminolConfig.pcaSyncPlayerEntity.equals("OPS_AND_SELF")) { -+ if (server.getProfilePermissions(player.getGameProfile()) < 2 && -+ entity != player) { -+ return; -+ } -+ } else if (!me.earthme.luminol.LuminolConfig.pcaSyncPlayerEntity.equals("EVERYONE")) { -+ // wtf???? -+ LogManager.getLogger().warn("pcaSyncPlayerEntity wtf???"); -+ return; -+ } -+ } -+ updateEntity(player, entity); -+ -+ Pair pair = new ImmutablePair<>(entity.level().dimension().location(), entity); -+ lock.lock(); -+ playerWatchEntity.put(player, pair); -+ if (!entityWatchPlayerSet.containsKey(pair)) { -+ entityWatchPlayerSet.put(pair, new HashSet<>()); -+ } -+ entityWatchPlayerSet.get(pair).add(player); -+ lock.unlock(); -+ } -+ },null,1); -+ } -+ -+ public static void enablePcaSyncProtocol(@NotNull ServerPlayer player) { -+ ProtocolUtils.sendEmptyPayloadPacket(player, ENABLE_PCA_SYNC_PROTOCOL); -+ } -+ -+ public static void disablePcaSyncProtocol(@NotNull ServerPlayer player) { -+ ProtocolUtils.sendEmptyPayloadPacket(player, DISABLE_PCA_SYNC_PROTOCOL); -+ } -+ -+ public static void updateEntity(@NotNull ServerPlayer player, @NotNull Entity entity) { -+ CompoundTag nbt = entity.saveWithoutId(new CompoundTag()); -+ ProtocolUtils.sendPayloadPacket(player, UPDATE_ENTITY, buf -> { -+ buf.writeResourceLocation(entity.level().dimension().location()); -+ buf.writeInt(entity.getId()); -+ buf.writeNbt(nbt); -+ }); -+ } -+ -+ public static void updateBlockEntity(@NotNull ServerPlayer player, @NotNull BlockEntity blockEntity) { -+ Level world = blockEntity.getLevel(); -+ -+ if (world == null) { -+ return; -+ } -+ -+ ProtocolUtils.sendPayloadPacket(player, UPDATE_BLOCK_ENTITY, buf -> { -+ buf.writeResourceLocation(world.dimension().location()); -+ buf.writeBlockPos(blockEntity.getBlockPos()); -+ buf.writeNbt(blockEntity.saveWithId()); -+ }); -+ } -+ -+ private static MutablePair getResourceLocationEntityPair(ResourceLocation ResourceLocation, Entity entity) { -+ pairLock.lock(); -+ ResourceLocationEntityPair.setLeft(ResourceLocation); -+ ResourceLocationEntityPair.setRight(entity); -+ pairLock.unlock(); -+ return ResourceLocationEntityPair; -+ } -+ -+ private static MutablePair getResourceLocationBlockPosPair(ResourceLocation ResourceLocation, BlockPos pos) { -+ pairLock.lock(); -+ ResourceLocationBlockPosPair.setLeft(ResourceLocation); -+ ResourceLocationBlockPosPair.setRight(pos); -+ pairLock.unlock(); -+ return ResourceLocationBlockPosPair; -+ } -+ -+ private static @Nullable Set getWatchPlayerList(@NotNull Entity entity) { -+ return entityWatchPlayerSet.get(getResourceLocationEntityPair(entity.level().dimension().location(), entity)); -+ } -+ -+ private static @Nullable Set getWatchPlayerList(@NotNull Level world, @NotNull BlockPos blockPos) { -+ return blockPosWatchPlayerSet.get(getResourceLocationBlockPosPair(world.dimension().location(), blockPos)); -+ } -+ -+ public static boolean syncEntityToClient(@NotNull Entity entity) { -+ if (entity.level().isClientSide()) { -+ return false; -+ } -+ lock.lock(); -+ Set playerList = getWatchPlayerList(entity); -+ boolean ret = false; -+ if (playerList != null) { -+ for (ServerPlayer player : playerList) { -+ updateEntity(player, entity); -+ ret = true; -+ } -+ } -+ lock.unlock(); -+ return ret; -+ } -+ -+ public static boolean syncBlockEntityToClient(@NotNull BlockEntity blockEntity) { -+ boolean ret = false; -+ Level world = blockEntity.getLevel(); -+ BlockPos pos = blockEntity.getBlockPos(); -+ if (world != null) { -+ if (world.isClientSide()) { -+ return false; -+ } -+ BlockState blockState = world.getBlockState(pos); -+ lock.lock(); -+ Set playerList = getWatchPlayerList(world, blockEntity.getBlockPos()); -+ -+ Set playerListAdj = null; -+ -+ if (blockState.getBlock() instanceof ChestBlock) { -+ if (blockState.getValue(ChestBlock.TYPE) != ChestType.SINGLE) { -+ BlockPos posAdj = pos.offset(ChestBlock.getConnectedDirection(blockState).getNormal()); -+ playerListAdj = getWatchPlayerList(world, posAdj); -+ } -+ } -+ if (playerListAdj != null) { -+ if (playerList == null) { -+ playerList = playerListAdj; -+ } else { -+ playerList.addAll(playerListAdj); -+ } -+ } -+ -+ if (playerList != null) { -+ for (ServerPlayer player : playerList) { -+ updateBlockEntity(player, blockEntity); -+ ret = true; -+ } -+ } -+ lock.unlock(); -+ } -+ return ret; -+ } -+ -+ private static void clearPlayerWatchEntity(ServerPlayer player) { -+ lock.lock(); -+ Pair pair = playerWatchEntity.get(player); -+ if (pair != null) { -+ Set playerSet = entityWatchPlayerSet.get(pair); -+ playerSet.remove(player); -+ if (playerSet.isEmpty()) { -+ entityWatchPlayerSet.remove(pair); -+ } -+ playerWatchEntity.remove(player); -+ } -+ lock.unlock(); -+ } -+ -+ private static void clearPlayerWatchBlock(ServerPlayer player) { -+ lock.lock(); -+ Pair pair = playerWatchBlockPos.get(player); -+ if (pair != null) { -+ Set playerSet = blockPosWatchPlayerSet.get(pair); -+ playerSet.remove(player); -+ if (playerSet.isEmpty()) { -+ blockPosWatchPlayerSet.remove(pair); -+ } -+ playerWatchBlockPos.remove(player); -+ } -+ lock.unlock(); -+ } -+ -+ public static void disablePcaSyncProtocolGlobal() { -+ lock.lock(); -+ playerWatchBlockPos.clear(); -+ playerWatchEntity.clear(); -+ blockPosWatchPlayerSet.clear(); -+ entityWatchPlayerSet.clear(); -+ lock.unlock(); -+ for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) { -+ disablePcaSyncProtocol(player); -+ } -+ } -+ -+ public static void enablePcaSyncProtocolGlobal() { -+ for (ServerPlayer player : MinecraftServer.getServer().getPlayerList().getPlayers()) { -+ enablePcaSyncProtocol(player); -+ } -+ } -+ -+ -+ public static void clearPlayerWatchData(ServerPlayer player) { -+ PcaSyncProtocol.clearPlayerWatchBlock(player); -+ PcaSyncProtocol.clearPlayerWatchEntity(player); -+ } -+ -+ public record SyncBlockEntityPayload(BlockPos pos) implements CustomPacketPayload { -+ -+ public static final ResourceLocation SYNC_BLOCK_ENTITY = PcaSyncProtocol.id("sync_block_entity"); -+ -+ public SyncBlockEntityPayload(ResourceLocation id, FriendlyByteBuf buf) { -+ this(buf.readBlockPos()); -+ } -+ -+ @Override -+ public void write(FriendlyByteBuf buf) { -+ buf.writeBlockPos(pos); -+ } -+ -+ @Override -+ public @NotNull ResourceLocation id() { -+ return SYNC_BLOCK_ENTITY; -+ } -+ } -+ -+ public record SyncEntityPayload(int entityId) implements CustomPacketPayload { -+ -+ public static final ResourceLocation SYNC_ENTITY = PcaSyncProtocol.id("sync_entity"); -+ -+ public SyncEntityPayload(ResourceLocation id, FriendlyByteBuf buf) { -+ this(buf.readInt()); -+ } -+ -+ @Override -+ public void write(FriendlyByteBuf buf) { -+ buf.writeInt(entityId); -+ } -+ -+ @Override -+ public @NotNull ResourceLocation id() { -+ return SYNC_ENTITY; -+ } -+ } -+} diff --git a/patches/server/0053-Gale-Use-platform-math-functions.patch b/patches/server/0042-Gale-Use-platform-math-functions.patch similarity index 100% rename from patches/server/0053-Gale-Use-platform-math-functions.patch rename to patches/server/0042-Gale-Use-platform-math-functions.patch diff --git a/patches/server/0042-Leaves-Bladeren-protocol.patch b/patches/server/0042-Leaves-Bladeren-protocol.patch deleted file mode 100644 index 995ebaf..0000000 --- a/patches/server/0042-Leaves-Bladeren-protocol.patch +++ /dev/null @@ -1,183 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 04:06:41 +0000 -Subject: [PATCH] Leaves Bladeren protocol - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index da818a35faf396e94192ee9ef18c2e5aaef5077a..63984447d9a6a00a6dc6f0dc1056c8c87b8e110f 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -65,6 +65,7 @@ public class LuminolConfig { - - public static boolean pcaSyncProtocol = false; - public static String pcaSyncPlayerEntity = "NOBODY"; -+ public static boolean bladerenLeavesProtocol = false; - - - public static void init() throws IOException { -@@ -195,6 +196,7 @@ public class LuminolConfig { - - pcaSyncProtocol = get("gameplay.enable_pca_sync_protocol",pcaSyncProtocol); - pcaSyncPlayerEntity = get("gameplay.pca_sync_player_entity",pcaSyncPlayerEntity,"Available values: NOBODY,EVERYBODY,OPS,OPS_AND_SELF"); -+ bladerenLeavesProtocol = get("gameplay.bladeren_leaves_protocol",bladerenLeavesProtocol); - } - - public static T get(String key,T def){ -diff --git a/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cf344ad5e928f1bf23953d7b25c4636734da69e6 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java -@@ -0,0 +1,151 @@ -+package top.leavesmc.leaves.protocol.bladeren; -+ -+import com.google.common.collect.Maps; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.protocol.common.custom.CustomPacketPayload; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+import me.earthme.luminol.LuminolConfig; -+import top.leavesmc.leaves.protocol.core.LeavesProtocol; -+import top.leavesmc.leaves.protocol.core.ProtocolHandler; -+import top.leavesmc.leaves.protocol.core.ProtocolUtils; -+ -+import java.util.HashMap; -+import java.util.Map; -+import java.util.function.BiConsumer; -+ -+@LeavesProtocol(namespace = "bladeren") -+public class BladerenProtocol { -+ -+ public static final String PROTOCOL_ID = "bladeren"; -+ public static final String PROTOCOL_VERSION = "1.0.0"; -+ -+ private static final ResourceLocation HELLO_ID = id("hello"); -+ private static final ResourceLocation FEATURE_MODIFY_ID = id("feature_modify"); -+ -+ private static final Map> registeredFeatures = Maps.newConcurrentMap(); -+ -+ @Contract("_ -> new") -+ public static @NotNull ResourceLocation id(String path) { -+ return new ResourceLocation(PROTOCOL_ID, path); -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = BladerenHelloPayload.class, payloadId = "hello") -+ private static void handleHello(@NotNull ServerPlayer player, @NotNull BladerenHelloPayload payload) { -+ if (LuminolConfig.bladerenLeavesProtocol) { -+ String clientVersion = payload.version; -+ CompoundTag tag = payload.nbt; -+ -+ if (tag != null) { -+ CompoundTag featureNbt = tag.getCompound("Features"); -+ for (String name : featureNbt.getAllKeys()) { -+ -+ final BiConsumer target = registeredFeatures.get(name); -+ -+ if (target != null){ -+ target.accept(player, featureNbt.getCompound(name)); -+ } -+ } -+ } -+ } -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = BladerenFeatureModifyPayload.class, payloadId = "feature_modify") -+ private static void handleModify(@NotNull ServerPlayer player, @NotNull BladerenFeatureModifyPayload payload) { -+ if (LuminolConfig.bladerenLeavesProtocol) { -+ String name = payload.name; -+ CompoundTag tag = payload.nbt; -+ -+ final BiConsumer target = registeredFeatures.get(name); -+ -+ if (target != null){ -+ target.accept(player, tag); -+ } -+ } -+ } -+ -+ @ProtocolHandler.PlayerJoin -+ public static void onPlayerJoin(@NotNull ServerPlayer player) { -+ if (LuminolConfig.bladerenLeavesProtocol) { -+ CompoundTag tag = new CompoundTag(); -+ LeavesFeatureSet.writeNBT(tag); -+ ProtocolUtils.sendPayloadPacket(player, new BladerenHelloPayload(PROTOCOL_VERSION, tag)); -+ } -+ } -+ -+ public static void registerFeature(String name, BiConsumer consumer) { -+ registeredFeatures.put(name, consumer); -+ } -+ -+ public static class LeavesFeatureSet { -+ -+ private static final Map features = new HashMap<>(); -+ -+ public static void writeNBT(@NotNull CompoundTag tag) { -+ CompoundTag featureNbt = new CompoundTag(); -+ features.values().forEach(feature -> feature.writeNBT(featureNbt)); -+ tag.put("Features", featureNbt); -+ } -+ -+ public static void register(LeavesFeature feature) { -+ features.put(feature.name, feature); -+ } -+ } -+ -+ public record LeavesFeature(String name, String value) { -+ -+ @NotNull -+ @Contract("_, _ -> new") -+ public static LeavesFeature of(String name, boolean value) { -+ return new LeavesFeature(name, Boolean.toString(value)); -+ } -+ -+ public void writeNBT(@NotNull CompoundTag rules) { -+ CompoundTag rule = new CompoundTag(); -+ rule.putString("Feature", name); -+ rule.putString("Value", value); -+ rules.put(name, rule); -+ } -+ } -+ -+ public record BladerenFeatureModifyPayload(String name, CompoundTag nbt) implements CustomPacketPayload { -+ -+ public BladerenFeatureModifyPayload(ResourceLocation location, FriendlyByteBuf buf) { -+ this(buf.readUtf(), buf.readNbt()); -+ } -+ -+ @Override -+ public void write(@NotNull FriendlyByteBuf buf) { -+ buf.writeUtf(name); -+ buf.writeNbt(nbt); -+ } -+ -+ @Override -+ @NotNull -+ public ResourceLocation id() { -+ return FEATURE_MODIFY_ID; -+ } -+ } -+ -+ public record BladerenHelloPayload(String version, CompoundTag nbt) implements CustomPacketPayload { -+ -+ public BladerenHelloPayload(ResourceLocation location, @NotNull FriendlyByteBuf buf) { -+ this(buf.readUtf(64), buf.readNbt()); -+ } -+ -+ @Override -+ public void write(@NotNull FriendlyByteBuf buf) { -+ buf.writeUtf(version); -+ buf.writeNbt(nbt); -+ } -+ -+ @Override -+ @NotNull -+ public ResourceLocation id() { -+ return HELLO_ID; -+ } -+ } -+} diff --git a/patches/server/0050-Gale-Skip-entity-move-if-movement-is-zero.patch b/patches/server/0043-Gale-Skip-entity-move-if-movement-is-zero.patch similarity index 86% rename from patches/server/0050-Gale-Skip-entity-move-if-movement-is-zero.patch rename to patches/server/0043-Gale-Skip-entity-move-if-movement-is-zero.patch index fd85540..3d42aa2 100644 --- a/patches/server/0050-Gale-Skip-entity-move-if-movement-is-zero.patch +++ b/patches/server/0043-Gale-Skip-entity-move-if-movement-is-zero.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Gale Skip entity move if movement is zero diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index ea7fe58bd68895dedeed2df1a7f1276d7fe5b70d..2016547a88e5f8c0a7f1913c74b22e04cfa9b089 100644 +index d1f31b991a2a10593fa0ae45d10d7761baffdd75..f7407665c286717456a2525ceea621f6f6db10b7 100644 --- a/src/main/java/net/minecraft/world/entity/Entity.java +++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -319,6 +319,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -318,6 +318,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S public float yRotO; public float xRotO; private AABB bb; @@ -16,7 +16,7 @@ index ea7fe58bd68895dedeed2df1a7f1276d7fe5b70d..2016547a88e5f8c0a7f1913c74b22e04 public boolean onGround; public boolean horizontalCollision; public boolean verticalCollision; -@@ -1090,6 +1091,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -1089,6 +1090,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S //Luminol end public void move(MoverType movementType, Vec3 movement) { @@ -28,7 +28,7 @@ index ea7fe58bd68895dedeed2df1a7f1276d7fe5b70d..2016547a88e5f8c0a7f1913c74b22e04 final Vec3 originalMovement = movement; // Paper - Expose pre-collision velocity // Paper start - detailed watchdog information io.papermc.paper.util.TickThread.ensureTickThread("Cannot move an entity off-main"); -@@ -4924,6 +4930,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S +@@ -4935,6 +4941,11 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S } public final void setBoundingBox(AABB boundingBox) { diff --git a/patches/server/0043-Leaves-Bladeren-mspt-sync-protocol.patch b/patches/server/0043-Leaves-Bladeren-mspt-sync-protocol.patch deleted file mode 100644 index 3ca7e07..0000000 --- a/patches/server/0043-Leaves-Bladeren-mspt-sync-protocol.patch +++ /dev/null @@ -1,126 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 04:08:12 +0000 -Subject: [PATCH] Leaves Bladeren mspt sync protocol - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 63984447d9a6a00a6dc6f0dc1056c8c87b8e110f..6936497ed6d3d54d429e25673e0ce29465538768 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -66,6 +66,9 @@ public class LuminolConfig { - public static boolean pcaSyncProtocol = false; - public static String pcaSyncPlayerEntity = "NOBODY"; - public static boolean bladerenLeavesProtocol = false; -+ public static boolean msptSyncProtocol = false; -+ public static int msptSyncTickInterval = 20; -+ - - - public static void init() throws IOException { -@@ -197,6 +200,8 @@ public class LuminolConfig { - pcaSyncProtocol = get("gameplay.enable_pca_sync_protocol",pcaSyncProtocol); - pcaSyncPlayerEntity = get("gameplay.pca_sync_player_entity",pcaSyncPlayerEntity,"Available values: NOBODY,EVERYBODY,OPS,OPS_AND_SELF"); - bladerenLeavesProtocol = get("gameplay.bladeren_leaves_protocol",bladerenLeavesProtocol); -+ msptSyncProtocol = get("gameplay.bladeren_mspt_sync_protocol",bladerenLeavesProtocol); -+ msptSyncTickInterval = get("gameplay.bladeren_mspt_sync_interval",msptSyncTickInterval); - } - - public static T get(String key,T def){ -diff --git a/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..de92ebdf9d51a4f9a58a7650b09f070e51710ef0 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java -@@ -0,0 +1,91 @@ -+package top.leavesmc.leaves.protocol.bladeren; -+ -+import io.papermc.paper.threadedregions.ThreadedRegionizer; -+import io.papermc.paper.threadedregions.TickData; -+import io.papermc.paper.threadedregions.TickRegions; -+import it.unimi.dsi.fastutil.objects.ObjectArrayList; -+import it.unimi.dsi.fastutil.objects.ObjectLists; -+import me.earthme.luminol.LuminolConfig; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.core.LeavesProtocol; -+import top.leavesmc.leaves.protocol.core.ProtocolHandler; -+import top.leavesmc.leaves.protocol.core.ProtocolUtils; -+ -+import java.util.List; -+ -+@LeavesProtocol(namespace = "bladeren") -+public class MsptSyncProtocol { -+ -+ public static final String PROTOCOL_ID = "bladeren"; -+ -+ private static final ResourceLocation MSPT_SYNC = id("mspt_sync"); -+ -+ private static final List players = ObjectLists.synchronize(new ObjectArrayList<>()); -+ -+ private static int tickCounter = 0; -+ -+ @Contract("_ -> new") -+ public static @NotNull ResourceLocation id(String path) { -+ return new ResourceLocation(PROTOCOL_ID, path); -+ } -+ -+ @ProtocolHandler.Init -+ public static void init() { -+ BladerenProtocol.registerFeature("mspt_sync", (player, compoundTag) -> { -+ if (compoundTag.getString("Value").equals("true")) { -+ onPlayerSubmit(player); -+ } else { -+ onPlayerLoggedOut(player); -+ } -+ }); -+ } -+ -+ @ProtocolHandler.PlayerLeave -+ public static void onPlayerLoggedOut(@NotNull ServerPlayer player) { -+ if (LuminolConfig.msptSyncProtocol) { -+ players.remove(player); -+ } -+ } -+ -+ @ProtocolHandler.Ticker -+ public static void tick() { -+ if (LuminolConfig.msptSyncProtocol) { -+ if (players.isEmpty()) { -+ return; -+ } -+ -+ if (tickCounter++ % LuminolConfig.msptSyncTickInterval == 0) { -+ for (ServerPlayer player : players){ -+ final ThreadedRegionizer.ThreadedRegion region = ((ServerLevel) player.level()).regioniser.getRegionAtUnsynchronised(player.sectionX,player.sectionZ); -+ -+ if (region == null){ -+ continue; -+ } -+ -+ final TickData.TickReportData reportData = region.getData().getRegionSchedulingHandle().getTickReport5s(System.nanoTime()); -+ -+ if (reportData != null){ -+ final TickData.SegmentData tpsData = reportData.tpsData().segmentAll(); -+ final double mspt = reportData.timePerTickData().segmentAll().average() / 1.0E6; -+ final double tps = tpsData.average(); -+ -+ ProtocolUtils.sendPayloadPacket(player, MSPT_SYNC, buf -> { -+ buf.writeDouble(mspt); -+ buf.writeDouble(tps); -+ }); -+ } -+ } -+ } -+ } -+ } -+ -+ public static void onPlayerSubmit(@NotNull ServerPlayer player) { -+ if (LuminolConfig.msptSyncProtocol) { -+ players.add(player); -+ } -+ } -+} diff --git a/patches/server/0044-Leaves-Syncmatica-Protocol.patch b/patches/server/0044-Leaves-Syncmatica-Protocol.patch deleted file mode 100644 index 75fe67a..0000000 --- a/patches/server/0044-Leaves-Syncmatica-Protocol.patch +++ /dev/null @@ -1,2044 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 04:08:50 +0000 -Subject: [PATCH] Leaves Syncmatica Protocol - - -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 6936497ed6d3d54d429e25673e0ce29465538768..ec372d91ed60534ecbe0d2b28ba3b9abda800683 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -68,6 +68,9 @@ public class LuminolConfig { - public static boolean bladerenLeavesProtocol = false; - public static boolean msptSyncProtocol = false; - public static int msptSyncTickInterval = 20; -+ public static boolean syncmaticaProtocol = false; -+ public static boolean syncmaticaQuota = false; -+ public static int syncmaticaQuotaLimit = 32767; - - - -@@ -202,6 +205,9 @@ public class LuminolConfig { - bladerenLeavesProtocol = get("gameplay.bladeren_leaves_protocol",bladerenLeavesProtocol); - msptSyncProtocol = get("gameplay.bladeren_mspt_sync_protocol",bladerenLeavesProtocol); - msptSyncTickInterval = get("gameplay.bladeren_mspt_sync_interval",msptSyncTickInterval); -+ syncmaticaProtocol = get("gameplay.syncmatica_protocol",syncmaticaProtocol); -+ syncmaticaQuota = get("gameplay.syncmatica_protocol_quota",syncmaticaQuota); -+ syncmaticaQuotaLimit = get("gameplay.syncmatica_protocol_quota_limit",syncmaticaQuotaLimit); - } - - public static T get(String key,T def){ -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 095134bb3c07ad8daeaf4b28076d60b96b481458..7dbd4dad666a0d43e9116f4e3d56faaec427112b 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -306,6 +306,7 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - Objects.requireNonNull(server); - this.signedMessageDecoder = SignedMessageChain.Decoder.unsigned(uuid, server::enforceSecureProfile); - this.chatMessageChain = new FutureChain(server.chatExecutor); // CraftBukkit - async chat -+ this.exchangeTarget = new top.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget(this); // Leaves - Syncmatica Protocol - } - - // CraftBukkit start - add fields -@@ -331,6 +332,8 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - public final Long disconnectTicketId = Long.valueOf(DISCONNECT_TICKET_ID_GENERATOR.getAndIncrement()); - // Folia end - region threading - -+ public final top.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget exchangeTarget; // Leaves - Syncmatica Protocol -+ - @Override - public void tick() { - // Folia start - region threading -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..fc229f23076147304754a267bcc345cc836b648b ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -@@ -0,0 +1,391 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.mojang.authlib.GameProfile; -+import io.netty.buffer.Unpooled; -+import net.minecraft.core.BlockPos; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.chat.Component; -+import net.minecraft.network.protocol.common.ServerboundCustomPayloadPacket; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.network.ServerGamePacketListenerImpl; -+import net.minecraft.world.level.block.Mirror; -+import net.minecraft.world.level.block.Rotation; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.core.LeavesProtocol; -+import top.leavesmc.leaves.protocol.core.LeavesProtocolManager; -+import top.leavesmc.leaves.protocol.core.ProtocolHandler; -+import top.leavesmc.leaves.protocol.syncmatica.exchange.DownloadExchange; -+import top.leavesmc.leaves.protocol.syncmatica.exchange.Exchange; -+import top.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget; -+import top.leavesmc.leaves.protocol.syncmatica.exchange.ModifyExchangeServer; -+import top.leavesmc.leaves.protocol.syncmatica.exchange.UploadExchange; -+import top.leavesmc.leaves.protocol.syncmatica.exchange.VersionHandshakeServer; -+ -+import java.io.File; -+import java.io.FileNotFoundException; -+import java.io.IOException; -+import java.security.NoSuchAlgorithmException; -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+import java.util.UUID; -+ -+@LeavesProtocol(namespace = "syncmatica") -+public class CommunicationManager { -+ -+ private static final Map> downloadingFile = new HashMap<>(); -+ private static final Map playerMap = new HashMap<>(); -+ -+ protected static final Collection broadcastTargets = new ArrayList<>(); -+ -+ protected static final Map downloadState = new HashMap<>(); -+ protected static final Map modifyState = new HashMap<>(); -+ -+ protected static final Rotation[] rotOrdinals = Rotation.values(); -+ protected static final Mirror[] mirOrdinals = Mirror.values(); -+ -+ public CommunicationManager() { -+ } -+ -+ public static GameProfile getGameProfile(final ExchangeTarget exchangeTarget) { -+ return playerMap.get(exchangeTarget).getGameProfile(); -+ } -+ -+ public void sendMessage(final @NotNull ExchangeTarget client, final MessageType type, final String identifier) { -+ if (client.getFeatureSet().hasFeature(Feature.MESSAGE)) { -+ final FriendlyByteBuf newPacketBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ newPacketBuf.writeUtf(type.toString()); -+ newPacketBuf.writeUtf(identifier); -+ client.sendPacket(PacketType.MESSAGE.identifier, newPacketBuf); -+ } else if (playerMap.containsKey(client)) { -+ final ServerPlayer player = playerMap.get(client); -+ player.sendSystemMessage(Component.literal("Syncmatica " + type.toString() + " " + identifier)); -+ } -+ } -+ -+ @ProtocolHandler.PlayerJoin -+ public static void onPlayerJoin(ServerPlayer player) { -+ final ExchangeTarget newPlayer = player.connection.exchangeTarget; -+ final VersionHandshakeServer hi = new VersionHandshakeServer(newPlayer); -+ playerMap.put(newPlayer, player); -+ final GameProfile profile = player.getGameProfile(); -+ SyncmaticaProtocol.getPlayerIdentifierProvider().updateName(profile.getId(), profile.getName()); -+ startExchangeUnchecked(hi); -+ } -+ -+ @ProtocolHandler.PlayerLeave -+ public static void onPlayerLeave(ServerPlayer player) { -+ final ExchangeTarget oldPlayer = player.connection.exchangeTarget; -+ final Collection potentialMessageTarget = oldPlayer.getExchanges(); -+ if (potentialMessageTarget != null) { -+ for (final Exchange target : potentialMessageTarget) { -+ target.close(false); -+ handleExchange(target); -+ } -+ } -+ broadcastTargets.remove(oldPlayer); -+ playerMap.remove(oldPlayer); -+ } -+ -+ @ProtocolHandler.PayloadReceiver(payload = LeavesProtocolManager.LeavesPayload.class, ignoreId = true) -+ public static void onPacketGet(ServerPlayer player, LeavesProtocolManager.LeavesPayload payload) { -+ onPacket(player.connection.exchangeTarget, payload.id(), payload.data()); -+ } -+ -+ public static void onPacket(final @NotNull ExchangeTarget source, final ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ Exchange handler = null; -+ final Collection potentialMessageTarget = source.getExchanges(); -+ if (potentialMessageTarget != null) { -+ for (final Exchange target : potentialMessageTarget) { -+ if (target.checkPacket(id, packetBuf)) { -+ target.handle(id, packetBuf); -+ handler = target; -+ break; -+ } -+ } -+ } -+ if (handler == null) { -+ handle(source, id, packetBuf); -+ } else if (handler.isFinished()) { -+ notifyClose(handler); -+ } -+ } -+ -+ protected static void handle(ExchangeTarget source, @NotNull ResourceLocation id, FriendlyByteBuf packetBuf) { -+ if (id.equals(PacketType.REQUEST_LITEMATIC.identifier)) { -+ final UUID syncmaticaId = packetBuf.readUUID(); -+ final ServerPlacement placement = SyncmaticaProtocol.getSyncmaticManager().getPlacement(syncmaticaId); -+ if (placement == null) { -+ return; -+ } -+ final File toUpload = SyncmaticaProtocol.getFileStorage().getLocalLitematic(placement); -+ final UploadExchange upload; -+ try { -+ upload = new UploadExchange(placement, toUpload, source); -+ } catch (final FileNotFoundException e) { -+ e.printStackTrace(); -+ return; -+ } -+ startExchange(upload); -+ return; -+ } -+ if (id.equals(PacketType.REGISTER_METADATA.identifier)) { -+ final ServerPlacement placement = receiveMetaData(packetBuf, source); -+ if (SyncmaticaProtocol.getSyncmaticManager().getPlacement(placement.getId()) != null) { -+ cancelShare(source, placement); -+ return; -+ } -+ -+ final GameProfile profile = playerMap.get(source).getGameProfile(); -+ final PlayerIdentifier playerIdentifier = SyncmaticaProtocol.getPlayerIdentifierProvider().createOrGet(profile); -+ if (!placement.getOwner().equals(playerIdentifier)) { -+ placement.setOwner(playerIdentifier); -+ placement.setLastModifiedBy(playerIdentifier); -+ } -+ -+ if (!SyncmaticaProtocol.getFileStorage().getLocalState(placement).isLocalFileReady()) { -+ if (SyncmaticaProtocol.getFileStorage().getLocalState(placement) == LocalLitematicState.DOWNLOADING_LITEMATIC) { -+ downloadingFile.computeIfAbsent(placement.getHash(), key -> new ArrayList<>()).add(placement); -+ return; -+ } -+ try { -+ download(placement, source); -+ } catch (final Exception e) { -+ e.printStackTrace(); -+ } -+ return; -+ } -+ -+ addPlacement(source, placement); -+ return; -+ } -+ if (id.equals(PacketType.REMOVE_SYNCMATIC.identifier)) { -+ final UUID placementId = packetBuf.readUUID(); -+ final ServerPlacement placement = SyncmaticaProtocol.getSyncmaticManager().getPlacement(placementId); -+ if (placement != null) { -+ if (!getGameProfile(source).getId().equals(placement.getOwner().uuid)) { -+ return; -+ } -+ -+ final Exchange modifier = getModifier(placement); -+ if (modifier != null) { -+ modifier.close(true); -+ notifyClose(modifier); -+ } -+ SyncmaticaProtocol.getSyncmaticManager().removePlacement(placement); -+ for (final ExchangeTarget client : broadcastTargets) { -+ final FriendlyByteBuf newPacketBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ newPacketBuf.writeUUID(placement.getId()); -+ client.sendPacket(PacketType.REMOVE_SYNCMATIC.identifier, newPacketBuf); -+ } -+ } -+ } -+ if (id.equals(PacketType.MODIFY_REQUEST.identifier)) { -+ final UUID placementId = packetBuf.readUUID(); -+ final ModifyExchangeServer modifier = new ModifyExchangeServer(placementId, source); -+ startExchange(modifier); -+ } -+ } -+ -+ protected static void handleExchange(Exchange exchange) { -+ if (exchange instanceof DownloadExchange) { -+ final ServerPlacement p = ((DownloadExchange) exchange).getPlacement(); -+ -+ if (exchange.isSuccessful()) { -+ addPlacement(exchange.getPartner(), p); -+ if (downloadingFile.containsKey(p.getHash())) { -+ for (final ServerPlacement placement : downloadingFile.get(p.getHash())) { -+ addPlacement(exchange.getPartner(), placement); -+ } -+ } -+ } else { -+ cancelShare(exchange.getPartner(), p); -+ if (downloadingFile.containsKey(p.getHash())) { -+ for (final ServerPlacement placement : downloadingFile.get(p.getHash())) { -+ cancelShare(exchange.getPartner(), placement); -+ } -+ } -+ } -+ -+ downloadingFile.remove(p.getHash()); -+ return; -+ } -+ if (exchange instanceof VersionHandshakeServer && exchange.isSuccessful()) { -+ broadcastTargets.add(exchange.getPartner()); -+ } -+ if (exchange instanceof ModifyExchangeServer && exchange.isSuccessful()) { -+ final ServerPlacement placement = ((ModifyExchangeServer) exchange).getPlacement(); -+ for (final ExchangeTarget client : broadcastTargets) { -+ if (client.getFeatureSet().hasFeature(Feature.MODIFY)) { -+ final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); -+ buf.writeUUID(placement.getId()); -+ putPositionData(placement, buf, client); -+ if (client.getFeatureSet().hasFeature(Feature.CORE_EX)) { -+ buf.writeUUID(placement.getLastModifiedBy().uuid); -+ buf.writeUtf(placement.getLastModifiedBy().getName()); -+ } -+ client.sendPacket(PacketType.MODIFY.identifier, buf); -+ } else { -+ final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); -+ buf.writeUUID(placement.getId()); -+ client.sendPacket(PacketType.REMOVE_SYNCMATIC.identifier, buf); -+ final FriendlyByteBuf buf2 = new FriendlyByteBuf(Unpooled.buffer()); -+ putMetaData(placement, buf2, client); -+ client.sendPacket(PacketType.REGISTER_METADATA.identifier, buf2); -+ } -+ } -+ } -+ } -+ -+ private static void addPlacement(final ExchangeTarget t, final @NotNull ServerPlacement placement) { -+ if (SyncmaticaProtocol.getSyncmaticManager().getPlacement(placement.getId()) != null) { -+ cancelShare(t, placement); -+ return; -+ } -+ SyncmaticaProtocol.getSyncmaticManager().addPlacement(placement); -+ for (final ExchangeTarget target : broadcastTargets) { -+ sendMetaData(placement, target); -+ } -+ } -+ -+ private static void cancelShare(final @NotNull ExchangeTarget source, final @NotNull ServerPlacement placement) { -+ final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ FriendlyByteBuf.writeUUID(placement.getId()); -+ source.sendPacket(PacketType.CANCEL_SHARE.identifier, FriendlyByteBuf); -+ } -+ -+ public static void sendMetaData(final ServerPlacement metaData, final ExchangeTarget target) { -+ final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); -+ putMetaData(metaData, buf, target); -+ target.sendPacket(PacketType.REGISTER_METADATA.identifier, buf); -+ } -+ -+ public static void putMetaData(final @NotNull ServerPlacement metaData, final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { -+ buf.writeUUID(metaData.getId()); -+ -+ buf.writeUtf(SyncmaticaProtocol.sanitizeFileName(metaData.getName())); -+ buf.writeUUID(metaData.getHash()); -+ -+ if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { -+ buf.writeUUID(metaData.getOwner().uuid); -+ buf.writeUtf(metaData.getOwner().getName()); -+ buf.writeUUID(metaData.getLastModifiedBy().uuid); -+ buf.writeUtf(metaData.getLastModifiedBy().getName()); -+ } -+ -+ putPositionData(metaData, buf, exchangeTarget); -+ } -+ -+ public static void putPositionData(final @NotNull ServerPlacement metaData, final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { -+ buf.writeBlockPos(metaData.getPosition()); -+ buf.writeUtf(metaData.getDimension()); -+ buf.writeInt(metaData.getRotation().ordinal()); -+ buf.writeInt(metaData.getMirror().ordinal()); -+ -+ if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { -+ if (metaData.getSubRegionData().getModificationData() == null) { -+ buf.writeInt(0); -+ return; -+ } -+ -+ final Collection regionData = metaData.getSubRegionData().getModificationData().values(); -+ buf.writeInt(regionData.size()); -+ -+ for (final SubRegionPlacementModification subPlacement : regionData) { -+ buf.writeUtf(subPlacement.name); -+ buf.writeBlockPos(subPlacement.position); -+ buf.writeInt(subPlacement.rotation.ordinal()); -+ buf.writeInt(subPlacement.mirror.ordinal()); -+ } -+ } -+ } -+ -+ public static ServerPlacement receiveMetaData(final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { -+ final UUID id = buf.readUUID(); -+ -+ final String fileName = SyncmaticaProtocol.sanitizeFileName(buf.readUtf(32767)); -+ final UUID hash = buf.readUUID(); -+ -+ PlayerIdentifier owner = PlayerIdentifier.MISSING_PLAYER; -+ PlayerIdentifier lastModifiedBy = PlayerIdentifier.MISSING_PLAYER; -+ -+ if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { -+ final PlayerIdentifierProvider provider = SyncmaticaProtocol.getPlayerIdentifierProvider(); -+ owner = provider.createOrGet(buf.readUUID(), buf.readUtf(32767)); -+ lastModifiedBy = provider.createOrGet(buf.readUUID(), buf.readUtf(32767)); -+ } -+ -+ final ServerPlacement placement = new ServerPlacement(id, fileName, hash, owner); -+ placement.setLastModifiedBy(lastModifiedBy); -+ -+ receivePositionData(placement, buf, exchangeTarget); -+ -+ return placement; -+ } -+ -+ public static void receivePositionData(final @NotNull ServerPlacement placement, final @NotNull FriendlyByteBuf buf, final @NotNull ExchangeTarget exchangeTarget) { -+ final BlockPos pos = buf.readBlockPos(); -+ final String dimensionId = buf.readUtf(32767); -+ final Rotation rot = rotOrdinals[buf.readInt()]; -+ final Mirror mir = mirOrdinals[buf.readInt()]; -+ placement.move(dimensionId, pos, rot, mir); -+ -+ if (exchangeTarget.getFeatureSet().hasFeature(Feature.CORE_EX)) { -+ final SubRegionData subRegionData = placement.getSubRegionData(); -+ subRegionData.reset(); -+ final int limit = buf.readInt(); -+ for (int i = 0; i < limit; i++) { -+ subRegionData.modify(buf.readUtf(32767), buf.readBlockPos(), rotOrdinals[buf.readInt()], mirOrdinals[buf.readInt()]); -+ } -+ } -+ } -+ -+ public static void download(final ServerPlacement syncmatic, final ExchangeTarget source) throws NoSuchAlgorithmException, IOException { -+ if (!SyncmaticaProtocol.getFileStorage().getLocalState(syncmatic).isReadyForDownload()) { -+ throw new IllegalArgumentException(syncmatic.toString() + " is not ready for download local state is: " + SyncmaticaProtocol.getFileStorage().getLocalState(syncmatic).toString()); -+ } -+ final File toDownload = SyncmaticaProtocol.getFileStorage().createLocalLitematic(syncmatic); -+ final Exchange downloadExchange = new DownloadExchange(syncmatic, toDownload, source); -+ setDownloadState(syncmatic, true); -+ startExchange(downloadExchange); -+ } -+ -+ public static void setDownloadState(final @NotNull ServerPlacement syncmatic, final boolean b) { -+ downloadState.put(syncmatic.getHash(), b); -+ } -+ -+ public static boolean getDownloadState(final @NotNull ServerPlacement syncmatic) { -+ return downloadState.getOrDefault(syncmatic.getHash(), false); -+ } -+ -+ public static void setModifier(final @NotNull ServerPlacement syncmatic, final Exchange exchange) { -+ modifyState.put(syncmatic.getHash(), exchange); -+ } -+ -+ public static Exchange getModifier(final @NotNull ServerPlacement syncmatic) { -+ return modifyState.get(syncmatic.getHash()); -+ } -+ -+ public static void startExchange(final @NotNull Exchange newExchange) { -+ if (!broadcastTargets.contains(newExchange.getPartner())) { -+ throw new IllegalArgumentException(newExchange.getPartner().toString() + " is not a valid ExchangeTarget"); -+ } -+ startExchangeUnchecked(newExchange); -+ } -+ -+ protected static void startExchangeUnchecked(final @NotNull Exchange newExchange) { -+ newExchange.getPartner().getExchanges().add(newExchange); -+ newExchange.init(); -+ if (newExchange.isFinished()) { -+ notifyClose(newExchange); -+ } -+ } -+ -+ public static void notifyClose(final @NotNull Exchange e) { -+ e.getPartner().getExchanges().remove(e); -+ handleExchange(e); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/Feature.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/Feature.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1125755d7d78a118d1fe407e9ca554a89f4d9a9a ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/Feature.java -@@ -0,0 +1,23 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import org.jetbrains.annotations.Nullable; -+ -+public enum Feature { -+ CORE, -+ FEATURE, -+ MODIFY, -+ MESSAGE, -+ QUOTA, -+ DEBUG, -+ CORE_EX; -+ -+ @Nullable -+ public static Feature fromString(final String s) { -+ for (final Feature f : Feature.values()) { -+ if (f.toString().equals(s)) { -+ return f; -+ } -+ } -+ return null; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/FeatureSet.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/FeatureSet.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3d851913e2016fcd384b6a8b1e91753cb8ea91ef ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/FeatureSet.java -@@ -0,0 +1,67 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.Collections; -+import java.util.HashMap; -+import java.util.Map; -+ -+public class FeatureSet { -+ -+ private static final Map versionFeatures; -+ private final Collection features; -+ -+ @Nullable -+ public static FeatureSet fromVersionString(@NotNull String version) { -+ if (version.matches("^\\d+(\\.\\d+){2,4}$")) { -+ final int minSize = version.indexOf("."); -+ while (version.length() > minSize) { -+ if (versionFeatures.containsKey(version)) { -+ return versionFeatures.get(version); -+ } -+ final int lastDot = version.lastIndexOf("."); -+ version = version.substring(0, lastDot); -+ } -+ } -+ return null; -+ } -+ -+ @NotNull -+ public static FeatureSet fromString(final @NotNull String features) { -+ final FeatureSet featureSet = new FeatureSet(new ArrayList<>()); -+ for (final String feature : features.split("\n")) { -+ final Feature f = Feature.fromString(feature); -+ if (f != null) { -+ featureSet.features.add(f); -+ } -+ } -+ return featureSet; -+ } -+ -+ @Override -+ public String toString() { -+ final StringBuilder output = new StringBuilder(); -+ boolean b = false; -+ for (final Feature feature : features) { -+ output.append(b ? "\n" + feature.toString() : feature.toString()); -+ b = true; -+ } -+ return output.toString(); -+ } -+ -+ public FeatureSet(final Collection features) { -+ this.features = features; -+ } -+ -+ public boolean hasFeature(final Feature f) { -+ return features.contains(f); -+ } -+ -+ static { -+ versionFeatures = new HashMap<>(); -+ versionFeatures.put("0.1", new FeatureSet(Collections.singletonList(Feature.CORE))); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/FileStorage.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/FileStorage.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5dccbce7287fe436de9436f35a7d1ffcfc5d74ab ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/FileStorage.java -@@ -0,0 +1,80 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+ -+import java.io.File; -+import java.io.FileInputStream; -+import java.io.IOException; -+import java.util.HashMap; -+import java.util.UUID; -+ -+public class FileStorage { -+ -+ private final HashMap buffer = new HashMap<>(); -+ -+ public LocalLitematicState getLocalState(final ServerPlacement placement) { -+ final File localFile = getSchematicPath(placement); -+ if (localFile.isFile()) { -+ if (isDownloading(placement)) { -+ return LocalLitematicState.DOWNLOADING_LITEMATIC; -+ } -+ if ((buffer.containsKey(placement) && buffer.get(placement) == localFile.lastModified()) || hashCompare(localFile, placement)) { -+ return LocalLitematicState.LOCAL_LITEMATIC_PRESENT; -+ } -+ return LocalLitematicState.LOCAL_LITEMATIC_DESYNC; -+ } -+ return LocalLitematicState.NO_LOCAL_LITEMATIC; -+ } -+ -+ private boolean isDownloading(final ServerPlacement placement) { -+ return SyncmaticaProtocol.getCommunicationManager().getDownloadState(placement); -+ } -+ -+ public File getLocalLitematic(final ServerPlacement placement) { -+ if (getLocalState(placement).isLocalFileReady()) { -+ return getSchematicPath(placement); -+ } else { -+ return null; -+ } -+ } -+ -+ public File createLocalLitematic(final ServerPlacement placement) { -+ if (getLocalState(placement).isLocalFileReady()) { -+ throw new IllegalArgumentException(""); -+ } -+ final File file = getSchematicPath(placement); -+ if (file.exists()) { -+ file.delete(); -+ } -+ try { -+ file.createNewFile(); -+ } catch (final IOException e) { -+ e.printStackTrace(); -+ } -+ return file; -+ } -+ -+ private boolean hashCompare(final File localFile, final ServerPlacement placement) { -+ UUID hash = null; -+ try { -+ hash = SyncmaticaProtocol.createChecksum(new FileInputStream(localFile)); -+ } catch (final Exception e) { -+ e.printStackTrace(); -+ } -+ -+ if (hash == null) { -+ return false; -+ } -+ if (hash.equals(placement.getHash())) { -+ buffer.put(placement, localFile.lastModified()); -+ return true; -+ } -+ return false; -+ } -+ -+ @Contract("_ -> new") -+ private @NotNull File getSchematicPath(final @NotNull ServerPlacement placement) { -+ return new File(SyncmaticaProtocol.getLitematicFolder(), placement.getHash().toString() + ".litematic"); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/LocalLitematicState.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/LocalLitematicState.java -new file mode 100644 -index 0000000000000000000000000000000000000000..82ffc8cbd1b488c8723693b685a91c2a4149fb47 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/LocalLitematicState.java -@@ -0,0 +1,24 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+public enum LocalLitematicState { -+ NO_LOCAL_LITEMATIC(true, false), -+ LOCAL_LITEMATIC_DESYNC(true, false), -+ DOWNLOADING_LITEMATIC(false, false), -+ LOCAL_LITEMATIC_PRESENT(false, true); -+ -+ private final boolean downloadReady; -+ private final boolean fileReady; -+ -+ LocalLitematicState(final boolean downloadReady, final boolean fileReady) { -+ this.downloadReady = downloadReady; -+ this.fileReady = fileReady; -+ } -+ -+ public boolean isReadyForDownload() { -+ return downloadReady; -+ } -+ -+ public boolean isLocalFileReady() { -+ return fileReady; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/MessageType.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/MessageType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..04d785846be3670b741d90634f5f691899127835 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/MessageType.java -@@ -0,0 +1,8 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+public enum MessageType { -+ SUCCESS, -+ INFO, -+ WARNING, -+ ERROR -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PacketType.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PacketType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8f3227d36da0a3055cc25e538437de58fd5730e3 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PacketType.java -@@ -0,0 +1,30 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import net.minecraft.resources.ResourceLocation; -+ -+public enum PacketType { -+ REGISTER_METADATA("register_metadata"), -+ CANCEL_SHARE("cancel_share"), -+ REQUEST_LITEMATIC("request_download"), -+ SEND_LITEMATIC("send_litematic"), -+ RECEIVED_LITEMATIC("received_litematic"), -+ FINISHED_LITEMATIC("finished_litematic"), -+ CANCEL_LITEMATIC("cancel_litematic"), -+ REMOVE_SYNCMATIC("remove_syncmatic"), -+ REGISTER_VERSION("register_version"), -+ CONFIRM_USER("confirm_user"), -+ FEATURE_REQUEST("feature_request"), -+ FEATURE("feature"), -+ MODIFY("modify"), -+ MODIFY_REQUEST("modify_request"), -+ MODIFY_REQUEST_DENY("modify_request_deny"), -+ MODIFY_REQUEST_ACCEPT("modify_request_accept"), -+ MODIFY_FINISH("modify_finish"), -+ MESSAGE("mesage"); -+ -+ public final ResourceLocation identifier; -+ -+ PacketType(final String id) { -+ identifier = new ResourceLocation(SyncmaticaProtocol.PROTOCOL_ID, id); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PlayerIdentifier.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PlayerIdentifier.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f9ba2a41ab1e0d50bf85fd024b6d29e65b3a5cf7 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PlayerIdentifier.java -@@ -0,0 +1,37 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.google.gson.JsonObject; -+import com.google.gson.JsonPrimitive; -+ -+import java.util.UUID; -+ -+public class PlayerIdentifier { -+ -+ public static final UUID MISSING_PLAYER_UUID = UUID.fromString("4c1b738f-56fa-4011-8273-498c972424ea"); -+ public static final PlayerIdentifier MISSING_PLAYER = new PlayerIdentifier(MISSING_PLAYER_UUID, "No Player"); -+ -+ public final UUID uuid; -+ private String bufferedPlayerName; -+ -+ PlayerIdentifier(final UUID uuid, final String bufferedPlayerName) { -+ this.uuid = uuid; -+ this.bufferedPlayerName = bufferedPlayerName; -+ } -+ -+ public String getName() { -+ return bufferedPlayerName; -+ } -+ -+ public void updatePlayerName(final String name) { -+ bufferedPlayerName = name; -+ } -+ -+ public JsonObject toJson() { -+ final JsonObject jsonObject = new JsonObject(); -+ -+ jsonObject.add("uuid", new JsonPrimitive(uuid.toString())); -+ jsonObject.add("name", new JsonPrimitive(bufferedPlayerName)); -+ -+ return jsonObject; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PlayerIdentifierProvider.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PlayerIdentifierProvider.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f4fc3bac20359ecf17a25d7b8e8f34cfebcf4b24 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/PlayerIdentifierProvider.java -@@ -0,0 +1,46 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.google.gson.JsonObject; -+import com.mojang.authlib.GameProfile; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.syncmatica.exchange.ExchangeTarget; -+ -+import java.util.HashMap; -+import java.util.Map; -+import java.util.UUID; -+ -+public class PlayerIdentifierProvider { -+ -+ private final Map identifiers = new HashMap<>(); -+ -+ public PlayerIdentifierProvider() { -+ identifiers.put(PlayerIdentifier.MISSING_PLAYER_UUID, PlayerIdentifier.MISSING_PLAYER); -+ } -+ -+ public PlayerIdentifier createOrGet(final ExchangeTarget exchangeTarget) { -+ return createOrGet(SyncmaticaProtocol.getCommunicationManager().getGameProfile(exchangeTarget)); -+ } -+ -+ public PlayerIdentifier createOrGet(final @NotNull GameProfile gameProfile) { -+ return createOrGet(gameProfile.getId(), gameProfile.getName()); -+ } -+ -+ public PlayerIdentifier createOrGet(final UUID uuid, final String playerName) { -+ return identifiers.computeIfAbsent(uuid, id -> new PlayerIdentifier(uuid, playerName)); -+ } -+ -+ public void updateName(final UUID uuid, final String playerName) { -+ createOrGet(uuid, playerName).updatePlayerName(playerName); -+ } -+ -+ public PlayerIdentifier fromJson(final @NotNull JsonObject obj) { -+ if (!obj.has("uuid") || !obj.has("name")) { -+ return PlayerIdentifier.MISSING_PLAYER; -+ } -+ -+ final UUID jsonUUID = UUID.fromString(obj.get("uuid").getAsString()); -+ return identifiers.computeIfAbsent(jsonUUID, -+ key -> new PlayerIdentifier(jsonUUID, obj.get("name").getAsString()) -+ ); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/ServerPlacement.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/ServerPlacement.java -new file mode 100644 -index 0000000000000000000000000000000000000000..8c5bc7d6244d6ccd9a561030fff44ccdecc1ed5c ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/ServerPlacement.java -@@ -0,0 +1,166 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.google.gson.JsonObject; -+import com.google.gson.JsonPrimitive; -+import net.minecraft.core.BlockPos; -+import net.minecraft.world.level.block.Mirror; -+import net.minecraft.world.level.block.Rotation; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+import java.util.UUID; -+ -+public class ServerPlacement { -+ -+ private final UUID id; -+ -+ private final String fileName; -+ private final UUID hashValue; -+ -+ private PlayerIdentifier owner; -+ private PlayerIdentifier lastModifiedBy; -+ -+ private ServerPosition origin; -+ private Rotation rotation; -+ private Mirror mirror; -+ -+ private SubRegionData subRegionData = new SubRegionData(); -+ -+ public ServerPlacement(final UUID id, final String fileName, final UUID hashValue, final PlayerIdentifier owner) { -+ this.id = id; -+ this.fileName = fileName; -+ this.hashValue = hashValue; -+ this.owner = owner; -+ lastModifiedBy = owner; -+ } -+ -+ public UUID getId() { -+ return id; -+ } -+ -+ public String getName() { -+ return fileName; -+ } -+ -+ public UUID getHash() { -+ return hashValue; -+ } -+ -+ public String getDimension() { -+ return origin.getDimensionId(); -+ } -+ -+ public BlockPos getPosition() { -+ return origin.getBlockPosition(); -+ } -+ -+ public ServerPosition getOrigin() { -+ return origin; -+ } -+ -+ public Rotation getRotation() { -+ return rotation; -+ } -+ -+ public Mirror getMirror() { -+ return mirror; -+ } -+ -+ public ServerPlacement move(final String dimensionId, final BlockPos origin, final Rotation rotation, final Mirror mirror) { -+ move(new ServerPosition(origin, dimensionId), rotation, mirror); -+ return this; -+ } -+ -+ public ServerPlacement move(final ServerPosition origin, final Rotation rotation, final Mirror mirror) { -+ this.origin = origin; -+ this.rotation = rotation; -+ this.mirror = mirror; -+ return this; -+ } -+ -+ public PlayerIdentifier getOwner() { -+ return owner; -+ } -+ -+ public void setOwner(final PlayerIdentifier playerIdentifier) { -+ owner = playerIdentifier; -+ } -+ -+ public PlayerIdentifier getLastModifiedBy() { -+ return lastModifiedBy; -+ } -+ -+ public void setLastModifiedBy(final PlayerIdentifier lastModifiedBy) { -+ this.lastModifiedBy = lastModifiedBy; -+ } -+ -+ public SubRegionData getSubRegionData() { -+ return subRegionData; -+ } -+ -+ public JsonObject toJson() { -+ final JsonObject obj = new JsonObject(); -+ obj.add("id", new JsonPrimitive(id.toString())); -+ -+ obj.add("file_name", new JsonPrimitive(fileName)); -+ obj.add("hash", new JsonPrimitive(hashValue.toString())); -+ -+ obj.add("origin", origin.toJson()); -+ obj.add("rotation", new JsonPrimitive(rotation.name())); -+ obj.add("mirror", new JsonPrimitive(mirror.name())); -+ -+ obj.add("owner", owner.toJson()); -+ if (!owner.equals(lastModifiedBy)) { -+ obj.add("lastModifiedBy", lastModifiedBy.toJson()); -+ } -+ -+ if (subRegionData.isModified()) { -+ obj.add("subregionData", subRegionData.toJson()); -+ } -+ -+ return obj; -+ } -+ -+ @Nullable -+ public static ServerPlacement fromJson(final @NotNull JsonObject obj) { -+ if (obj.has("id") -+ && obj.has("file_name") -+ && obj.has("hash") -+ && obj.has("origin") -+ && obj.has("rotation") -+ && obj.has("mirror")) { -+ final UUID id = UUID.fromString(obj.get("id").getAsString()); -+ final String name = obj.get("file_name").getAsString(); -+ final UUID hashValue = UUID.fromString(obj.get("hash").getAsString()); -+ -+ PlayerIdentifier owner = PlayerIdentifier.MISSING_PLAYER; -+ if (obj.has("owner")) { -+ owner = SyncmaticaProtocol.getPlayerIdentifierProvider().fromJson(obj.get("owner").getAsJsonObject()); -+ } -+ -+ final ServerPlacement newPlacement = new ServerPlacement(id, name, hashValue, owner); -+ final ServerPosition pos = ServerPosition.fromJson(obj.get("origin").getAsJsonObject()); -+ if (pos == null) { -+ return null; -+ } -+ newPlacement.origin = pos; -+ newPlacement.rotation = Rotation.valueOf(obj.get("rotation").getAsString()); -+ newPlacement.mirror = Mirror.valueOf(obj.get("mirror").getAsString()); -+ -+ if (obj.has("lastModifiedBy")) { -+ newPlacement.lastModifiedBy = SyncmaticaProtocol.getPlayerIdentifierProvider() -+ .fromJson(obj.get("lastModifiedBy").getAsJsonObject()); -+ } else { -+ newPlacement.lastModifiedBy = owner; -+ } -+ -+ if (obj.has("subregionData")) { -+ newPlacement.subRegionData = SubRegionData.fromJson(obj.get("subregionData")); -+ } -+ -+ return newPlacement; -+ } -+ -+ return null; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/ServerPosition.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/ServerPosition.java -new file mode 100644 -index 0000000000000000000000000000000000000000..3f6ee21ce72943e11f8d924321eb286652c5c533 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/ServerPosition.java -@@ -0,0 +1,51 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.google.gson.JsonArray; -+import com.google.gson.JsonObject; -+import com.google.gson.JsonPrimitive; -+import net.minecraft.core.BlockPos; -+ -+public class ServerPosition { -+ -+ private final BlockPos position; -+ private final String dimensionId; -+ -+ public ServerPosition(final BlockPos pos, final String dim) { -+ position = pos; -+ dimensionId = dim; -+ } -+ -+ public BlockPos getBlockPosition() { -+ return position; -+ } -+ -+ public String getDimensionId() { -+ return dimensionId; -+ } -+ -+ public JsonObject toJson() { -+ final JsonObject obj = new JsonObject(); -+ final JsonArray arr = new JsonArray(); -+ arr.add(new JsonPrimitive(position.getX())); -+ arr.add(new JsonPrimitive(position.getY())); -+ arr.add(new JsonPrimitive(position.getZ())); -+ obj.add("position", arr); -+ obj.add("dimension", new JsonPrimitive(dimensionId)); -+ return obj; -+ } -+ -+ public static ServerPosition fromJson(final JsonObject obj) { -+ if (obj.has("position") && obj.has("dimension")) { -+ final int x; -+ final int y; -+ final int z; -+ final JsonArray arr = obj.get("position").getAsJsonArray(); -+ x = arr.get(0).getAsInt(); -+ y = arr.get(1).getAsInt(); -+ z = arr.get(2).getAsInt(); -+ final BlockPos pos = new BlockPos(x, y, z); -+ return new ServerPosition(pos, obj.get("dimension").getAsString()); -+ } -+ return null; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SubRegionData.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SubRegionData.java -new file mode 100644 -index 0000000000000000000000000000000000000000..6903c26742f5e10aa75f52b7abd5273e7116600b ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SubRegionData.java -@@ -0,0 +1,90 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.google.gson.JsonArray; -+import com.google.gson.JsonElement; -+import net.minecraft.core.BlockPos; -+import net.minecraft.world.level.block.Mirror; -+import net.minecraft.world.level.block.Rotation; -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.HashMap; -+import java.util.Map; -+ -+public class SubRegionData { -+ -+ private boolean isModified; -+ private Map modificationData; // is null when isModified is false -+ -+ public SubRegionData() { -+ this(false, null); -+ } -+ -+ public SubRegionData(final boolean isModified, final Map modificationData) { -+ this.isModified = isModified; -+ this.modificationData = modificationData; -+ } -+ -+ public void reset() { -+ isModified = false; -+ modificationData = null; -+ } -+ -+ public void modify(final String name, final BlockPos position, final Rotation rotation, final Mirror mirror) { -+ modify(new SubRegionPlacementModification(name, position, rotation, mirror)); -+ } -+ -+ public void modify(final SubRegionPlacementModification subRegionPlacementModification) { -+ if (subRegionPlacementModification == null) { -+ return; -+ } -+ isModified = true; -+ if (modificationData == null) { -+ modificationData = new HashMap<>(); -+ } -+ modificationData.put(subRegionPlacementModification.name, subRegionPlacementModification); -+ } -+ -+ public boolean isModified() { -+ return isModified; -+ } -+ -+ public Map getModificationData() { -+ return modificationData; -+ } -+ -+ public JsonElement toJson() { -+ return modificationDataToJson(); -+ } -+ -+ @NotNull -+ private JsonElement modificationDataToJson() { -+ final JsonArray arr = new JsonArray(); -+ -+ for (final Map.Entry entry : modificationData.entrySet()) { -+ arr.add(entry.getValue().toJson()); -+ } -+ -+ return arr; -+ } -+ -+ @NotNull -+ public static SubRegionData fromJson(final @NotNull JsonElement obj) { -+ final SubRegionData newSubRegionData = new SubRegionData(); -+ -+ newSubRegionData.isModified = true; -+ -+ for (final JsonElement modification : obj.getAsJsonArray()) { -+ newSubRegionData.modify(SubRegionPlacementModification.fromJson(modification.getAsJsonObject())); -+ } -+ -+ return newSubRegionData; -+ } -+ -+ @Override -+ public String toString() { -+ if (!isModified) { -+ return "[]"; -+ } -+ return modificationData == null ? "[ERROR:null]" : modificationData.toString(); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SubRegionPlacementModification.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SubRegionPlacementModification.java -new file mode 100644 -index 0000000000000000000000000000000000000000..0d67b562ed06f8de990c2f3d545e2839837f853d ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SubRegionPlacementModification.java -@@ -0,0 +1,65 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.google.gson.JsonArray; -+import com.google.gson.JsonObject; -+import com.google.gson.JsonPrimitive; -+import net.minecraft.core.BlockPos; -+import net.minecraft.world.level.block.Mirror; -+import net.minecraft.world.level.block.Rotation; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+ -+public class SubRegionPlacementModification { -+ -+ public final String name; -+ public final BlockPos position; -+ public final Rotation rotation; -+ public final Mirror mirror; -+ -+ SubRegionPlacementModification(final String name, final BlockPos position, final Rotation rotation, final Mirror mirror) { -+ this.name = name; -+ this.position = position; -+ this.rotation = rotation; -+ this.mirror = mirror; -+ } -+ -+ public JsonObject toJson() { -+ final JsonObject obj = new JsonObject(); -+ -+ final JsonArray arr = new JsonArray(); -+ arr.add(position.getX()); -+ arr.add(position.getY()); -+ arr.add(position.getZ()); -+ obj.add("position", arr); -+ -+ obj.add("name", new JsonPrimitive(name)); -+ obj.add("rotation", new JsonPrimitive(rotation.name())); -+ obj.add("mirror", new JsonPrimitive(mirror.name())); -+ -+ return obj; -+ } -+ -+ @Nullable -+ public static SubRegionPlacementModification fromJson(final @NotNull JsonObject obj) { -+ if (!obj.has("name") || !obj.has("position") || !obj.has("rotation") || !obj.has("mirror")) { -+ return null; -+ } -+ -+ final String name = obj.get("name").getAsString(); -+ final JsonArray arr = obj.get("position").getAsJsonArray(); -+ if (arr.size() != 3) { -+ return null; -+ } -+ -+ final BlockPos position = new BlockPos(arr.get(0).getAsInt(), arr.get(1).getAsInt(), arr.get(2).getAsInt()); -+ final Rotation rotation = Rotation.valueOf(obj.get("rotation").getAsString()); -+ final Mirror mirror = Mirror.valueOf(obj.get("mirror").getAsString()); -+ -+ return new SubRegionPlacementModification(name, position, rotation, mirror); -+ } -+ -+ @Override -+ public String toString() { -+ return String.format("[name=%s, position=%s, rotation=%s, mirror=%s]", name, position, rotation, mirror); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SyncmaticManager.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SyncmaticManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9fbeef1ef528504276895faed4dba41ee0789e77 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SyncmaticManager.java -@@ -0,0 +1,108 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import com.google.gson.GsonBuilder; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonElement; -+import com.google.gson.JsonObject; -+import com.google.gson.JsonParser; -+import org.jetbrains.annotations.NotNull; -+ -+import java.io.File; -+import java.io.FileReader; -+import java.io.FileWriter; -+import java.io.IOException; -+import java.util.Collection; -+import java.util.HashMap; -+import java.util.Map; -+import java.util.UUID; -+ -+public class SyncmaticManager { -+ -+ public static final String PLACEMENTS_JSON_KEY = "placements"; -+ private final Map schematics = new HashMap<>(); -+ -+ public void addPlacement(final ServerPlacement placement) { -+ schematics.put(placement.getId(), placement); -+ updateServerPlacement(); -+ } -+ -+ public ServerPlacement getPlacement(final UUID id) { -+ return schematics.get(id); -+ } -+ -+ public Collection getAll() { -+ return schematics.values(); -+ } -+ -+ public void removePlacement(final @NotNull ServerPlacement placement) { -+ schematics.remove(placement.getId()); -+ updateServerPlacement(); -+ } -+ -+ public void updateServerPlacement() { -+ saveServer(); -+ } -+ -+ public void startup() { -+ loadServer(); -+ } -+ -+ private void saveServer() { -+ final JsonObject obj = new JsonObject(); -+ final JsonArray arr = new JsonArray(); -+ -+ for (final ServerPlacement p : getAll()) { -+ arr.add(p.toJson()); -+ } -+ -+ obj.add(PLACEMENTS_JSON_KEY, arr); -+ final File backup = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json.bak"); -+ final File incoming = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json.new"); -+ final File current = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json"); -+ -+ try (final FileWriter writer = new FileWriter(incoming)) { -+ writer.write(new GsonBuilder().setPrettyPrinting().create().toJson(obj)); -+ } catch (final IOException e) { -+ e.printStackTrace(); -+ return; -+ } -+ -+ SyncmaticaProtocol.backupAndReplace(backup.toPath(), current.toPath(), incoming.toPath()); -+ } -+ -+ private void loadServer() { -+ final File f = new File(SyncmaticaProtocol.getLitematicFolder(), "placements.json"); -+ if (f.exists() && f.isFile() && f.canRead()) { -+ JsonElement element = null; -+ try { -+ final JsonParser parser = new JsonParser(); -+ final FileReader reader = new FileReader(f); -+ -+ element = parser.parse(reader); -+ reader.close(); -+ -+ } catch (final Exception e) { -+ e.printStackTrace(); -+ } -+ if (element == null) { -+ return; -+ } -+ try { -+ final JsonObject obj = element.getAsJsonObject(); -+ if (obj == null || !obj.has(PLACEMENTS_JSON_KEY)) { -+ return; -+ } -+ final JsonArray arr = obj.getAsJsonArray(PLACEMENTS_JSON_KEY); -+ for (final JsonElement elem : arr) { -+ final ServerPlacement placement = ServerPlacement.fromJson(elem.getAsJsonObject()); -+ if (placement != null) { -+ schematics.put(placement.getId(), placement); -+ } -+ } -+ -+ } catch (final IllegalStateException | NullPointerException e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SyncmaticaProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SyncmaticaProtocol.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b41cbd5c834801e3673bd132b544d304567c66df ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/SyncmaticaProtocol.java -@@ -0,0 +1,123 @@ -+package top.leavesmc.leaves.protocol.syncmatica; -+ -+import org.jetbrains.annotations.NotNull; -+import me.earthme.luminol.LuminolConfig; -+ -+import java.io.File; -+import java.io.IOException; -+import java.io.InputStream; -+import java.nio.file.Files; -+import java.nio.file.Path; -+import java.security.MessageDigest; -+import java.security.NoSuchAlgorithmException; -+import java.util.Arrays; -+import java.util.UUID; -+ -+public class SyncmaticaProtocol { -+ -+ public static final String PROTOCOL_ID = "syncmatica"; -+ public static final String PROTOCOL_VERSION = "leaves-syncmatica-1.0.0"; -+ -+ private static final File litematicFolder = new File("." + File.separator + "syncmatics"); -+ private static final PlayerIdentifierProvider playerIdentifierProvider = new PlayerIdentifierProvider(); -+ private static final CommunicationManager communicationManager = new CommunicationManager(); -+ private static final FeatureSet featureSet = new FeatureSet(Arrays.asList(Feature.values())); -+ private static final SyncmaticManager syncmaticManager = new SyncmaticManager(); -+ private static final FileStorage fileStorage = new FileStorage(); -+ -+ public static File getLitematicFolder() { -+ return litematicFolder; -+ } -+ -+ public static PlayerIdentifierProvider getPlayerIdentifierProvider() { -+ return playerIdentifierProvider; -+ } -+ -+ public static CommunicationManager getCommunicationManager() { -+ return communicationManager; -+ } -+ -+ public static FeatureSet getFeatureSet() { -+ return featureSet; -+ } -+ -+ public static SyncmaticManager getSyncmaticManager() { -+ return syncmaticManager; -+ } -+ -+ public static FileStorage getFileStorage() { -+ return fileStorage; -+ } -+ -+ public static void init() { -+ litematicFolder.mkdirs(); -+ syncmaticManager.startup(); -+ } -+ -+ @NotNull -+ public static UUID createChecksum(final @NotNull InputStream fis) throws NoSuchAlgorithmException, IOException { -+ final byte[] buffer = new byte[4096]; -+ final MessageDigest messageDigest = MessageDigest.getInstance("MD5"); -+ int numRead; -+ -+ do { -+ numRead = fis.read(buffer); -+ if (numRead > 0) { -+ messageDigest.update(buffer, 0, numRead); -+ } -+ } while (numRead != -1); -+ -+ fis.close(); -+ return UUID.nameUUIDFromBytes(messageDigest.digest()); -+ } -+ -+ private static final int[] ILLEGAL_CHARS = {34, 60, 62, 124, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 58, 42, 63, 92, 47}; -+ private static final String ILLEGAL_PATTERNS = "(^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\..*)?$)|(^\\.\\.*$)"; -+ -+ @NotNull -+ public static String sanitizeFileName(final @NotNull String badFileName) { -+ final StringBuilder sanitized = new StringBuilder(); -+ final int len = badFileName.codePointCount(0, badFileName.length()); -+ -+ for (int i = 0; i < len; i++) { -+ final int c = badFileName.codePointAt(i); -+ if (Arrays.binarySearch(ILLEGAL_CHARS, c) < 0) { -+ sanitized.appendCodePoint(c); -+ if (sanitized.length() == 255) { -+ break; -+ } -+ } -+ } -+ -+ return sanitized.toString().replaceAll(ILLEGAL_PATTERNS, "_"); -+ } -+ -+ public static boolean isOverQuota(int sent) { -+ return LuminolConfig.syncmaticaQuota && sent > LuminolConfig.syncmaticaQuotaLimit; -+ } -+ -+ public static void backupAndReplace(final Path backup, final Path current, final Path incoming) { -+ if (!Files.exists(incoming)) { -+ return; -+ } -+ if (overwrite(backup, current, 2) && !overwrite(current, incoming, 4)) { -+ overwrite(current, backup, 8); -+ } -+ } -+ -+ private static boolean overwrite(final Path backup, final Path current, final int tries) { -+ if (!Files.exists(current)) { -+ return true; -+ } -+ try { -+ Files.deleteIfExists(backup); -+ Files.move(current, backup); -+ } catch (final IOException exception) { -+ if (tries <= 0) { -+ return false; -+ } -+ return overwrite(backup, current, tries - 1); -+ } -+ return true; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/AbstractExchange.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/AbstractExchange.java -new file mode 100644 -index 0000000000000000000000000000000000000000..625974f9ce0791b476336abafa6aa1af2f2ffbac ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/AbstractExchange.java -@@ -0,0 +1,66 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import net.minecraft.network.FriendlyByteBuf; -+import top.leavesmc.leaves.protocol.syncmatica.CommunicationManager; -+import top.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; -+ -+import java.util.UUID; -+ -+public abstract class AbstractExchange implements Exchange { -+ -+ private boolean success = false; -+ private boolean finished = false; -+ private final ExchangeTarget partner; -+ -+ protected AbstractExchange(final ExchangeTarget partner) { -+ this.partner = partner; -+ } -+ -+ @Override -+ public ExchangeTarget getPartner() { -+ return partner; -+ } -+ -+ @Override -+ public boolean isFinished() { -+ return finished; -+ } -+ -+ @Override -+ public boolean isSuccessful() { -+ return success; -+ } -+ -+ @Override -+ public void close(final boolean notifyPartner) { -+ finished = true; -+ success = false; -+ onClose(); -+ if (notifyPartner) { -+ sendCancelPacket(); -+ } -+ } -+ -+ public CommunicationManager getManager() { -+ return SyncmaticaProtocol.getCommunicationManager(); -+ } -+ -+ protected void sendCancelPacket() { -+ } -+ -+ protected void onClose() { -+ } -+ -+ protected void succeed() { -+ finished = true; -+ success = true; -+ onClose(); -+ } -+ -+ protected static boolean checkUUID(final FriendlyByteBuf sourceBuf, final UUID targetId) { -+ final int r = sourceBuf.readerIndex(); -+ final UUID sourceId = sourceBuf.readUUID(); -+ sourceBuf.readerIndex(r); -+ return sourceId.equals(targetId); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/DownloadExchange.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/DownloadExchange.java -new file mode 100644 -index 0000000000000000000000000000000000000000..7303769570656f36a3a76215e22020b1292007fb ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/DownloadExchange.java -@@ -0,0 +1,125 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import io.netty.buffer.Unpooled; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.resources.ResourceLocation; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.syncmatica.MessageType; -+import top.leavesmc.leaves.protocol.syncmatica.PacketType; -+import top.leavesmc.leaves.protocol.syncmatica.ServerPlacement; -+import top.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; -+ -+import java.io.File; -+import java.io.FileOutputStream; -+import java.io.IOException; -+import java.io.OutputStream; -+import java.security.DigestOutputStream; -+import java.security.MessageDigest; -+import java.security.NoSuchAlgorithmException; -+import java.util.UUID; -+ -+public class DownloadExchange extends AbstractExchange { -+ -+ private final ServerPlacement toDownload; -+ private final OutputStream outputStream; -+ private final MessageDigest md5; -+ private final File downloadFile; -+ private int bytesSent; -+ -+ public DownloadExchange(final ServerPlacement syncmatic, final File downloadFile, final ExchangeTarget partner) throws IOException, NoSuchAlgorithmException { -+ super(partner); -+ this.downloadFile = downloadFile; -+ final OutputStream os = new FileOutputStream(downloadFile); -+ toDownload = syncmatic; -+ md5 = MessageDigest.getInstance("MD5"); -+ outputStream = new DigestOutputStream(os, md5); -+ } -+ -+ @Override -+ public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ if (id.equals(PacketType.SEND_LITEMATIC.identifier) -+ || id.equals(PacketType.FINISHED_LITEMATIC.identifier) -+ || id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { -+ return checkUUID(packetBuf, toDownload.getId()); -+ } -+ return false; -+ } -+ -+ @Override -+ public void handle(final @NotNull ResourceLocation id, final @NotNull FriendlyByteBuf packetBuf) { -+ packetBuf.readUUID(); -+ if (id.equals(PacketType.SEND_LITEMATIC.identifier)) { -+ final int size = packetBuf.readInt(); -+ bytesSent += size; -+ if (SyncmaticaProtocol.isOverQuota(bytesSent)) { -+ close(true); -+ SyncmaticaProtocol.getCommunicationManager().sendMessage( -+ getPartner(), -+ MessageType.ERROR, -+ "syncmatica.error.cancelled_transmit_exceed_quota" -+ ); -+ } -+ try { -+ packetBuf.readBytes(outputStream, size); -+ } catch (final IOException e) { -+ close(true); -+ e.printStackTrace(); -+ return; -+ } -+ final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ FriendlyByteBuf.writeUUID(toDownload.getId()); -+ getPartner().sendPacket(PacketType.RECEIVED_LITEMATIC.identifier, FriendlyByteBuf); -+ return; -+ } -+ if (id.equals(PacketType.FINISHED_LITEMATIC.identifier)) { -+ try { -+ outputStream.flush(); -+ } catch (final IOException e) { -+ close(false); -+ e.printStackTrace(); -+ return; -+ } -+ final UUID downloadHash = UUID.nameUUIDFromBytes(md5.digest()); -+ if (downloadHash.equals(toDownload.getHash())) { -+ succeed(); -+ } else { -+ close(false); -+ } -+ return; -+ } -+ if (id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { -+ close(false); -+ } -+ } -+ -+ @Override -+ public void init() { -+ final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ FriendlyByteBuf.writeUUID(toDownload.getId()); -+ getPartner().sendPacket(PacketType.REQUEST_LITEMATIC.identifier, FriendlyByteBuf); -+ } -+ -+ @Override -+ protected void onClose() { -+ getManager().setDownloadState(toDownload, false); -+ try { -+ outputStream.close(); -+ } catch (final IOException e) { -+ e.printStackTrace(); -+ } -+ if (!isSuccessful() && downloadFile.exists()) { -+ downloadFile.delete(); -+ } -+ } -+ -+ @Override -+ protected void sendCancelPacket() { -+ final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ FriendlyByteBuf.writeUUID(toDownload.getId()); -+ getPartner().sendPacket(PacketType.CANCEL_LITEMATIC.identifier, FriendlyByteBuf); -+ } -+ -+ public ServerPlacement getPlacement() { -+ return toDownload; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/Exchange.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/Exchange.java -new file mode 100644 -index 0000000000000000000000000000000000000000..26482e63b7c24c80bdc111cea51b8d7b8052d64e ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/Exchange.java -@@ -0,0 +1,20 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.resources.ResourceLocation; -+ -+public interface Exchange { -+ ExchangeTarget getPartner(); -+ -+ boolean checkPacket(ResourceLocation id, FriendlyByteBuf packetBuf); -+ -+ void handle(ResourceLocation id, FriendlyByteBuf packetBuf); -+ -+ boolean isFinished(); -+ -+ boolean isSuccessful(); -+ -+ void close(boolean notifyPartner); -+ -+ void init(); -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/ExchangeTarget.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/ExchangeTarget.java -new file mode 100644 -index 0000000000000000000000000000000000000000..706680a3d7fae22f94cb86b8da2e306cfcf4cb1b ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/ExchangeTarget.java -@@ -0,0 +1,40 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.resources.ResourceLocation; -+import net.minecraft.server.network.ServerGamePacketListenerImpl; -+import top.leavesmc.leaves.protocol.core.ProtocolUtils; -+import top.leavesmc.leaves.protocol.syncmatica.FeatureSet; -+ -+import java.util.ArrayList; -+import java.util.Collection; -+import java.util.List; -+ -+public class ExchangeTarget { -+ -+ private final List ongoingExchanges = new ArrayList<>(); -+ private final ServerGamePacketListenerImpl client; -+ private FeatureSet features; -+ -+ public ExchangeTarget(final ServerGamePacketListenerImpl client) { -+ this.client = client; -+ } -+ -+ public void sendPacket(final ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ ProtocolUtils.sendPayloadPacket(client.player, id, buf -> { -+ buf.writeBytes(packetBuf); -+ }); -+ } -+ -+ public FeatureSet getFeatureSet() { -+ return features; -+ } -+ -+ public void setFeatureSet(final FeatureSet f) { -+ features = f; -+ } -+ -+ public Collection getExchanges() { -+ return ongoingExchanges; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/FeatureExchange.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/FeatureExchange.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f92739dbfa00de0e078834818dab79e34fc3d245 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/FeatureExchange.java -@@ -0,0 +1,48 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import io.netty.buffer.Unpooled; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.resources.ResourceLocation; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.syncmatica.FeatureSet; -+import top.leavesmc.leaves.protocol.syncmatica.PacketType; -+import top.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; -+ -+public abstract class FeatureExchange extends AbstractExchange { -+ -+ protected FeatureExchange(final ExchangeTarget partner) { -+ super(partner); -+ } -+ -+ @Override -+ public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ return id.equals(PacketType.FEATURE_REQUEST.identifier) -+ || id.equals(PacketType.FEATURE.identifier); -+ } -+ -+ @Override -+ public void handle(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ if (id.equals(PacketType.FEATURE_REQUEST.identifier)) { -+ sendFeatures(); -+ } else if (id.equals(PacketType.FEATURE.identifier)) { -+ final FeatureSet fs = FeatureSet.fromString(packetBuf.readUtf(32767)); -+ getPartner().setFeatureSet(fs); -+ onFeatureSetReceive(); -+ } -+ } -+ -+ protected void onFeatureSetReceive() { -+ succeed(); -+ } -+ -+ public void requestFeatureSet() { -+ getPartner().sendPacket(PacketType.FEATURE_REQUEST.identifier, new FriendlyByteBuf(Unpooled.buffer())); -+ } -+ -+ private void sendFeatures() { -+ final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); -+ final FeatureSet fs = SyncmaticaProtocol.getFeatureSet(); -+ buf.writeUtf(fs.toString(), 32767); -+ getPartner().sendPacket(PacketType.FEATURE.identifier, buf); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/ModifyExchangeServer.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/ModifyExchangeServer.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d87602fa78a8e599b71556f3dd103ff71ee83ae0 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/ModifyExchangeServer.java -@@ -0,0 +1,81 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import io.netty.buffer.Unpooled; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.resources.ResourceLocation; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.syncmatica.PacketType; -+import top.leavesmc.leaves.protocol.syncmatica.PlayerIdentifier; -+import top.leavesmc.leaves.protocol.syncmatica.ServerPlacement; -+import top.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; -+ -+import java.util.UUID; -+ -+public class ModifyExchangeServer extends AbstractExchange { -+ -+ private final ServerPlacement placement; -+ UUID placementId; -+ -+ public ModifyExchangeServer(final UUID placeId, final ExchangeTarget partner) { -+ super(partner); -+ placementId = placeId; -+ placement = SyncmaticaProtocol.getSyncmaticManager().getPlacement(placementId); -+ } -+ -+ @Override -+ public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ return id.equals(PacketType.MODIFY_FINISH.identifier) && checkUUID(packetBuf, placement.getId()); -+ } -+ -+ @Override -+ public void handle(final @NotNull ResourceLocation id, final @NotNull FriendlyByteBuf packetBuf) { -+ packetBuf.readUUID(); -+ if (id.equals(PacketType.MODIFY_FINISH.identifier)) { -+ SyncmaticaProtocol.getCommunicationManager().receivePositionData(placement, packetBuf, getPartner()); -+ final PlayerIdentifier identifier = SyncmaticaProtocol.getPlayerIdentifierProvider().createOrGet( -+ getPartner() -+ ); -+ placement.setLastModifiedBy(identifier); -+ SyncmaticaProtocol.getSyncmaticManager().updateServerPlacement(); -+ succeed(); -+ } -+ } -+ -+ @Override -+ public void init() { -+ if (getPlacement() == null || SyncmaticaProtocol.getCommunicationManager().getModifier(placement) != null) { -+ close(true); -+ } else { -+ if (SyncmaticaProtocol.getPlayerIdentifierProvider().createOrGet(this.getPartner()).uuid.equals(placement.getOwner().uuid)) { -+ accept(); -+ } else { -+ close(true); -+ } -+ } -+ } -+ -+ private void accept() { -+ final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); -+ buf.writeUUID(placement.getId()); -+ getPartner().sendPacket(PacketType.MODIFY_REQUEST_ACCEPT.identifier, buf); -+ SyncmaticaProtocol.getCommunicationManager().setModifier(placement, this); -+ } -+ -+ @Override -+ protected void sendCancelPacket() { -+ final FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer()); -+ buf.writeUUID(placementId); -+ getPartner().sendPacket(PacketType.MODIFY_REQUEST_DENY.identifier, buf); -+ } -+ -+ public ServerPlacement getPlacement() { -+ return placement; -+ } -+ -+ @Override -+ protected void onClose() { -+ if (SyncmaticaProtocol.getCommunicationManager().getModifier(placement) == this) { -+ SyncmaticaProtocol.getCommunicationManager().setModifier(placement, null); -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/UploadExchange.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/UploadExchange.java -new file mode 100644 -index 0000000000000000000000000000000000000000..9a1b37c69a3946b8f042a1118bf7dcf6ff0967ae ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/UploadExchange.java -@@ -0,0 +1,101 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import io.netty.buffer.Unpooled; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.resources.ResourceLocation; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.syncmatica.PacketType; -+import top.leavesmc.leaves.protocol.syncmatica.ServerPlacement; -+ -+import java.io.File; -+import java.io.FileInputStream; -+import java.io.FileNotFoundException; -+import java.io.IOException; -+import java.io.InputStream; -+ -+public class UploadExchange extends AbstractExchange { -+ -+ private static final int BUFFER_SIZE = 16384; -+ -+ private final ServerPlacement toUpload; -+ private final InputStream inputStream; -+ private final byte[] buffer = new byte[BUFFER_SIZE]; -+ -+ public UploadExchange(final ServerPlacement syncmatic, final File uploadFile, final ExchangeTarget partner) throws FileNotFoundException { -+ super(partner); -+ toUpload = syncmatic; -+ inputStream = new FileInputStream(uploadFile); -+ } -+ -+ @Override -+ public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ if (id.equals(PacketType.RECEIVED_LITEMATIC.identifier) -+ || id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { -+ return checkUUID(packetBuf, toUpload.getId()); -+ } -+ return false; -+ } -+ -+ @Override -+ public void handle(final @NotNull ResourceLocation id, final @NotNull FriendlyByteBuf packetBuf) { -+ packetBuf.readUUID(); -+ if (id.equals(PacketType.RECEIVED_LITEMATIC.identifier)) { -+ send(); -+ } -+ if (id.equals(PacketType.CANCEL_LITEMATIC.identifier)) { -+ close(false); -+ } -+ } -+ -+ private void send() { -+ final int bytesRead; -+ try { -+ bytesRead = inputStream.read(buffer); -+ } catch (final IOException e) { -+ close(true); -+ e.printStackTrace(); -+ return; -+ } -+ if (bytesRead == -1) { -+ sendFinish(); -+ } else { -+ sendData(bytesRead); -+ } -+ } -+ -+ private void sendData(final int bytesRead) { -+ final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ FriendlyByteBuf.writeUUID(toUpload.getId()); -+ FriendlyByteBuf.writeInt(bytesRead); -+ FriendlyByteBuf.writeBytes(buffer, 0, bytesRead); -+ getPartner().sendPacket(PacketType.SEND_LITEMATIC.identifier, FriendlyByteBuf); -+ } -+ -+ private void sendFinish() { -+ final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ FriendlyByteBuf.writeUUID(toUpload.getId()); -+ getPartner().sendPacket(PacketType.FINISHED_LITEMATIC.identifier, FriendlyByteBuf); -+ succeed(); -+ } -+ -+ @Override -+ public void init() { -+ send(); -+ } -+ -+ @Override -+ protected void onClose() { -+ try { -+ inputStream.close(); -+ } catch (final IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ -+ @Override -+ protected void sendCancelPacket() { -+ final FriendlyByteBuf FriendlyByteBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ FriendlyByteBuf.writeUUID(toUpload.getId()); -+ getPartner().sendPacket(PacketType.CANCEL_LITEMATIC.identifier, FriendlyByteBuf); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/VersionHandshakeServer.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/VersionHandshakeServer.java -new file mode 100644 -index 0000000000000000000000000000000000000000..448d5e8423347c0154a146906617e32e18fbc30f ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/exchange/VersionHandshakeServer.java -@@ -0,0 +1,65 @@ -+package top.leavesmc.leaves.protocol.syncmatica.exchange; -+ -+import io.netty.buffer.Unpooled; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.resources.ResourceLocation; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.protocol.syncmatica.FeatureSet; -+import top.leavesmc.leaves.protocol.syncmatica.PacketType; -+import top.leavesmc.leaves.protocol.syncmatica.ServerPlacement; -+import top.leavesmc.leaves.protocol.syncmatica.SyncmaticaProtocol; -+ -+import java.util.Collection; -+ -+public class VersionHandshakeServer extends FeatureExchange { -+ -+ public VersionHandshakeServer(final ExchangeTarget partner) { -+ super(partner); -+ } -+ -+ @Override -+ public boolean checkPacket(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ return id.equals(PacketType.REGISTER_VERSION.identifier) -+ || super.checkPacket(id, packetBuf); -+ } -+ -+ @Override -+ public void handle(final @NotNull ResourceLocation id, final FriendlyByteBuf packetBuf) { -+ if (id.equals(PacketType.REGISTER_VERSION.identifier)) { -+ String partnerVersion = packetBuf.readUtf(32767); -+ if (partnerVersion.equals("0.0.1")) { -+ close(false); -+ return; -+ } -+ final FeatureSet fs = FeatureSet.fromVersionString(partnerVersion); -+ if (fs == null) { -+ requestFeatureSet(); -+ } else { -+ getPartner().setFeatureSet(fs); -+ onFeatureSetReceive(); -+ } -+ } else { -+ super.handle(id, packetBuf); -+ } -+ -+ } -+ -+ @Override -+ public void onFeatureSetReceive() { -+ final FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ final Collection l = SyncmaticaProtocol.getSyncmaticManager().getAll(); -+ newBuf.writeInt(l.size()); -+ for (final ServerPlacement p : l) { -+ getManager().putMetaData(p, newBuf, getPartner()); -+ } -+ getPartner().sendPacket(PacketType.CONFIRM_USER.identifier, newBuf); -+ succeed(); -+ } -+ -+ @Override -+ public void init() { -+ final FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); -+ newBuf.writeUtf(SyncmaticaProtocol.PROTOCOL_VERSION); -+ getPartner().sendPacket(PacketType.REGISTER_VERSION.identifier, newBuf); -+ } -+} diff --git a/patches/server/0058-LinearPaper-Remove-all-locks-on-region-files.patch b/patches/server/0044-LinearPaper-Remove-all-locks-on-region-files.patch similarity index 99% rename from patches/server/0058-LinearPaper-Remove-all-locks-on-region-files.patch rename to patches/server/0044-LinearPaper-Remove-all-locks-on-region-files.patch index 0c36f45..90a2c99 100644 --- a/patches/server/0058-LinearPaper-Remove-all-locks-on-region-files.patch +++ b/patches/server/0044-LinearPaper-Remove-all-locks-on-region-files.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 11:53:38 +0000 +Date: Wed, 7 Feb 2024 06:30:38 +0000 Subject: [PATCH] LinearPaper Remove all locks on region files diff --git a/patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch b/patches/server/0045-Sparkly-Paper-Optimize-canSee-checks.patch similarity index 95% rename from patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch rename to patches/server/0045-Sparkly-Paper-Optimize-canSee-checks.patch index 2685e11..f7194bf 100644 --- a/patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch +++ b/patches/server/0045-Sparkly-Paper-Optimize-canSee-checks.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Sparkly Paper Optimize canSee checks diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 5fc083b58f6f120d234513c7c36999f034e1d869..369b0eabe2313eea0ce71553baa965bc71794274 100644 +index c212030a24174115a975604b91d03cf8ad4043de..2fc86eb396ed600154840dd6cd43b9294a34595c 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -1408,7 +1408,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -18,7 +18,7 @@ index 5fc083b58f6f120d234513c7c36999f034e1d869..369b0eabe2313eea0ce71553baa965bc } // CraftBukkit end diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java -index 91678602a5509b7ee0ff792d1a626e271b7db6b9..be0e51bfb6d083781693edf3644d637aa07c551f 100644 +index f4b7f2f223964df7533577342d8af158af35363b..93e022f9b30da70d86638b9ac9105d1b97a53e12 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftPlayer.java @@ -181,7 +181,7 @@ public class CraftPlayer extends CraftHumanEntity implements Player { diff --git a/patches/server/0046-Do-not-process-any-packet-if-the-leaves-protocol-sup.patch b/patches/server/0046-Do-not-process-any-packet-if-the-leaves-protocol-sup.patch deleted file mode 100644 index fc7f5ba..0000000 --- a/patches/server/0046-Do-not-process-any-packet-if-the-leaves-protocol-sup.patch +++ /dev/null @@ -1,74 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Sat, 27 Jan 2024 13:38:56 +0000 -Subject: [PATCH] Do not process any packet if the leaves protocol supports are - disabled - - -diff --git a/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java -index ebd28033ddf0fe6a354585dc2818a9b481d90ed4..33c7221a1f33cdb81dfac92fc3332f92cf3cd2d9 100644 ---- a/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java -+++ b/src/main/java/top/leavesmc/leaves/protocol/PcaSyncProtocol.java -@@ -1,5 +1,6 @@ - package top.leavesmc.leaves.protocol; - -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.core.BlockPos; - import net.minecraft.nbt.CompoundTag; - import net.minecraft.network.FriendlyByteBuf; -diff --git a/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java -index de92ebdf9d51a4f9a58a7650b09f070e51710ef0..b309963dcf41f16a7b53e4cc2816975523ccba55 100644 ---- a/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java -+++ b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java -@@ -35,6 +35,9 @@ public class MsptSyncProtocol { - - @ProtocolHandler.Init - public static void init() { -+ if (!LuminolConfig.msptSyncProtocol){ -+ return; -+ } - BladerenProtocol.registerFeature("mspt_sync", (player, compoundTag) -> { - if (compoundTag.getString("Value").equals("true")) { - onPlayerSubmit(player); -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -index 4c2aa74795b0883f280eaa721a83ea6891ffdab2..19277aa7b9bd16b3e70d581d38a4c28e60165f65 100644 ---- a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -@@ -2,6 +2,7 @@ package top.leavesmc.leaves.protocol.syncmatica; - - import com.mojang.authlib.GameProfile; - import io.netty.buffer.Unpooled; -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.core.BlockPos; - import net.minecraft.network.FriendlyByteBuf; - import net.minecraft.network.chat.Component; -@@ -68,6 +69,9 @@ public class CommunicationManager { - - @ProtocolHandler.PlayerJoin - public static void onPlayerJoin(ServerPlayer player) { -+ if (!LuminolConfig.syncmaticaProtocol){ -+ return; -+ } - final ExchangeTarget newPlayer = player.connection.exchangeTarget; - final VersionHandshakeServer hi = new VersionHandshakeServer(newPlayer); - playerMap.put(newPlayer, player); -@@ -78,6 +82,9 @@ public class CommunicationManager { - - @ProtocolHandler.PlayerLeave - public static void onPlayerLeave(ServerPlayer player) { -+ if (!LuminolConfig.syncmaticaProtocol){ -+ return; -+ } - final ExchangeTarget oldPlayer = player.connection.exchangeTarget; - final Collection potentialMessageTarget = oldPlayer.getExchanges(); - if (potentialMessageTarget != null) { -@@ -92,6 +99,9 @@ public class CommunicationManager { - - @ProtocolHandler.PayloadReceiver(payload = LeavesProtocolManager.LeavesPayload.class, ignoreId = true, payloadId = "") - public static void onPacketGet(ServerPlayer player, LeavesProtocolManager.LeavesPayload payload) { -+ if (!LuminolConfig.syncmaticaProtocol){ -+ return; -+ } - onPacket(player.connection.exchangeTarget, payload.id(), payload.data()); - } - diff --git a/patches/server/0039-Purpur-use-alternative-keep-alive.patch b/patches/server/0046-Purpur-use-alternative-keep-alive.patch similarity index 67% rename from patches/server/0039-Purpur-use-alternative-keep-alive.patch rename to patches/server/0046-Purpur-use-alternative-keep-alive.patch index 25599cf..9469999 100644 --- a/patches/server/0039-Purpur-use-alternative-keep-alive.patch +++ b/patches/server/0046-Purpur-use-alternative-keep-alive.patch @@ -1,31 +1,37 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 04:01:44 +0000 +Date: Wed, 7 Feb 2024 08:35:11 +0000 Subject: [PATCH] Purpur use alternative keep alive -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 785dc39724f3fb2e27a9fbbe9ea6b4e489b9e0ec..a15bf25fb01fb9cf239ecb8c05d795c61d6a8bb9 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -61,6 +61,7 @@ public class LuminolConfig { - public static boolean asyncPathProcessing = false; - public static int asyncPathProcessingMaxThreads = 0; - public static int asyncPathProcessingKeepalive = 60; +diff --git a/src/main/java/me/earthme/luminol/config/modules/optimizations/PurpurAlternativeKeepaliveConfig.java b/src/main/java/me/earthme/luminol/config/modules/optimizations/PurpurAlternativeKeepaliveConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..43bbc2c30bdd3872a0179e0070403c3e257c320e +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/optimizations/PurpurAlternativeKeepaliveConfig.java +@@ -0,0 +1,20 @@ ++package me.earthme.luminol.config.modules.optimizations; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class PurpurAlternativeKeepaliveConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enabled") + public static boolean useAlternateKeepAlive = false; - - public static void init() throws IOException { - PARENT_FOLDER.mkdir(); -@@ -186,6 +187,7 @@ public class LuminolConfig { - asyncPathProcessingMaxThreads = Math.max(Runtime.getRuntime().availableProcessors() / 4, 1); - if (!asyncPathProcessing) - asyncPathProcessingMaxThreads = 0; -+ useAlternateKeepAlive = get("optimizations.enable_alternative_keep_alive_handling",useAlternateKeepAlive,"Enabling this sends a keepalive packet once per second to a player, and only kicks for timeout if none of them were responded to in 30 seconds. Responding to any of them in any order will keep the player connected. AKA, it won't kick your players because one packet gets dropped somewhere along the lines(From purpur)"); - } - - public static T get(String key,T def){ ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.OPTIMIZATIONS; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "alternative_keepalive_handling"; ++ } ++} diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 22f0d91df0a81040d72c499fbff32b3a9d41598f..7ae11e8716d45a53cab24a3966bcb880df69027c 100644 +index 22f0d91df0a81040d72c499fbff32b3a9d41598f..c68910b2a2eb703406fb406a86783cf6ab48651e 100644 --- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java @@ -51,6 +51,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack @@ -41,7 +47,7 @@ index 22f0d91df0a81040d72c499fbff32b3a9d41598f..7ae11e8716d45a53cab24a3966bcb880 @Override public void handleKeepAlive(ServerboundKeepAlivePacket packet) { + // Purpur start -+ if (me.earthme.luminol.LuminolConfig.useAlternateKeepAlive) { ++ if (me.earthme.luminol.config.modules.optimizations.PurpurAlternativeKeepaliveConfig.useAlternateKeepAlive) { + long id = packet.getId(); + if (keepAlives.size() > 0 && keepAlives.contains(id)) { + int ping = (int) (Util.getMillis() - id); @@ -58,7 +64,7 @@ index 22f0d91df0a81040d72c499fbff32b3a9d41598f..7ae11e8716d45a53cab24a3966bcb880 long elapsedTime = currentTime - this.keepAliveTime; + // Purpur start -+ if (me.earthme.luminol.LuminolConfig.useAlternateKeepAlive) { ++ if (me.earthme.luminol.config.modules.optimizations.PurpurAlternativeKeepaliveConfig.useAlternateKeepAlive) { + if (elapsedTime >= 1000L) { // 1 second + if (!processedDisconnect && keepAlives.size() * 1000L >= KEEPALIVE_LIMIT) { + LOGGER.warn("{} was kicked due to keepalive timeout!", this.player.getScoreboardName()); diff --git a/patches/server/0040-Leaves-Protocol-Core.patch b/patches/server/0047-Leaves-Protocol-Core.patch similarity index 99% rename from patches/server/0040-Leaves-Protocol-Core.patch rename to patches/server/0047-Leaves-Protocol-Core.patch index 1aedea8..d556e78 100644 --- a/patches/server/0040-Leaves-Protocol-Core.patch +++ b/patches/server/0047-Leaves-Protocol-Core.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Tue, 6 Feb 2024 04:03:25 +0000 +Date: Wed, 7 Feb 2024 08:51:49 +0000 Subject: [PATCH] Leaves Protocol Core @@ -36,7 +36,7 @@ index af86f752c33a2990405fea058b7c41c437ba9d46..bada9fae1e7178162429e1f5a1608b9c } diff --git a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java -index 7ae11e8716d45a53cab24a3966bcb880df69027c..53783a2b174a46fd79bc7ae6fc5a8e6fc5e56a24 100644 +index c68910b2a2eb703406fb406a86783cf6ab48651e..f935214ed80fe54038a96a5cd668a072cdf406ec 100644 --- a/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java +++ b/src/main/java/net/minecraft/server/network/ServerCommonPacketListenerImpl.java @@ -139,6 +139,7 @@ public abstract class ServerCommonPacketListenerImpl implements ServerCommonPack diff --git a/patches/server/0048-Leaves-Bladeren-Protocol.patch b/patches/server/0048-Leaves-Bladeren-Protocol.patch new file mode 100644 index 0000000..75aff16 --- /dev/null +++ b/patches/server/0048-Leaves-Bladeren-Protocol.patch @@ -0,0 +1,288 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrHua269 +Date: Wed, 7 Feb 2024 08:59:41 +0000 +Subject: [PATCH] Leaves Bladeren Protocol + + +diff --git a/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesBladerenProtocolConfig.java b/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesBladerenProtocolConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..b882549a3c3bc8c192014fd6e1ac7b4f0feddafc +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/gameplay/LeavesBladerenProtocolConfig.java +@@ -0,0 +1,24 @@ ++package me.earthme.luminol.config.modules.gameplay; ++ ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++ ++public class LeavesBladerenProtocolConfig implements IConfigModule { ++ @ConfigInfo(baseName = "enable_base_protocol") ++ public static boolean enableBaseProtocol = false; ++ @ConfigInfo(baseName = "enable_mspt_sync_protocol") ++ public static boolean msptSyncProtocol = false; ++ @ConfigInfo(baseName = "mspt_sync_interval") ++ public static int msptSyncTickInterval = 20; ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.GAMEPLAY; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "leaves_bladeren_protocol"; ++ } ++} +diff --git a/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java +new file mode 100644 +index 0000000000000000000000000000000000000000..6415f17fa6c06199e59705a29605d2aef834fc17 +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/protocol/bladeren/BladerenProtocol.java +@@ -0,0 +1,150 @@ ++package top.leavesmc.leaves.protocol.bladeren; ++ ++import com.google.common.collect.Maps; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.network.FriendlyByteBuf; ++import net.minecraft.network.protocol.common.custom.CustomPacketPayload; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.server.level.ServerPlayer; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++import top.leavesmc.leaves.protocol.core.LeavesProtocol; ++import top.leavesmc.leaves.protocol.core.ProtocolHandler; ++import top.leavesmc.leaves.protocol.core.ProtocolUtils; ++ ++import java.util.HashMap; ++import java.util.Map; ++import java.util.function.BiConsumer; ++ ++@LeavesProtocol(namespace = "bladeren") ++public class BladerenProtocol { ++ ++ public static final String PROTOCOL_ID = "bladeren"; ++ public static final String PROTOCOL_VERSION = "1.0.0"; ++ ++ private static final ResourceLocation HELLO_ID = id("hello"); ++ private static final ResourceLocation FEATURE_MODIFY_ID = id("feature_modify"); ++ ++ private static final Map> registeredFeatures = Maps.newConcurrentMap(); ++ ++ @Contract("_ -> new") ++ public static @NotNull ResourceLocation id(String path) { ++ return new ResourceLocation(PROTOCOL_ID, path); ++ } ++ ++ @ProtocolHandler.PayloadReceiver(payload = BladerenHelloPayload.class, payloadId = "hello") ++ private static void handleHello(@NotNull ServerPlayer player, @NotNull BladerenHelloPayload payload) { ++ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.enableBaseProtocol) { ++ String clientVersion = payload.version; ++ CompoundTag tag = payload.nbt; ++ ++ if (tag != null) { ++ CompoundTag featureNbt = tag.getCompound("Features"); ++ for (String name : featureNbt.getAllKeys()) { ++ ++ final BiConsumer target = registeredFeatures.get(name); ++ ++ if (target != null){ ++ target.accept(player, featureNbt.getCompound(name)); ++ } ++ } ++ } ++ } ++ } ++ ++ @ProtocolHandler.PayloadReceiver(payload = BladerenFeatureModifyPayload.class, payloadId = "feature_modify") ++ private static void handleModify(@NotNull ServerPlayer player, @NotNull BladerenFeatureModifyPayload payload) { ++ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.enableBaseProtocol) { ++ String name = payload.name; ++ CompoundTag tag = payload.nbt; ++ ++ final BiConsumer target = registeredFeatures.get(name); ++ ++ if (target != null){ ++ target.accept(player, tag); ++ } ++ } ++ } ++ ++ @ProtocolHandler.PlayerJoin ++ public static void onPlayerJoin(@NotNull ServerPlayer player) { ++ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.enableBaseProtocol) { ++ CompoundTag tag = new CompoundTag(); ++ LeavesFeatureSet.writeNBT(tag); ++ ProtocolUtils.sendPayloadPacket(player, new BladerenHelloPayload(PROTOCOL_VERSION, tag)); ++ } ++ } ++ ++ public static void registerFeature(String name, BiConsumer consumer) { ++ registeredFeatures.put(name, consumer); ++ } ++ ++ public static class LeavesFeatureSet { ++ ++ private static final Map features = new HashMap<>(); ++ ++ public static void writeNBT(@NotNull CompoundTag tag) { ++ CompoundTag featureNbt = new CompoundTag(); ++ features.values().forEach(feature -> feature.writeNBT(featureNbt)); ++ tag.put("Features", featureNbt); ++ } ++ ++ public static void register(LeavesFeature feature) { ++ features.put(feature.name, feature); ++ } ++ } ++ ++ public record LeavesFeature(String name, String value) { ++ ++ @NotNull ++ @Contract("_, _ -> new") ++ public static LeavesFeature of(String name, boolean value) { ++ return new LeavesFeature(name, Boolean.toString(value)); ++ } ++ ++ public void writeNBT(@NotNull CompoundTag rules) { ++ CompoundTag rule = new CompoundTag(); ++ rule.putString("Feature", name); ++ rule.putString("Value", value); ++ rules.put(name, rule); ++ } ++ } ++ ++ public record BladerenFeatureModifyPayload(String name, CompoundTag nbt) implements CustomPacketPayload { ++ ++ public BladerenFeatureModifyPayload(ResourceLocation location, FriendlyByteBuf buf) { ++ this(buf.readUtf(), buf.readNbt()); ++ } ++ ++ @Override ++ public void write(@NotNull FriendlyByteBuf buf) { ++ buf.writeUtf(name); ++ buf.writeNbt(nbt); ++ } ++ ++ @Override ++ @NotNull ++ public ResourceLocation id() { ++ return FEATURE_MODIFY_ID; ++ } ++ } ++ ++ public record BladerenHelloPayload(String version, CompoundTag nbt) implements CustomPacketPayload { ++ ++ public BladerenHelloPayload(ResourceLocation location, @NotNull FriendlyByteBuf buf) { ++ this(buf.readUtf(64), buf.readNbt()); ++ } ++ ++ @Override ++ public void write(@NotNull FriendlyByteBuf buf) { ++ buf.writeUtf(version); ++ buf.writeNbt(nbt); ++ } ++ ++ @Override ++ @NotNull ++ public ResourceLocation id() { ++ return HELLO_ID; ++ } ++ } ++} +diff --git a/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java +new file mode 100644 +index 0000000000000000000000000000000000000000..db63ea1cf65e6ca06bd1c6ce978193e068a9a951 +--- /dev/null ++++ b/src/main/java/top/leavesmc/leaves/protocol/bladeren/MsptSyncProtocol.java +@@ -0,0 +1,90 @@ ++package top.leavesmc.leaves.protocol.bladeren; ++ ++import io.papermc.paper.threadedregions.ThreadedRegionizer; ++import io.papermc.paper.threadedregions.TickData; ++import io.papermc.paper.threadedregions.TickRegions; ++import it.unimi.dsi.fastutil.objects.ObjectArrayList; ++import it.unimi.dsi.fastutil.objects.ObjectLists; ++import net.minecraft.resources.ResourceLocation; ++import net.minecraft.server.level.ServerLevel; ++import net.minecraft.server.level.ServerPlayer; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++import top.leavesmc.leaves.protocol.core.LeavesProtocol; ++import top.leavesmc.leaves.protocol.core.ProtocolHandler; ++import top.leavesmc.leaves.protocol.core.ProtocolUtils; ++ ++import java.util.List; ++ ++@LeavesProtocol(namespace = "bladeren") ++public class MsptSyncProtocol { ++ ++ public static final String PROTOCOL_ID = "bladeren"; ++ ++ private static final ResourceLocation MSPT_SYNC = id("mspt_sync"); ++ ++ private static final List players = ObjectLists.synchronize(new ObjectArrayList<>()); ++ ++ private static int tickCounter = 0; ++ ++ @Contract("_ -> new") ++ public static @NotNull ResourceLocation id(String path) { ++ return new ResourceLocation(PROTOCOL_ID, path); ++ } ++ ++ @ProtocolHandler.Init ++ public static void init() { ++ BladerenProtocol.registerFeature("mspt_sync", (player, compoundTag) -> { ++ if (compoundTag.getString("Value").equals("true")) { ++ onPlayerSubmit(player); ++ } else { ++ onPlayerLoggedOut(player); ++ } ++ }); ++ } ++ ++ @ProtocolHandler.PlayerLeave ++ public static void onPlayerLoggedOut(@NotNull ServerPlayer player) { ++ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncProtocol) { ++ players.remove(player); ++ } ++ } ++ ++ @ProtocolHandler.Ticker ++ public static void tick() { ++ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncProtocol) { ++ if (players.isEmpty()) { ++ return; ++ } ++ ++ if (tickCounter++ % me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncTickInterval == 0) { ++ for (ServerPlayer player : players){ ++ final ThreadedRegionizer.ThreadedRegion region = ((ServerLevel) player.level()).regioniser.getRegionAtUnsynchronised(player.sectionX,player.sectionZ); ++ ++ if (region == null){ ++ continue; ++ } ++ ++ final TickData.TickReportData reportData = region.getData().getRegionSchedulingHandle().getTickReport5s(System.nanoTime()); ++ ++ if (reportData != null){ ++ final TickData.SegmentData tpsData = reportData.tpsData().segmentAll(); ++ final double mspt = reportData.timePerTickData().segmentAll().average() / 1.0E6; ++ final double tps = tpsData.average(); ++ ++ ProtocolUtils.sendPayloadPacket(player, MSPT_SYNC, buf -> { ++ buf.writeDouble(mspt); ++ buf.writeDouble(tps); ++ }); ++ } ++ } ++ } ++ } ++ } ++ ++ public static void onPlayerSubmit(@NotNull ServerPlayer player) { ++ if (me.earthme.luminol.config.modules.gameplay.LeavesBladerenProtocolConfig.msptSyncProtocol) { ++ players.add(player); ++ } ++ } ++} diff --git a/patches/server/0045-Leaves-Fix-Bladeren-Protocol.patch b/patches/server/0049-Leaves-Fix-Bladeren-Protocol.patch similarity index 84% rename from patches/server/0045-Leaves-Fix-Bladeren-Protocol.patch rename to patches/server/0049-Leaves-Fix-Bladeren-Protocol.patch index f2ebe57..b2eb343 100644 --- a/patches/server/0045-Leaves-Fix-Bladeren-Protocol.patch +++ b/patches/server/0049-Leaves-Fix-Bladeren-Protocol.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: MrHua269 -Date: Sat, 27 Jan 2024 13:37:13 +0000 +Date: Wed, 7 Feb 2024 09:00:10 +0000 Subject: [PATCH] Leaves Fix Bladeren Protocol @@ -91,16 +91,3 @@ index d696f001d2576d1b61cc732c81f22eb52205072b..92ad6e9b1c0d9640b80c1ebe739c613d boolean ignoreId() default false; } -diff --git a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -index fc229f23076147304754a267bcc345cc836b648b..4c2aa74795b0883f280eaa721a83ea6891ffdab2 100644 ---- a/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -+++ b/src/main/java/top/leavesmc/leaves/protocol/syncmatica/CommunicationManager.java -@@ -90,7 +90,7 @@ public class CommunicationManager { - playerMap.remove(oldPlayer); - } - -- @ProtocolHandler.PayloadReceiver(payload = LeavesProtocolManager.LeavesPayload.class, ignoreId = true) -+ @ProtocolHandler.PayloadReceiver(payload = LeavesProtocolManager.LeavesPayload.class, ignoreId = true, payloadId = "") - public static void onPacketGet(ServerPlayer player, LeavesProtocolManager.LeavesPayload payload) { - onPacket(player.connection.exchangeTarget, payload.id(), payload.data()); - } diff --git a/patches/server/0054-Leaves-Command-Utilities.patch b/patches/server/0054-Leaves-Command-Utilities.patch deleted file mode 100644 index 1f05053..0000000 --- a/patches/server/0054-Leaves-Command-Utilities.patch +++ /dev/null @@ -1,166 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Mon, 29 Jan 2024 13:28:54 +0000 -Subject: [PATCH] Leaves Command Utilities - - -diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgument.java b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java -new file mode 100644 -index 0000000000000000000000000000000000000000..eadc6d168fb13299348b0c275ae352ee2f1e1ea2 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java -@@ -0,0 +1,43 @@ -+package top.leavesmc.leaves.command; -+ -+import org.jetbrains.annotations.NotNull; -+ -+import java.util.ArrayList; -+import java.util.Arrays; -+import java.util.List; -+ -+public class CommandArgument { -+ -+ private final List> argumentTypes; -+ private final List> tabComplete; -+ -+ public CommandArgument(CommandArgumentType... argumentTypes) { -+ this.argumentTypes = List.of(argumentTypes); -+ this.tabComplete = new ArrayList<>(); -+ for (int i = 0; i < argumentTypes.length; i++) { -+ tabComplete.add(new ArrayList<>()); -+ } -+ } -+ -+ public List tabComplete(int n) { -+ if (tabComplete.size() > n) { -+ return tabComplete.get(n); -+ } else { -+ return List.of(); -+ } -+ } -+ -+ public CommandArgument setTabComplete(int index, List list) { -+ tabComplete.set(index, list); -+ return this; -+ } -+ -+ public CommandArgumentResult parse(int index, String @NotNull [] args) { -+ Object[] result = new Object[argumentTypes.size()]; -+ Arrays.fill(result, null); -+ for (int i = index, j = 0; i < args.length && j < result.length; i++, j++) { -+ result[j] = argumentTypes.get(j).pasre(args[i]); -+ } -+ return new CommandArgumentResult(new ArrayList<>(Arrays.asList(result))); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java -new file mode 100644 -index 0000000000000000000000000000000000000000..340eaca64c96180b895a075ce9e44402cd104eed ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java -@@ -0,0 +1,62 @@ -+package top.leavesmc.leaves.command; -+ -+import net.minecraft.core.BlockPos; -+import org.bukkit.util.Vector; -+ -+import java.util.List; -+import java.util.Objects; -+ -+public class CommandArgumentResult { -+ -+ private final List result; -+ -+ public CommandArgumentResult(List result) { -+ this.result = result; -+ } -+ -+ public Integer readInt(int def) { -+ return Objects.requireNonNullElse(read(Integer.class), def); -+ } -+ -+ public Double readDouble(double def) { -+ return Objects.requireNonNullElse(read(Double.class), def); -+ } -+ -+ public String readString(String def) { -+ return Objects.requireNonNullElse(read(String.class), def); -+ } -+ -+ public BlockPos readPos() { -+ Integer[] pos = {read(Integer.class), read(Integer.class), read(Integer.class)}; -+ for (Integer po : pos) { -+ if (po == null) { -+ return null; -+ } -+ } -+ return new BlockPos(pos[0], pos[1], pos[2]); -+ } -+ -+ public Vector readVector() { -+ Double[] pos = {read(Double.class), read(Double.class), read(Double.class)}; -+ for (Double po : pos) { -+ if (po == null) { -+ return null; -+ } -+ } -+ return new Vector(pos[0], pos[1], pos[2]); -+ } -+ -+ public T read(Class tClass) { -+ if (result.isEmpty()) { -+ return null; -+ } -+ -+ Object obj = result.remove(0); -+ if (tClass.isInstance(obj)) { -+ return tClass.cast(obj); -+ } else { -+ return null; -+ } -+ } -+ -+} -diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java b/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java -new file mode 100644 -index 0000000000000000000000000000000000000000..edf12195c7224ca2fb5d3c2ac3fcf485d3049d07 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgumentType.java -@@ -0,0 +1,37 @@ -+package top.leavesmc.leaves.command; -+ -+import org.jetbrains.annotations.NotNull; -+ -+public abstract class CommandArgumentType { -+ -+ public static final CommandArgumentType INTEGER = new CommandArgumentType<>() { -+ @Override -+ public Integer pasre(@NotNull String arg) { -+ try { -+ return Integer.parseInt(arg); -+ } catch (NumberFormatException e) { -+ return null; -+ } -+ } -+ }; -+ -+ public static final CommandArgumentType DOUBLE = new CommandArgumentType<>() { -+ @Override -+ public Double pasre(@NotNull String arg) { -+ try { -+ return Double.parseDouble(arg); -+ } catch (NumberFormatException e) { -+ return null; -+ } -+ } -+ }; -+ -+ public static final CommandArgumentType STRING = new CommandArgumentType<>() { -+ @Override -+ public String pasre(@NotNull String arg) { -+ return arg; -+ } -+ }; -+ -+ public abstract E pasre(@NotNull String arg); -+} diff --git a/patches/server/0055-Leaves-fakeplayer-support.patch b/patches/server/0055-Leaves-fakeplayer-support.patch deleted file mode 100644 index 2213994..0000000 --- a/patches/server/0055-Leaves-fakeplayer-support.patch +++ /dev/null @@ -1,3396 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 6 Feb 2024 04:26:57 +0000 -Subject: [PATCH] Leaves fakeplayer support - - -diff --git a/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java b/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java -index 3f3fd8b1881106f893ffb677272e50d77cbb6626..60be05f46fc19c8dc69afd8f1eb9dc7a6ae8e01d 100644 ---- a/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java -+++ b/src/main/java/io/papermc/paper/threadedregions/RegionShutdownThread.java -@@ -124,6 +124,8 @@ public final class RegionShutdownThread extends TickThread { - - @Override - public final void run() { -+ top.leavesmc.leaves.bot.ServerBot.saveOrRemoveAllBot(); // Leaves - save or remove bot -+ - // await scheduler termination - LOGGER.info("Awaiting scheduler termination for 60s"); - if (TickRegions.getScheduler().halt(true, TimeUnit.SECONDS.toNanos(60L))) { -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 3f560bd27c5a43c5681b50492e04290dda51f37e..6d2318f31a38d5111679ab1bc8f7a474d44f86ed 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -73,7 +73,17 @@ public class LuminolConfig { - public static boolean syncmaticaProtocol = false; - public static boolean syncmaticaQuota = false; - public static int syncmaticaQuotaLimit = 32767; -- -+ public static boolean fakeplayerSupport = false; -+ public static boolean fakeplayerSkipSleep = false; -+ public static boolean fakeplayerSpawnPhantom = true; -+ public static boolean alwaysSendFakeplayerData = true; -+ public static int fakeplayerLimit = 20; -+ public static List unableFakeplayerNames = List.of("player-name"); -+ public static String fakeplayerPrefix = ""; -+ public static String fakeplayerSuffix = ""; -+ public static boolean fakeplayerResident = false; -+ public static boolean openFakeplayerInventory = false; -+ public static double fakeplayerRegenAmount = 0.010; - - - public static void init() throws IOException { -@@ -90,6 +100,23 @@ public class LuminolConfig { - MAIN_CONFIG.save(); - } - -+ public static void initFakePlayer(){ -+ fakeplayerSupport = get("gameplay.fakeplayer.enabled",fakeplayerSupport); -+ fakeplayerLimit = get("gameplay.fakeplayer.max_count",fakeplayerLimit); -+ fakeplayerPrefix = get("gameplay.fakeplayer.name_prefix",fakeplayerPrefix); -+ fakeplayerSuffix = get("gameplay.fakeplayer.name_suffix",fakeplayerSuffix); -+ fakeplayerSkipSleep = get("gameplay.fakeplayer.fakeplayer_skip_sleep",fakeplayerSkipSleep); -+ fakeplayerResident = get("gameplay.fakeplayer.resident",fakeplayerResident); -+ fakeplayerSpawnPhantom = get("gameplay.fakeplayer.spawn_phantom_for_fakeplayer",fakeplayerSpawnPhantom); -+ fakeplayerRegenAmount = Double.parseDouble(get("gameplay.fakeplayer.regen_amount",String.valueOf(fakeplayerRegenAmount))); -+ unableFakeplayerNames = get("gameplay.fakeplayer.name_black_list",unableFakeplayerNames); -+ -+ if (fakeplayerSupport){ -+ MinecraftServer.getServer().server.getCommandMap().register("bot", "Leaves", new top.leavesmc.leaves.bot.BotCommand("bot")); -+ top.leavesmc.leaves.bot.agent.Actions.registerAll(); -+ } -+ } -+ - public static void initTpsbar(){ - if (tpsbarEnabled){ - GlobalServerTpsBar.init(); -@@ -212,6 +239,7 @@ public class LuminolConfig { - syncmaticaProtocol = get("gameplay.syncmatica_protocol",syncmaticaProtocol); - syncmaticaQuota = get("gameplay.syncmatica_protocol_quota",syncmaticaQuota); - syncmaticaQuotaLimit = get("gameplay.syncmatica_protocol_quota_limit",syncmaticaQuotaLimit); -+ initFakePlayer(); - } - - public static T get(String key,T def){ -diff --git a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -index a327973e37b5b8d4e15683ef24548482ac3dc3d5..65d82963d611a6dbbd7ca58d363854e4fad59230 100644 ---- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -+++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java -@@ -42,6 +42,7 @@ public abstract class SimpleCriterionTrigger predicate) { -+ if (player instanceof top.leavesmc.leaves.bot.ServerBot) return; // Leaves - bot skip - PlayerAdvancements playerAdvancements = player.getAdvancements(); - Set> set = (Set) playerAdvancements.criterionData.get(this); // Paper - fix AdvancementDataPlayer leak - if (set != null && !set.isEmpty()) { -diff --git a/src/main/java/net/minecraft/network/Connection.java b/src/main/java/net/minecraft/network/Connection.java -index 14c82f0903d08e289cec49d095af986b83b500aa..f8e9d43336cc2ff26ad0c47479ce07c5e5eda5c2 100644 ---- a/src/main/java/net/minecraft/network/Connection.java -+++ b/src/main/java/net/minecraft/network/Connection.java -@@ -365,6 +365,14 @@ public class Connection extends SimpleChannelInboundHandler> { - } - } - -+ // Leaves start - fakeplayer -+ public void setListenerForce(PacketListener packetListener) { -+ Validate.notNull(packetListener, "packetListener"); -+ this.packetListener = packetListener; -+ this.disconnectListener = null; -+ } -+ // Leaves end - fakeplayer -+ - public void setListenerForServerboundHandshake(PacketListener packetListener) { - if (this.packetListener != null) { - throw new IllegalStateException("Listener already set"); -diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index 76522b9fd7c0aaa17ab6df2183dfb30da2a35a68..e491559873b2d4f8da2e90b85fe070c8b93d90f3 100644 ---- a/src/main/java/net/minecraft/server/MinecraftServer.java -+++ b/src/main/java/net/minecraft/server/MinecraftServer.java -@@ -712,6 +712,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop loot = new java.util.ArrayList<>(this.getInventory().getContainerSize()); // Paper - Restore vanilla drops behavior - boolean keepInventory = this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator(); - -- if (!keepInventory) { -+ if (!keepInventory || this instanceof ServerBot) { // Leaves - skip bot - for (ItemStack item : this.getInventory().getContents()) { - if (!item.isEmpty() && !EnchantmentHelper.hasVanishingCurse(item)) { - loot.add(new DefaultDrop(item, stack -> this.drop(stack, true, false, false))); // Paper - Restore vanilla drops behavior; drop function taken from Inventory#dropAll (don't fire drop event) -@@ -1733,6 +1739,13 @@ public class ServerPlayer extends Player { - this.lastSentHealth = -1.0F; - this.lastSentFood = -1; - -+ // Leaves start - bot support -+ if (me.earthme.luminol.LuminolConfig.fakeplayerSupport) { -+ ServerBot.getBots().forEach(bot1 -> -+ bot1.sendFakeDataIfNeed(this, true)); // Leaves - render bot -+ } -+ // Leaves end - bot support -+ - // CraftBukkit start - PlayerChangedWorldEvent changeEvent = new PlayerChangedWorldEvent(this.getBukkitEntity(), worldserver1.getWorld()); - this.level().getCraftServer().getPluginManager().callEvent(changeEvent); -diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 7dbd4dad666a0d43e9116f4e3d56faaec427112b..cb4acce1c458331f7e1db423a446f8b337bdfe57 100644 ---- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -+++ b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java -@@ -297,7 +297,13 @@ public class ServerGamePacketListenerImpl extends ServerCommonPacketListenerImpl - public ServerGamePacketListenerImpl(MinecraftServer server, Connection connection, ServerPlayer player, CommonListenerCookie clientData) { - super(server, connection, clientData, player); // CraftBukkit - this.chunkSender = new PlayerChunkSender(connection.isMemoryConnection()); -- connection.setListener(this); -+ // Leaves start - fakeplayer -+ if (player instanceof top.leavesmc.leaves.bot.ServerBot) { -+ connection.setListenerForce(this); -+ } else { -+ connection.setListener(this); -+ } -+ // Leaves end - fakeplayer - this.player = player; - player.connection = this; - player.getTextFilter().join(); -diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java -index c8c72cefba44ce8587a9ae22f5a87d3199f8ca5f..f3b71d9761d4ef1a6b9a8d07cd46ea921235efe0 100644 ---- a/src/main/java/net/minecraft/server/players/PlayerList.java -+++ b/src/main/java/net/minecraft/server/players/PlayerList.java -@@ -121,6 +121,8 @@ import org.bukkit.event.player.PlayerRespawnEvent.RespawnReason; - import org.bukkit.event.player.PlayerSpawnChangeEvent; - // CraftBukkit end - -+import top.leavesmc.leaves.bot.ServerBot; -+ - public abstract class PlayerList { - - public static final File USERBANLIST_FILE = new File("banned-players.json"); -@@ -435,6 +437,21 @@ public abstract class PlayerList { - - top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol - -+ // Leaves start - bot support -+ if (me.earthme.luminol.LuminolConfig.fakeplayerSupport) { -+ ServerBot bot = ServerBot.getBot(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); -+ if (bot != null) { -+ bot.die(bot.damageSources().fellOutOfWorld()); // Leaves - remove bot with the same name -+ this.playersByName.put(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT), player); -+ this.playersByUUID.put(player.getUUID(), player); -+ } -+ ServerBot.getBots().forEach(bot1 -> { -+ bot1.sendPlayerInfo(player); -+ bot1.sendFakeDataIfNeed(player, true); -+ }); // Leaves - render bot -+ } -+ // Leaves end - bot support -+ - final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage(); - - if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure -@@ -1088,6 +1105,13 @@ public abstract class PlayerList { - } - // Paper end - Add PlayerPostRespawnEvent - -+ // Leaves start - bot support -+ if (me.earthme.luminol.LuminolConfig.fakeplayerSupport) { -+ ServerBot.getBots().forEach(bot1 -> -+ bot1.sendFakeDataIfNeed(entityplayer1, true)); // Leaves - render bot -+ } -+ // Leaves end - bot support -+ - // CraftBukkit end - return entityplayer1; - } -@@ -1203,12 +1227,17 @@ public abstract class PlayerList { - - public String[] getPlayerNamesArray() { - List players = new java.util.ArrayList<>(this.players); // Folia start - region threading -- String[] astring = new String[players.size()]; -+ String[] astring = new String[players.size() + ServerBot.getBots().size()]; - - for (int i = 0; i < players.size(); ++i) { - astring[i] = ((ServerPlayer) players.get(i)).getGameProfile().getName(); - // Folia end - region threading - } -+ // Leaves start - fakeplayer support -+ for (int i = this.players.size(); i < astring.length; ++i) { -+ astring[i] = ((ServerPlayer) ServerBot.getBots().get(i - this.players.size())).getGameProfile().getName(); -+ } -+ // Leaves end - fakeplayer support - - return astring; - } -@@ -1719,4 +1748,16 @@ public abstract class PlayerList { - public boolean isAllowCheatsForAllPlayers() { - return this.allowCheatsForAllPlayers; - } -+ -+ // Leaves start - fakeplayer support -+ public void addNewBot(ServerBot bot) { -+ playersByName.put(bot.getScoreboardName().toLowerCase(java.util.Locale.ROOT), bot); -+ playersByUUID.put(bot.getUUID(), bot); -+ } -+ -+ public void removeBot(ServerBot bot) { -+ playersByName.remove(bot.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); -+ playersByUUID.remove(bot.getUUID()); -+ } -+ // Leaves end - fakeplayer support - } -diff --git a/src/main/java/net/minecraft/world/entity/Entity.java b/src/main/java/net/minecraft/world/entity/Entity.java -index 2016547a88e5f8c0a7f1913c74b22e04cfa9b089..11e992e88dc9e7a268535d356eab1e60db57b7ac 100644 ---- a/src/main/java/net/minecraft/world/entity/Entity.java -+++ b/src/main/java/net/minecraft/world/entity/Entity.java -@@ -1499,7 +1499,7 @@ public abstract class Entity implements Nameable, EntityAccess, CommandSource, S - return offsetFactor; - } - -- private Vec3 collide(Vec3 movement) { -+ public Vec3 collide(Vec3 movement) { // Leaves - private -> public - // Paper start - optimise collisions - final boolean xZero = movement.x == 0.0; - final boolean yZero = movement.y == 0.0; -diff --git a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -index 702949d3d4c46222d2ef8227a559acd54d399bc0..7eb451df26f7bb7886e0392df485844558cca94f 100644 ---- a/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -+++ b/src/main/java/net/minecraft/world/entity/projectile/FishingHook.java -@@ -61,7 +61,7 @@ public class FishingHook extends Projectile { - public static final EntityDataAccessor DATA_HOOKED_ENTITY = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.INT); - private static final EntityDataAccessor DATA_BITING = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.BOOLEAN); - private int life; -- private int nibble; -+ public int nibble; // Leaves - private -> public - public int timeUntilLured; - private int timeUntilHooked; - private float fishAngle; -diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -index 48f634a7521d31c1e9dfd3cfc83139d428dbd37a..7cef5c518207752f7e1bfdd5bbec55fe9fafca6b 100644 ---- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -406,6 +406,8 @@ public abstract class AbstractContainerMenu { - ItemStack itemstack1; - int l; - -+ if (!doClickCheck(slotIndex, button, actionType, player)) return; // Leaves - doClick check -+ - if (actionType == ClickType.QUICK_CRAFT) { - int i1 = this.quickcraftStatus; - -@@ -680,6 +682,23 @@ public abstract class AbstractContainerMenu { - - } - -+ // Leaves start - doClick check -+ private boolean doClickCheck(int slotIndex, int button, ClickType actionType, Player player) { -+ if (slotIndex < 0) { -+ return true; -+ } -+ -+ Slot slot = getSlot(slotIndex); -+ ItemStack itemStack = slot.getItem(); -+ if (itemStack.getTag() != null) { -+ if (itemStack.getTag().get("Leaves.Gui.Placeholder") != null) { -+ return !itemStack.getTag().getBoolean("Leaves.Gui.Placeholder"); -+ } -+ } -+ return true; -+ } -+ // Leaves end - doClick check -+ - private boolean tryItemClickBehaviourOverride(Player player, ClickAction clickType, Slot slot, ItemStack stack, ItemStack cursorStack) { - FeatureFlagSet featureflagset = player.level().enabledFeatures(); - -diff --git a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -index b52455178290dd27478da4c062863562942ae2ba..1bc7a0265e3f55c4cdf051af76775876ae2c7b20 100644 ---- a/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -+++ b/src/main/java/net/minecraft/world/level/levelgen/PhantomSpawner.java -@@ -70,6 +70,11 @@ public class PhantomSpawner implements CustomSpawner { - ServerStatsCounter serverstatisticmanager = entityplayer.getStats(); - int j = Mth.clamp(serverstatisticmanager.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE); - boolean flag2 = true; -+ // Leaves start - fakeplayer spawn -+ if (entityplayer instanceof top.leavesmc.leaves.bot.ServerBot bot && bot.spawnPhantom) { -+ j = bot.notSleepTicks; -+ } -+ // Leaves end - fakeplayer spawn - - if (randomsource.nextInt(j) >= world.paperConfig().entities.behavior.playerInsomniaStartTicks) { // Paper - Ability to control player's insomnia and phantoms - BlockPos blockposition1 = blockposition.above(20 + randomsource.nextInt(15)).east(-10 + randomsource.nextInt(21)).south(-10 + randomsource.nextInt(21)); -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -index 23cd0290f8939aec85b5699feb6ac7f12bde14a7..ad339a085f8e5fc86cfe4c4064f56080adc8427d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java -@@ -259,6 +259,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor; - import org.yaml.snakeyaml.error.MarkedYAMLException; - - import net.md_5.bungee.api.chat.BaseComponent; // Spigot -+import top.leavesmc.leaves.entity.CraftBotManager; - - import javax.annotation.Nullable; // Paper - import javax.annotation.Nonnull; // Paper -@@ -305,6 +306,7 @@ public final class CraftServer implements Server { - public static Exception excessiveVelEx; // Paper - Velocity warnings - private final io.papermc.paper.logging.SysoutCatcher sysoutCatcher = new io.papermc.paper.logging.SysoutCatcher(); // Paper - private final CraftPotionBrewer potionBrewer = new CraftPotionBrewer(); // Paper - Custom Potion Mixes -+ private final CraftBotManager botManager = new CraftBotManager(); - - // Paper start - Folia region threading API - private final io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FoliaRegionScheduler(); // Folia - region threading -@@ -3274,4 +3276,11 @@ public final class CraftServer implements Server { - } - - // Paper end -+ -+ //Leaves start - Bot API -+ @Override -+ public CraftBotManager getBotManager() { -+ return botManager; -+ } -+ // Leaves end - Bot API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -index 5adbfb278aed3c32b6d4992b8932cc3dafd8f9cc..1aba799113d9848256ed83a44c904d8a59b2e114 100644 ---- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java -@@ -54,6 +54,8 @@ import org.bukkit.plugin.Plugin; - import org.bukkit.util.BoundingBox; - import org.bukkit.util.NumberConversions; - import org.bukkit.util.Vector; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.entity.CraftBot; - - import net.md_5.bungee.api.chat.BaseComponent; // Spigot - -@@ -91,6 +93,8 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { - return new CraftHumanEntity(server, (net.minecraft.world.entity.player.Player) entity); - } - -+ if (entity instanceof ServerBot) { return new CraftBot(server, (ServerBot) entity); } -+ - // Special case complex part, since there is no extra entity type for them - if (entity instanceof EnderDragonPart complexPart) { - if (complexPart.parentMob instanceof EnderDragon) { -diff --git a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4563284facbfd01733d6a0efdfe7d0cabebdc1e7 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java -@@ -0,0 +1,330 @@ -+package top.leavesmc.leaves.bot; -+ -+import org.bukkit.Bukkit; -+import org.bukkit.ChatColor; -+import org.bukkit.Location; -+import org.bukkit.World; -+import org.bukkit.command.Command; -+import org.bukkit.command.CommandSender; -+import org.bukkit.command.ConsoleCommandSender; -+import org.bukkit.craftbukkit.entity.CraftPlayer; -+import org.bukkit.entity.Player; -+import org.bukkit.generator.WorldInfo; -+import org.bukkit.permissions.Permission; -+import org.bukkit.permissions.PermissionDefault; -+import org.bukkit.plugin.PluginManager; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.agent.Actions; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.bot.agent.actions.CraftCustomBotAction; -+import top.leavesmc.leaves.entity.Bot; -+ -+import java.util.ArrayList; -+import java.util.HashMap; -+import java.util.List; -+import java.util.Map; -+ -+public class BotCommand extends Command { -+ -+ public BotCommand(String name) { -+ super(name); -+ this.description = "FakePlayer Command"; -+ this.usageMessage = "/bot [create | remove | action | list]"; -+ this.setPermission("bukkit.command.bot"); -+ final PluginManager pluginManager = Bukkit.getServer().getPluginManager(); -+ if (pluginManager.getPermission("bukkit.command.bot") == null) { -+ pluginManager.addPermission(new Permission("bukkit.command.bot", PermissionDefault.OP)); -+ } -+ } -+ -+ @Override -+ public @NotNull List tabComplete(@NotNull CommandSender sender, @NotNull String alias, String @NotNull [] args, Location location) throws IllegalArgumentException { -+ var list = new ArrayList(); -+ -+ if (args.length <= 1) { -+ list.add("create"); -+ list.add("remove"); -+ list.add("action"); -+ list.add("config"); -+ list.add("list"); -+ } -+ -+ if (args.length == 2) { -+ switch (args[0]) { -+ case "create" -> list.add(""); -+ case "remove", "action", "config" -> -+ list.addAll(ServerBot.getBots().stream().map(e -> e.getName().getString()).toList()); -+ case "list" -> list.addAll(Bukkit.getWorlds().stream().map(WorldInfo::getName).toList()); -+ } -+ } -+ -+ if (args.length == 3) { -+ switch (args[0]) { -+ case "action" -> { -+ list.add("list"); -+ list.addAll(Actions.getNames()); -+ } -+ case "create" -> list.add(""); -+ case "config" -> list.addAll(acceptConfig); -+ } -+ } -+ -+ if (args.length == 4) { -+ switch (args[0]) { -+ case "config" -> { -+ list.add("true"); -+ list.add("false"); -+ } -+ } -+ } -+ -+ if (args.length >= 4 && args[0].equals("action")) { -+ BotAction action = Actions.getForName(args[2]); -+ if (action != null) { -+ list.addAll(action.getArgument().tabComplete(args.length - 4)); -+ } -+ } -+ -+ return list; -+ } -+ -+ @Override -+ public boolean execute(@NotNull CommandSender sender, @NotNull String commandLabel, String[] args) { -+ if (!testPermission(sender) || !me.earthme.luminol.LuminolConfig.fakeplayerSupport) return true; -+ -+ if (args.length == 0) { -+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); -+ return false; -+ } -+ -+ switch (args[0]) { -+ case "create" -> this.onCreate(sender, args); -+ -+ case "remove" -> this.onRemove(sender, args); -+ -+ case "action" -> this.onAction(sender, args); -+ -+ case "config" -> this.onConfig(sender, args); -+ -+ case "list" -> this.onList(sender, args); -+ -+ default -> { -+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage); -+ return false; -+ } -+ } -+ -+ return true; -+ } -+ -+ private void onCreate(CommandSender sender, String @NotNull [] args) { -+ if (args.length < 2) { -+ sender.sendMessage(ChatColor.RED + "Use /bot create [skin_name] to create a fakeplayer"); -+ return; -+ } -+ -+ if (canCreate(sender, args[1])) { -+ if (sender instanceof Player player) { -+ new ServerBot.BotCreateState(player.getLocation(), args[1], args.length < 3 ? args[1] : args[2]).createAsync(bot -> bot.createPlayer = player.getUniqueId()); -+ } else if (sender instanceof ConsoleCommandSender) { -+ if (args.length < 6) { -+ sender.sendMessage(ChatColor.RED + "Use /bot create to create a fakeplayer"); -+ return; -+ } -+ -+ try { -+ World world = Bukkit.getWorld(args[3]); -+ double x = Double.parseDouble(args[4]); -+ double y = Double.parseDouble(args[5]); -+ double z = Double.parseDouble(args[6]); -+ -+ if (world != null) { -+ new ServerBot.BotCreateState(new Location(world, x, y, z), args[1], args[2]).createAsync(null); -+ } -+ } catch (Exception e) { -+ e.printStackTrace(); -+ } -+ } -+ } -+ } -+ -+ private boolean canCreate(CommandSender sender, @NotNull String name) { -+ if (!name.matches("^[a-zA-Z0-9_]{4,16}$")) { -+ sender.sendMessage(ChatColor.RED + "This name is illegal"); -+ return false; -+ } -+ -+ if (Bukkit.getPlayer(name) != null || ServerBot.getBot(name) != null) { -+ sender.sendMessage(ChatColor.RED + "This player is in server"); -+ return false; -+ } -+ -+ if (me.earthme.luminol.LuminolConfig.unableFakeplayerNames.contains(name)) { -+ sender.sendMessage(ChatColor.RED + "This name is not allowed"); -+ return false; -+ } -+ -+ if (ServerBot.getBots().size() >= me.earthme.luminol.LuminolConfig.fakeplayerLimit) { -+ sender.sendMessage(ChatColor.RED + "Fakeplayer limit is full"); -+ return false; -+ } -+ -+ return true; -+ } -+ -+ private void onRemove(CommandSender sender, String @NotNull [] args) { -+ if (args.length < 2) { -+ sender.sendMessage(ChatColor.RED + "Use /bot remove to remove a fakeplayer"); -+ return; -+ } -+ -+ ServerBot bot = ServerBot.getBot(args[1]); -+ -+ if (bot == null) { -+ sender.sendMessage(ChatColor.RED + "This fakeplayer is not in server"); -+ return; -+ } -+ -+ bot.die(bot.damageSources().fellOutOfWorld()); -+ } -+ -+ private void onAction(CommandSender sender, String @NotNull [] args) { -+ if (args.length < 3) { -+ sender.sendMessage(ChatColor.RED + "Use /bot action to make fakeplayer do action"); -+ return; -+ } -+ -+ ServerBot bot = ServerBot.getBot(args[1]); -+ if (bot == null) { -+ sender.sendMessage(ChatColor.RED + "This fakeplayer is not in server"); -+ return; -+ } -+ -+ if (args[2].equals("list")) { -+ sender.sendMessage(bot.getScoreboardName() + "'s action list:"); -+ for (BotAction action : bot.getBotActions()) { -+ sender.sendMessage(action.getName()); -+ } -+ return; -+ } -+ -+ BotAction action = Actions.getForName(args[2]); -+ if (action == null) { -+ sender.sendMessage(ChatColor.RED + "Invalid action"); -+ return; -+ } -+ -+ CraftPlayer player; -+ if (sender instanceof CraftPlayer) { -+ player = (CraftPlayer) sender; -+ } else { -+ player = bot.getBukkitEntity(); -+ } -+ -+ BotAction newAction; -+ if (action instanceof CraftCustomBotAction customBotAction) { -+ String[] realArgs = new String[args.length - 3]; -+ if (realArgs.length != 0) { -+ System.arraycopy(args, 3, realArgs, 0, realArgs.length); -+ } -+ newAction = customBotAction.getNew(player, realArgs); -+ } else { -+ newAction = action.getNew(player.getHandle(), action.getArgument().parse(3, args)); -+ } -+ -+ if (newAction == null) { -+ sender.sendMessage(ChatColor.RED + "Action create error, please check your arguments"); -+ return; -+ } -+ -+ bot.setBotAction(newAction); -+ sender.sendMessage("Action " + action.getName() + " has been issued to " + bot.getName().getString()); -+ } -+ -+ private static final List acceptConfig = List.of("skip_sleep", "spawn_phantom", "always_send_data"); -+ -+ private void onConfig(CommandSender sender, String @NotNull [] args) { -+ if (args.length < 3) { -+ sender.sendMessage(ChatColor.RED + "Use /bot config to modify fakeplayer's config"); -+ return; -+ } -+ -+ ServerBot bot = ServerBot.getBot(args[1]); -+ if (bot == null) { -+ sender.sendMessage(ChatColor.RED + "This fakeplayer is not in server"); -+ return; -+ } -+ -+ if (!acceptConfig.contains(args[2])) { -+ sender.sendMessage(ChatColor.RED + "This config is not accept"); -+ return; -+ } -+ -+ if (args.length < 4) { -+ switch (args[2]) { -+ case "skip_sleep" -> sender.sendMessage(bot.getScoreboardName() + "'s skip_sleep: " + bot.fauxSleeping); -+ case "spawn_phantom" -> { -+ sender.sendMessage(bot.getScoreboardName() + "'s spawn_phantom: " + bot.spawnPhantom); -+ if (bot.spawnPhantom) { -+ sender.sendMessage(bot.getScoreboardName() + "'s not_sleeping_ticks: " + bot.notSleepTicks); -+ } -+ } -+ case "always_send_data" -> -+ sender.sendMessage(bot.getScoreboardName() + "'s always_send_data: " + bot.alwaysSendData); -+ } -+ } else { -+ boolean value = args[3].equals("true"); -+ switch (args[2]) { -+ case "skip_sleep" -> bot.fauxSleeping = value; -+ case "spawn_phantom" -> bot.spawnPhantom = value; -+ case "always_send_data" -> bot.alwaysSendData = value; -+ } -+ sender.sendMessage(bot.getScoreboardName() + "'s " + args[2] + " changed: " + value); -+ } -+ } -+ -+ private void onList(CommandSender sender, String @NotNull [] args) { -+ if (args.length < 2) { -+ Map> botMap = new HashMap<>(); -+ for (World world : Bukkit.getWorlds()) { -+ botMap.put(world, new ArrayList<>()); -+ } -+ -+ for (ServerBot bot : ServerBot.getBots()) { -+ Bot bukkitBot = bot.getBukkitPlayer(); -+ botMap.get(bukkitBot.getWorld()).add(bukkitBot.getName()); -+ } -+ -+ sender.sendMessage("Total number: (" + ServerBot.getBots().size() + "/" + me.earthme.luminol.LuminolConfig.fakeplayerLimit + ")"); -+ for (World world : botMap.keySet()) { -+ sender.sendMessage(world.getName() + "(" + botMap.get(world).size() + "): " + formatPlayerNameList(botMap.get(world))); -+ } -+ } else { -+ World world = Bukkit.getWorld(args[2]); -+ -+ if (world == null) { -+ sender.sendMessage(ChatColor.RED + "Unknown world"); -+ return; -+ } -+ -+ List botList = new ArrayList<>(); -+ for (ServerBot bot : ServerBot.getBots()) { -+ Bot bukkitBot = bot.getBukkitPlayer(); -+ if (bukkitBot.getWorld() == world) { -+ botList.add(bukkitBot.getName()); -+ } -+ } -+ -+ sender.sendMessage(world.getName() + "(" + botList.size() + "): " + formatPlayerNameList(botList)); -+ } -+ } -+ -+ @NotNull -+ private static String formatPlayerNameList(@NotNull List list) { -+ if (list.isEmpty()) { -+ return ""; -+ } -+ String string = list.toString(); -+ return string.substring(1, string.length() - 1); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/BotInventoryContainer.java b/src/main/java/top/leavesmc/leaves/bot/BotInventoryContainer.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b83ad5bf2a338d589eb200d3f3b3153571ba2cad ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/BotInventoryContainer.java -@@ -0,0 +1,180 @@ -+package top.leavesmc.leaves.bot; -+ -+import com.google.common.collect.ImmutableList; -+import com.mojang.datafixers.util.Pair; -+import net.minecraft.core.NonNullList; -+import net.minecraft.network.chat.Component; -+import net.minecraft.world.ContainerHelper; -+import net.minecraft.world.SimpleContainer; -+import net.minecraft.world.entity.player.Player; -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.item.Items; -+ -+import javax.annotation.Nonnull; -+import java.util.List; -+ -+// Power by gugle-carpet-addition(https://github.com/Gu-ZT/gugle-carpet-addition) -+public class BotInventoryContainer extends SimpleContainer { -+ -+ public final NonNullList items; -+ public final NonNullList armor; -+ public final NonNullList offhand; -+ private final List> compartments; -+ private final NonNullList buttons = NonNullList.withSize(13, ItemStack.EMPTY); -+ private final ServerBot player; -+ -+ public BotInventoryContainer(ServerBot player) { -+ this.player = player; -+ this.items = this.player.getInventory().items; -+ this.armor = this.player.getInventory().armor; -+ this.offhand = this.player.getInventory().offhand; -+ this.compartments = ImmutableList.of(this.items, this.armor, this.offhand, this.buttons); -+ createButton(); -+ } -+ -+ @Override -+ public int getContainerSize() { -+ return this.items.size() + this.armor.size() + this.offhand.size() + this.buttons.size(); -+ } -+ -+ @Override -+ public boolean isEmpty() { -+ for (ItemStack itemStack : this.items) { -+ if (itemStack.isEmpty()) { -+ continue; -+ } -+ return false; -+ } -+ for (ItemStack itemStack : this.armor) { -+ if (itemStack.isEmpty()) { -+ continue; -+ } -+ return false; -+ } -+ for (ItemStack itemStack : this.offhand) { -+ if (itemStack.isEmpty()) { -+ continue; -+ } -+ return false; -+ } -+ return true; -+ } -+ -+ @Override -+ @Nonnull -+ public ItemStack getItem(int slot) { -+ Pair, Integer> pair = getItemSlot(slot); -+ if (pair != null) { -+ return pair.getFirst().get(pair.getSecond()); -+ } else { -+ return ItemStack.EMPTY; -+ } -+ } -+ -+ public Pair, Integer> getItemSlot(int slot) { -+ switch (slot) { -+ case 0 -> { -+ return new Pair<>(buttons, 0); -+ } -+ case 1, 2, 3, 4 -> { -+ return new Pair<>(armor, 4 - slot); -+ } -+ case 5, 6 -> { -+ return new Pair<>(buttons, slot - 4); -+ } -+ case 7 -> { -+ return new Pair<>(offhand, 0); -+ } -+ case 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 -> { -+ return new Pair<>(buttons, slot - 5); -+ } -+ case 18, 19, 20, 21, 22, 23, 24, 25, 26, -+ 27, 28, 29, 30, 31, 32, 33, 34, 35, -+ 36, 37, 38, 39, 40, 41, 42, 43, 44 -> { -+ return new Pair<>(items, slot - 9); -+ } -+ case 45, 46, 47, 48, 49, 50, 51, 52, 53 -> { -+ return new Pair<>(items, slot - 45); -+ } -+ default -> { -+ return null; -+ } -+ } -+ } -+ -+ @Override -+ @Nonnull -+ public ItemStack removeItem(int slot, int amount) { -+ Pair, Integer> pair = getItemSlot(slot); -+ NonNullList list = null; -+ ItemStack itemStack = ItemStack.EMPTY; -+ if (pair != null) { -+ list = pair.getFirst(); -+ slot = pair.getSecond(); -+ } -+ if (list != null && !list.get(slot).isEmpty()) { -+ itemStack = ContainerHelper.removeItem(list, slot, amount); -+ player.detectEquipmentUpdatesPublic(); -+ } -+ return itemStack; -+ } -+ -+ @Override -+ @Nonnull -+ public ItemStack removeItemNoUpdate(int slot) { -+ Pair, Integer> pair = getItemSlot(slot); -+ NonNullList list = null; -+ if (pair != null) { -+ list = pair.getFirst(); -+ slot = pair.getSecond(); -+ } -+ if (list != null && !list.get(slot).isEmpty()) { -+ ItemStack itemStack = list.get(slot); -+ list.set(slot, ItemStack.EMPTY); -+ return itemStack; -+ } -+ return ItemStack.EMPTY; -+ } -+ -+ @Override -+ public void setItem(int slot, @Nonnull ItemStack stack) { -+ Pair, Integer> pair = getItemSlot(slot); -+ NonNullList list = null; -+ if (pair != null) { -+ list = pair.getFirst(); -+ slot = pair.getSecond(); -+ } -+ if (list != null) { -+ list.set(slot, stack); -+ player.detectEquipmentUpdatesPublic(); -+ } -+ } -+ -+ @Override -+ public void setChanged() { -+ } -+ -+ @Override -+ public boolean stillValid(@Nonnull Player player) { -+ if (this.player.isRemoved()) { -+ return false; -+ } -+ return !(player.distanceToSqr(this.player) > 64.0); -+ } -+ -+ @Override -+ public void clearContent() { -+ for (List list : this.compartments) { -+ list.clear(); -+ } -+ } -+ -+ private void createButton() { -+ for (int i = 0; i < 13; i++) { -+ ItemStack button = new ItemStack(Items.STRUCTURE_VOID); -+ button.setHoverName(Component.empty()); -+ button.getOrCreateTag().putBoolean("Leaves.Gui.Placeholder", true); -+ buttons.set(i, button); -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/BotStatsCounter.java b/src/main/java/top/leavesmc/leaves/bot/BotStatsCounter.java -new file mode 100644 -index 0000000000000000000000000000000000000000..c3f114fba0759221b5fea0ccc4862f0579260cef ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/BotStatsCounter.java -@@ -0,0 +1,38 @@ -+package top.leavesmc.leaves.bot; -+ -+import com.mojang.datafixers.DataFixer; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.stats.ServerStatsCounter; -+import net.minecraft.stats.Stat; -+import net.minecraft.world.entity.player.Player; -+ -+import java.io.File; -+ -+public class BotStatsCounter extends ServerStatsCounter { -+ -+ private static final File UNKOWN_FILE = new File("BOT_STATS_REMOVE_THIS"); -+ -+ public BotStatsCounter(MinecraftServer server) { -+ super(server, UNKOWN_FILE); -+ } -+ -+ @Override -+ public void save() { -+ -+ } -+ -+ @Override -+ public void setValue(Player player, Stat stat, int value) { -+ -+ } -+ -+ @Override -+ public void parseLocal(DataFixer dataFixer, String json) { -+ -+ } -+ -+ @Override -+ public int getValue(Stat stat) { -+ return 0; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/BotUtil.java b/src/main/java/top/leavesmc/leaves/bot/BotUtil.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b0ad5ed3d2a179001312733b780dd532d3b4a001 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/BotUtil.java -@@ -0,0 +1,183 @@ -+package top.leavesmc.leaves.bot; -+ -+import com.google.common.base.Charsets; -+import com.google.gson.JsonArray; -+import com.google.gson.JsonElement; -+import com.google.gson.JsonObject; -+import net.minecraft.core.NonNullList; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.ListTag; -+import net.minecraft.nbt.NbtAccounter; -+import net.minecraft.nbt.NbtIo; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.world.entity.EquipmentSlot; -+import net.minecraft.world.item.ItemStack; -+import net.minecraft.world.level.storage.LevelResource; -+import org.bukkit.Bukkit; -+import org.bukkit.Location; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.agent.Actions; -+import top.leavesmc.leaves.bot.agent.BotAction; -+ -+import java.io.File; -+import java.io.IOException; -+import java.util.Collection; -+import java.util.Map; -+import java.util.UUID; -+ -+public class BotUtil { -+ -+ public static void replenishment(@NotNull ItemStack itemStack, NonNullList itemStackList) { -+ int count = itemStack.getMaxStackSize() / 2; -+ if (itemStack.getCount() <= 8 && count > 8) { -+ for (ItemStack itemStack1 : itemStackList) { -+ if (itemStack1 == ItemStack.EMPTY || itemStack1 == itemStack) { -+ continue; -+ } -+ -+ if (ItemStack.isSameItemSameTags(itemStack1, itemStack)) { -+ if (itemStack1.getCount() > count) { -+ itemStack.setCount(itemStack.getCount() + count); -+ itemStack1.setCount(itemStack1.getCount() - count); -+ } else { -+ itemStack.setCount(itemStack.getCount() + itemStack1.getCount()); -+ itemStack1.setCount(0); -+ } -+ break; -+ } -+ } -+ } -+ } -+ -+ public static void replaceTool(@NotNull EquipmentSlot slot, @NotNull ServerBot bot) { -+ ItemStack itemStack = bot.getItemBySlot(slot); -+ for (int i = 0; i < 36; i++) { -+ ItemStack itemStack1 = bot.getInventory().getItem(i); -+ if (itemStack1 == ItemStack.EMPTY || itemStack1 == itemStack) { -+ continue; -+ } -+ -+ if (itemStack1.getItem().getClass() == itemStack.getItem().getClass() && !isDamage(itemStack1, 10)) { -+ ItemStack itemStack2 = itemStack1.copy(); -+ bot.getInventory().setItem(i, itemStack); -+ bot.setItemSlot(slot, itemStack2); -+ return; -+ } -+ } -+ -+ for (int i = 0; i < 36; i++) { -+ ItemStack itemStack1 = bot.getInventory().getItem(i); -+ if (itemStack1 == ItemStack.EMPTY && itemStack1 != itemStack) { -+ bot.getInventory().setItem(i, itemStack); -+ bot.setItemSlot(slot, ItemStack.EMPTY); -+ return; -+ } -+ } -+ } -+ -+ public static boolean isDamage(@NotNull ItemStack item, int minDamage) { -+ return item.isDamageableItem() && (item.getMaxDamage() - item.getDamageValue()) <= minDamage; -+ } -+ -+ @NotNull -+ public static JsonObject saveBot(@NotNull ServerBot bot) { -+ double pos_x = bot.getX(); -+ double pos_y = bot.getY(); -+ double pos_z = bot.getZ(); -+ float yaw = bot.getYRot(); -+ float pitch = bot.getXRot(); -+ String dimension = bot.getLocation().getWorld().getName(); -+ String skin = bot.createState.skinName; -+ -+ JsonObject fakePlayer = new JsonObject(); -+ fakePlayer.addProperty("pos_x", pos_x); -+ fakePlayer.addProperty("pos_y", pos_y); -+ fakePlayer.addProperty("pos_z", pos_z); -+ fakePlayer.addProperty("yaw", yaw); -+ fakePlayer.addProperty("pitch", pitch); -+ fakePlayer.addProperty("dimension", dimension); -+ fakePlayer.addProperty("skin", skin); -+ -+ Collection actions = bot.getBotActions(); -+ JsonArray botActions = new JsonArray(); -+ for (BotAction action : actions) { -+ JsonObject actionObj = new JsonObject(); -+ actionObj.addProperty("name", action.getName()); -+ actionObj.addProperty("number", String.valueOf(action.getNumber())); -+ actionObj.addProperty("delay", String.valueOf(action.getTickDelay())); -+ botActions.add(actionObj); -+ } -+ fakePlayer.add("actions", botActions); -+ -+ CompoundTag invnbt = new CompoundTag(); -+ invnbt.put("Inventory", bot.getInventory().save(new ListTag())); -+ -+ File file = MinecraftServer.getServer().getWorldPath(LevelResource.ROOT).resolve("fakeplayer/" + bot.getStringUUID() + ".dat").toFile(); -+ File parent = file.getParentFile(); -+ try { -+ if (!parent.exists() || !parent.isDirectory()) { -+ parent.mkdirs(); -+ } -+ if (file.exists() && file.isFile()) { -+ file.delete(); -+ } -+ file.createNewFile(); -+ NbtIo.writeCompressed(invnbt, file.toPath()); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ -+ return fakePlayer; -+ } -+ -+ public static void loadBot(Map.@NotNull Entry entry) { -+ String username = entry.getKey(); -+ JsonObject fakePlayer = entry.getValue().getAsJsonObject(); -+ double pos_x = fakePlayer.get("pos_x").getAsDouble(); -+ double pos_y = fakePlayer.get("pos_y").getAsDouble(); -+ double pos_z = fakePlayer.get("pos_z").getAsDouble(); -+ float yaw = fakePlayer.get("yaw").getAsFloat(); -+ float pitch = fakePlayer.get("pitch").getAsFloat(); -+ String dimension = fakePlayer.get("dimension").getAsString(); -+ String skin = fakePlayer.get("skin").getAsString(); -+ -+ Location location = new Location(Bukkit.getWorld(dimension), pos_x, pos_y, pos_z, yaw, pitch); -+ ServerBot.BotCreateState state = new ServerBot.BotCreateState(location, username, skin); -+ -+ ListTag inv = null; -+ File file = MinecraftServer.getServer().getWorldPath(LevelResource.ROOT).resolve("fakeplayer/" + getBotUUID(state) + ".dat").toFile(); -+ if (file.exists()) { -+ try { -+ CompoundTag nbt = NbtIo.readCompressed(file.toPath(), NbtAccounter.unlimitedHeap()); -+ inv = nbt.getList("Inventory", 10); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ file.delete(); -+ } -+ -+ final JsonArray finalActions = fakePlayer.get("actions").getAsJsonArray(); -+ final ListTag finalInv = inv; -+ state.createAsync(serverBot -> { -+ if (finalInv != null) { -+ serverBot.getInventory().load(finalInv); -+ } -+ -+ for (JsonElement element : finalActions) { -+ JsonObject actionObj = element.getAsJsonObject(); -+ BotAction action = Actions.getForName(actionObj.get("name").getAsString()); -+ if (action != null) { -+ BotAction newAction = action.getNew(serverBot, -+ action.getArgument().parse(0, new String[]{actionObj.get("delay").getAsString(), actionObj.get("number").getAsString()}) -+ ); -+ serverBot.setBotAction(newAction); -+ } -+ } -+ }); -+ } -+ -+ @NotNull -+ public static UUID getBotUUID(ServerBot.@NotNull BotCreateState state) { -+ return UUID.nameUUIDFromBytes(("Fakeplayer:" + state.getRealName()).getBytes(Charsets.UTF_8)); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/MojangAPI.java b/src/main/java/top/leavesmc/leaves/bot/MojangAPI.java -new file mode 100644 -index 0000000000000000000000000000000000000000..daaece30b2a3983f1cc9ee9a851e8f373974d5ec ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/MojangAPI.java -@@ -0,0 +1,41 @@ -+package top.leavesmc.leaves.bot; -+ -+import com.google.gson.JsonObject; -+import com.google.gson.JsonParser; -+ -+import java.io.IOException; -+import java.io.InputStreamReader; -+import java.net.URL; -+import java.util.HashMap; -+import java.util.Map; -+ -+public class MojangAPI { -+ -+ private static final boolean CACHE_ENABLED = false; -+ -+ private static final Map CACHE = new HashMap<>(); -+ -+ public static String[] getSkin(String name) { -+ if (CACHE_ENABLED && CACHE.containsKey(name)) { -+ return CACHE.get(name); -+ } -+ -+ String[] values = pullFromAPI(name); -+ CACHE.put(name, values); -+ return values; -+ } -+ -+ // Laggggggggggggggggggggggggggggggggggggggggg -+ public static String[] pullFromAPI(String name) { -+ try { -+ String uuid = new JsonParser().parse(new InputStreamReader(new URL("https://api.mojang.com/users/profiles/minecraft/" + name) -+ .openStream())).getAsJsonObject().get("id").getAsString(); -+ JsonObject property = new JsonParser() -+ .parse(new InputStreamReader(new URL("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid + "?unsigned=false") -+ .openStream())).getAsJsonObject().get("properties").getAsJsonArray().get(0).getAsJsonObject(); -+ return new String[] {property.get("value").getAsString(), property.get("signature").getAsString()}; -+ } catch (IOException | IllegalStateException e) { -+ return null; -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/ServerBot.java b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java -new file mode 100644 -index 0000000000000000000000000000000000000000..daef37d0b1185657ce89a3ed5f2a76c1e135ce93 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java -@@ -0,0 +1,782 @@ -+package top.leavesmc.leaves.bot; -+ -+import com.google.common.collect.Lists; -+import com.google.gson.Gson; -+import com.google.gson.JsonElement; -+import com.google.gson.JsonObject; -+import com.mojang.authlib.GameProfile; -+import com.mojang.authlib.properties.Property; -+import io.papermc.paper.threadedregions.RegionizedServer; -+import io.papermc.paper.threadedregions.ThreadedRegionizer; -+import io.papermc.paper.threadedregions.TickRegionScheduler; -+import io.papermc.paper.util.TickThread; -+import net.minecraft.Util; -+import net.minecraft.core.BlockPos; -+import net.minecraft.network.Connection; -+import net.minecraft.network.PacketSendListener; -+import net.minecraft.network.protocol.Packet; -+import net.minecraft.network.protocol.PacketFlow; -+import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; -+import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; -+import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; -+import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; -+import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; -+import net.minecraft.network.syncher.EntityDataAccessor; -+import net.minecraft.network.syncher.EntityDataSerializers; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ClientInformation; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.server.network.CommonListenerCookie; -+import net.minecraft.server.network.ServerGamePacketListenerImpl; -+import net.minecraft.server.network.ServerPlayerConnection; -+import net.minecraft.stats.ServerStatsCounter; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.InteractionResult; -+import net.minecraft.world.SimpleMenuProvider; -+import net.minecraft.world.damagesource.DamageSource; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.entity.EntityType; -+import net.minecraft.world.entity.EquipmentSlot; -+import net.minecraft.world.entity.ai.attributes.Attributes; -+import net.minecraft.world.entity.item.ItemEntity; -+import net.minecraft.world.entity.player.Player; -+import net.minecraft.world.inventory.ChestMenu; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.level.gameevent.GameEvent; -+import net.minecraft.world.level.storage.LevelResource; -+import net.minecraft.world.phys.AABB; -+import net.minecraft.world.phys.Vec3; -+import org.bukkit.Bukkit; -+import org.bukkit.ChatColor; -+import org.bukkit.Location; -+import org.bukkit.Material; -+import org.bukkit.craftbukkit.CraftWorld; -+import org.bukkit.craftbukkit.scheduler.CraftScheduler; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.NotNull; -+import me.earthme.luminol.LuminolConfig; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.bot.agent.actions.StopAction; -+import top.leavesmc.leaves.entity.Bot; -+import top.leavesmc.leaves.entity.CraftBot; -+import top.leavesmc.leaves.event.bot.BotCreateEvent; -+import top.leavesmc.leaves.event.bot.BotInventoryOpenEvent; -+import top.leavesmc.leaves.event.bot.BotJoinEvent; -+import top.leavesmc.leaves.util.MathUtils; -+ -+import javax.annotation.Nullable; -+import java.io.BufferedReader; -+import java.io.BufferedWriter; -+import java.io.File; -+import java.io.IOException; -+import java.nio.charset.StandardCharsets; -+import java.nio.file.Files; -+import java.util.Collection; -+import java.util.EnumSet; -+import java.util.HashMap; -+import java.util.Iterator; -+import java.util.List; -+import java.util.Map; -+import java.util.UUID; -+import java.util.concurrent.CompletableFuture; -+import java.util.concurrent.CopyOnWriteArrayList; -+import java.util.function.Consumer; -+import java.util.function.Supplier; -+ -+// TODO remake all -+public class ServerBot extends ServerPlayer { -+ -+ private final Map actions; -+ private final boolean removeOnDeath; -+ private final int tracingRange; -+ -+ private Vec3 velocity; -+ private int fireTicks; -+ private int jumpTicks; -+ private int noFallTicks; -+ public boolean waterSwim; -+ private Vec3 knockback; -+ public BotCreateState createState; -+ public UUID createPlayer; -+ -+ private final ServerStatsCounter stats; -+ private final BotInventoryContainer container; -+ -+ private static final List bots = new CopyOnWriteArrayList<>(); -+ -+ public boolean spawnPhantom; -+ public int notSleepTicks; -+ public boolean alwaysSendData; -+ -+ private ServerBot(MinecraftServer server, ServerLevel world, GameProfile profile) { -+ super(server, world, profile, ClientInformation.createDefault()); -+ this.entityData.set(new EntityDataAccessor<>(16, EntityDataSerializers.INT), 0xFF); -+ this.entityData.set(Player.DATA_PLAYER_MODE_CUSTOMISATION, (byte) -2); -+ -+ this.velocity = new Vec3(this.xxa, this.yya, this.zza); -+ this.noFallTicks = 60; -+ this.fireTicks = 0; -+ this.actions = new HashMap<>(); -+ this.removeOnDeath = true; -+ this.stats = new BotStatsCounter(server); -+ this.container = new BotInventoryContainer(this); -+ this.waterSwim = true; -+ this.knockback = Vec3.ZERO; -+ this.tracingRange = world.spigotConfig.playerTrackingRange * world.spigotConfig.playerTrackingRange; -+ this.notSleepTicks = 0; -+ -+ this.fauxSleeping = LuminolConfig.fakeplayerSkipSleep; -+ this.spawnPhantom = LuminolConfig.fakeplayerSpawnPhantom; -+ this.alwaysSendData = LuminolConfig.alwaysSendFakeplayerData; -+ } -+ -+ public static ServerBot createBot(@NotNull BotCreateState state) { -+ if (!isCreateLegal(state.name)) { -+ return null; -+ } -+ -+ MinecraftServer server = MinecraftServer.getServer(); -+ -+ Supplier creator = () -> { -+ BotCreateEvent event = new BotCreateEvent(state.name, state.skinName, state.loc, ChatColor.YELLOW + state.name + " joined the game"); -+ server.server.getPluginManager().callEvent(event); -+ -+ if (event.isCancelled()) { -+ return null; -+ } -+ -+ Location location = event.getCreateLocation(); -+ -+ ServerLevel world = ((CraftWorld) location.getWorld()).getHandle(); -+ CustomGameProfile profile = new CustomGameProfile(BotUtil.getBotUUID(state), state.name, state.skin); -+ -+ ServerBot bot = new ServerBot(server, world, profile); -+ -+ bot.connection = new ServerGamePacketListenerImpl(server, new Connection(PacketFlow.SERVERBOUND) { // ? -+ @Override -+ public void send(@NotNull Packet packet) { -+ } -+ -+ @Override -+ public void send(@NotNull Packet packet, @Nullable PacketSendListener packetsendlistener) { -+ } -+ -+ @Override -+ public void send(@NotNull Packet packet, @Nullable PacketSendListener callbacks, boolean flush) { -+ } -+ }, bot, CommonListenerCookie.createInitial(profile)); -+ bot.isRealPlayer = true; -+ bot.createState = state; -+ -+ if (event.getJoinMessage() != null) { -+ Bukkit.broadcastMessage(event.getJoinMessage()); -+ } -+ -+ bot.teleportTo(location.getX(), location.getY(), location.getZ()); -+ bot.setRot(location.getYaw(), location.getPitch()); -+ bot.getBukkitEntity().setRotation(location.getYaw(), location.getPitch()); -+ world.addFreshEntity(bot, CreatureSpawnEvent.SpawnReason.COMMAND); -+ -+ bot.renderAll(); -+ server.getPlayerList().addNewBot(bot); -+ bots.add(bot); -+ -+ BotJoinEvent event1 = new BotJoinEvent(bot.getBukkitPlayer()); -+ server.server.getPluginManager().callEvent(event1); -+ -+ return bot; -+ }; -+ -+ if (TickThread.isTickThreadFor( -+ ((CraftWorld) state.loc.getWorld()).getHandle(), -+ state.loc.getBlockX() >> 4, -+ state.loc.getBlockZ() >> 4 -+ )){ -+ return creator.get(); -+ } -+ -+ return CompletableFuture.supplyAsync( -+ creator, -+ task -> -+ RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( -+ ((CraftWorld) state.loc.getWorld()).getHandle(), -+ state.loc.getBlockX() >> 4, -+ state.loc.getBlockZ() >> 4, -+ task -+ ) -+ ).join(); -+ } -+ -+ public static boolean isCreateLegal(@NotNull String name) { -+ if (!name.matches("^[a-zA-Z0-9_]{4,16}$")) { -+ return false; -+ } -+ -+ if (Bukkit.getPlayer(name) != null || ServerBot.getBot(name) != null) { -+ return false; -+ } -+ -+ if (me.earthme.luminol.LuminolConfig.unableFakeplayerNames.contains(name)) { -+ return false; -+ } -+ -+ return ServerBot.getBots().size() < me.earthme.luminol.LuminolConfig.fakeplayerLimit; -+ } -+ -+ public void renderAll() { -+ MinecraftServer.getServer().getPlayerList().getPlayers().forEach( -+ player -> { -+ this.sendPlayerInfo(player); -+ this.sendFakeData(player.connection, false); -+ } -+ ); -+ } -+ -+ public void sendPlayerInfo(ServerPlayer player) { -+ player.connection.send(new ClientboundPlayerInfoUpdatePacket(EnumSet.of(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LISTED, ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME), List.of(this))); -+ } -+ -+ public boolean needSendFakeData(ServerPlayer player) { -+ return alwaysSendData && (player.level() == this.level() && player.position().distanceToSqr(this.position()) > this.tracingRange); -+ } -+ -+ public void sendFakeDataIfNeed(ServerPlayer player, boolean login) { -+ if (needSendFakeData(player)) { -+ this.sendFakeData(player.connection, login); -+ } -+ } -+ -+ public void sendFakeData(ServerPlayerConnection playerConnection, boolean login) { -+ playerConnection.send(new ClientboundAddEntityPacket(this)); -+ if (login) { -+ playerConnection.getPlayer().getBukkitEntity().taskScheduler.schedule(task -> { -+ connection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))); -+ },null,10); -+ } else { -+ connection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))); -+ } -+ } -+ -+ private void sendPacket(Packet packet) { -+ MinecraftServer.getServer().getPlayerList().getPlayers().forEach( -+ player -> player.connection.send(packet) -+ ); -+ } -+ -+ // die check start -+ @Override -+ public void die(@NotNull DamageSource damageSource) { -+ super.die(damageSource); -+ this.dieCheck(); -+ } -+ -+ private void dieCheck() { -+ if (removeOnDeath) { -+ bots.remove(this); -+ server.getPlayerList().removeBot(this); -+ remove(RemovalReason.KILLED); -+ this.setDead(); -+ this.removeTab(); -+ Bukkit.broadcastMessage(ChatColor.YELLOW + this.getName().getString() + " left the game"); // TODO i18n -+ } -+ } -+ -+ private void removeTab() { -+ sendPacket(new ClientboundPlayerInfoRemovePacket(List.of(this.getUUID()))); -+ } -+ -+ private void setDead() { -+ sendPacket(new ClientboundRemoveEntitiesPacket(getId())); -+ this.dead = true; -+ this.inventoryMenu.removed(this); -+ this.containerMenu.removed(this); -+ } -+ -+ // die check end -+ -+ @Nullable -+ @Override -+ public Entity changeDimension(@NotNull ServerLevel destination) { -+ return null; // disable dimension change -+ } -+ -+ public Bot getBukkitPlayer() { -+ return getBukkitEntity(); -+ } -+ -+ @Override -+ @NotNull -+ public CraftBot getBukkitEntity() { -+ return (CraftBot) super.getBukkitEntity(); -+ } -+ -+ @Override -+ public boolean isInWater() { -+ Location loc = getLocation(); -+ for (int i = 0; i <= 2; i++) { -+ Material type = loc.getBlock().getType(); -+ if (type == Material.WATER || type == Material.LAVA) { -+ return true; -+ } -+ loc.add(0, 0.9, 0); -+ } -+ return false; -+ } -+ -+ @Override -+ public void tick() { -+ super.tick(); -+ this.doTick(); -+ -+ if (!isAlive()) { -+ return; -+ } -+ -+ if (spawnPhantom) { -+ notSleepTicks++; -+ } -+ -+ if (fireTicks > 0) { -+ --fireTicks; -+ } -+ if (jumpTicks > 0) { -+ --jumpTicks; -+ } -+ if (noFallTicks > 0) { -+ --noFallTicks; -+ } -+ if (takeXpDelay > 0) { -+ --takeXpDelay; -+ } -+ -+ this.updateLocation(); -+ this.updatePlayerPose(); -+ -+ if (TickRegionScheduler.getCurrentRegion().getData().getCurrentTick() % 20 == 0) { -+ float health = getHealth(); -+ float maxHealth = getMaxHealth(); -+ float regenAmount = (float) (me.earthme.luminol.LuminolConfig.fakeplayerRegenAmount * 20); -+ float amount; -+ -+ if (health < maxHealth - regenAmount) { -+ amount = health + regenAmount; -+ } else { -+ amount = maxHealth; -+ } -+ -+ this.setHealth(amount); -+ } -+ -+ BlockPos blockposition = this.getOnPosLegacy(); -+ BlockState iblockdata = this.level().getBlockState(blockposition); -+ Vec3 vec3d1 = this.collide(velocity); -+ this.checkFallDamage(vec3d1.y, this.onGround(), iblockdata, blockposition); -+ -+ ++this.attackStrengthTicker; -+ -+ if (this.getHealth() > 0.0F) { -+ AABB axisalignedbb; -+ -+ if (this.isPassenger() && !this.getVehicle().isRemoved()) { -+ axisalignedbb = this.getBoundingBox().minmax(this.getVehicle().getBoundingBox()).inflate(1.0D, 0.0D, 1.0D); -+ } else { -+ axisalignedbb = this.getBoundingBox().inflate(1.0D, 0.5D, 1.0D); -+ } -+ -+ List list = this.level().getEntities(this, axisalignedbb); -+ List list1 = Lists.newArrayList(); -+ -+ for (Entity entity : list) { -+ if (entity.getType() == EntityType.EXPERIENCE_ORB) { -+ list1.add(entity); -+ } else if (!entity.isRemoved()) { -+ this.touch(entity); -+ } -+ } -+ -+ if (!list1.isEmpty()) { -+ this.touch(Util.getRandom(list1, this.random)); -+ } -+ } -+ -+ Iterator> iterator = actions.entrySet().iterator(); -+ while (iterator.hasNext()) { -+ Map.Entry entry = iterator.next(); -+ if (entry.getValue().isCancel()) { -+ iterator.remove(); -+ } else { -+ entry.getValue().tryTick(this); -+ } -+ } -+ } -+ -+ private void touch(@NotNull Entity entity) { -+ entity.playerTouch(this); -+ } -+ -+ @Override -+ public void onItemPickup(@NotNull ItemEntity item) { -+ super.onItemPickup(item); -+ this.updateItemInMainHand(); -+ } -+ -+ public void updateItemInMainHand() { -+ tryReplenishOrReplaceInMainHand(); -+ detectEquipmentUpdatesPublic(); -+ } -+ -+ public void updateItemInOffHand() { -+ tryReplenishOrReplaceInOffHand(); -+ detectEquipmentUpdatesPublic(); -+ } -+ -+ public void tryReplenishOrReplaceInOffHand() { -+ net.minecraft.world.item.ItemStack offhand = getOffhandItem(); -+ -+ if (!offhand.isEmpty()) { -+ BotUtil.replenishment(offhand, getInventory().items); -+ if (BotUtil.isDamage(offhand, 10)) { -+ BotUtil.replaceTool(EquipmentSlot.OFFHAND, this); -+ } -+ } -+ } -+ -+ public void tryReplenishOrReplaceInMainHand() { -+ net.minecraft.world.item.ItemStack mainHand = getMainHandItem(); -+ -+ if (!mainHand.isEmpty()) { -+ BotUtil.replenishment(mainHand, getInventory().items); -+ if (BotUtil.isDamage(mainHand, 10)) { -+ BotUtil.replaceTool(EquipmentSlot.MAINHAND, this); -+ } -+ } -+ } -+ -+ @Override -+ public void checkFallDamage(double heightDifference, boolean onGround, @NotNull BlockState state, @NotNull BlockPos landedPosition) { -+ if (onGround) { -+ if (this.fallDistance > 0.0F) { -+ state.getBlock().fallOn(this.level(), state, landedPosition, this, this.fallDistance); -+ this.level().gameEvent(GameEvent.HIT_GROUND, this.position(), GameEvent.Context.of(this, this.mainSupportingBlockPos.map((blockposition1) -> { -+ return this.level().getBlockState(blockposition1); -+ }).orElse(state))); -+ } -+ -+ this.resetFallDistance(); -+ } else if (heightDifference < 0.0D) { -+ this.fallDistance -= (float) heightDifference; -+ } -+ } -+ -+ @Override -+ public void doTick() { -+ if (this.hurtTime > 0) { -+ this.hurtTime -= 1; -+ } -+ -+ baseTick(); -+ -+ this.lerpSteps = (int) this.zza; -+ this.animStep = this.run; -+ this.yRotO = this.getYRot(); -+ this.xRotO = this.getXRot(); -+ } -+ -+ public Location getLocation() { -+ return getBukkitPlayer().getLocation(); -+ } -+ -+ @Override -+ public void knockback(double strength, double x, double z, @NotNull Entity knockingBackEntity) { -+ strength *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE); -+ if (strength > 0.0D) { -+ this.hasImpulse = true; -+ Vec3 vec3d = this.getDeltaMovement(); -+ Vec3 vec3d1 = (new Vec3(x, 0.0D, z)).normalize().scale(strength); -+ knockback = new Vec3(vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + strength) : vec3d.y, vec3d.z / 2.0D - vec3d1.z); -+ } -+ } -+ -+ private void updateLocation() { -+ this.velocity = new Vec3(this.xxa, this.yya, this.zza); -+ -+ if (waterSwim && isInWater()) { -+ this.addDeltaMovement(new Vec3(0, 0.05, 0)); -+ } -+ this.addDeltaMovement(knockback); -+ knockback = Vec3.ZERO; -+ -+ this.travel(this.velocity); -+ } -+ -+ public void faceLocation(@NotNull Location loc) { -+ look(loc.toVector().subtract(getLocation().toVector()), false); -+ } -+ -+ public void look(Vector dir, boolean keepYaw) { -+ float yaw, pitch; -+ -+ if (keepYaw) { -+ yaw = this.getYHeadRot(); -+ pitch = MathUtils.fetchPitch(dir); -+ } else { -+ float[] vals = MathUtils.fetchYawPitch(dir); -+ yaw = vals[0]; -+ pitch = vals[1]; -+ -+ sendPacket(new ClientboundRotateHeadPacket(this, (byte) (yaw * 256 / 360f))); -+ } -+ -+ setRot(yaw, pitch); -+ this.getBukkitEntity().setRotation(yaw, pitch); -+ } -+ -+ public void punch() { -+ swing(InteractionHand.MAIN_HAND); -+ } -+ -+ public void attack(@NotNull Entity target) { -+ super.attack(target); -+ punch(); -+ } -+ -+ public void jumpFromGround() { -+ double jumpPower = (double) this.getJumpPower() + this.getJumpBoostPower(); -+ this.addDeltaMovement(new Vec3(0, jumpPower, 0)); -+ } -+ -+ public void dropAll() { -+ getInventory().dropAll(); -+ detectEquipmentUpdatesPublic(); -+ } -+ -+ public void setBotAction(BotAction action) { -+ if (action instanceof StopAction) { -+ this.actions.clear(); -+ } -+ action.init(); -+ this.actions.put(action.getName(), action); -+ } -+ -+ public Collection getBotActions() { -+ return actions.values(); -+ } -+ -+ public BotAction getBotAction(String name) { -+ return actions.get(name); -+ } -+ -+ @Deprecated -+ public BotAction getBotAction() { -+ return null; -+ } -+ -+ @Override -+ public @NotNull ServerStatsCounter getStats() { -+ return stats; -+ } -+ -+ public BotInventoryContainer getContainer() { -+ return container; -+ } -+ -+ @Override -+ public @NotNull InteractionResult interact(@NotNull Player player, @NotNull InteractionHand hand) { -+ if (me.earthme.luminol.LuminolConfig.openFakeplayerInventory) { -+ if (player instanceof ServerPlayer player1 && player.getMainHandItem().isEmpty()) { -+ BotInventoryOpenEvent event = new BotInventoryOpenEvent(this.getBukkitEntity(), player1.getBukkitEntity()); -+ server.server.getPluginManager().callEvent(event); -+ if (!event.isCancelled()) { -+ player.openMenu(new SimpleMenuProvider((i, inventory, p) -> ChestMenu.sixRows(i, inventory, container), getDisplayName())); -+ return InteractionResult.SUCCESS; -+ } -+ } -+ } -+ return super.interact(player, hand); -+ } -+ -+ public static ServerBot getBot(ServerPlayer player) { -+ ServerBot bot = null; -+ for (ServerBot b : bots) { -+ if (b.getId() == player.getId()) { -+ bot = b; -+ break; -+ } -+ } -+ return bot; -+ } -+ -+ public static ServerBot getBot(String name) { -+ ServerBot bot = null; -+ for (ServerBot b : bots) { -+ if (b.getName().getString().equals(name)) { -+ bot = b; -+ break; -+ } -+ } -+ return bot; -+ } -+ -+ public static ServerBot getBot(UUID uuid) { -+ ServerBot bot = null; -+ for (ServerBot b : bots) { -+ if (b.uuid == uuid) { -+ bot = b; -+ break; -+ } -+ } -+ return bot; -+ } -+ -+ public static void saveOrRemoveAllBot() { -+ if (me.earthme.luminol.LuminolConfig.fakeplayerSupport && me.earthme.luminol.LuminolConfig.fakeplayerResident) { -+ JsonObject fakePlayerList = new JsonObject(); -+ bots.forEach(bot -> fakePlayerList.add(bot.createState.realName, BotUtil.saveBot(bot))); -+ File file = MinecraftServer.getServer().getWorldPath(LevelResource.ROOT).resolve("fake_player.leaves.json").toFile(); -+ if (!file.isFile()) { -+ try { -+ file.createNewFile(); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } -+ try (BufferedWriter bfw = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8)) { -+ bfw.write(new Gson().toJson(fakePlayerList)); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ } else { -+ removeAllBot(); -+ } -+ } -+ -+ public static void loadAllBot() { -+ if (me.earthme.luminol.LuminolConfig.fakeplayerSupport && me.earthme.luminol.LuminolConfig.fakeplayerResident) { -+ JsonObject fakePlayerList = new JsonObject(); -+ File file = MinecraftServer.getServer().getWorldPath(LevelResource.ROOT).resolve("fake_player.leaves.json").toFile(); -+ if (!file.isFile()) { -+ return; -+ } -+ try (BufferedReader bfr = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) { -+ fakePlayerList = new Gson().fromJson(bfr, JsonObject.class); -+ } catch (IOException e) { -+ e.printStackTrace(); -+ } -+ for (Map.Entry entry : fakePlayerList.entrySet()) { -+ BotUtil.loadBot(entry); -+ } -+ file.delete(); -+ } -+ } -+ -+ public static boolean removeAllBot() { -+ CompletableFuture.allOf( -+ bots.stream() -+ .map(bot ->{ -+ //Do not check if it is on region thread,return to the target region anyway -+ /*if (TickThread.isTickThreadFor(bot)){ -+ bot.die(bot.damageSources().fellOutOfWorld()); -+ return CompletableFuture.completedFuture(null); -+ }*/ -+ -+ return CompletableFuture.runAsync(()->{ -+ bot.die(bot.damageSources().fellOutOfWorld()); -+ }, task -> -+ RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( -+ bot.serverLevel(), -+ bot.sectionX, -+ bot.sectionZ, -+ task -+ ) -+ ); -+ }) -+ .toArray(CompletableFuture[]::new) -+ ).join(); -+ bots.clear(); -+ return true; -+ } -+ -+ public static List getBots() { -+ return bots; -+ } -+ -+ public static class CustomGameProfile extends GameProfile { -+ -+ public CustomGameProfile(UUID uuid, String name, String[] skin) { -+ super(uuid, name); -+ setSkin(skin); -+ } -+ -+ public void setSkin(String[] skin) { -+ if (skin != null) { -+ getProperties().put("textures", new Property("textures", skin[0], skin[1])); -+ } -+ } -+ } -+ -+ public static class BotCreateState { -+ -+ public Location loc; -+ -+ public String[] skin; -+ public String skinName; -+ -+ private String realName; -+ private String name; -+ -+ public BotCreateState(Location loc, String realName, String skinName) { -+ this.loc = loc; -+ this.skinName = skinName; -+ this.setRealName(realName); -+ } -+ -+ public BotCreateState(Location loc, String name, String realName, String skinName, String[] skin) { -+ this.loc = loc; -+ this.skinName = skinName; -+ this.skin = skin; -+ this.realName = realName; -+ this.name = name; -+ } -+ -+ public ServerBot createSync() { -+ return createBot(this); -+ } -+ -+ public void createAsync(Consumer consumer) { -+ Bukkit.getAsyncScheduler().runNow(CraftScheduler.MINECRAFT,scheduledTask -> { -+ try { -+ if (skinName != null) { -+ this.skin = MojangAPI.getSkin(skinName); -+ } -+ -+ -+ ServerBot bot = createBot(this); -+ if (bot != null && consumer != null) { -+ consumer.accept(bot); -+ } -+ }catch (Exception e){ -+ MinecraftServer.LOGGER.error("Exception in processing async task for fakeplayer!",e); -+ } -+ }); -+ } -+ -+ public void setName(String name) { -+ this.name = name; -+ } -+ -+ public void setRealName(String realName) { -+ this.realName = realName; -+ this.name = me.earthme.luminol.LuminolConfig.fakeplayerPrefix + realName + me.earthme.luminol.LuminolConfig.fakeplayerSuffix; -+ } -+ -+ public String getName() { -+ return name; -+ } -+ -+ public String getRealName() { -+ return realName; -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java b/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java -new file mode 100644 -index 0000000000000000000000000000000000000000..a7e98848e400641077ac567d9ea9a58c32123c98 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/Actions.java -@@ -0,0 +1,66 @@ -+package top.leavesmc.leaves.bot.agent; -+ -+import org.jetbrains.annotations.Contract; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.agent.actions.*; -+ -+import java.util.Collection; -+import java.util.HashMap; -+import java.util.Map; -+import java.util.Set; -+ -+public class Actions { -+ -+ private static final Map actions = new HashMap<>(); -+ -+ public static void registerAll() { -+ register(new AttackAction()); -+ register(new BreakBlockAction()); -+ register(new DropAction()); -+ register(new JumpAction()); -+ register(new RotateAction()); -+ register(new SneakAction()); -+ register(new StopAction()); -+ register(new UseItemAction()); -+ register(new UseItemOnAction()); -+ register(new UseItemToAction()); -+ register(new LookAction()); -+ register(new FishAction()); -+ register(new AttackSelfAction()); -+ register(new SwimAction()); -+ register(new UseItemOffHandAction()); -+ register(new UseItemOnOffhandAction()); -+ register(new UseItemToOffhandAction()); -+ } -+ -+ public static boolean register(@NotNull BotAction action) { -+ if (!actions.containsKey(action.getName())) { -+ actions.put(action.getName(), action); -+ return true; -+ } -+ return false; -+ } -+ -+ public static boolean unregister(@NotNull String name) { -+ if (actions.containsKey(name)) { -+ actions.remove(name); -+ return true; -+ } -+ return false; -+ } -+ -+ @NotNull -+ @Contract(pure = true) -+ public static Collection getAll() { -+ return actions.values(); -+ } -+ -+ @NotNull -+ public static Set getNames() { -+ return actions.keySet(); -+ } -+ -+ public static BotAction getForName(String name) { -+ return actions.get(name); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/BotAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/BotAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..20ba4904219d015903cd3a5b2e1693eaba6088d8 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/BotAction.java -@@ -0,0 +1,93 @@ -+package top.leavesmc.leaves.bot.agent; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+ -+import java.util.List; -+ -+public abstract class BotAction { -+ -+ private final String name; -+ private final CommandArgument argument; -+ -+ private boolean cancel; -+ private int tickDelay; -+ private int number; -+ -+ private int needWaitTick; -+ private int canDoNumber; -+ -+ public BotAction(String name, CommandArgument argument) { -+ this.name = name; -+ this.argument = argument; -+ -+ this.cancel = false; -+ this.tickDelay = 20; -+ this.number = -1; -+ } -+ -+ public String getName() { -+ return name; -+ } -+ -+ public int getTickDelay() { -+ return tickDelay; -+ } -+ -+ public int getNumber() { -+ return number; -+ } -+ -+ public boolean isCancel() { -+ return cancel; -+ } -+ -+ public BotAction setTickDelay(int tickDelay) { -+ this.tickDelay = Math.max(0, tickDelay); -+ return this; -+ } -+ -+ public BotAction setTabComplete(int index, List list) { -+ argument.setTabComplete(index, list); -+ return this; -+ } -+ -+ public BotAction setNumber(int number) { -+ this.number = Math.max(-1, number); -+ return this; -+ } -+ -+ public void setCancel(boolean cancel) { -+ this.cancel = cancel; -+ } -+ -+ public void init() { -+ this.needWaitTick = 0; -+ this.canDoNumber = this.getNumber(); -+ this.setCancel(false); -+ } -+ -+ public void tryTick(ServerBot bot) { -+ if (canDoNumber == 0) { -+ this.setCancel(true); -+ return; -+ } -+ if (needWaitTick-- <= 0) { -+ if (this.doTick(bot)) { -+ canDoNumber--; -+ needWaitTick = this.getTickDelay(); -+ } -+ } -+ } -+ -+ public CommandArgument getArgument() { -+ return argument; -+ } -+ -+ public abstract BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result); -+ -+ public abstract boolean doTick(@NotNull ServerBot bot); -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..609605b21cfe5af8876f76ea4922e379c5dd166e ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackAction.java -@@ -0,0 +1,36 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.phys.EntityHitResult; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class AttackAction extends BotAction { -+ -+ public AttackAction() { -+ super("attack", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new AttackAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ EntityHitResult result = bot.getTargetEntity(3); -+ if (result != null) { -+ bot.attack(result.getEntity()); -+ return true; -+ } -+ return false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackSelfAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackSelfAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5a0e5626751d0b6ea12a6074b5626937b6668608 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/AttackSelfAction.java -@@ -0,0 +1,42 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import com.google.common.base.Predicates; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.entity.Entity; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class AttackSelfAction extends BotAction { -+ -+ public AttackSelfAction() { -+ super("attack_self", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new AttackSelfAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ List entities = bot.level().getEntities((Entity) null, bot.getBoundingBox(), Predicates.alwaysTrue()); -+ if (!entities.isEmpty()) { -+ for (int i = 0; i < entities.size(); i++) { -+ Entity entity = entities.get(i); -+ if (entity != bot) { -+ bot.attack(entity); -+ return true; -+ } -+ } -+ } -+ return false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/BreakBlockAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/BreakBlockAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..2a3ca671b43fec658bf5cd8a6eb08b476a766c29 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/BreakBlockAction.java -@@ -0,0 +1,104 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.core.BlockPos; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.level.block.state.BlockState; -+import org.bukkit.block.Block; -+import org.bukkit.craftbukkit.block.CraftBlock; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class BreakBlockAction extends BotAction { -+ -+ public BreakBlockAction() { -+ super("break", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new BreakBlockAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public BotAction setTickDelay(int tickDelay) { -+ super.setTickDelay(0); -+ this.delay = tickDelay; -+ return this; -+ } -+ -+ private int delay = 0; -+ private int nowDelay = 0; -+ -+ private BlockPos lastPos = null; -+ private int destroyProgressTime = 0; -+ private int lastSentState = -1; -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ if (nowDelay > 0) { -+ nowDelay--; -+ return false; -+ } -+ -+ Block block = bot.getBukkitEntity().getTargetBlockExact(5); -+ if (block != null) { -+ BlockPos pos = ((CraftBlock) block).getPosition(); -+ -+ if (lastPos == null || !lastPos.equals(pos)) { -+ lastPos = pos; -+ destroyProgressTime = 0; -+ lastSentState = -1; -+ } -+ -+ BlockState iblockdata = bot.level().getBlockState(pos); -+ if (!iblockdata.isAir()) { -+ bot.punch(); -+ -+ if (iblockdata.getDestroyProgress(bot, bot.level(), pos) >= 1.0F) { -+ bot.gameMode.destroyAndAck(pos, 0, "insta mine"); -+ bot.level().destroyBlockProgress(bot.getId(), pos, -1); -+ bot.updateItemInMainHand(); -+ finalBreak(); -+ return true; -+ } -+ -+ float damage = this.incrementDestroyProgress(bot, iblockdata, pos); -+ if (damage >= 1.0F) { -+ bot.gameMode.destroyAndAck(pos, 0, "destroyed"); -+ bot.level().destroyBlockProgress(bot.getId(), pos, -1); -+ bot.updateItemInMainHand(); -+ finalBreak(); -+ return true; -+ } -+ } -+ } -+ return false; -+ } -+ -+ private void finalBreak() { -+ lastPos = null; -+ destroyProgressTime = 0; -+ lastSentState = -1; -+ nowDelay = delay; -+ } -+ -+ private float incrementDestroyProgress(ServerBot bot, @NotNull BlockState state, BlockPos pos) { -+ float f = state.getDestroyProgress(bot, bot.level(), pos) * (float) (++destroyProgressTime); -+ int k = (int) (f * 10.0F); -+ -+ if (k != lastSentState) { -+ bot.level().destroyBlockProgress(bot.getId(), pos, k); -+ lastSentState = k; -+ } -+ -+ return f; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/CraftCustomBotAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/CraftCustomBotAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..89a361249179d7a0a84768e715ced05aafc13272 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/CraftCustomBotAction.java -@@ -0,0 +1,48 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.bukkit.entity.Player; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.entity.botaction.CustomBotAction; -+ -+public class CraftCustomBotAction extends BotAction { -+ -+ private final CustomBotAction realAction; -+ -+ public CraftCustomBotAction(String name, @NotNull CustomBotAction realAction) { -+ super(name, new CommandArgument().setAllTabComplete(realAction.getTabComplete())); -+ this.realAction = realAction; -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ throw new UnsupportedOperationException("Not supported."); -+ } -+ -+ public BotAction getNew(@NotNull Player player, String[] args) { -+ CustomBotAction newRealAction = realAction.getNew(player, args); -+ if (newRealAction != null) { -+ return new CraftCustomBotAction(getName(), newRealAction); -+ } -+ return null; -+ } -+ -+ @Override -+ public int getNumber() { -+ return realAction.getNumber(); -+ } -+ -+ @Override -+ public int getTickDelay() { -+ return realAction.getTickDelay(); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ return realAction.doTick(bot.getBukkitPlayer()); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/DropAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/DropAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cc72960b8490a72aca5db3e834c71f97e3742f7d ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/DropAction.java -@@ -0,0 +1,26 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+ -+public class DropAction extends BotAction { -+ -+ public DropAction() { -+ super("drop", new CommandArgument()); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return this.setTickDelay(0).setNumber(1); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ bot.dropAll(); -+ return true; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/FishAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/FishAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d92ea54770bce73c2f10f1ebcb0dff5b9532e0e9 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/FishAction.java -@@ -0,0 +1,70 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.entity.projectile.FishingHook; -+import net.minecraft.world.item.FishingRodItem; -+import net.minecraft.world.item.ItemStack; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class FishAction extends BotAction { -+ -+ public FishAction() { -+ super("fish", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new FishAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public BotAction setTickDelay(int tickDelay) { -+ super.setTickDelay(0); -+ this.delay = tickDelay; -+ return this; -+ } -+ -+ private int delay = 0; -+ private int nowDelay = 0; -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ if (nowDelay > 0) { -+ nowDelay--; -+ return false; -+ } -+ -+ ItemStack mainHand = bot.getMainHandItem(); -+ if (mainHand == ItemStack.EMPTY || mainHand.getItem().getClass() != FishingRodItem.class) { -+ return false; -+ } -+ -+ FishingHook fishingHook = bot.fishing; -+ if (fishingHook != null) { -+ if (fishingHook.currentState == FishingHook.FishHookState.HOOKED_IN_ENTITY) { -+ mainHand.use(bot.level(), bot, InteractionHand.MAIN_HAND); -+ nowDelay = 20; -+ return false; -+ } -+ if (fishingHook.nibble > 0) { -+ mainHand.use(bot.level(), bot, InteractionHand.MAIN_HAND); -+ nowDelay = delay; -+ return true; -+ } -+ } else { -+ mainHand.use(bot.level(), bot, InteractionHand.MAIN_HAND); -+ } -+ -+ return false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/JumpAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/JumpAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d99f667992e45e85c0fe0bd74682d563fe1315eb ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/JumpAction.java -@@ -0,0 +1,35 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class JumpAction extends BotAction { -+ -+ public JumpAction() { -+ super("jump", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new JumpAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ if (bot.onGround()) { -+ bot.jumpFromGround(); -+ return true; -+ } else { -+ return false; -+ } -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/LookAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/LookAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5432e61c156a1a6d49dcf4b24e3bcfcc6c1aa7bb ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/LookAction.java -@@ -0,0 +1,49 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.bukkit.util.Vector; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class LookAction extends BotAction { -+ -+ public LookAction() { -+ super("look", new CommandArgument(CommandArgumentType.DOUBLE, CommandArgumentType.DOUBLE, CommandArgumentType.DOUBLE)); -+ setTabComplete(0, List.of("")); -+ setTabComplete(1, List.of("")); -+ setTabComplete(2, List.of("")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ Vector pos = result.readVector(); -+ if (pos != null) { -+ return new LookAction().setPos(pos).setTickDelay(0).setNumber(1); -+ } else { -+ return null; -+ } -+ } -+ -+ private Vector pos; -+ -+ public LookAction setPos(Vector pos) { -+ if (pos != null) { -+ this.pos = pos; -+ return this; -+ } else { -+ return null; -+ } -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ bot.look(pos.subtract(bot.getLocation().toVector()), false); -+ return true; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/RotateAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/RotateAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1e5be54b33467591924cb2400639fb593dc50ec6 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/RotateAction.java -@@ -0,0 +1,33 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+ -+public class RotateAction extends BotAction { -+ -+ public RotateAction() { -+ super("rotate", new CommandArgument()); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new RotateAction().setPlayer(player).setTickDelay(0).setNumber(1); -+ } -+ -+ private ServerPlayer player; -+ -+ public RotateAction setPlayer(ServerPlayer player) { -+ this.player = player; -+ return this; -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ bot.faceLocation(player.getBukkitEntity().getLocation()); -+ return true; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/SneakAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/SneakAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..18e276c0252fa867b2cdc9770e3a7ed0b9cc63de ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/SneakAction.java -@@ -0,0 +1,27 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.entity.Pose; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+ -+public class SneakAction extends BotAction { -+ -+ public SneakAction() { -+ super("sneak", new CommandArgument()); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return this.setTickDelay(0).setNumber(1); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ bot.setShiftKeyDown(!bot.isShiftKeyDown()); -+ return true; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/StopAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/StopAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..36d199269afc46783b0815e3887842cd82b6e813 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/StopAction.java -@@ -0,0 +1,26 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+ -+public class StopAction extends BotAction { -+ -+ public StopAction() { -+ super("stop", new CommandArgument()); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return this.setTickDelay(0).setNumber(0); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ this.setCancel(true); -+ return true; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/SwimAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/SwimAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..58c815bd0ebfd455fcf4903ee5ced6b81be00982 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/SwimAction.java -@@ -0,0 +1,26 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+ -+public class SwimAction extends BotAction { -+ -+ public SwimAction() { -+ super("swim", new CommandArgument()); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return this.setTickDelay(0).setNumber(1); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ bot.waterSwim = !bot.waterSwim; -+ return true; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..5dc3fbf8e62ccffc8291962c835a568efd65d7af ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemAction.java -@@ -0,0 +1,33 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class UseItemAction extends BotAction { -+ -+ public UseItemAction() { -+ super("use", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new UseItemAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ bot.punch(); -+ bot.updateItemInMainHand(); -+ return bot.getInventory().getSelected().use(bot.level(), bot, InteractionHand.MAIN_HAND).getResult().consumesAction(); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOffHandAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOffHandAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..345932e779f5187355ca722c2bb9b05f384660a1 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOffHandAction.java -@@ -0,0 +1,33 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class UseItemOffHandAction extends BotAction { -+ -+ public UseItemOffHandAction() { -+ super("use_offhand", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new UseItemOffHandAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ bot.punch(); -+ bot.updateItemInOffHand(); -+ return bot.getInventory().getSelected().use(bot.level(), bot, InteractionHand.OFF_HAND).getResult().consumesAction(); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..f4837f60909763df89ea7474f70dd0236360e657 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnAction.java -@@ -0,0 +1,56 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.level.ClipContext; -+import net.minecraft.world.level.block.Blocks; -+import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.entity.TrappedChestBlockEntity; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.phys.BlockHitResult; -+import net.minecraft.world.phys.HitResult; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.scheduler.CraftScheduler; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class UseItemOnAction extends BotAction { -+ -+ public UseItemOnAction() { -+ super("use_on", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new UseItemOnAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ HitResult result = bot.getRayTrace(5, ClipContext.Fluid.NONE); -+ if (result instanceof BlockHitResult blockHitResult) { -+ BlockState state = bot.serverLevel().getBlockState(blockHitResult.getBlockPos()); -+ bot.punch(); -+ if (state.getBlock() == Blocks.TRAPPED_CHEST) { -+ BlockEntity entity = bot.serverLevel().getBlockEntity(blockHitResult.getBlockPos()); -+ if (entity instanceof TrappedChestBlockEntity chestBlockEntity) { -+ chestBlockEntity.startOpen(bot); -+ Bukkit.getScheduler().runTaskLater(CraftScheduler.MINECRAFT, () -> chestBlockEntity.stopOpen(bot), 1); -+ return true; -+ } -+ } else { -+ bot.updateItemInMainHand(); -+ return bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND, (BlockHitResult) result).consumesAction(); -+ } -+ } -+ return false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnOffhandAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnOffhandAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4ab84fba3624a8e8c4d345c03fe678a012a5c367 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnOffhandAction.java -@@ -0,0 +1,56 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.level.ClipContext; -+import net.minecraft.world.level.block.Blocks; -+import net.minecraft.world.level.block.entity.BlockEntity; -+import net.minecraft.world.level.block.entity.TrappedChestBlockEntity; -+import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.world.phys.BlockHitResult; -+import net.minecraft.world.phys.HitResult; -+import org.bukkit.Bukkit; -+import org.bukkit.craftbukkit.scheduler.CraftScheduler; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class UseItemOnOffhandAction extends BotAction { -+ -+ public UseItemOnOffhandAction() { -+ super("use_on_offhand", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new UseItemOnOffhandAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ HitResult result = bot.getRayTrace(5, ClipContext.Fluid.NONE); -+ if (result instanceof BlockHitResult blockHitResult) { -+ BlockState state = bot.serverLevel().getBlockState(blockHitResult.getBlockPos()); -+ bot.punch(); -+ if (state.getBlock() == Blocks.TRAPPED_CHEST) { -+ BlockEntity entity = bot.serverLevel().getBlockEntity(blockHitResult.getBlockPos()); -+ if (entity instanceof TrappedChestBlockEntity chestBlockEntity) { -+ chestBlockEntity.startOpen(bot); -+ Bukkit.getScheduler().runTaskLater(CraftScheduler.MINECRAFT, () -> chestBlockEntity.stopOpen(bot), 1); -+ return true; -+ } -+ } else { -+ bot.updateItemInMainHand(); -+ return bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.OFF_HAND), InteractionHand.OFF_HAND, (BlockHitResult) result).consumesAction(); -+ } -+ } -+ return false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..cc8689ee726144f220e4ccc5cd418b79a29b79ab ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToAction.java -@@ -0,0 +1,38 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.phys.EntityHitResult; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class UseItemToAction extends BotAction { -+ -+ public UseItemToAction() { -+ super("use_to", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new UseItemToAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ EntityHitResult result = bot.getTargetEntity(3); -+ if (result != null) { -+ bot.punch(); -+ bot.updateItemInMainHand(); -+ return result.getEntity().interact(bot, InteractionHand.MAIN_HAND).consumesAction(); -+ } -+ return false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToOffhandAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToOffhandAction.java -new file mode 100644 -index 0000000000000000000000000000000000000000..1fde496c993ec0c961a63b32a8088479da88c91d ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemToOffhandAction.java -@@ -0,0 +1,38 @@ -+package top.leavesmc.leaves.bot.agent.actions; -+ -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.world.InteractionHand; -+import net.minecraft.world.phys.EntityHitResult; -+import org.jetbrains.annotations.NotNull; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.command.CommandArgument; -+import top.leavesmc.leaves.command.CommandArgumentResult; -+import top.leavesmc.leaves.command.CommandArgumentType; -+ -+import java.util.List; -+ -+public class UseItemToOffhandAction extends BotAction { -+ -+ public UseItemToOffhandAction() { -+ super("use_to_offhand", new CommandArgument(CommandArgumentType.INTEGER, CommandArgumentType.INTEGER)); -+ setTabComplete(0, List.of("[TickDelay]")); -+ setTabComplete(1, List.of("[DoNumber]")); -+ } -+ -+ @Override -+ public BotAction getNew(@NotNull ServerPlayer player, @NotNull CommandArgumentResult result) { -+ return new UseItemToOffhandAction().setTickDelay(result.readInt(20)).setNumber(result.readInt(-1)); -+ } -+ -+ @Override -+ public boolean doTick(@NotNull ServerBot bot) { -+ EntityHitResult result = bot.getTargetEntity(3); -+ if (result != null) { -+ bot.punch(); -+ bot.updateItemInOffHand(); -+ return result.getEntity().interact(bot, InteractionHand.OFF_HAND).consumesAction(); -+ } -+ return false; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgument.java b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java -index eadc6d168fb13299348b0c275ae352ee2f1e1ea2..134c6d26acc612bf6142ae6b6885a0ee53d2a196 100644 ---- a/src/main/java/top/leavesmc/leaves/command/CommandArgument.java -+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgument.java -@@ -32,6 +32,12 @@ public class CommandArgument { - return this; - } - -+ public CommandArgument setAllTabComplete(List> tabComplete) { -+ this.tabComplete.clear(); -+ this.tabComplete.addAll(tabComplete); -+ return this; -+ } -+ - public CommandArgumentResult parse(int index, String @NotNull [] args) { - Object[] result = new Object[argumentTypes.size()]; - Arrays.fill(result, null); -diff --git a/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java -index 340eaca64c96180b895a075ce9e44402cd104eed..39e90dcff0de259373d7955021c29397c2cc15d5 100644 ---- a/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java -+++ b/src/main/java/top/leavesmc/leaves/command/CommandArgumentResult.java -@@ -58,5 +58,4 @@ public class CommandArgumentResult { - return null; - } - } -- - } -diff --git a/src/main/java/top/leavesmc/leaves/entity/CraftBot.java b/src/main/java/top/leavesmc/leaves/entity/CraftBot.java -new file mode 100644 -index 0000000000000000000000000000000000000000..713240da3ba37915b455d952a45ae7f68b8294ee ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/entity/CraftBot.java -@@ -0,0 +1,67 @@ -+package top.leavesmc.leaves.entity; -+ -+import org.bukkit.craftbukkit.CraftServer; -+import org.bukkit.craftbukkit.entity.CraftPlayer; -+import org.bukkit.entity.Player; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.Actions; -+import top.leavesmc.leaves.bot.agent.BotAction; -+import top.leavesmc.leaves.entity.botaction.LeavesBotAction; -+ -+import java.util.UUID; -+ -+public class CraftBot extends CraftPlayer implements Bot { -+ -+ public CraftBot(CraftServer server, ServerBot entity) { -+ super(server, entity); -+ } -+ -+ @Override -+ public String getSkinName() { -+ return getHandle().createState.skinName; -+ } -+ -+ @Override -+ public @NotNull String getRealName() { -+ return getHandle().createState.getRealName(); -+ } -+ -+ @Override -+ public @Nullable UUID getCreatePlayerUUID() { -+ return getHandle().createPlayer; -+ } -+ -+ @Override -+ public boolean setBotAction(@NotNull String action, @NotNull Player player, @NotNull String[] args) { -+ BotAction botAction = Actions.getForName(action); -+ if (botAction != null) { -+ BotAction newAction = botAction.getNew(((CraftPlayer) player).getHandle(), botAction.getArgument().parse(0, args)); -+ if (newAction != null) { -+ getHandle().setBotAction(newAction); -+ return true; -+ } -+ } -+ return false; -+ } -+ -+ @Override -+ public boolean setBotAction(@NotNull LeavesBotAction action, @NotNull Player player, @NotNull String[] args) { -+ return setBotAction(action.getName(), player, args); -+ } -+ -+ @Override -+ public ServerBot getHandle() { -+ return (ServerBot) entity; -+ } -+ -+ public void setHandle(final ServerBot entity) { -+ super.setHandle(entity); -+ } -+ -+ @Override -+ public String toString() { -+ return "CraftBot{" + "name=" + getName() + '}'; -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/entity/CraftBotManager.java b/src/main/java/top/leavesmc/leaves/entity/CraftBotManager.java -new file mode 100644 -index 0000000000000000000000000000000000000000..df5796bfa333a287ccd486be9a9cdae4ca5dc757 ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/entity/CraftBotManager.java -@@ -0,0 +1,93 @@ -+package top.leavesmc.leaves.entity; -+ -+import com.google.common.base.Function; -+import com.google.common.collect.Lists; -+import org.bukkit.Location; -+import org.bukkit.util.Consumer; -+import org.jetbrains.annotations.NotNull; -+import org.jetbrains.annotations.Nullable; -+import top.leavesmc.leaves.bot.ServerBot; -+import top.leavesmc.leaves.bot.agent.Actions; -+import top.leavesmc.leaves.bot.agent.actions.CraftCustomBotAction; -+import top.leavesmc.leaves.entity.botaction.CustomBotAction; -+ -+import java.util.Collection; -+import java.util.Collections; -+import java.util.UUID; -+ -+public class CraftBotManager implements BotManager { -+ -+ private final Collection botViews = Collections.unmodifiableList(Lists.transform(ServerBot.getBots(), new Function() { -+ @Override -+ public CraftBot apply(ServerBot bot) { -+ return bot.getBukkitEntity(); -+ } -+ })); -+ -+ @Override -+ public @Nullable Bot getBot(@NotNull UUID uuid) { -+ return ServerBot.getBot(uuid).getBukkitPlayer(); -+ } -+ -+ @Override -+ public @Nullable Bot getBot(@NotNull String name) { -+ return ServerBot.getBot(name).getBukkitPlayer(); -+ } -+ -+ @Override -+ public @Nullable Bot createBot(@NotNull String name, @NotNull String realName, @Nullable String[] skin, @Nullable String skinName, @NotNull Location location) { -+ ServerBot bot = new ServerBot.BotCreateState(location, name, realName, skinName, skin).createSync(); -+ if (bot != null) { -+ return bot.getBukkitPlayer(); -+ } -+ return null; -+ } -+ -+ @Override -+ public void createBot(@NotNull String name, @Nullable String skinName, @NotNull Location location, Consumer consumer) { -+ new ServerBot.BotCreateState(location, name, skinName).createAsync((serverBot -> { -+ consumer.accept(serverBot.getBukkitPlayer()); -+ })); -+ } -+ -+ @Override -+ public void removeBot(@NotNull String name) { -+ ServerBot bot = ServerBot.getBot(name); -+ if (bot != null) { -+ bot.die(bot.damageSources().fellOutOfWorld()); -+ } -+ } -+ -+ @Override -+ public void removeBot(@NotNull UUID uuid) { -+ ServerBot bot = ServerBot.getBot(uuid); -+ if (bot != null) { -+ bot.die(bot.damageSources().fellOutOfWorld()); -+ } -+ } -+ -+ @Override -+ public void removeAllBots() { -+ ServerBot.removeAllBot(); -+ } -+ -+ @Override -+ public void saveOrRemoveAllBots() { -+ ServerBot.saveOrRemoveAllBot(); -+ } -+ -+ @Override -+ public Collection getBots() { -+ return botViews; -+ } -+ -+ @Override -+ public boolean registerCustomBotAction(String name, CustomBotAction action) { -+ return Actions.register(new CraftCustomBotAction(name, action)); -+ } -+ -+ @Override -+ public boolean unregisterCustomBotAction(String name) { -+ return Actions.unregister(name); -+ } -+} -diff --git a/src/main/java/top/leavesmc/leaves/util/MathUtils.java b/src/main/java/top/leavesmc/leaves/util/MathUtils.java -new file mode 100644 -index 0000000000000000000000000000000000000000..349cd0c0d2d9dc2c9c745ef3469e548a798931ba ---- /dev/null -+++ b/src/main/java/top/leavesmc/leaves/util/MathUtils.java -@@ -0,0 +1,78 @@ -+package top.leavesmc.leaves.util; -+ -+import org.bukkit.util.NumberConversions; -+import org.bukkit.util.Vector; -+ -+import java.util.regex.Pattern; -+ -+public class MathUtils { -+ // Lag ? -+ public static void clean(Vector vector) { -+ if (!NumberConversions.isFinite(vector.getX())) vector.setX(0); -+ if (!NumberConversions.isFinite(vector.getY())) vector.setY(0); -+ if (!NumberConversions.isFinite(vector.getZ())) vector.setZ(0); -+ } -+ -+ private static final Pattern numericPattern = Pattern.compile("^-?[1-9]\\d*$|^0$"); -+ public static boolean isNumeric(String str){ -+ return numericPattern.matcher(str).matches(); -+ } -+ -+ public static float[] fetchYawPitch(Vector dir) { -+ double x = dir.getX(); -+ double z = dir.getZ(); -+ -+ float[] out = new float[2]; -+ -+ if (x == 0.0D && z == 0.0D) { -+ out[1] = (float) (dir.getY() > 0.0D ? -90 : 90); -+ } -+ -+ else { -+ double theta = Math.atan2(-x, z); -+ out[0] = (float) Math.toDegrees((theta + 6.283185307179586D) % 6.283185307179586D); -+ -+ double x2 = NumberConversions.square(x); -+ double z2 = NumberConversions.square(z); -+ double xz = Math.sqrt(x2 + z2); -+ out[1] = (float) Math.toDegrees(Math.atan(-dir.getY() / xz)); -+ } -+ -+ return out; -+ } -+ -+ public static float fetchPitch(Vector dir) { -+ double x = dir.getX(); -+ double z = dir.getZ(); -+ -+ float result; -+ -+ if (x == 0.0D && z == 0.0D) { -+ result = (float) (dir.getY() > 0.0D ? -90 : 90); -+ } -+ -+ else { -+ double x2 = NumberConversions.square(x); -+ double z2 = NumberConversions.square(z); -+ double xz = Math.sqrt(x2 + z2); -+ result = (float) Math.toDegrees(Math.atan(-dir.getY() / xz)); -+ } -+ -+ return result; -+ } -+ -+ public static Vector getDirection(double rotX, double rotY) { -+ Vector vector = new Vector(); -+ -+ rotX = Math.toRadians(rotX); -+ rotY = Math.toRadians(rotY); -+ -+ double xz = Math.abs(Math.cos(rotY)); -+ -+ vector.setX(-Math.sin(rotX) * xz); -+ vector.setZ(Math.cos(rotX) * xz); -+ vector.setY(-Math.sin(rotY)); -+ -+ return vector; -+ } -+} diff --git a/patches/server/0056-Io_uring-channel-type-support.patch b/patches/server/0056-Io_uring-channel-type-support.patch deleted file mode 100644 index cdc4660..0000000 --- a/patches/server/0056-Io_uring-channel-type-support.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Tue, 30 Jan 2024 13:02:45 +0000 -Subject: [PATCH] Io_uring channel type support - - -diff --git a/build.gradle.kts b/build.gradle.kts -index 1bdeb0e9d0c04509d7ed4003f6b79c806dc55eed..c0199b93a69a2d0b99d7c61a1bdb55fc8a9a07de 100644 ---- a/build.gradle.kts -+++ b/build.gradle.kts -@@ -39,6 +39,7 @@ dependencies { - log4jPlugins.annotationProcessorConfigurationName("org.apache.logging.log4j:log4j-core:2.19.0") // Paper - Needed to generate meta for our Log4j plugins - runtimeOnly(log4jPlugins.output) - alsoShade(log4jPlugins.output) -+ implementation("io.netty.incubator:netty-incubator-transport-native-io_uring:0.0.21.Final:linux-x86_64") //Luminol - io_uring Libraries - implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Paper - Add support for proxy protocol - // Paper end - implementation("org.apache.logging.log4j:log4j-iostreams:2.19.0") // Paper - remove exclusion -diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java -index 6d2318f31a38d5111679ab1bc8f7a474d44f86ed..39b089fa8e347f5efba3be071164d831d4dc95c2 100644 ---- a/src/main/java/me/earthme/luminol/LuminolConfig.java -+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java -@@ -34,6 +34,7 @@ public class LuminolConfig { - public static boolean disableUsernameCheck = false; - public static boolean disableOfflineModeWarning = false; - public static boolean fixSpectorTeleportFolia = false; -+ public static boolean enableIoUring = false; - - public static boolean safeTeleportation = true; - public static boolean enableSandDuping = false; -@@ -178,6 +179,7 @@ public class LuminolConfig { - disableUsernameCheck = get("misc.disable_username_check",disableUsernameCheck,"Disable username check that can accept usernames with other characters(such as Chinese).Not recommended to use"); - fixSpectorTeleportFolia = get("misc.fix_folia_spector_teleport",fixSpectorTeleportFolia); - disableOfflineModeWarning = get("misc.disable_offline_mode_warning",disableOfflineModeWarning); -+ enableIoUring = get("misc.enable_io_uring_support",enableIoUring); - - if (tpsbarEnabled){ - initTpsbar(); -diff --git a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -index 6e95017f4c36208abdf344e3b7d55efe2d5b4e10..96237f8665d58be4fd86524daa0160cc7f9f5c1f 100644 ---- a/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -+++ b/src/main/java/net/minecraft/server/network/ServerConnectionListener.java -@@ -20,9 +20,11 @@ import io.netty.channel.epoll.EpollServerSocketChannel; - import io.netty.channel.local.LocalAddress; - import io.netty.channel.local.LocalServerChannel; - import io.netty.channel.nio.NioEventLoopGroup; --import io.netty.channel.socket.ServerSocketChannel; - import io.netty.channel.socket.nio.NioServerSocketChannel; - import io.netty.handler.timeout.ReadTimeoutHandler; -+import io.netty.incubator.channel.uring.IOUring; -+import io.netty.incubator.channel.uring.IOUringEventLoopGroup; -+import io.netty.incubator.channel.uring.IOUringServerSocketChannel; - import io.netty.util.HashedWheelTimer; - import io.netty.util.Timeout; - import io.netty.util.Timer; -@@ -35,6 +37,8 @@ import java.util.List; - import java.util.concurrent.TimeUnit; - import java.util.function.Supplier; - import javax.annotation.Nullable; -+ -+import me.earthme.luminol.LuminolConfig; - import net.minecraft.CrashReport; - import net.minecraft.ReportedException; - import net.minecraft.network.BandwidthDebugMonitor; -@@ -73,6 +77,10 @@ public class ServerConnectionListener { - } - // Paper end - prevent blocking on adding a new connection while the server is ticking - -+ //Luminol start - io_uring support -+ public static final Supplier SERVER_IO_URING_WORKER_GROUP = Suppliers.memoize(() -> new IOUringEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty IO_URING Server IO #%d").setDaemon(true).setUncaughtExceptionHandler(new net.minecraft.DefaultUncaughtExceptionHandlerWithName(LOGGER)).build())); -+ //Luminol end -+ - public ServerConnectionListener(MinecraftServer server) { - this.server = server; - this.running = true; -@@ -90,7 +98,14 @@ public class ServerConnectionListener { - Class oclass; - EventLoopGroup eventloopgroup; - -- if (Epoll.isAvailable() && this.server.isEpollEnabled()) { -+ //Luminol start - io_uring support -+ if (IOUring.isAvailable() && LuminolConfig.enableIoUring){ -+ eventloopgroup = SERVER_IO_URING_WORKER_GROUP.get(); -+ oclass = IOUringServerSocketChannel.class; -+ ServerConnectionListener.LOGGER.info("Using io_uring channel type"); -+ } -+ else if (Epoll.isAvailable() && this.server.isEpollEnabled()) { -+ //Luminol end - // Paper start - Unix domain socket support - if (address instanceof io.netty.channel.unix.DomainSocketAddress) { - oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class;