diff --git a/patches/api/0003-Add-fakeplayer-api.patch b/patches/api/0003-Add-fakeplayer-api.patch
index d72a46b4..c38a816b 100644
--- a/patches/api/0003-Add-fakeplayer-api.patch
+++ b/patches/api/0003-Add-fakeplayer-api.patch
@@ -4,6 +4,62 @@ Date: Wed, 27 Jul 2022 15:30:34 +0800
Subject: [PATCH] Add fakeplayer api
+diff --git a/src/main/java/org/bukkit/Bukkit.java b/src/main/java/org/bukkit/Bukkit.java
+index b243db56756c67cd2c41d7768898d01539f9260a..99a096e52775a58a38540dfd736b0f57236fd488 100644
+--- a/src/main/java/org/bukkit/Bukkit.java
++++ b/src/main/java/org/bukkit/Bukkit.java
+@@ -57,6 +57,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
+@@ -2658,6 +2659,17 @@ public final class Bukkit {
+ }
+ // Paper end - Folia 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 3c4915b8dd1b6e802a5942658b15d3a9db472364..0bfe5628c8327e9cd5728cea7ae6c2ce1ec9541d 100644
+--- a/src/main/java/org/bukkit/Server.java
++++ b/src/main/java/org/bukkit/Server.java
+@@ -57,6 +57,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.
+@@ -2321,4 +2322,13 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
+ */
+ boolean isOwnedByCurrentRegion(@NotNull Entity entity);
+ // Paper end - Folia 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..8057d1faa66540b8c4042a0f5c0f862e8a39eef1
@@ -37,6 +93,101 @@ index 0000000000000000000000000000000000000000..8057d1faa66540b8c4042a0f5c0f862e
+ @NotNull
+ public String getRealName();
+}
+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..d9b2248ef7e080851bf5f1c4539aa6edb3927966
+--- /dev/null
++++ b/src/main/java/top/leavesmc/leaves/entity/BotManager.java
+@@ -0,0 +1,89 @@
++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 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();
++}
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
diff --git a/patches/server/0008-Fakeplayer-support.patch b/patches/server/0008-Fakeplayer-support.patch
index 02e238ca..9551122a 100644
--- a/patches/server/0008-Fakeplayer-support.patch
+++ b/patches/server/0008-Fakeplayer-support.patch
@@ -267,6 +267,38 @@ index 706b354ac9a1a6a4a1e61b2a109180d1dd22bbbd..f13f21dbd50f63a71276837abbcf82e0
private boolean tryItemClickBehaviourOverride(Player player, ClickAction clickType, Slot slot, ItemStack stack, ItemStack cursorStack) {
FeatureFlagSet featureflagset = player.level().enabledFeatures();
+diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+index a394fcb1afe37efda30893e06352941f1a049319..1be2fbe522fcf54ef4a9a0dd03aebf57ced5880c 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
+@@ -304,6 +305,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
++ private final CraftBotManager botManager = new CraftBotManager();
+
+ // Paper start - Folia region threading API
+ private final io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler regionizedScheduler = new io.papermc.paper.threadedregions.scheduler.FallbackRegionScheduler();
+@@ -3088,4 +3090,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 fc0dc8e607cc24020106ea1af92b4421a5f9393d..81670f76c4d7ccec6f9e95465687c83b37c544bd 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -295,7 +327,7 @@ index fc0dc8e607cc24020106ea1af92b4421a5f9393d..81670f76c4d7ccec6f9e95465687c83b
}
// Water Animals
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
-index 5ca9ffe8747ef9e8bd2936402e2f7201ec3a5762..4a919417ffefde2afdeaa3da222ca8f79f6567a9 100644
+index 28c18d02a1d04582e6f0badbc9917e6356bf8532..f621ae9f8a1c1488f4d4c3c98555cd3f4c769b87 100644
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -7,6 +7,9 @@ import org.bukkit.Bukkit;
@@ -1028,10 +1060,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..e649d92c3c51a1087c0ff8b8b90e362bf57a8d29
+index 0000000000000000000000000000000000000000..a80777a9b2b6f5cb57671e722b29e60cd83b7a2f
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java
-@@ -0,0 +1,630 @@
+@@ -0,0 +1,643 @@
+package top.leavesmc.leaves.bot;
+
+import com.google.common.collect.Lists;
@@ -1102,12 +1134,14 @@ index 0000000000000000000000000000000000000000..e649d92c3c51a1087c0ff8b8b90e362b
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.util.ArrayList;
++import java.util.Collections;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.UUID;
++import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.function.Consumer;
+
+// TODO remake all
@@ -1131,7 +1165,7 @@ index 0000000000000000000000000000000000000000..e649d92c3c51a1087c0ff8b8b90e362b
+
+ private final BotInventoryContainer container;
+
-+ private static final List bots = new ArrayList<>();
++ private static final List bots = new CopyOnWriteArrayList<>();
+ private static final Plugin MINECRAFT_PLUGIN = new MinecraftInternalPlugin();
+
+ private ServerBot(MinecraftServer server, ServerLevel world, GameProfile profile) {
@@ -1593,6 +1627,17 @@ index 0000000000000000000000000000000000000000..e649d92c3c51a1087c0ff8b8b90e362b
+ 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 (LeavesConfig.fakeplayerSupport && LeavesConfig.fakeplayerResident) {
+ JsonObject fakePlayerList = new JsonObject();
@@ -1644,7 +1689,7 @@ index 0000000000000000000000000000000000000000..e649d92c3c51a1087c0ff8b8b90e362b
+ return true;
+ }
+
-+ public static List getBots() { // It needs unmodifiable
++ public static List getBots() {
+ return bots;
+ }
+
@@ -2511,6 +2556,95 @@ index 0000000000000000000000000000000000000000..7c436136a1f2a61978fbf992b90312a3
+ 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..35a9c428432a65825a4712939574df5301bf2248
+--- /dev/null
++++ b/src/main/java/top/leavesmc/leaves/entity/CraftBotManager.java
+@@ -0,0 +1,83 @@
++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 java.util.Collection;
++import java.util.Collections;
++import java.util.List;
++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 = ServerBot.createBot(location, name, realName, skin, skinName);
++ if (bot != null) {
++ return bot.getBukkitPlayer();
++ }
++ return null;
++ }
++
++ @Override
++ public void createBot(@NotNull String name, @Nullable String skinName, @NotNull Location location, Consumer consumer) {
++ ServerBot.createBot(location, name, skinName, serverBot -> {
++ if (consumer != null) {
++ 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;
++ }
++}
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
diff --git a/patches/server/0043-PCA-sync-protocol.patch b/patches/server/0043-PCA-sync-protocol.patch
index 12999c4f..ef346075 100644
--- a/patches/server/0043-PCA-sync-protocol.patch
+++ b/patches/server/0043-PCA-sync-protocol.patch
@@ -343,10 +343,10 @@ index b7686fd63b7c5d88c3a12ec4ee9bc01a17f997e0..25a9c38c60d183bb65b14f4d7550ab98
public int[] getSlotsForFace(Direction side) {
return ShulkerBoxBlockEntity.SLOTS;
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-index a394fcb1afe37efda30893e06352941f1a049319..31c7ec216108388954694c1ca0ae26d23c0c4c3c 100644
+index 1be2fbe522fcf54ef4a9a0dd03aebf57ced5880c..c1f0e7fe9eb7247fef6bb088c64ca49cce17a14e 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-@@ -465,6 +465,7 @@ public final class CraftServer implements Server {
+@@ -467,6 +467,7 @@ public final class CraftServer implements Server {
MapPalette.setMapColorCache(new CraftMapColorCache(this.logger));
}
datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper
@@ -354,7 +354,7 @@ index a394fcb1afe37efda30893e06352941f1a049319..31c7ec216108388954694c1ca0ae26d2
}
public boolean getCommandBlockOverride(String command) {
-@@ -1057,6 +1058,13 @@ public final class CraftServer implements Server {
+@@ -1059,6 +1060,13 @@ public final class CraftServer implements Server {
org.spigotmc.SpigotConfig.init((File) console.options.valueOf("spigot-settings")); // Spigot
this.console.paperConfigurations.reloadConfigs(this.console);
top.leavesmc.leaves.LeavesConfig.init((File) console.options.valueOf("leaves-settings")); // Leaves - Server Config
diff --git a/patches/server/0044-BBOR-Protocol.patch b/patches/server/0044-BBOR-Protocol.patch
index 8f777ecd..1c5dd354 100644
--- a/patches/server/0044-BBOR-Protocol.patch
+++ b/patches/server/0044-BBOR-Protocol.patch
@@ -77,10 +77,10 @@ index cc224af0139a6e3adefd22cbfa0cd519735b7191..2c3ca05644bc97d505e8ca92e7a5f486
public Level getLevel() {
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-index 31c7ec216108388954694c1ca0ae26d23c0c4c3c..6a8c524d401e421dbf6aa7a40d12e1e1b44f6110 100644
+index c1f0e7fe9eb7247fef6bb088c64ca49cce17a14e..19b68c4a1807342cbe08420380877680a2519054 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-@@ -1065,6 +1065,13 @@ public final class CraftServer implements Server {
+@@ -1067,6 +1067,13 @@ public final class CraftServer implements Server {
top.leavesmc.leaves.protocol.PcaSyncProtocol.disablePcaSyncProtocolGlobal();
}
// Leaves end - pca
diff --git a/patches/server/0047-Jade-Protocol.patch b/patches/server/0047-Jade-Protocol.patch
index deb844a8..d2e6e76b 100644
--- a/patches/server/0047-Jade-Protocol.patch
+++ b/patches/server/0047-Jade-Protocol.patch
@@ -45,10 +45,10 @@ index 4aeab90e778629c355189dfe79c39c4b21f5f5ac..fe8c9b7e7956837829b4fe3eb449b2c0
}
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-index 6a8c524d401e421dbf6aa7a40d12e1e1b44f6110..6888d0b096b665a10cf6b050a4e69be1b7d7928d 100644
+index 19b68c4a1807342cbe08420380877680a2519054..9fba7105b7e70ad05c243ee6cec27a8ebe875d83 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-@@ -466,6 +466,7 @@ public final class CraftServer implements Server {
+@@ -468,6 +468,7 @@ public final class CraftServer implements Server {
}
datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper
top.leavesmc.leaves.protocol.PcaSyncProtocol.init(); // Leaves - pca
@@ -56,7 +56,7 @@ index 6a8c524d401e421dbf6aa7a40d12e1e1b44f6110..6888d0b096b665a10cf6b050a4e69be1
}
public boolean getCommandBlockOverride(String command) {
-@@ -1072,6 +1073,11 @@ public final class CraftServer implements Server {
+@@ -1074,6 +1075,11 @@ public final class CraftServer implements Server {
top.leavesmc.leaves.protocol.BBORProtocol.loggedOutAllPlayer();
}
// Leaves end - bbor
diff --git a/patches/server/0055-Appleskin-Protocol.patch b/patches/server/0055-Appleskin-Protocol.patch
index 4926756b..390f3e04 100644
--- a/patches/server/0055-Appleskin-Protocol.patch
+++ b/patches/server/0055-Appleskin-Protocol.patch
@@ -37,10 +37,10 @@ index 3994583f24bd558e7b0f7649e27fcea79da32026..dc1c9c106593aed9ede4ea4a09dc085c
ServerLevel worldserver = entityplayer.serverLevel();
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-index 6888d0b096b665a10cf6b050a4e69be1b7d7928d..e2fc4933f8e1faaed5837e54588a20582090dc65 100644
+index 9fba7105b7e70ad05c243ee6cec27a8ebe875d83..75c4b20c1637f4b2e1a77450d30a21b4d2db5af0 100644
--- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java
+++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java
-@@ -1078,6 +1078,13 @@ public final class CraftServer implements Server {
+@@ -1080,6 +1080,13 @@ public final class CraftServer implements Server {
top.leavesmc.leaves.protocol.JadeProtocol.enableAllPlayer();
}
// Leaves end - Jade