9
0
mirror of https://github.com/LeavesMC/Leaves.git synced 2025-12-28 19:39:22 +00:00

Add fakeplayer api

This commit is contained in:
violetc
2022-07-27 16:19:38 +08:00
parent 1a6a146d6a
commit e7fe0db891
4 changed files with 590 additions and 342 deletions

View File

@@ -0,0 +1,148 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: violetc <58360096+s-yh-china@users.noreply.github.com>
Date: Wed, 27 Jul 2022 15:30:34 +0800
Subject: [PATCH] Add fakeplayer 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..d4afe549b5e1aba7d468450c5e1570d2e0c0a1f3
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/entity/Bot.java
@@ -0,0 +1,9 @@
+package top.leavesmc.leaves.entity;
+
+import org.bukkit.entity.Player;
+
+/**
+ * Represents a fakeplayer
+ */
+public interface Bot extends Player {
+}
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..9424a0b82ebfedd571e759db4f41d51364ad0b88
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/event/bot/BotCreateEvent.java
@@ -0,0 +1,84 @@
+package top.leavesmc.leaves.event.bot;
+
+import org.bukkit.Location;
+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;
+
+/**
+ * Call when a fakeplayer creates a server
+ */
+public class BotCreateEvent extends BotEvent implements Cancellable {
+ private static final HandlerList handlers = new HandlerList();
+
+ private String joinMessage;
+ private Location createLocation;
+ private boolean cancel = false;
+
+ public BotCreateEvent(@NotNull final Bot who, @NotNull final Location createLocation, @Nullable final String joinMessage) {
+ super(who);
+ this.joinMessage = joinMessage;
+ this.createLocation = createLocation;
+ }
+
+ /**
+ * 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 fakeplyer
+ */
+ public void setCreateLocation(@NotNull Location createLocation) {
+ this.createLocation = createLocation;
+ }
+
+ @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;
+ }
+}

View File

