Compare commits

...

6 Commits

Author SHA1 Message Date
MrHua269
909b208b67 Merge remote-tracking branch 'origin/ver/1.20.2' into ver/1.20.2 2024-01-31 09:29:52 +00:00
MrHua269
b159640ebe Fixes in fakeplayer and io_uring channel type 2024-01-31 09:29:36 +00:00
M2ke4U
76aa79aa3c Correct wrong thread name
How careless I could be()
2024-01-30 21:14:57 +08:00
MrHua269
f2d8696e94 Io_uring channel type support 2024-01-30 13:09:21 +00:00
MrHua269
31e86623e1 Set CI auto release from release to prerelease 2024-01-30 13:09:10 +00:00
MrHua269
a290a8d6a0 Reapply leaves fakeplayer 2024-01-30 09:08:54 +00:00
4 changed files with 254 additions and 352 deletions

View File

@@ -60,4 +60,4 @@ jobs:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
file: "build/libs/luminol-1.20.2-paperclip.jar"
file_glob: true
prerelease: false
prerelease: true

View File

@@ -1,11 +1,11 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrHua269 <novau233@163.com>
Date: Mon, 29 Jan 2024 12:44:10 +0000
Date: Tue, 30 Jan 2024 09:03:08 +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 b7e1c8bd8dd38e1a9e74925740b22dad61a75f49..36863cd765277b9b551ae04a4ecbee502c4d0a4e 100644
index b7e1c8bd8dd38e1a9e74925740b22dad61a75f49..5ee1ba3847599ac67b5cd8ca26e61b1231c45dcd 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;
@@ -16,7 +16,7 @@ index b7e1c8bd8dd38e1a9e74925740b22dad61a75f49..36863cd765277b9b551ae04a4ecbee50
/**
* Represents the Bukkit core, for version and Server singleton handling
@@ -2836,6 +2837,18 @@ public final class Bukkit {
@@ -2836,6 +2837,17 @@ public final class Bukkit {
}
// Folia end - region threading API
@@ -30,13 +30,12 @@ index b7e1c8bd8dd38e1a9e74925740b22dad61a75f49..36863cd765277b9b551ae04a4ecbee50
+ 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 85b169c04f44431363d4e14d4857140f160ceace..ed89520a9bf17a6f2665a17ded0c334d8f9bf130 100644
index 85b169c04f44431363d4e14d4857140f160ceace..9e12552aca127892d122a2616d303d3cdfc67416 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;
@@ -52,6 +51,7 @@ index 85b169c04f44431363d4e14d4857140f160ceace..ed89520a9bf17a6f2665a17ded0c334d
public boolean isGlobalTickThread();
// Folia end - region threading API
+
+
+ // Leaves start - Bot API
+ /**
+ * Returns a bot manager.
@@ -60,14 +60,13 @@ index 85b169c04f44431363d4e14d4857140f160ceace..ed89520a9bf17a6f2665a17ded0c334d
+ */
+ @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
index 0000000000000000000000000000000000000000..8816683c795f9be6a4f112203cfac3f59d8faba5
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/entity/Bot.java
@@ -0,0 +1,51 @@
@@ -0,0 +1,46 @@
+package top.leavesmc.leaves.entity;
+
+import org.bukkit.entity.Player;
@@ -75,8 +74,6 @@ index 0000000000000000000000000000000000000000..02815077dcd6d5c1b155ef3ca5cd6e3a
+import org.jetbrains.annotations.Nullable;
+import top.leavesmc.leaves.entity.botaction.LeavesBotAction;
+
+import java.util.UUID;
+
+/**
+ * Represents a fakeplayer
+ */
@@ -98,15 +95,12 @@ index 0000000000000000000000000000000000000000..02815077dcd6d5c1b155ef3ca5cd6e3a
+ @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
+ * @param args passed action arguments
+ */
+ public boolean setBotAction(@NotNull String action, @NotNull Player player, @NotNull String[] args);
+
@@ -115,7 +109,7 @@ index 0000000000000000000000000000000000000000..02815077dcd6d5c1b155ef3ca5cd6e3a
+ *
+ * @param action leaves bot action
+ * @param player player who create this action
+ * @param args passed action arguments
+ * @param args passed action arguments
+ */
+ public boolean setBotAction(@NotNull LeavesBotAction action, @NotNull Player player, @NotNull String[] args);
+}
@@ -477,58 +471,6 @@ index 0000000000000000000000000000000000000000..4a4fe07ce965d4a97e0d8105a91310da
+ 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

