From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Bacteriawa Date: Sat, 30 Aug 2025 17:07:02 +0800 Subject: [PATCH] Leaves: Leaves Fakeplayer Co-authored by: violetc <58360096+s-yh-china@users.noreply.github.com> As a part of : Leaves (https://github.com/LeavesMC/Leaves) Licensed under: GPL-3.0 (https://www.gnu.org/licenses/gpl-3.0.html) diff --git a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java index 9180f23529a31b6b0a5b38bb7cda3e32d487f691..e1f456b31ffda9370b63e51f343847d6f9f62263 100644 --- a/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java +++ b/src/main/java/io/papermc/paper/plugin/manager/PaperEventManager.java @@ -36,6 +36,15 @@ class PaperEventManager { // SimplePluginManager public void callEvent(@NotNull Event event) { + // Leaves start - process bot load/save + if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable && fun.bm.lophine.config.modules.function.FakeplayerConfig.canResident) { + if (event instanceof org.bukkit.event.world.WorldLoadEvent worldLoadEvent) { + org.leavesmc.leaves.bot.BotList.INSTANCE.loadResume(worldLoadEvent.getWorld().getUID().toString()); + } else if (event instanceof org.bukkit.event.world.WorldUnloadEvent worldUnloadEvent) { + org.leavesmc.leaves.bot.BotList.INSTANCE.removeAllIn(worldUnloadEvent.getWorld().getUID().toString()); + } + } + // Leaves end - process bot load/save // Leaf start - Skip event if no listeners RegisteredListener[] listeners = event.getHandlers().getRegisteredListeners(); if (listeners.length == 0) return; @@ -47,6 +56,12 @@ class PaperEventManager { throw new IllegalStateException(event.getEventName() + " may only be triggered synchronously."); } + // Leaves start - skip bot + if (event instanceof org.bukkit.event.player.PlayerEvent playerEvent && playerEvent.getPlayer() instanceof org.leavesmc.leaves.entity.bot.Bot) { + return; + } + // Leaves end - skip bot + for (RegisteredListener registration : listeners) { if (!registration.getPlugin().isEnabled()) { continue; diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java index 0a10f49ee410d93e95ceb90108200a1a9d12b54b..d2eee37d810a6d5cf514bc71dea66a4d2b0d09e2 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java @@ -423,6 +423,7 @@ public abstract class CraftRegionAccessor implements RegionAccessor { @SuppressWarnings("unchecked") public T addEntity(T entity) { Preconditions.checkArgument(!entity.isInWorld(), "Entity has already been added to a world"); + Preconditions.checkState(!(entity instanceof org.leavesmc.leaves.entity.bot.CraftBot), "[Leaves] Fakeplayers do not support changing world, Please use leaves fakeplayer-api instead!"); net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle(); if (nmsEntity.level() != this.getHandle().getLevel()) { nmsEntity = nmsEntity.teleport(new TeleportTransition(this.getHandle().getLevel(), nmsEntity, TeleportTransition.DO_NOTHING)); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/src/main/java/org/bukkit/craftbukkit/CraftServer.java index de72f36bd22e2c7452b9c3ee40657f6119ca70b3..0a96721797b9bbc643f68677bbb1d10c3c89e815 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -316,6 +316,7 @@ public final class CraftServer implements Server { private final io.papermc.paper.potion.PaperPotionBrewer potionBrewer; public io.papermc.paper.SparksFly spark; // Paper - spark // Luminol - Force disable builtin spark private final ServerConfiguration serverConfig = new PaperServerConfiguration(); + private final org.leavesmc.leaves.entity.bot.CraftBotManager botManager; // Leaves // 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 @@ -498,6 +499,7 @@ public final class CraftServer implements Server { datapackManager = new io.papermc.paper.datapack.PaperDatapackManager(console.getPackRepository()); // Paper if (false) this.spark = new io.papermc.paper.SparksFly(this); // Paper - spark // Luminol - Force disable builtin spark org.leavesmc.leaves.protocol.core.LeavesProtocolManager.init(); // Leaves - protocol + this.botManager = new org.leavesmc.leaves.entity.bot.CraftBotManager(); // Leaves } public boolean getCommandBlockOverride(String command) { @@ -1482,7 +1484,7 @@ public final class CraftServer implements Server { return false; } - if (!handle.players().isEmpty()) { + if (!handle.realPlayers().isEmpty()) { // Leaves - skip return false; } @@ -3260,6 +3262,13 @@ public final class CraftServer implements Server { this.console.addPluginAllowingSleep(plugin.getName(), value); } + // Leaves start - Bot API + @Override + public org.leavesmc.leaves.entity.bot.CraftBotManager getBotManager() { + return botManager; + } + // Leaves end - Bot API + // Folia start - region TPS API /** * Gets the TPS from the region which owns the specified location, or {@code null} if no region owns diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 9b9eea4babcd67a088e9400b369d168d11c06ac1..3177db282013e6dc3c7215fc2a851e2630a29409 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -249,7 +249,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public int getPlayerCount() { - return world.players().size(); + return world.realPlayers().size(); // Leaves - skip } @Override @@ -1279,9 +1279,9 @@ public class CraftWorld extends CraftRegionAccessor implements World { @Override public List getPlayers() { - List list = new ArrayList(this.world.players().size()); + List list = new ArrayList(this.world.realPlayers().size()); // Leaves - skip - for (net.minecraft.world.entity.player.Player human : this.world.players()) { + for (net.minecraft.world.entity.player.Player human : this.world.realPlayers()) { // Leaves - skip HumanEntity bukkitEntity = human.getBukkitEntity(); if ((bukkitEntity != null) && (bukkitEntity instanceof Player)) { @@ -1988,7 +1988,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { public void playSound(final net.kyori.adventure.sound.Sound sound) { org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper final long seed = sound.seed().orElseGet(this.world.getRandom()::nextLong); - for (ServerPlayer player : this.getHandle().players()) { + for (ServerPlayer player : this.getHandle().realPlayers()) { // Leaves - skip player.connection.send(io.papermc.paper.adventure.PaperAdventure.asSoundPacket(sound, player.getX(), player.getY(), player.getZ(), seed, null)); } } @@ -2016,7 +2016,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { org.spigotmc.AsyncCatcher.catchOp("play sound"); // Paper final long seed = sound.seed().orElseGet(this.getHandle().getRandom()::nextLong); if (emitter == net.kyori.adventure.sound.Sound.Emitter.self()) { - for (ServerPlayer player : this.getHandle().players()) { + for (ServerPlayer player : this.getHandle().realPlayers()) { // Leaves - skip player.connection.send(io.papermc.paper.adventure.PaperAdventure.asSoundPacket(sound, player, seed, null)); } } else if (emitter instanceof CraftEntity craftEntity) { @@ -2248,7 +2248,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { Preconditions.checkArgument(particle.getDataType().isInstance(data), "data (%s) should be %s", data.getClass(), particle.getDataType()); } this.getHandle().sendParticlesSource( - receivers == null ? this.getHandle().players() : receivers.stream().map(player -> ((CraftPlayer) player).getHandle()).collect(java.util.stream.Collectors.toList()), // Paper - Particle API + receivers == null ? this.getHandle().realPlayers() : receivers.stream().map(player -> ((CraftPlayer) player).getHandle()).collect(java.util.stream.Collectors.toList()), // Paper - Particle API // Leaves - skip sender != null ? ((CraftPlayer) sender).getHandle() : null, // Sender // Paper - Particle API CraftParticle.createParticleParam(particle, data), // Particle force, diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 852e1ffef6a022caad7c8eff34091e50112a2290..8eb5d014d9ed688ffebaffb4ce0bb40896961a04 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -126,6 +126,8 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { return new CraftHumanEntity(server, (net.minecraft.world.entity.player.Player) entity); } + if (entity instanceof org.leavesmc.leaves.bot.ServerBot bot) { return new org.leavesmc.leaves.entity.bot.CraftBot(server, bot); } + // Special case complex part, since there is no extra entity type for them if (entity instanceof EnderDragonPart complexPart) { if (complexPart.parentMob instanceof EnderDragon) { diff --git a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java index 317837a2a9b3b511b5cac4df4db248d4652816dc..a8253d1a3129c8258e9ead7c430e1bcf82f735d7 100644 --- a/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java +++ b/src/main/java/org/bukkit/craftbukkit/event/CraftEventFactory.java @@ -897,7 +897,11 @@ public class CraftEventFactory { event.setKeepInventory(keepInventory); event.setKeepLevel(victim.keepLevel); // SPIGOT-2222: pre-set keepLevel populateFields(victim, event); // Paper - make cancellable - Bukkit.getServer().getPluginManager().callEvent(event); + // Leaves start - disable bot death event + if (!(victim instanceof org.leavesmc.leaves.bot.ServerBot)) { + Bukkit.getServer().getPluginManager().callEvent(event); + } + // Leaves end - disable bot death event // Paper start - make cancellable if (event.isCancelled()) { return event;