@@ -5,14 +5,14 @@ Subject: [PATCH] Add fakeplayer support
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
index de0513b38e5fa0138f1cee6bb633561be12449fc..6de539d8819b9c25fbf96cd2ac8ef4a87c0fb231 100644
index de0513b38e5fa0138f1cee6bb633561be12449fc..8548ef7f79e85aca593928b8e748d8b6d53e52bd 100644
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
@@ -50,6 +50,7 @@ import net.minecraft.server.players.PlayerList;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.level.GameRules;
import org.slf4j.Logger;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
public class PlayerAdvancements {
@@ -21,7 +21,7 @@ index de0513b38e5fa0138f1cee6bb633561be12449fc..6de539d8819b9c25fbf96cd2ac8ef4a8
public boolean award(Advancement advancement, String criterionName) {
+ // Leaves start - bot can't get advancement
+ if (player instanceof Bot) {
+ if (player instanceof ServerBot) {
+ return false;
+ }
+ // Leaves end - bot can't get advancement
@@ -29,35 +29,74 @@ index de0513b38e5fa0138f1cee6bb633561be12449fc..6de539d8819b9c25fbf96cd2ac8ef4a8
AdvancementProgress advancementprogress = this.getOrStartProgress(advancement);
boolean flag1 = advancementprogress.isDone();
diff --git a/src/main/java/net/minecraft/server/players/PlayerList.java b/src/main/java/net/minecraft/server/players/PlayerList.java
index 20cdfdb3b9351f74e89bc45b3ab972384165659a..e7fc2bd7241430354509158e1dceafb723d6f692 100644
index 20cdfdb3b9351f74e89bc45b3ab972384165659a..fe38a9cd9724d0547e0d1689153a8c155c377d0c 100644
--- a/src/main/java/net/minecraft/server/players/PlayerList.java
+++ b/src/main/java/net/minecraft/server/players/PlayerList.java
@@ -100,6 +100,7 @@ import net.minecraft.world.scores.Objective;
@@ -100,10 +100,10 @@ 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.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
import org.slf4j.Logger;
// CraftBukkit start
@@ -368,6 +369,17 @@ public abstract class PlayerList {
-import io.papermc.paper.adventure.PaperAdventure; // Paper
import com.google.common.base.Predicate;
import java.util.stream.Collectors;
import net.minecraft.server.dedicated.DedicatedServer;
@@ -113,7 +113,6 @@ import org.bukkit.Location;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
-import org.bukkit.craftbukkit.util.CraftChatMessage;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerJoinEvent;
@@ -368,6 +367,17 @@ public abstract class PlayerList {
return;
}
+ // Leaves start - bot support
+ if (top.leavesmc.leaves.LeavesConfig.fakeplayerSupport) {
+ Bot bot = Bot.getBot(player.getName().getString());
+ ServerBot bot = ServerBot.getBot(player.getName().getString());
+ if (bot != null) {
+ bot.kill(); // Leaves - remove bot with the same name
+ }
+
+ Bot.getBots().forEach(bot1 -> bot1.render(playerconnection, true)); // Leaves - render bot
+ ServerBot.getBots().forEach(bot1 -> bot1.render(playerconnection, 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
diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
index 2a6c67634c31c332102d24bef293da1bacd0c000..877c9fa13c0ff1fbc90d957258bd0bc1f42c0fd4 100644
--- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
+++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java
@@ -187,6 +187,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;
public abstract class CraftEntity implements org.bukkit.entity.Entity {
private static PermissibleBase perm;
@@ -211,7 +213,12 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity {
if (entity instanceof LivingEntity) {
// Players
if (entity instanceof Player) {
- if (entity instanceof ServerPlayer) { return new CraftPlayer(server, (ServerPlayer) entity); }
+ // Leaves start - add CraftBot
+ if (entity instanceof ServerPlayer) {
+ if (entity instanceof ServerBot) { return new CraftBot(server, (ServerBot) entity); }
+ else { return new CraftPlayer(server, (ServerPlayer) entity); }
+ }
+ // Leaves end - add CraftBot
else { return new CraftHumanEntity(server, (Player) entity); }
}
// Water Animals
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
index a85a5de7d85cf6c5e19c0245c40e6106e6623007..898c61c25675232e203ee2c872ca25804c41358c 100644
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -121,12 +160,166 @@ index a85a5de7d85cf6c5e19c0245c40e6106e6623007..898c61c25675232e203ee2c872ca2580
public static final class WorldConfig {
public final String worldName;
diff --git a/src/main/java/top/leavesmc/leaves/bot/Bot.java b/src/main/java/top/leavesmc/leaves/bot/Bot.java
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..7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f
index 0000000000000000000000000000000000000000..292fede3bb850892e57640814440bdcebfd43aec
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/Bot.java
@@ -0,0 +1,489 @@
+++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
@@ -0,0 +1,101 @@
+package top.leavesmc.leaves.bot;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class BotCommand extends Command {
+
+ public BotCommand(String name) {
+ super(name);
+ this.description = "FakePlayer Command";
+ this.usageMessage = "/bot [create | remove]";
+ this.setPermission("bukkit.command.bot");
+ }
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
+ var list = new ArrayList<String>();
+
+ if (args.length <= 1) {
+ list.add("create");
+ list.add("remove");
+ } else {
+ switch (args[0]) {
+ case "create" -> list.add("[BotName]");
+ case "remove" -> list.addAll(ServerBot.getBots().stream().map(e -> e.getName().getString()).toList());
+ }
+ }
+
+ return list;
+ }
+
+ @Override
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
+ if (!testPermission(sender)) 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);
+
+ default -> {
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void onCreate(CommandSender sender, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(ChatColor.RED + "Use /bot create [name] to create a fakeplayer");
+ return;
+ }
+
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(ChatColor.RED + "This command only can use by player");
+ return;
+ }
+
+ if (Bukkit.getPlayer(args[1]) != null || ServerBot.getBot(args[1]) != null) {
+ sender.sendMessage(ChatColor.RED + "This player is in server");
+ return;
+ }
+
+ if (top.leavesmc.leaves.LeavesConfig.unableFakeplayerNames.contains(args[1])) {
+ sender.sendMessage(ChatColor.RED + "This name is unable");
+ return;
+ }
+
+ ServerBot.createBot(((Player) sender).getLocation(), args[1]);
+ }
+
+ private void onRemove(CommandSender sender, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(ChatColor.RED + "Use /bot remove [name] to remove a fakeplayer");
+ return;
+ }
+
+ ServerBot bot = ServerBot.getBot(args[1]);
+
+ if (bot == null) {
+ sender.sendMessage(ChatColor.RED + "This fakeplayer is null");
+ return;
+ }
+
+ bot.kill();
+ }
+}
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<String, String[]> 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..b833653b671df660686134754c794d3e6686b112
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java
@@ -0,0 +1,510 @@
+package top.leavesmc.leaves.bot;
+
+import com.mojang.authlib.GameProfile;
@@ -155,7 +348,6 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+import net.minecraft.world.entity.Entity;
+import net.minecraft.world.entity.MoverType;
+import net.minecraft.world.level.ChunkPos;
+import net.minecraft.world.level.Level;
+import net.minecraft.world.level.chunk.LevelChunk;
+import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.Vec3;
@@ -167,15 +359,18 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+import org.bukkit.block.Block;
+import org.bukkit.craftbukkit.CraftWorld;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin;
+import org.bukkit.entity.Player;
+import org.bukkit.event.entity.CreatureSpawnEvent;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.event.player.PlayerTeleportEvent;
+import org.bukkit.plugin.Plugin;
+import org.bukkit.util.BoundingBox;
+import org.bukkit.util.Vector;
+import org.jetbrains.annotations.NotNull;
+import top.leavesmc.leaves.entity.Bot;
+import top.leavesmc.leaves.entity.CraftBot;
+import top.leavesmc.leaves.event.bot.BotCreateEvent;
+import top.leavesmc.leaves.util.MathUtils;
+
+import javax.annotation.Nullable;
@@ -184,7 +379,7 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+import java.util.Set;
+import java.util.UUID;
+
+public class Bot extends ServerPlayer {
+public class ServerBot extends ServerPlayer {
+
+ private Vector velocity;
+ private Vector oldVelocity;
@@ -195,10 +390,10 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ private byte jumpTicks;
+ private byte noFallTicks;
+
+ private static final Set<Bot> bots = new HashSet<>();
+ private static final Set<ServerBot> bots = new HashSet<>();
+ private static final Plugin MINECRAFT_PLUGIN = new MinecraftInternalPlugin();
+
+ public Bot(MinecraftServer server, ServerLevel world, GameProfile profile) {
+ public ServerBot(MinecraftServer server, ServerLevel world, GameProfile profile) {
+ super(server, world, profile, null);
+ this.entityData.set(new EntityDataAccessor<>(16, EntityDataSerializers.INT), 0xFF);
+
@@ -216,14 +411,15 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ });
+ }
+
+ public static Bot createBot(Location loc, String name, String[] skin) {
+ @Nullable
+ public static ServerBot createBot(@NotNull Location loc, @NotNull String name, String[] skin) {
+ MinecraftServer server = MinecraftServer.getServer();
+ ServerLevel world = ((CraftWorld) Objects.requireNonNull(loc.getWorld())).getHandle();
+
+ UUID uuid = UUID.randomUUID();
+ CustomGameProfile profile = new CustomGameProfile(uuid, name.length() > 16 ? name.substring(0, 16) : name, skin);
+
+ Bot bot = new Bot(server, world, profile);
+ ServerBot bot = new ServerBot(server, world, profile);
+
+ bot.connection = new ServerGamePacketListenerImpl(server, new Connection(PacketFlow.CLIENTBOUND) {
+ @Override
@@ -232,20 +428,32 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ }, bot);
+ bot.isRealPlayer = true;
+
+ bot.teleportTo(loc.getX(), loc.getY(), loc.getZ());
+ bot.setRot(loc.getYaw(), loc.getPitch());
+ world.addFreshEntity(bot, CreatureSpawnEvent.SpawnReason.COMMAND);
+
+ bot.renderAll();
+ PlayerJoinEvent event = new PlayerJoinEvent(bot.getBukkitPlayer(), ChatColor.YELLOW + bot.getName().getString() + " joined the game");
+ BotCreateEvent event = new BotCreateEvent(bot.getBukkitPlayer(), loc, ChatColor.YELLOW + bot.getName().getString() + " joined the game");
+ server.server.getPluginManager().callEvent(event);
+ if (event.getJoinMessage() != null) {
+ Bukkit.broadcastMessage(event.getJoinMessage());
+ if (!event.isCancelled()) {
+ if (event.getJoinMessage() != null) {
+ Bukkit.broadcastMessage(event.getJoinMessage());
+ }
+
+ loc = event.getCreateLocation();
+ ServerLevel world1 = ((CraftWorld) Objects.requireNonNull(loc.getWorld())).getHandle();
+
+ if (world1 != world) {
+ world = world1;
+ bot.changeDimension(world, PlayerTeleportEvent.TeleportCause.COMMAND);
+ }
+
+ bot.teleportTo(loc.getX(), loc.getY(), loc.getZ());
+ bot.setRot(loc.getYaw(), loc.getPitch());
+ world.addFreshEntity(bot, CreatureSpawnEvent.SpawnReason.COMMAND);
+
+ bot.renderAll();
+
+ bots.add(bot);
+ return bot;
+ }
+
+ bots.add(bot);
+
+ return bot;
+ return null;
+ }
+
+ private void renderAll() {
@@ -383,11 +591,17 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ return false;
+ }
+
+ public Player getBukkitPlayer() {
+ 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++) {
@@ -576,9 +790,9 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ this.move(MoverType.SELF, new Vec3(velocity.getX(), y, velocity.getZ()));
+ }
+
+ public static Bot getBot(ServerPlayer player) {
+ Bot bot = null;
+ for (Bot b : bots) {
+ public static ServerBot getBot(ServerPlayer player) {
+ ServerBot bot = null;
+ for (ServerBot b : bots) {
+ if (b.getId() == player.getId()) {
+ bot = b;
+ break;
@@ -587,9 +801,9 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ return bot;
+ }
+
+ public static Bot getBot(String name) {
+ Bot bot = null;
+ for (Bot b : bots) {
+ public static ServerBot getBot(String name) {
+ ServerBot bot = null;
+ for (ServerBot b : bots) {
+ if (b.getName().getString().equals(name)) {
+ bot = b;
+ break;
@@ -598,7 +812,7 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ return bot;
+ }
+
+ public static Set<Bot> getBots() { // It needs unmodifiable
+ public static Set<ServerBot> getBots() { // It needs unmodifiable
+ return bots;
+ }
+
@@ -616,158 +830,36 @@ index 0000000000000000000000000000000000000000..7a81e5b8aa7aaa5c8a6718d0ad603790
+ }
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
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..3b8d44fb61d504e521e73d3a34f6bd8ad9f13aee
index 0000000000000000000000000000000000000000..2d5044c4a09044364e818b7674908bf98932bf58
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
@@ -0,0 +1,101 @@
+package top.leavesmc.leaves.bot;
+++ b/src/main/java/top/leavesmc/leaves/entity/CraftBot.java
@@ -0,0 +1,26 @@
+package top.leavesmc.leaves.entity;
+
+import org.bukkit.Bukkit;
+import org.bukkit.ChatColor;
+import org.bukkit.Location;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.craftbukkit.CraftServer;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
+import top.leavesmc.leaves.bot.ServerBot;
+
+import java.util.ArrayList;
+import java.util.List;
+public class CraftBot extends CraftPlayer implements Bot {
+
+public class BotCommand extends Command {
+
+ public BotCommand(String name) {
+ super(name);
+ this.description = "FakePlayer Command";
+ this.usageMessage = "/bot [create | remove]";
+ this.setPermission("bukkit.command.bot");
+ public CraftBot(CraftServer server, ServerBot entity) {
+ super(server, entity);
+ }
+
+ @Override
+ public List<String> tabComplete(CommandSender sender, String alias, String[] args, Location location) throws IllegalArgumentException {
+ var list = new ArrayList<String>();
+ public ServerBot getHandle() {
+ return (ServerBot) entity;
+ }
+
+ if (args.length <= 1) {
+ list.add("create");
+ list.add("remove");
+ } else {
+ switch (args[0]) {
+ case "create" -> list.add("[BotName]");
+ case "remove" -> list.addAll(Bot.getBots().stream().map(e -> e.getName().getString()).toList());
+ }
+ }
+
+ return list;
+ public void setHandle(final ServerBot entity) {
+ super.setHandle(entity);
+ }
+
+ @Override
+ public boolean execute(CommandSender sender, String commandLabel, String[] args) {
+ if (!testPermission(sender)) 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);
+
+ default -> {
+ sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void onCreate(CommandSender sender, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(ChatColor.RED + "Use /bot create [name] to create a fakeplayer");
+ return;
+ }
+
+ if (!(sender instanceof Player)) {
+ sender.sendMessage(ChatColor.RED + "This command only can use by player");
+ return;
+ }
+
+ if (Bukkit.getPlayer(args[1]) != null || Bot.getBot(args[1]) != null) {
+ sender.sendMessage(ChatColor.RED + "This player is in server");
+ return;
+ }
+
+ if (top.leavesmc.leaves.LeavesConfig.unableFakeplayerNames.contains(args[1])) {
+ sender.sendMessage(ChatColor.RED + "This name is unable");
+ return;
+ }
+
+ Bot.createBot(((Player) sender).getLocation(), args[1]);
+ }
+
+ private void onRemove(CommandSender sender, String[] args) {
+ if (args.length < 2) {
+ sender.sendMessage(ChatColor.RED + "Use /bot remove [name] to remove a fakeplayer");
+ return;
+ }
+
+ Bot bot = Bot.getBot(args[1]);
+
+ if (bot == null) {
+ sender.sendMessage(ChatColor.RED + "This fakeplayer is null");
+ return;
+ }
+
+ bot.kill();
+ }
+}
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<String, String[]> 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;
+ }
+ public String toString() {
+ return "CraftBot{" + "name=" + getName() + '}';
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/util/MathUtils.java b/src/main/java/top/leavesmc/leaves/util/MathUtils.java

View File

@@ -29,10 +29,125 @@ index 898c61c25675232e203ee2c872ca25804c41358c..4d6d025c78086f186da710ae46f65eda
}
}
diff --git a/src/main/java/top/leavesmc/leaves/bot/Bot.java b/src/main/java/top/leavesmc/leaves/bot/Bot.java
index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab398d2b468 100644
--- a/src/main/java/top/leavesmc/leaves/bot/Bot.java
+++ b/src/main/java/top/leavesmc/leaves/bot/Bot.java
diff --git a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
index 292fede3bb850892e57640814440bdcebfd43aec..7693118ee1bb06d9938b866dca8e6cc9d2f1dded 100644
--- a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
+++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
@@ -6,6 +6,10 @@ import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
+import top.leavesmc.leaves.bot.agent.Actions;
+import top.leavesmc.leaves.bot.agent.BotAction;
+import top.leavesmc.leaves.entity.CraftBot;
+import top.leavesmc.leaves.util.MathUtils;
import java.util.ArrayList;
import java.util.List;
@@ -15,7 +19,7 @@ public class BotCommand extends Command {
public BotCommand(String name) {
super(name);
this.description = "FakePlayer Command";
- this.usageMessage = "/bot [create | remove]";
+ this.usageMessage = "/bot [create | remove | action]";
this.setPermission("bukkit.command.bot");
}
@@ -26,13 +30,29 @@ public class BotCommand extends Command {
if (args.length <= 1) {
list.add("create");
list.add("remove");
- } else {
+ list.add("action");
+ }
+
+ if (args.length == 2) {
+ switch (args[0]) {
+ case "create" -> list.add("<BotName>");
+ case "remove", "action" -> list.addAll(ServerBot.getBots().stream().map(e -> e.getName().getString()).toList());
+ }
+ }
+
+ if (args.length == 3) {
+ switch (args[0]) {
+ case "action" -> list.addAll(Actions.getAll().stream().map(BotAction::getName).toList());
+ }
+ }
+
+ if (args.length == 4) {
switch (args[0]) {
case "create" -> list.add("[BotName]");
case "remove" -> list.addAll(ServerBot.getBots().stream().map(e -> e.getName().getString()).toList());
+ case "action" -> list.add("[tickDelay]");
}
}
-
return list;
}
@@ -50,6 +70,8 @@ public class BotCommand extends Command {
case "remove" -> this.onRemove(sender, args);
+ case "action" -> this.onAction(sender, args);
+
default -> {
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
return false;
@@ -61,7 +83,7 @@ public class BotCommand extends Command {
private void onCreate(CommandSender sender, String[] args) {
if (args.length < 2) {
- sender.sendMessage(ChatColor.RED + "Use /bot create [name] to create a fakeplayer");
+ sender.sendMessage(ChatColor.RED + "Use /bot create <name> to create a fakeplayer");
return;
}
@@ -85,7 +107,7 @@ public class BotCommand extends Command {
private void onRemove(CommandSender sender, String[] args) {
if (args.length < 2) {
- sender.sendMessage(ChatColor.RED + "Use /bot remove [name] to remove a fakeplayer");
+ sender.sendMessage(ChatColor.RED + "Use /bot remove <name> to remove a fakeplayer");
return;
}
@@ -98,4 +120,31 @@ public class BotCommand extends Command {
bot.kill();
}
+
+ private void onAction(CommandSender sender, String[] args) {
+ if (args.length < 3) {
+ sender.sendMessage(ChatColor.RED + "Use /bot action <name> <action> to make fakeplayer do action");
+ return;
+ }
+
+ int tickDelay = 20;
+ if (args.length > 3 && MathUtils.isNumeric(args[3])) {
+ tickDelay = Integer.parseInt(args[3]);
+ }
+
+ ServerBot bot = ServerBot.getBot(args[1]);
+ BotAction action = Actions.getForName(args[2]);
+
+ if (bot == null) {
+ sender.sendMessage(ChatColor.RED + "This fakeplayer is null");
+ return;
+ }
+ if (action == null) {
+ sender.sendMessage(ChatColor.RED + "This action is null");
+ return;
+ }
+
+ bot.setBotAction(action.getNew(tickDelay, ((CraftBot) sender).getHandle()));
+ sender.sendMessage("Action set");
+ }
}
diff --git a/src/main/java/top/leavesmc/leaves/bot/ServerBot.java b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java
index b833653b671df660686134754c794d3e6686b112..d0b88733427d81aacb9699faf695c67988e83fe6 100644
--- a/src/main/java/top/leavesmc/leaves/bot/ServerBot.java
+++ b/src/main/java/top/leavesmc/leaves/bot/ServerBot.java
@@ -1,9 +1,12 @@
package top.leavesmc.leaves.bot;
@@ -54,7 +169,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
import net.minecraft.network.syncher.EntityDataAccessor;
import net.minecraft.network.syncher.EntityDataSerializers;
import net.minecraft.server.MinecraftServer;
@@ -22,11 +26,14 @@ import net.minecraft.server.level.TicketType;
@@ -22,9 +26,13 @@ import net.minecraft.server.level.TicketType;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.server.network.ServerPlayerConnection;
import net.minecraft.util.Mth;
@@ -66,14 +181,26 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
import net.minecraft.world.entity.MoverType;
+import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.level.ChunkPos;
-import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
@@ -47,10 +54,14 @@ import org.bukkit.inventory.ItemStack;
@@ -37,11 +45,13 @@ import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.scheduler.MinecraftInternalPlugin;
import org.bukkit.entity.Player;
import org.bukkit.event.entity.CreatureSpawnEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
+import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.BoundingBox;
import org.bukkit.util.Vector;
@@ -49,10 +59,14 @@ import org.jetbrains.annotations.NotNull;
import top.leavesmc.leaves.entity.Bot;
import top.leavesmc.leaves.entity.CraftBot;
import top.leavesmc.leaves.event.bot.BotCreateEvent;
+import top.leavesmc.leaves.bot.agent.BotAction;
import top.leavesmc.leaves.util.MathUtils;
@@ -85,7 +212,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -59,12 +70,17 @@ public class Bot extends ServerPlayer {
@@ -61,12 +75,17 @@ public class ServerBot extends ServerPlayer {
private Vector velocity;
private Vector oldVelocity;
@@ -105,13 +232,9 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
+
+ private final ItemStack defaultItem;
private static final Set<Bot> bots = new HashSet<>();
private static final Set<ServerBot> bots = new HashSet<>();
private static final Plugin MINECRAFT_PLUGIN = new MinecraftInternalPlugin();
@@ -74,9 +90,12 @@ public class Bot extends ServerPlayer {
this.entityData.set(new EntityDataAccessor<>(16, EntityDataSerializers.INT), 0xFF);
this.velocity = new Vector(0, 0, 0);
+ this.action = null;
@@ -79,6 +98,8 @@ public class ServerBot extends ServerPlayer {
this.oldVelocity = velocity.clone();
this.noFallTicks = 60;
this.fireTicks = 0;
@@ -120,7 +243,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
this.removeOnDeath = true;
}
@@ -170,12 +189,17 @@ public class Bot extends ServerPlayer {
@@ -185,12 +206,17 @@ public class ServerBot extends ServerPlayer {
}
}
@@ -138,7 +261,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
// die check end
@Override
@@ -183,10 +207,6 @@ public class Bot extends ServerPlayer {
@@ -198,10 +224,6 @@ public class ServerBot extends ServerPlayer {
return groundTicks != 0;
}
@@ -149,7 +272,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
public static boolean solidAt(Location loc) {
Block block = loc.getBlock();
BoundingBox box = block.getBoundingBox();
@@ -275,12 +295,24 @@ public class Bot extends ServerPlayer {
@@ -296,12 +318,24 @@ public class ServerBot extends ServerPlayer {
public void tick() {
// loadChunks(); // Load chunks
super.tick();
@@ -178,7 +301,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
if (checkGround()) {
if (groundTicks < 5) groundTicks++;
@@ -308,7 +340,88 @@ public class Bot extends ServerPlayer {
@@ -329,7 +363,88 @@ public class ServerBot extends ServerPlayer {
checkOutOfWorld();
@@ -267,7 +390,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
}
@Override
@@ -341,21 +454,6 @@ public class Bot extends ServerPlayer {
@@ -362,21 +477,6 @@ public class ServerBot extends ServerPlayer {
}
}
@@ -289,7 +412,7 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
public Location getLocation() {
return getBukkitPlayer().getLocation();
}
@@ -447,6 +545,68 @@ public class Bot extends ServerPlayer {
@@ -468,6 +568,68 @@ public class ServerBot extends ServerPlayer {
this.move(MoverType.SELF, new Vec3(velocity.getX(), y, velocity.getZ()));
}
@@ -355,124 +478,9 @@ index 7a81e5b8aa7aaa5c8a6718d0ad60379094e7b15f..2a0aff502b03d149c0c42da7e8ad3ab3
+ this.newAction = botAction;
+ }
+
public static Bot getBot(ServerPlayer player) {
Bot bot = null;
for (Bot b : bots) {
diff --git a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
index 3b8d44fb61d504e521e73d3a34f6bd8ad9f13aee..ec1c53e2f98717b648c80ddf7573edad7f29b135 100644
--- a/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
+++ b/src/main/java/top/leavesmc/leaves/bot/BotCommand.java
@@ -5,7 +5,11 @@ import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
+import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.entity.Player;
+import top.leavesmc.leaves.bot.agent.Actions;
+import top.leavesmc.leaves.bot.agent.BotAction;
+import top.leavesmc.leaves.util.MathUtils;
import java.util.ArrayList;
import java.util.List;
@@ -15,7 +19,7 @@ public class BotCommand extends Command {
public BotCommand(String name) {
super(name);
this.description = "FakePlayer Command";
- this.usageMessage = "/bot [create | remove]";
+ this.usageMessage = "/bot [create | remove | action]";
this.setPermission("bukkit.command.bot");
}
@@ -26,13 +30,27 @@ public class BotCommand extends Command {
if (args.length <= 1) {
list.add("create");
list.add("remove");
- } else {
+ list.add("action");
+ }
+
+ if (args.length == 2) {
switch (args[0]) {
- case "create" -> list.add("[BotName]");
- case "remove" -> list.addAll(Bot.getBots().stream().map(e -> e.getName().getString()).toList());
+ case "create" -> list.add("<BotName>");
+ case "remove", "action" -> list.addAll(Bot.getBots().stream().map(e -> e.getName().getString()).toList());
}
}
+ if (args.length == 3) {
+ switch (args[0]) {
+ case "action" -> list.addAll(Actions.getAll().stream().map(BotAction::getName).toList());
+ }
+ }
+
+ if (args.length == 4) {
+ switch (args[0]) {
+ case "action" -> list.add("[tickDelay]");
+ }
+ }
return list;
}
@@ -50,6 +68,8 @@ public class BotCommand extends Command {
case "remove" -> this.onRemove(sender, args);
+ case "action" -> this.onAction(sender, args);
+
default -> {
sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
return false;
@@ -61,7 +81,7 @@ public class BotCommand extends Command {
private void onCreate(CommandSender sender, String[] args) {
if (args.length < 2) {
- sender.sendMessage(ChatColor.RED + "Use /bot create [name] to create a fakeplayer");
+ sender.sendMessage(ChatColor.RED + "Use /bot create <name> to create a fakeplayer");
return;
}
@@ -85,7 +105,7 @@ public class BotCommand extends Command {
private void onRemove(CommandSender sender, String[] args) {
if (args.length < 2) {
- sender.sendMessage(ChatColor.RED + "Use /bot remove [name] to remove a fakeplayer");
+ sender.sendMessage(ChatColor.RED + "Use /bot remove <name> to remove a fakeplayer");
return;
}
@@ -98,4 +118,31 @@ public class BotCommand extends Command {
bot.kill();
}
+
+ private void onAction(CommandSender sender, String[] args) {
+ if (args.length < 3) {
+ sender.sendMessage(ChatColor.RED + "Use /bot action <name> <action> to make fakeplayer do action");
+ return;
+ }
+
+ int tickDelay = 20;
+ if (args.length > 3 && MathUtils.isNumeric(args[3])) {
+ tickDelay = Integer.parseInt(args[3]);
+ }
+
+ Bot bot = Bot.getBot(args[1]);
+ BotAction action = Actions.getForName(args[2]);
+
+ if (bot == null) {
+ sender.sendMessage(ChatColor.RED + "This fakeplayer is null");
+ return;
+ }
+ if (action == null) {
+ sender.sendMessage(ChatColor.RED + "This action is null");
+ return;
+ }
+
+ bot.setBotAction(action.getNew(tickDelay, ((CraftPlayer) sender).getHandle()));
+ sender.sendMessage("Action set");
+ }
}
public static ServerBot getBot(ServerPlayer player) {
ServerBot bot = null;
for (ServerBot b : bots) {
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..ccedc7b77bef852b66dfa8c4ee3d69b3c71717a0
@@ -528,14 +536,14 @@ index 0000000000000000000000000000000000000000..ccedc7b77bef852b66dfa8c4ee3d69b3
+}
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..78f04e28afa856c900f84af42f22666bec3ec830
index 0000000000000000000000000000000000000000..dd19f41fd5e1ad27637c0c3a8e96e7c17a96f891
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/BotAction.java
@@ -0,0 +1,42 @@
+package top.leavesmc.leaves.bot.agent;
+
+import net.minecraft.server.level.ServerPlayer;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
+
+public abstract class BotAction {
+
@@ -572,11 +580,11 @@ index 0000000000000000000000000000000000000000..78f04e28afa856c900f84af42f22666b
+
+ public abstract BotAction getNew(int tickDelay, ServerPlayer player);
+
+ public abstract void tick(Bot bot);
+ public abstract void tick(ServerBot bot);
+}
diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/AttackAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/AttackAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..975b45b7ba3107b143577f53c6b54194e3a699b6
index 0000000000000000000000000000000000000000..b69de7c67d39a84310f6105ae0619eb90b278cb8
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/AttackAction.java
@@ -0,0 +1,26 @@
@@ -584,7 +592,7 @@ index 0000000000000000000000000000000000000000..975b45b7ba3107b143577f53c6b54194
+
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.phys.EntityHitResult;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
+import top.leavesmc.leaves.bot.agent.BotAction;
+
+public class AttackAction extends BotAction {
@@ -599,7 +607,7 @@ index 0000000000000000000000000000000000000000..975b45b7ba3107b143577f53c6b54194
+ }
+
+ @Override
+ public void tick(Bot bot) {
+ public void tick(ServerBot bot) {
+ EntityHitResult result = bot.getTargetEntity(3);
+ if (result != null) {
+ bot.attack(result.getEntity());
@@ -608,14 +616,14 @@ index 0000000000000000000000000000000000000000..975b45b7ba3107b143577f53c6b54194
+}
diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/DropAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/DropAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..91da2f89b6937a78a39da2a6f2c346f0ad446001
index 0000000000000000000000000000000000000000..4a072e9b2b6c33e5c3d5b2230b66484bb2dfc191
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/DropAction.java
@@ -0,0 +1,22 @@
+package top.leavesmc.leaves.bot.agent.action;
+
+import net.minecraft.server.level.ServerPlayer;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
+import top.leavesmc.leaves.bot.agent.BotAction;
+
+public class DropAction extends BotAction {
@@ -629,21 +637,21 @@ index 0000000000000000000000000000000000000000..91da2f89b6937a78a39da2a6f2c346f0
+ }
+
+ @Override
+ public void tick(Bot bot) {
+ public void tick(ServerBot bot) {
+ bot.dropAll();
+ this.setCancel(true);
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/RotateAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/RotateAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f7263a97f56144e98794eae3e137a3a73a6d909
index 0000000000000000000000000000000000000000..450d74eddb7667b2c720cca76a397eaf7daa14d1
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/RotateAction.java
@@ -0,0 +1,29 @@
+package top.leavesmc.leaves.bot.agent.action;
+
+import net.minecraft.server.level.ServerPlayer;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
+import top.leavesmc.leaves.bot.agent.BotAction;
+
+public class RotateAction extends BotAction {
@@ -664,21 +672,21 @@ index 0000000000000000000000000000000000000000..8f7263a97f56144e98794eae3e137a3a
+ }
+
+ @Override
+ public void tick(Bot bot) {
+ public void tick(ServerBot bot) {
+ bot.faceLocation(player.getBukkitEntity().getLocation());
+ this.setCancel(true);
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/StopAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/StopAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..09049b934d34aece15a201473f1cf4ed500a05a7
index 0000000000000000000000000000000000000000..ec47646ca94b2eab55ac0f32de859f10867f87f3
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/StopAction.java
@@ -0,0 +1,21 @@
+package top.leavesmc.leaves.bot.agent.action;
+
+import net.minecraft.server.level.ServerPlayer;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
+import top.leavesmc.leaves.bot.agent.BotAction;
+
+public class StopAction extends BotAction {
@@ -692,13 +700,13 @@ index 0000000000000000000000000000000000000000..09049b934d34aece15a201473f1cf4ed
+ }
+
+ @Override
+ public void tick(Bot bot) {
+ public void tick(ServerBot bot) {
+ this.setCancel(true);
+ }
+}
diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..8f39161ff8f84392ef57a1ecda3b098a791841e5
index 0000000000000000000000000000000000000000..7d12bc08b92cffbddf29b60fbaff2f2a43c4867e
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemAction.java
@@ -0,0 +1,24 @@
@@ -706,7 +714,7 @@ index 0000000000000000000000000000000000000000..8f39161ff8f84392ef57a1ecda3b098a
+
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.world.InteractionHand;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
+import top.leavesmc.leaves.bot.agent.BotAction;
+
+public class UseItemAction extends BotAction {
@@ -720,7 +728,7 @@ index 0000000000000000000000000000000000000000..8f39161ff8f84392ef57a1ecda3b098a
+ }
+
+ @Override
+ public void tick(Bot bot) {
+ public void tick(ServerBot bot) {
+ bot.getInventory().getSelected().use(bot.getLevel(), bot, InteractionHand.MAIN_HAND);
+ bot.punch();
+ bot.updateItemInMainHand();
@@ -728,7 +736,7 @@ index 0000000000000000000000000000000000000000..8f39161ff8f84392ef57a1ecda3b098a
+}
diff --git a/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemOnAction.java b/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemOnAction.java
new file mode 100644
index 0000000000000000000000000000000000000000..a58c57e572b5cd952b0b276a8157250170ce6285
index 0000000000000000000000000000000000000000..d32cf3ddb83a8e9f18fc2a2bb19d4e5c76df9296
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/bot/agent/action/UseItemOnAction.java
@@ -0,0 +1,29 @@
@@ -738,7 +746,7 @@ index 0000000000000000000000000000000000000000..a58c57e572b5cd952b0b276a81572501
+import net.minecraft.world.InteractionHand;
+import net.minecraft.world.phys.BlockHitResult;
+import net.minecraft.world.phys.HitResult;
+import top.leavesmc.leaves.bot.Bot;
+import top.leavesmc.leaves.bot.ServerBot;
+import top.leavesmc.leaves.bot.agent.BotAction;
+
+public class UseItemOnAction extends BotAction {
@@ -752,7 +760,7 @@ index 0000000000000000000000000000000000000000..a58c57e572b5cd952b0b276a81572501
+ }
+
+ @Override
+ public void tick(Bot bot) {
+ public void tick(ServerBot bot) {
+ HitResult result = bot.getRayTrace(4);
+ if (result != null && result.getType() == HitResult.Type.BLOCK) {
+ bot.gameMode.useItemOn(bot, bot.getLevel(), bot.getItemInHand(InteractionHand.MAIN_HAND), InteractionHand.MAIN_HAND, (BlockHitResult) result);

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Spectator dont get Advancement
diff --git a/src/main/java/net/minecraft/server/PlayerAdvancements.java b/src/main/java/net/minecraft/server/PlayerAdvancements.java
index 6de539d8819b9c25fbf96cd2ac8ef4a87c0fb231..d8ae25c5c012b18f5b2ca7d5ec92b0965fb2087a 100644
index 8548ef7f79e85aca593928b8e748d8b6d53e52bd..7f9786de88a03786c39fa3e85779ac1e751ef51a 100644
--- a/src/main/java/net/minecraft/server/PlayerAdvancements.java
+++ b/src/main/java/net/minecraft/server/PlayerAdvancements.java
@@ -49,6 +49,7 @@ import net.minecraft.server.level.ServerPlayer;
@@ -14,7 +14,7 @@ index 6de539d8819b9c25fbf96cd2ac8ef4a87c0fb231..d8ae25c5c012b18f5b2ca7d5ec92b096
import net.minecraft.world.level.GameRules;
+import net.minecraft.world.level.GameType;
import org.slf4j.Logger;
import top.leavesmc.leaves.bot.Bot;
import top.leavesmc.leaves.bot.ServerBot;
@@ -280,6 +281,11 @@ public class PlayerAdvancements {
return false;