View File

@@ -1,11 +1,11 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrHua269 <novau233@163.com>
Date: Mon, 29 Jan 2024 13:22:53 +0000
Date: Tue, 30 Jan 2024 08:59:03 +0000
Subject: [PATCH] Leaves fakeplayer support
diff --git a/src/main/java/me/earthme/luminol/LuminolConfig.java b/src/main/java/me/earthme/luminol/LuminolConfig.java
index e531453e3d25700e38ff41548c7e32e278a6304d..f924a238f211c22a00b8df67a209dcfea751039c 100644
index e531453e3d25700e38ff41548c7e32e278a6304d..610642b0a0c3f17c66ec27ed812b97c68cee1be6 100644
--- a/src/main/java/me/earthme/luminol/LuminolConfig.java
+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java
@@ -78,7 +78,17 @@ public class LuminolConfig {
@@ -39,7 +39,7 @@ index e531453e3d25700e38ff41548c7e32e278a6304d..f924a238f211c22a00b8df67a209dcfe
+ fakeplayerSkipSleep = get("gameplay.fakeplayer.fakeplayer_skip_sleep",fakeplayerSkipSleep);
+ fakeplayerResident = get("gameplay.fakeplayer.resident",fakeplayerResident);
+ fakeplayerSpawnPhantom = get("gameplay.fakeplayer.spawn_phantom_for_fakeplayer",fakeplayerSpawnPhantom);
+ fakeplayerRegenAmount = get("gameplay.fakeplayer.regen_amount",fakeplayerRegenAmount);
+ fakeplayerRegenAmount = Double.parseDouble(get("gameplay.fakeplayer.regen_amount",String.valueOf(fakeplayerRegenAmount)));
+ unableFakeplayerNames = get("gameplay.fakeplayer.name_black_list",unableFakeplayerNames);
+
+ if (fakeplayerSupport){
@@ -59,18 +59,6 @@ index e531453e3d25700e38ff41548c7e32e278a6304d..f924a238f211c22a00b8df67a209dcfe
}
public static <T> 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 f0367a9cce13ef576fbb7023c0aba6eb48963606..7b156d147c409ded1b0385583e0b34d3bd5c48de 100644
--- a/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
+++ b/src/main/java/net/minecraft/advancements/critereon/SimpleCriterionTrigger.java
@@ -51,6 +51,7 @@ public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.Si
}
protected void trigger(ServerPlayer player, Predicate<T> predicate) {
+ if (player instanceof top.leavesmc.leaves.bot.ServerBot) return; // Leaves - bot skip
PlayerAdvancements playerAdvancements = player.getAdvancements();
Set<CriterionTrigger.Listener<T>> 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 b84e9d5ae5efe1a8257a5f1f78a0ab66113a698e..832f6851a3f72cefe95c96757645374ac592f33b 100644
--- a/src/main/java/net/minecraft/network/Connection.java
@@ -91,10 +79,18 @@ index b84e9d5ae5efe1a8257a5f1f78a0ab66113a698e..832f6851a3f72cefe95c96757645374a
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 675bbf1f69011f7f95fabc050c9877d6e70070b2..926b80aa09b0a593f4074efc86601ac176692c72 100644
index 675bbf1f69011f7f95fabc050c9877d6e70070b2..87d8338900d09be1962965abfd62f7484fa31a25 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -669,6 +669,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -128,6 +128,7 @@ import net.minecraft.util.profiling.metrics.storage.MetricsPersister;
import net.minecraft.util.thread.ReentrantBlockableEventLoop;
import net.minecraft.world.Difficulty;
import net.minecraft.world.RandomSequences;
+import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.ai.village.VillageSiege;
import net.minecraft.world.entity.npc.CatSpawner;
@@ -669,6 +670,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
// Paper end
@@ -103,7 +99,7 @@ index 675bbf1f69011f7f95fabc050c9877d6e70070b2..926b80aa09b0a593f4074efc86601ac1
this.server.enablePlugins(org.bukkit.plugin.PluginLoadOrder.POSTWORLD);
this.server.getPluginManager().callEvent(new ServerLoadEvent(ServerLoadEvent.LoadType.STARTUP));
this.connection.acceptConnections();
@@ -962,6 +964,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -962,6 +965,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
// Folia end - region threading
public void stopServer() {
@@ -128,7 +124,7 @@ index e38e2e5a7ddba9c140f362021b6be0b0974f7cd1..870a9c94885c983cd7a557b76cb4dbac
AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
boolean flag1 = advancementprogress.isDone();
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 3cba356b74362c2fc010d0c1bfb6eeecb449908e..45873f2c51a82287c5ab9bfec4d893bea39b42a5 100644
index 3cba356b74362c2fc010d0c1bfb6eeecb449908e..afcf83aea7e1b43cb925856076d6c09aa9e47800 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -1438,6 +1438,13 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
@@ -137,7 +133,7 @@ index 3cba356b74362c2fc010d0c1bfb6eeecb449908e..45873f2c51a82287c5ab9bfec4d893be
this.serverEntity.removePairing(player);
+ // Leaves start - render bot
+ if (entity instanceof top.leavesmc.leaves.bot.ServerBot bot) {
+ if (bot.alwaysSendData) {
+ if (me.earthme.luminol.LuminolConfig.alwaysSendFakeplayerData) {
+ bot.sendFakeData(player.connection, false);
+ }
+ }
@@ -146,10 +142,18 @@ index 3cba356b74362c2fc010d0c1bfb6eeecb449908e..45873f2c51a82287c5ab9bfec4d893be
}
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
index 755294e3f5b3fbcfbdc0cc85627b2487663ce591..5910c1585385d44e90280032ca3cc8e2ee2b4b70 100644
index 755294e3f5b3fbcfbdc0cc85627b2487663ce591..ea409d2a03c35990c6857c24305346a6ec7f4bf8 100644
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -183,6 +183,7 @@ import org.bukkit.event.player.PlayerTeleportEvent;
@@ -98,7 +98,6 @@ import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.util.Unit;
import net.minecraft.world.damagesource.DamageSource;
-import net.minecraft.world.damagesource.DamageSources;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.effect.MobEffects;
import net.minecraft.world.entity.Entity;
@@ -183,6 +182,7 @@ import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause;
import org.bukkit.event.player.PlayerToggleSneakEvent;
import org.bukkit.inventory.MainHand;
@@ -157,11 +161,10 @@ index 755294e3f5b3fbcfbdc0cc85627b2487663ce591..5910c1585385d44e90280032ca3cc8e2
// CraftBukkit end
public class ServerPlayer extends Player {
@@ -826,21 +827,25 @@ public class ServerPlayer extends Player {
--this.invulnerableTime;
@@ -827,20 +827,24 @@ public class ServerPlayer extends Player {
}
- // Paper start - Configurable container update tick rate
// Paper start - Configurable container update tick rate
- if (--containerUpdateDelay <= 0) {
- this.containerMenu.broadcastChanges();
- containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate;
@@ -172,7 +175,6 @@ index 755294e3f5b3fbcfbdc0cc85627b2487663ce591..5910c1585385d44e90280032ca3cc8e2
- this.containerMenu = this.inventoryMenu;
+ // Leaves start - skip bot
+ if (!(this instanceof ServerBot)) {
+ // Paper start - Configurable container update tick rate
+ if (--containerUpdateDelay <= 0) {
+ this.containerMenu.broadcastChanges();
+ containerUpdateDelay = this.level().paperConfig().tickRates.containerUpdate;
@@ -193,7 +195,7 @@ index 755294e3f5b3fbcfbdc0cc85627b2487663ce591..5910c1585385d44e90280032ca3cc8e2
if (this.levitationStartPos != null) {
CriteriaTriggers.LEVITATION.trigger(this, this.levitationStartPos, this.tickCount - this.levitationStartTime);
}
@@ -1065,7 +1070,7 @@ public class ServerPlayer extends Player {
@@ -1065,7 +1069,7 @@ public class ServerPlayer extends Player {
java.util.List<org.bukkit.inventory.ItemStack> loot = new java.util.ArrayList<org.bukkit.inventory.ItemStack>(this.getInventory().getContainerSize());
boolean keepInventory = this.level().getGameRules().getBoolean(GameRules.RULE_KEEPINVENTORY) || this.isSpectator();
@@ -202,7 +204,7 @@ index 755294e3f5b3fbcfbdc0cc85627b2487663ce591..5910c1585385d44e90280032ca3cc8e2
for (ItemStack item : this.getInventory().getContents()) {
if (!item.isEmpty() && !EnchantmentHelper.hasVanishingCurse(item)) {
loot.add(CraftItemStack.asCraftMirror(item));
@@ -1730,6 +1735,13 @@ public class ServerPlayer extends Player {
@@ -1730,6 +1734,13 @@ public class ServerPlayer extends Player {
this.lastSentHealth = -1.0F;
this.lastSentFood = -1;
@@ -236,19 +238,18 @@ index c4652f250e22f33e8505183b4050e08aedf9245c..18745ee33843d668613fd9e7f15d6a79
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 3f366ad035ada0ac8170d2925bbfe86b80bd84cb..f2329d24a4e3f4637b78d4894b0e6c99a0e00faa 100644
index 3f366ad035ada0ac8170d2925bbfe86b80bd84cb..c90fc6a926e19c74358bda6c6f3fa11dafba97bc 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -123,6 +123,8 @@ import org.bukkit.event.player.PlayerRespawnEvent.RespawnReason;
import org.bukkit.event.player.PlayerSpawnChangeEvent;
// CraftBukkit end
@@ -102,6 +102,7 @@ import net.minecraft.world.scores.Objective;
import net.minecraft.world.scores.PlayerTeam;
import net.minecraft.world.scores.Scoreboard; // Paper
import net.minecraft.world.scores.Team;
+import top.leavesmc.leaves.bot.ServerBot;
+
public abstract class PlayerList {
import org.slf4j.Logger;
public static final File USERBANLIST_FILE = new File("banned-players.json");
@@ -437,6 +439,21 @@ public abstract class PlayerList {
// CraftBukkit start
@@ -437,6 +438,21 @@ public abstract class PlayerList {
top.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
@@ -270,13 +271,13 @@ index 3f366ad035ada0ac8170d2925bbfe86b80bd84cb..f2329d24a4e3f4637b78d4894b0e6c99
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
@@ -1092,6 +1109,13 @@ public abstract class PlayerList {
@@ -1092,6 +1108,13 @@ public abstract class PlayerList {
}
// Paper end
+ // Leaves start - bot support
+ if (me.earthme.luminol.LuminolConfig.fakeplayerSupport) {
+ ServerBot.getBots().forEach(bot1 ->
+ top.leavesmc.leaves.bot.ServerBot.getBots().forEach(bot1 ->
+ bot1.sendFakeDataIfNeed(entityplayer1, true)); // Leaves - render bot
+ }
+ // Leaves end - bot support
@@ -284,12 +285,12 @@ index 3f366ad035ada0ac8170d2925bbfe86b80bd84cb..f2329d24a4e3f4637b78d4894b0e6c99
// CraftBukkit end
return entityplayer1;
}
@@ -1201,12 +1225,17 @@ public abstract class PlayerList {
@@ -1201,12 +1224,17 @@ public abstract class PlayerList {
public String[] getPlayerNamesArray() {
List<ServerPlayer> 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()];
+ String[] astring = new String[players.size() + ServerBot.getBots().size()]; // Leaves - fakeplayer support
for (int i = 0; i < players.size(); ++i) {
astring[i] = ((ServerPlayer) players.get(i)).getGameProfile().getName();
@@ -303,12 +304,11 @@ index 3f366ad035ada0ac8170d2925bbfe86b80bd84cb..f2329d24a4e3f4637b78d4894b0e6c99
return astring;
}
@@ -1715,4 +1744,17 @@ public abstract class PlayerList {
@@ -1715,4 +1743,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);
@@ -385,7 +385,7 @@ index f664da5a8413bb13cc95d2cf1604f11a5d285dae..2d5f6a69e0c2dc96375ec24d41522ae4
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 a127b6cbaab211d324d42b3bddcd6ebd84c250e3..2649177134985505a341c40473dfdbb210d0ae87 100644
index a127b6cbaab211d324d42b3bddcd6ebd84c250e3..6898de0b40e00125ba3153cacfc60a98493c8d38 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 {
@@ -393,15 +393,15 @@ index a127b6cbaab211d324d42b3bddcd6ebd84c250e3..2649177134985505a341c40473dfdbb2
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;
+ if (me.earthme.luminol.LuminolConfig.fakeplayerSpawnPhantom && entityplayer instanceof top.leavesmc.leaves.bot.ServerBot) {
+ j = world.paperConfig().entities.behavior.playerInsomniaStartTicks + 1;
+ }
+ // Leaves end - fakeplayer spawn
if (randomsource.nextInt(j) >= world.paperConfig().entities.behavior.playerInsomniaStartTicks) { // Paper
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 ee66241a422acb8920395fd5e41578a966746f5c..913ea63d7103d6a54990b55683d4cf0341d4b722 100644
index ee66241a422acb8920395fd5e41578a966746f5c..a73fc518d5b6c156bf31a1d08d0a0fd0b31bd271 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
@@ -264,6 +264,7 @@ import org.yaml.snakeyaml.constructor.SafeConstructor;
@@ -420,13 +420,12 @@ index ee66241a422acb8920395fd5e41578a966746f5c..913ea63d7103d6a54990b55683d4cf03
// 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
@@ -3241,4 +3243,12 @@ public final class CraftServer implements Server {
@@ -3241,4 +3243,11 @@ public final class CraftServer implements Server {
}
// Paper end
+
+
+ //Leaves start - Bot API
+ // Leaves start - Bot API
+ @Override
+ public CraftBotManager getBotManager() {
+ return botManager;
@@ -462,10 +461,10 @@ index 9f070a9f0894d88688ff50efc3f4dba8188c3885..5699adccb5c2e5e7e6612940cf42fcf9
// Water Animals
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
index 0000000000000000000000000000000000000000..9aa304d4709149ce1104d05bb375d3cf7f54729e
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
@@ -0,0 +1,330 @@
@@ -0,0 +1,274 @@
+package top.leavesmc.leaves.bot;
+
+import org.bukkit.Bukkit;
@@ -513,14 +512,13 @@ index 0000000000000000000000000000000000000000..4563284facbfd01733d6a0efdfe7d0ca
+ 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("<BotName>");
+ case "remove", "action", "config" ->
+ case "remove", "action" ->
+ list.addAll(ServerBot.getBots().stream().map(e -> e.getName().getString()).toList());
+ case "list" -> list.addAll(Bukkit.getWorlds().stream().map(WorldInfo::getName).toList());
+ }
@@ -533,16 +531,6 @@ index 0000000000000000000000000000000000000000..4563284facbfd01733d6a0efdfe7d0ca
+ list.addAll(Actions.getNames());
+ }
+ case "create" -> list.add("<BotSkinName>");
+ case "config" -> list.addAll(acceptConfig);
+ }
+ }
+
+ if (args.length == 4) {
+ switch (args[0]) {
+ case "config" -> {
+ list.add("true");
+ list.add("false");
+ }
+ }
+ }
+
@@ -552,13 +540,12 @@ index 0000000000000000000000000000000000000000..4563284facbfd01733d6a0efdfe7d0ca
+ 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 (!testPermission(sender)) return true;
+
+ if (args.length == 0) {
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
@@ -572,8 +559,6 @@ index 0000000000000000000000000000000000000000..4563284facbfd01733d6a0efdfe7d0ca
+
+ case "action" -> this.onAction(sender, args);
+
+ case "config" -> this.onConfig(sender, args);
+
+ case "list" -> this.onList(sender, args);
+
+ default -> {
@@ -593,7 +578,7 @@ index 0000000000000000000000000000000000000000..4563284facbfd01733d6a0efdfe7d0ca
+
+ 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());
+ new ServerBot.BotCreateState(player.getLocation(), args[1], args.length < 3 ? args[1] : args[2]).createAsync(null);
+ } else if (sender instanceof ConsoleCommandSender) {
+ if (args.length < 6) {
+ sender.sendMessage(ChatColor.RED + "Use /bot create <name> <skin_name> <bukkit_world_name> <x> <y> <z> to create a fakeplayer");
@@ -709,48 +694,6 @@ index 0000000000000000000000000000000000000000..4563284facbfd01733d6a0efdfe7d0ca
+ sender.sendMessage("Action " + action.getName() + " has been issued to " + bot.getName().getString());
+ }
+
+ private static final List<String> 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 <name> <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<World, List<String>> botMap = new HashMap<>();
@@ -1028,10 +971,10 @@ index 0000000000000000000000000000000000000000..c3f114fba0759221b5fea0ccc4862f05
+}
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..8e8edd0a9fb53449fa3d1bee81629d667d0aa572
index 0000000000000000000000000000000000000000..be3a40e3100ec838cf8de6437cc6b1b0c454bc68
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/BotUtil.java
@@ -0,0 +1,183 @@
@@ -0,0 +1,182 @@
+package top.leavesmc.leaves.bot;
+
+import com.google.common.base.Charsets;
@@ -1041,7 +984,6 @@ index 0000000000000000000000000000000000000000..8e8edd0a9fb53449fa3d1bee81629d66
+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;
@@ -1264,10 +1206,10 @@ index 0000000000000000000000000000000000000000..daaece30b2a3983f1cc9ee9a851e8f37
+}
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..30391d5dc0e1bdaeaf9ee190e74c3da0440eeef8
index 0000000000000000000000000000000000000000..dcdc4fac1bf972085ea4cd789efd27370410e5e1
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java
@@ -0,0 +1,760 @@
@@ -0,0 +1,715 @@
+package top.leavesmc.leaves.bot;
+
+import com.google.common.collect.Lists;
@@ -1277,9 +1219,6 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+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;
@@ -1322,17 +1261,19 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.scheduler.CraftScheduler;
+import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.Contract;
+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;
+
@@ -1350,10 +1291,8 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+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 {
@@ -1369,17 +1308,12 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+ public boolean waterSwim;
+ private Vec3 knockback;
+ public BotCreateState createState;
+ public UUID createPlayer;
+
+ private final ServerStatsCounter stats;
+ private final BotInventoryContainer container;
+
+ private static final List<ServerBot> 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);
@@ -1392,14 +1326,10 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+ this.removeOnDeath = true;
+ this.stats = new BotStatsCounter(server);
+ this.container = new BotInventoryContainer(this);
+ this.fauxSleeping = me.earthme.luminol.LuminolConfig.fakeplayerSkipSleep;
+ 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) {
@@ -1409,70 +1339,45 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+
+ MinecraftServer server = MinecraftServer.getServer();
+
+ Supplier<ServerBot> creator = () -> {
+ BotCreateEvent event = new BotCreateEvent(state.name, state.skinName, state.loc, ChatColor.YELLOW + state.name + " joined the game");
+ server.server.getPluginManager().callEvent(event);
+ 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();
+ if (event.isCancelled()) {
+ return null;
+ }
+
+ return CompletableFuture.supplyAsync(
+ creator,
+ task ->
+ RegionizedServer.getInstance().taskQueue.queueTickTaskQueue(
+ ((CraftWorld) state.loc.getWorld()).getHandle(),
+ state.loc.getBlockX() >> 4,
+ state.loc.getBlockZ() >> 4,
+ task
+ )
+ ).join();
+ 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, @Nullable PacketSendListener packetsendlistener) {
+ }
+ }, 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;
+ }
+
+ public static boolean isCreateLegal(@NotNull String name) {
@@ -1505,7 +1410,7 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+ }
+
+ public boolean needSendFakeData(ServerPlayer player) {
+ return alwaysSendData && (player.level() == this.level() && player.position().distanceToSqr(this.position()) > this.tracingRange);
+ return me.earthme.luminol.LuminolConfig.alwaysSendFakeplayerData && (player.level() == this.level() && player.position().distanceToSqr(this.position()) > this.tracingRange);
+ }
+
+ public void sendFakeDataIfNeed(ServerPlayer player, boolean login) {
@@ -1515,11 +1420,11 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+ }
+
+ public void sendFakeData(ServerPlayerConnection playerConnection, boolean login) {
+ playerConnection.send(new ClientboundAddEntityPacket(this));
+ playerConnection.send(new ClientboundAddEntityPacket(this));
+ if (login) {
+ Bukkit.getScheduler().runTaskLater(CraftScheduler.MINECRAFT, () -> {
+ playerConnection.getPlayer().getBukkitEntity().taskScheduler.schedule(task -> {
+ connection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f)));
+ }, 10);
+ },null,10);
+ } else {
+ connection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f)));
+ }
@@ -1600,10 +1505,6 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+ return;
+ }
+
+ if (spawnPhantom) {
+ notSleepTicks++;
+ }
+
+ if (fireTicks > 0) {
+ --fireTicks;
+ }
@@ -1620,21 +1521,19 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+ 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;
+ float health = getHealth();
+ float maxHealth = getMaxHealth();
+ float regenAmount = 0.010f;
+ float amount;
+
+ if (health < maxHealth - regenAmount) {
+ amount = health + regenAmount;
+ } else {
+ amount = maxHealth;
+ }
+
+ this.setHealth(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);
@@ -1851,13 +1750,9 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+ @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;
+ }
+ if (player.getMainHandItem().isEmpty()) {
+ player.openMenu(new SimpleMenuProvider((i, inventory, p) -> ChestMenu.sixRows(i, inventory, container), getDisplayName()));
+ return InteractionResult.SUCCESS;
+ }
+ }
+ return super.interact(player, hand);
@@ -1994,19 +1889,21 @@ index 0000000000000000000000000000000000000000..30391d5dc0e1bdaeaf9ee190e74c3da0
+
+ public void createAsync(Consumer<ServerBot> 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);
+ if (skinName != null) {
+ this.skin = MojangAPI.getSkin(skinName);
+ }
+
+ RegionizedServer.getInstance().taskQueue.queueTickTaskQueue(
+ ((CraftWorld) loc.getWorld()).getHandle(),
+ loc.getBlockX() >> 4,
+ loc.getBlockZ() >> 4,
+ ()->{
+ ServerBot bot = createBot(this);
+ if (bot != null && consumer != null) {
+ consumer.accept(bot);
+ }
+ }
+ );
+ });
+ }
+
@@ -2873,23 +2770,17 @@ index 0000000000000000000000000000000000000000..345932e779f5187355ca722c2bb9b05f
+}
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
index 0000000000000000000000000000000000000000..886e37227e66dc25653b8ad53fef600c705aa101
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnAction.java
@@ -0,0 +1,56 @@
@@ -0,0 +1,40 @@
+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;
@@ -2915,43 +2806,27 @@ index 0000000000000000000000000000000000000000..f4837f60909763df89ea7474f70dd023
+ @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());
+ if (result.getType() == HitResult.Type.BLOCK) {
+ 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();
+ }
+ 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
index 0000000000000000000000000000000000000000..16ae37e2ffb4189041986e759d563d00a9126ad8
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/actions/UseItemOnOffhandAction.java
@@ -0,0 +1,56 @@
@@ -0,0 +1,40 @@
+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;
@@ -2977,20 +2852,10 @@ index 0000000000000000000000000000000000000000..4ab84fba3624a8e8c4d345c03fe678a0
+ @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());
+ if (result.getType() == HitResult.Type.BLOCK) {
+ 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();
+ }
+ bot.updateItemInOffHand();
+ return bot.gameMode.useItemOn(bot, bot.level(), bot.getItemInHand(InteractionHand.OFF_HAND), InteractionHand.OFF_HAND, (BlockHitResult) result).consumesAction();
+ }
+ return false;
+ }
@@ -3112,10 +2977,10 @@ index 340eaca64c96180b895a075ce9e44402cd104eed..39e90dcff0de259373d7955021c29397
}
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
index 0000000000000000000000000000000000000000..e30ce391f638778fc805ca75287917af99b37443
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/entity/CraftBot.java
@@ -0,0 +1,67 @@
@@ -0,0 +1,60 @@
+package top.leavesmc.leaves.entity;
+
+import org.bukkit.craftbukkit.CraftServer;
@@ -3128,8 +2993,6 @@ index 0000000000000000000000000000000000000000..713240da3ba37915b455d952a45ae7f6
+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) {
@@ -3147,11 +3010,6 @@ index 0000000000000000000000000000000000000000..713240da3ba37915b455d952a45ae7f6
+ }
+
+ @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) {

View File

@@ -0,0 +1,102 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrHua269 <novau233@163.com>
Date: Tue, 30 Jan 2024 13:08:25 +0000
Subject: [PATCH] Io_uring channel type support
diff --git a/build.gradle.kts b/build.gradle.kts
index 8a926993088d33983f75071b3320dd67c3e857c3..aa1033e0de7d59c32acd2afa58c0b916588b97ed 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 610642b0a0c3f17c66ec27ed812b97c68cee1be6..87f5c0fc3f92feecb167c3e28d86a67ba848cb61 100644
--- a/src/main/java/me/earthme/luminol/LuminolConfig.java
+++ b/src/main/java/me/earthme/luminol/LuminolConfig.java
@@ -37,6 +37,7 @@ public class LuminolConfig {
public static boolean fixSpectorTeleportFolia = false;
public static boolean disableRootUserWarning = false;
public static boolean fixDoubleEntitySchedulerRetring = false;
+ public static boolean enableIoUring = false;
public static boolean safeTeleportation = true;
public static boolean enableSandDuping = false;
@@ -185,6 +186,7 @@ public class LuminolConfig {
disableOfflineModeWarning = get("misc.disable_offline_mode_warning",disableOfflineModeWarning);
disableRootUserWarning = get("misc.disable_root_user_warning",disableRootUserWarning);
fixDoubleEntitySchedulerRetring = get("misc.fix_folia_double_entity_scheduler_retring",fixDoubleEntitySchedulerRetring,"Fix https://github.com/PaperMC/Folia/pull/181 on Folia");
+ 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 81090d1b5d67506268a41c6387a1d45302e88a5c..637d321b75dc7b5653ff9aa6134f900c634a19d8 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
+ //Luminol start - io_uring support
+ public static final Supplier<IOUringEventLoopGroup> 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;
@@ -89,8 +97,14 @@ public class ServerConnectionListener {
synchronized (this.channels) {
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
if (address instanceof io.netty.channel.unix.DomainSocketAddress) {
oclass = io.netty.channel.epoll.EpollServerDomainSocketChannel.class;
@@ -100,7 +114,8 @@ public class ServerConnectionListener {
// Paper end
eventloopgroup = (EventLoopGroup) ServerConnectionListener.SERVER_EPOLL_EVENT_GROUP.get();
ServerConnectionListener.LOGGER.info("Using epoll channel type");
- } else {
+ }
+ else {
oclass = NioServerSocketChannel.class;
eventloopgroup = (EventLoopGroup) ServerConnectionListener.SERVER_EVENT_GROUP.get();
ServerConnectionListener.LOGGER.info("Using default channel type");