796 lines
44 KiB
Diff
796 lines
44 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Bacteriawa <A3167717663@hotmail.com>
|
|
Date: Sat, 30 Aug 2025 17:16:32 +0800
|
|
Subject: [PATCH] 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/net/minecraft/advancements/triggers/SimpleCriterionTrigger.java b/net/minecraft/advancements/triggers/SimpleCriterionTrigger.java
|
|
index d76a338ab4f326e6105adc451eee3d4601403c98..b827d51d23ceaebef2191a9f349bbd346e73f1af 100644
|
|
--- a/net/minecraft/advancements/triggers/SimpleCriterionTrigger.java
|
|
+++ b/net/minecraft/advancements/triggers/SimpleCriterionTrigger.java
|
|
@@ -17,6 +17,7 @@ import net.minecraft.world.level.storage.loot.ValidationContextSource;
|
|
|
|
public abstract class SimpleCriterionTrigger<T extends SimpleCriterionTrigger.SimpleInstance> implements CriterionTrigger<T> {
|
|
protected void trigger(final ServerPlayer player, final Predicate<T> matcher) {
|
|
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) return; // Leaves - bot skip
|
|
PlayerAdvancements advancements = player.getAdvancements();
|
|
Map<PlayerAdvancements.TriggerInstanceKey, T> listenersForType = advancements.getTriggerMapForType(this);
|
|
if (listenersForType != null && !listenersForType.isEmpty()) {
|
|
diff --git a/net/minecraft/network/Connection.java b/net/minecraft/network/Connection.java
|
|
index d2e9d46bbd9ee4ce45419b11499d7a7bc50f0219..848967dbe41694411603ef369cfdc3a0b00240d3 100644
|
|
--- a/net/minecraft/network/Connection.java
|
|
+++ b/net/minecraft/network/Connection.java
|
|
@@ -74,7 +74,7 @@ public class Connection extends SimpleChannelInboundHandler<Packet<?>> {
|
|
public boolean preparing = true;
|
|
// Spigot end
|
|
private volatile @Nullable PacketListener disconnectListener;
|
|
- private volatile @Nullable PacketListener packetListener;
|
|
+ protected volatile @Nullable PacketListener packetListener; // Leaves - private -> protected
|
|
private @Nullable DisconnectionDetails disconnectionDetails;
|
|
private final java.util.concurrent.atomic.AtomicBoolean disconnectionHandled = new java.util.concurrent.atomic.AtomicBoolean(false); // Folia - region threading - may be called concurrently during configuration stage
|
|
private int receivedPackets;
|
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
|
index a4536d82830370ce74313cf9721968b3344f3f08..c91e4b2143e4a801a124dfb9c2f807445539685f 100644
|
|
--- a/net/minecraft/server/MinecraftServer.java
|
|
+++ b/net/minecraft/server/MinecraftServer.java
|
|
@@ -296,6 +296,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
// Paper - per-level scheduledEvents
|
|
private final ServerClockManager clockManager;
|
|
|
|
+ private org.leavesmc.leaves.bot.BotList botList; // Leaves - fakeplayer
|
|
+
|
|
public static <S extends MinecraftServer> S spin(final Function<Thread, S> factory) {
|
|
ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system
|
|
AtomicReference<S> serverReference = new AtomicReference<>();
|
|
@@ -1192,6 +1194,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
this.halt(wait, false);
|
|
}
|
|
public void halt(final boolean wait, final boolean isRestarting) {
|
|
+ // Lophine start - Folia changes
|
|
+ halt(wait, isRestarting, false);
|
|
+ }
|
|
+
|
|
+ public void halt(final boolean wait, final boolean isRestarting, boolean force) {
|
|
+ if (!force && !this.getBotList().forceShutdown && !this.getBotList().removeAll()) { // Leaves - save or remove bot
|
|
+ this.getPlayerList().broadcastSystemMessage(Component.literal("Bot Still need to save, please wait! If you want to shuntdown without bot data saving, please use /stop force"), false);
|
|
+ return;
|
|
+ }
|
|
+ // Lophine end - Folia changes
|
|
this.isRestarting = isRestarting;
|
|
this.hasLoggedStop = true; // Paper - Debugging
|
|
if (this.isDebugging()) io.papermc.paper.util.TraceUtil.dumpTraceForThread("Server stopped"); // Paper - Debugging
|
|
@@ -1661,7 +1673,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
int emptyTickThreshold = this.pauseWhenEmptySeconds() * 20;
|
|
this.removeDisabledPluginsBlockingSleep(); // Paper - API to allow/disallow tick sleeping
|
|
if (false && emptyTickThreshold > 0) { // Folia - region threading - this is complicated to implement, and even if done correctly is messy
|
|
- if (this.playerList.getPlayerCount() == 0 && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping
|
|
+ if (this.playerList.getPlayerCount() == 0 && this.botList.bots.isEmpty() && !this.tickRateManager.isSprinting() && this.pluginsBlockingSleep.isEmpty()) { // Paper - API to allow/disallow tick sleeping // Leaves - fakeplayer
|
|
this.emptyTicks++;
|
|
} else {
|
|
this.emptyTicks = 0;
|
|
@@ -1793,6 +1805,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
this.isSaving = true;
|
|
if (playerSaveInterval > 0) {
|
|
this.playerList.saveAll(playerSaveInterval);
|
|
+ org.leavesmc.leaves.bot.BotList.INSTANCE.saveAllResumeBots(playerSaveInterval); // Leaves - resident fakeplayer
|
|
}
|
|
if (region == null && fullSave) { // Folia - region threading - don't auto save level data
|
|
this.saveGlobalData(false);
|
|
@@ -2031,6 +2044,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
|
|
protected void tickConnection() {
|
|
this.getConnection().tick();
|
|
+ this.botList.networkTick(); // Leaves - fakeplayer
|
|
}
|
|
|
|
public void forceGameTimeSynchronization() {
|
|
@@ -3240,6 +3254,16 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
return this.debugSubscribers;
|
|
}
|
|
|
|
+ // Leaves start - fakeplayer
|
|
+ protected void setBotList(org.leavesmc.leaves.bot.BotList botList) {
|
|
+ this.botList = botList;
|
|
+ }
|
|
+
|
|
+ public org.leavesmc.leaves.bot.BotList getBotList() {
|
|
+ return botList;
|
|
+ }
|
|
+ // Leaves end - fakeplayer
|
|
+
|
|
public enum MultiplayerScope {
|
|
OFF("off"),
|
|
LAN("lan");
|
|
diff --git a/net/minecraft/server/PlayerAdvancements.java b/net/minecraft/server/PlayerAdvancements.java
|
|
index d447b444abd9b62ab241419301a96d19ae77a7eb..cdafcb724106807c6bc77c9930090839bd2cc007 100644
|
|
--- a/net/minecraft/server/PlayerAdvancements.java
|
|
+++ b/net/minecraft/server/PlayerAdvancements.java
|
|
@@ -166,6 +166,11 @@ public class PlayerAdvancements {
|
|
}
|
|
|
|
public boolean award(final AdvancementHolder holder, final String criterion) {
|
|
+ // Leaves start - bot can't get advancement
|
|
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
|
|
+ return false;
|
|
+ }
|
|
+ // Leaves end - bot can't get advancement
|
|
boolean result = false;
|
|
AdvancementProgress progress = this.getOrStartProgress(holder);
|
|
boolean wasDone = progress.isDone();
|
|
diff --git a/net/minecraft/server/commands/BanIpCommands.java b/net/minecraft/server/commands/BanIpCommands.java
|
|
index dee5e12db878c13392083a46496de88d0b5924c3..922afd5e0fad3519ff2d7dc692574e5f65f119d6 100644
|
|
--- a/net/minecraft/server/commands/BanIpCommands.java
|
|
+++ b/net/minecraft/server/commands/BanIpCommands.java
|
|
@@ -40,6 +40,12 @@ public class BanIpCommands {
|
|
return banIp(source, target, reason);
|
|
} else {
|
|
ServerPlayer player = source.getServer().getPlayerList().getPlayerByName(target);
|
|
+ // Leaves start - disable ban
|
|
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
|
|
+ source.sendFailure(Component.literal("Permission denied"));
|
|
+ return 0;
|
|
+ }
|
|
+ // Leaves end - disable ban
|
|
if (player != null) {
|
|
return banIp(source, player.getIpAddress(), reason);
|
|
} else {
|
|
diff --git a/net/minecraft/server/commands/BanPlayerCommands.java b/net/minecraft/server/commands/BanPlayerCommands.java
|
|
index c87bc86c57fde9d92e3927bdead5cdaf2e935744..950f8ed955bc09713348936ae7aa1a8b14006c2a 100644
|
|
--- a/net/minecraft/server/commands/BanPlayerCommands.java
|
|
+++ b/net/minecraft/server/commands/BanPlayerCommands.java
|
|
@@ -38,8 +38,15 @@ public class BanPlayerCommands {
|
|
private static int banPlayers(final CommandSourceStack source, final Collection<NameAndId> players, final @Nullable Component reason) throws CommandSyntaxException {
|
|
UserBanList list = source.getServer().getPlayerList().getBans();
|
|
int count = 0;
|
|
-
|
|
+ boolean hasBot = false; // Leaves - disable kick
|
|
for (NameAndId player : players) {
|
|
+ // Leaves start - disable ban
|
|
+ if (player.isBot()) {
|
|
+ source.sendFailure(Component.literal("Permission denied"));
|
|
+ hasBot = true;
|
|
+ continue;
|
|
+ }
|
|
+ // Leaves end - disable ban
|
|
if (!list.isBanned(player)) {
|
|
UserBanListEntry entry = new UserBanListEntry(player, null, source.getTextName(), null, reason == null ? null : reason.getString());
|
|
list.add(entry);
|
|
@@ -53,7 +60,13 @@ public class BanPlayerCommands {
|
|
}
|
|
|
|
if (count == 0) {
|
|
- throw ERROR_ALREADY_BANNED.create();
|
|
+ // Leaves start - disable kick
|
|
+ if (hasBot) {
|
|
+ return count;
|
|
+ } else {
|
|
+ throw ERROR_ALREADY_BANNED.create();
|
|
+ }
|
|
+ // Leaves end - disable kick
|
|
} else {
|
|
return count;
|
|
}
|
|
diff --git a/net/minecraft/server/commands/KickCommand.java b/net/minecraft/server/commands/KickCommand.java
|
|
index bf361ef4cbf2a55b8bba5a75111257fb2d6d471f..82629ecca8b0e216db4ccb6f4c38de53ac1a6419 100644
|
|
--- a/net/minecraft/server/commands/KickCommand.java
|
|
+++ b/net/minecraft/server/commands/KickCommand.java
|
|
@@ -39,9 +39,17 @@ public class KickCommand {
|
|
throw ERROR_SINGLEPLAYER.create();
|
|
}
|
|
|
|
- int count = 0;
|
|
+ boolean hasBot = false; // Leaves - disable kick
|
|
+ int count = 0;
|
|
|
|
for (ServerPlayer player : players) {
|
|
+ // Leaves start - disable kick
|
|
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot) {
|
|
+ source.sendFailure(Component.literal("Permission denied"));
|
|
+ hasBot = true;
|
|
+ continue;
|
|
+ }
|
|
+ // Leaves end - disable kick
|
|
if (!source.getServer().isSingleplayerOwner(player.nameAndId())) {
|
|
player.connection.disconnect(reason, org.bukkit.event.player.PlayerKickEvent.Cause.KICKED); // Paper - kick event cause
|
|
source.sendSuccess(() -> Component.translatable("commands.kick.success", player.getDisplayName(), reason), true);
|
|
@@ -50,7 +58,13 @@ public class KickCommand {
|
|
}
|
|
|
|
if (count == 0) {
|
|
- throw ERROR_KICKING_OWNER.create();
|
|
+ // Leaves start - disable kick
|
|
+ if (hasBot) {
|
|
+ return count;
|
|
+ } else {
|
|
+ throw ERROR_KICKING_OWNER.create();
|
|
+ }
|
|
+ // Leaves end - disable kick
|
|
} else {
|
|
return count;
|
|
}
|
|
diff --git a/net/minecraft/server/commands/OpCommand.java b/net/minecraft/server/commands/OpCommand.java
|
|
index 636f56bfc0e9075b257e2eb14e858975bdedd801..20cbc0e65fea3fc2d0033259c2f35e158ea81926 100644
|
|
--- a/net/minecraft/server/commands/OpCommand.java
|
|
+++ b/net/minecraft/server/commands/OpCommand.java
|
|
@@ -39,6 +39,7 @@ public class OpCommand {
|
|
int count = 0;
|
|
|
|
for (NameAndId player : players) {
|
|
+ if (player.isBot()) continue; // Leaves - disable op
|
|
if (!list.isOp(player)) {
|
|
list.op(player);
|
|
count++;
|
|
diff --git a/net/minecraft/server/commands/StopCommand.java b/net/minecraft/server/commands/StopCommand.java
|
|
index 3021b70b941ed09c5c58b98d30830a2279b8339c..d289f59475b617ae527d123239297f695468b80c 100644
|
|
--- a/net/minecraft/server/commands/StopCommand.java
|
|
+++ b/net/minecraft/server/commands/StopCommand.java
|
|
@@ -12,6 +12,10 @@ public class StopCommand {
|
|
c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
|
|
c.getSource().getServer().halt(false);
|
|
return Command.SINGLE_SUCCESS;
|
|
- }));
|
|
+ }).then(Commands.literal("force").requires(Commands.hasPermission(Commands.LEVEL_OWNERS)).executes(c -> {
|
|
+ c.getSource().sendSuccess(() -> Component.translatable("commands.stop.stopping"), true);
|
|
+ c.getSource().getServer().halt(false, false, true);
|
|
+ return 1;
|
|
+ })));
|
|
}
|
|
}
|
|
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index 2dae0f4249eade60ac55c9fa289dd146dc3675e1..239cad02f85f0d14d4abfa746ecdc4dd82b04657 100644
|
|
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -230,6 +230,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
}
|
|
|
|
// Spigot start
|
|
+ this.setBotList(new org.leavesmc.leaves.bot.BotList(this)); // Leaves - fakeplayer
|
|
this.setPlayerList(new DedicatedPlayerList(this, this.registries(), this.playerDataStorage));
|
|
org.spigotmc.SpigotConfig.init((java.io.File) this.options.valueOf("spigot-settings"));
|
|
org.spigotmc.SpigotConfig.registerCommands();
|
|
@@ -251,6 +252,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
consoleThread.start(); // Paper - Enhance console tab completions for brigadier commands; start console thread after MinecraftServer.console & PaperConfig are initialized
|
|
io.papermc.paper.command.PaperCommands.registerCommands(this); // Paper - setup /paper command
|
|
if (false) this.server.spark.registerCommandBeforePlugins(this.server); // Paper - spark // Luminol - Force disable builtin spark
|
|
+ this.getBotList().loadResumeBotInfo(); // Leaves - load resident bot info
|
|
com.destroystokyo.paper.Metrics.PaperMetrics.startMetrics(); // Paper - start metrics
|
|
com.destroystokyo.paper.VersionHistoryManager.INSTANCE.getClass(); // Paper - load version history now
|
|
|
|
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
|
index e9cd960a0733ac37fac8e956ae36628bf42b79f2..4ab6959f20d8593f504f00a4feaaea7c41bb3339 100644
|
|
--- a/net/minecraft/server/level/ChunkMap.java
|
|
+++ b/net/minecraft/server/level/ChunkMap.java
|
|
@@ -1388,6 +1388,13 @@ public class ChunkMap extends SimpleRegionStorage implements ChunkHolder.PlayerP
|
|
}
|
|
} else {
|
|
this.removePlayer(player);
|
|
+ // Leaves start - render bot
|
|
+ if (this.entity instanceof org.leavesmc.leaves.bot.ServerBot bot) {
|
|
+ if (bot.needSendFakeData(player)) {
|
|
+ bot.sendFakeData(player.connection, false);
|
|
+ }
|
|
+ }
|
|
+ // Leaves end - render bot
|
|
}
|
|
}
|
|
}
|
|
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
|
|
index e1298bbb83d1d31406c47eaf6d10db3e8d8611ea..41c7179cf2b530d8e4b0fc8161aec75fc9d6c4df 100644
|
|
--- a/net/minecraft/server/level/ServerLevel.java
|
|
+++ b/net/minecraft/server/level/ServerLevel.java
|
|
@@ -243,6 +243,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
|
private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
|
|
public final org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer = new org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer(DATA_TYPE_REGISTRY);
|
|
//private final alternate.current.wire.WireHandler wireHandler = new alternate.current.wire.WireHandler(this); // Paper - optimize redstone (Alternate Current) // Folia - region threading - move to regionised world data
|
|
+ final List<ServerPlayer> realPlayers; // Leaves - skip
|
|
|
|
@Override
|
|
public @Nullable LevelChunk getChunkIfLoaded(int x, int z) {
|
|
@@ -709,6 +710,7 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
|
this.chunkDataController = new ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.ChunkDataController((ServerLevel)(Object)this, this.chunkTaskScheduler);
|
|
// Paper end - rewrite chunk system
|
|
this.getCraftServer().addWorld(this.getWorld()); // CraftBukkit
|
|
+ this.realPlayers = Lists.newArrayList(); // Leaves - skip
|
|
this.updateTickData(); // Folia - region threading - make sure it is initialised before ticked
|
|
}
|
|
|
|
@@ -2621,6 +2623,12 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
|
return this.players;
|
|
}
|
|
|
|
+ // Leaves start - fakeplayer skip
|
|
+ public List<ServerPlayer> realPlayers() {
|
|
+ return this.realPlayers;
|
|
+ }
|
|
+ // Leaves end - fakeplayer skip
|
|
+
|
|
@Override
|
|
public void updatePOIOnBlockStateChange(final BlockPos pos, final BlockState oldState, final BlockState newState) {
|
|
Optional<Holder<PoiType>> oldType = PoiTypes.forState(oldState);
|
|
@@ -3094,6 +3102,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
|
// ServerLevel.this.getChunkSource().addEntity(entity); // Paper - ignore and warn about illegal addEntity calls instead of crashing server; moved down below valid=true
|
|
if (entity instanceof ServerPlayer player) {
|
|
ServerLevel.this.players.add(player);
|
|
+ // Leaves start - skip
|
|
+ if (!(player instanceof org.leavesmc.leaves.bot.ServerBot)) {
|
|
+ ServerLevel.this.realPlayers.add(player);
|
|
+ }
|
|
+ // Leaves end - skip
|
|
if (player.isReceivingWaypoints()) {
|
|
ServerLevel.this.getWaypointManager().addPlayer(player);
|
|
}
|
|
@@ -3175,6 +3188,11 @@ public class ServerLevel extends Level implements WorldGenLevel, ServerEntityGet
|
|
ServerLevel.this.getChunkSource().removeEntity(entity);
|
|
if (entity instanceof ServerPlayer player) {
|
|
ServerLevel.this.players.remove(player);
|
|
+ // Leaves start - skip
|
|
+ if (!(player instanceof org.leavesmc.leaves.bot.ServerBot)) {
|
|
+ ServerLevel.this.realPlayers.remove(player);
|
|
+ }
|
|
+ // Leaves end - skip
|
|
ServerLevel.this.getWaypointManager().removePlayer(player);
|
|
ServerLevel.this.updateSleepingPlayerList();
|
|
}
|
|
diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java
|
|
index a13b6e60251151295e13d40840096cb002968b82..5affc3c101848e689a9044790c0f47f3dc3e214a 100644
|
|
--- a/net/minecraft/server/level/ServerPlayer.java
|
|
+++ b/net/minecraft/server/level/ServerPlayer.java
|
|
@@ -232,7 +232,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
|
private static final boolean DEFAULT_SPAWN_EXTRA_PARTICLES_ON_FALL = false;
|
|
public ServerGamePacketListenerImpl connection;
|
|
private final MinecraftServer server;
|
|
- public final ServerPlayerGameMode gameMode;
|
|
+ public ServerPlayerGameMode gameMode; // Leaves - not final
|
|
private final PlayerAdvancements advancements;
|
|
private final ServerStatsCounter stats;
|
|
private float lastRecordedHealthAndAbsorption = Float.MIN_VALUE;
|
|
@@ -251,9 +251,9 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
|
private boolean canChatColor = true;
|
|
private long lastActionTime = Util.getMillis();
|
|
private @Nullable Entity camera;
|
|
- private boolean isChangingDimension;
|
|
+ protected boolean isChangingDimension;
|
|
public boolean seenCredits = false;
|
|
- private final ServerRecipeBook recipeBook;
|
|
+ protected ServerRecipeBook recipeBook; // Leaves - not final and private -> protected
|
|
private @Nullable Vec3 levitationStartPos;
|
|
private int levitationStartTime;
|
|
private boolean disconnected;
|
|
@@ -1489,7 +1489,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
|
}
|
|
// Lophine End - Cross Region Damage trace
|
|
|
|
- private void tellNeutralMobsThatIDied() {
|
|
+ protected void tellNeutralMobsThatIDied() { // Leaves private -> protected
|
|
AABB aabb = new AABB(this.blockPosition()).inflate(32.0, 10.0, 32.0);
|
|
this.level()
|
|
.getEntitiesOfClass(Mob.class, aabb, EntitySelector.NO_SPECTATORS)
|
|
@@ -2161,6 +2161,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc
|
|
this.lastSentHealth = -1.0F;
|
|
this.lastSentFood = -1;
|
|
this.teleportSpectators(transition, oldLevel);
|
|
+ // Leaves start - bot support
|
|
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
|
|
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(this, true)); // Leaves - render bot
|
|
+ }
|
|
+ // Leaves end - bot support
|
|
// CraftBukkit start
|
|
org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), oldLevel.getWorld());
|
|
this.level().getCraftServer().getPluginManager().callEvent(changeEvent);
|
|
diff --git a/net/minecraft/server/players/CachedUserNameToIdResolver.java b/net/minecraft/server/players/CachedUserNameToIdResolver.java
|
|
index b7553611723f7120c66e1f3e51d89df28bd2756b..7109a22a9911d452242207ab0286ee985dafd439 100644
|
|
--- a/net/minecraft/server/players/CachedUserNameToIdResolver.java
|
|
+++ b/net/minecraft/server/players/CachedUserNameToIdResolver.java
|
|
@@ -122,6 +122,12 @@ public class CachedUserNameToIdResolver implements UserNameToIdResolver {
|
|
|
|
@Override
|
|
public Optional<NameAndId> get(final String name) {
|
|
+ // Leaves start - fix bot
|
|
+ org.leavesmc.leaves.bot.ServerBot bot = org.leavesmc.leaves.bot.BotList.INSTANCE.getBotByName(name);
|
|
+ if (bot != null) {
|
|
+ return Optional.of(bot.nameAndId());
|
|
+ }
|
|
+ // Leaves end - fix bot
|
|
String userName = name.toLowerCase(Locale.ROOT);
|
|
boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency
|
|
CachedUserNameToIdResolver.GameProfileInfo profileInfo = this.profilesByName.get(userName);
|
|
diff --git a/net/minecraft/server/players/NameAndId.java b/net/minecraft/server/players/NameAndId.java
|
|
index 12190f2a2856b0d0cf95144d0b1622f1b9600bf6..be01f06d4ee02854345842c97382e8b6401ab948 100644
|
|
--- a/net/minecraft/server/players/NameAndId.java
|
|
+++ b/net/minecraft/server/players/NameAndId.java
|
|
@@ -8,18 +8,22 @@ import java.util.UUID;
|
|
import net.minecraft.core.UUIDUtil;
|
|
import org.jspecify.annotations.Nullable;
|
|
|
|
-public record NameAndId(UUID id, String name) {
|
|
+public record NameAndId(UUID id, String name, boolean isBot) { // Leaves - fakeplayer
|
|
public static final Codec<NameAndId> CODEC = RecordCodecBuilder.create(
|
|
i -> i.group(UUIDUtil.STRING_CODEC.fieldOf("id").forGetter(NameAndId::id), Codec.STRING.fieldOf("name").forGetter(NameAndId::name))
|
|
.apply(i, NameAndId::new)
|
|
);
|
|
|
|
public NameAndId(final GameProfile profile) {
|
|
- this(profile.id(), profile.name());
|
|
+ this(profile.id(), profile.name(), com.google.common.collect.Iterables.getFirst(profile.properties().get("is_bot"), "false").equals("true")); // Leaves - fakeplayer
|
|
}
|
|
|
|
public NameAndId(final com.mojang.authlib.yggdrasil.response.NameAndId profile) {
|
|
- this(profile.id(), profile.name());
|
|
+ this(profile.id(), profile.name(), false); // Leaves - fakeplayer
|
|
+ }
|
|
+
|
|
+ public NameAndId(UUID uuid, String name) {
|
|
+ this(uuid, name, false); // Leaves - fakeplayer
|
|
}
|
|
|
|
public static @Nullable NameAndId fromJson(final JsonObject object) {
|
|
@@ -33,7 +37,7 @@ public record NameAndId(UUID id, String name) {
|
|
return null;
|
|
}
|
|
|
|
- return new NameAndId(uuid, object.get("name").getAsString());
|
|
+ return new NameAndId(uuid, object.get("name").getAsString(), false); // Leaves - fakeplayer
|
|
} else {
|
|
return null;
|
|
}
|
|
@@ -46,7 +50,7 @@ public record NameAndId(UUID id, String name) {
|
|
|
|
public static NameAndId createOffline(final String name) {
|
|
UUID id = UUIDUtil.createOfflinePlayerUUID(name);
|
|
- return new NameAndId(id, name);
|
|
+ return new NameAndId(id, name, false); // Leaves - fakeplayer
|
|
}
|
|
|
|
// Paper start - utility method for common conversion back to the game profile
|
|
diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java
|
|
index bb3049ed94088337f18f2373f97846b2f0add8f1..b5a22510fede9521a0d8330272876d2ceedfb1cc 100644
|
|
--- a/net/minecraft/server/players/PlayerList.java
|
|
+++ b/net/minecraft/server/players/PlayerList.java
|
|
@@ -320,6 +320,19 @@ public abstract class PlayerList {
|
|
|
|
org.leavesmc.leaves.protocol.core.LeavesProtocolManager.handlePlayerJoin(player); // Leaves - protocol
|
|
|
|
+ // Leaves start - bot support
|
|
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
|
|
+ org.leavesmc.leaves.bot.ServerBot bot = this.server.getBotList().getBotByName(player.getScoreboardName());
|
|
+ if (bot != null) {
|
|
+ this.server.getBotList().removeBot(bot, org.leavesmc.leaves.event.bot.BotRemoveEvent.RemoveReason.INTERNAL, player.getBukkitEntity(), false, false);
|
|
+ }
|
|
+ this.server.getBotList().bots.forEach(bot1 -> {
|
|
+ bot1.sendPlayerInfo(player);
|
|
+ bot1.sendFakeDataIfNeed(player, true);
|
|
+ }); // Leaves - render bot
|
|
+ }
|
|
+ // Leaves end - bot support
|
|
+
|
|
final net.kyori.adventure.text.Component jm = playerJoinEvent.joinMessage();
|
|
|
|
if (jm != null && !jm.equals(net.kyori.adventure.text.Component.empty())) { // Paper - Adventure
|
|
@@ -791,6 +804,11 @@ public abstract class PlayerList {
|
|
respawnReason
|
|
).callEvent();
|
|
// Paper end
|
|
+ // Leaves start - bot support
|
|
+ if (fun.bm.lophine.config.modules.function.FakeplayerConfig.enable) {
|
|
+ this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(player, true)); // Leaves - render bot
|
|
+ }
|
|
+ // Leaves end - bot support
|
|
|
|
return player;
|
|
}
|
|
@@ -893,11 +911,16 @@ public abstract class PlayerList {
|
|
|
|
public String[] getPlayerNamesArray() {
|
|
List<ServerPlayer> players = new java.util.ArrayList<>(this.players); // Folia - region threading
|
|
- String[] names = new String[players.size()]; // Folia - region threading
|
|
+ String[] names = new String[players.size() + this.server.getBotList().bots.size()]; // Leaves - fakeplayer support
|
|
|
|
for (int i = 0; i < players.size(); i++) { // Folia - region threading
|
|
names[i] = players.get(i).getGameProfile().name(); // Folia - region threading
|
|
}
|
|
+ // Leaves start - fakeplayer support
|
|
+ for (int i = this.players.size(); i < names.length; ++i) {
|
|
+ names[i] = this.server.getBotList().bots.get(i - this.players.size()).gameProfile.name();
|
|
+ }
|
|
+ // Leaves end - fakeplayer support
|
|
|
|
return names;
|
|
}
|
|
@@ -1018,8 +1041,15 @@ public abstract class PlayerList {
|
|
}
|
|
}
|
|
|
|
- public @Nullable ServerPlayer getPlayerByName(final String name) {
|
|
- return this.playersByName.get(name.toLowerCase(java.util.Locale.ROOT)); // Spigot
|
|
+ public @Nullable ServerPlayer getPlayerByName(String name) {
|
|
+ // Leaves start - fakeplayer support
|
|
+ name = name.toLowerCase(java.util.Locale.ROOT);
|
|
+ ServerPlayer player = this.playersByName.get(name);
|
|
+ if (player == null) {
|
|
+ player = this.server.getBotList().getBotByName(name);
|
|
+ }
|
|
+ return player; // Spigot
|
|
+ // Leaves end - fakeplayer support
|
|
}
|
|
|
|
public void broadcast(
|
|
@@ -1366,7 +1396,13 @@ public abstract class PlayerList {
|
|
}
|
|
|
|
public @Nullable ServerPlayer getPlayer(final UUID uuid) {
|
|
- return this.playersByUUID.get(uuid);
|
|
+ // Leaves start - fakeplayer support
|
|
+ ServerPlayer player = this.playersByUUID.get(uuid);
|
|
+ if (player == null) {
|
|
+ player = this.server.getBotList().getBot(uuid);
|
|
+ }
|
|
+ return player;
|
|
+ // Leaves start - fakeplayer support
|
|
}
|
|
|
|
public @Nullable ServerPlayer getPlayer(final String playerName) {
|
|
diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java
|
|
index cc47f02936cad38627c2ee87e54aa8b80a66a8af..bab9b0dbbcb76e4474305db7540f1e703ef0ae62 100644
|
|
--- a/net/minecraft/world/entity/Entity.java
|
|
+++ b/net/minecraft/world/entity/Entity.java
|
|
@@ -1263,7 +1263,7 @@ public abstract class Entity
|
|
|
|
BlockPos effectPos = this.getOnPosLegacy();
|
|
BlockState effectState = this.level().getBlockState(effectPos);
|
|
- if (this.isLocalInstanceAuthoritative()) {
|
|
+ if (this.isLocalInstanceAuthoritative() || this instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - ServerBot needs check fall damage
|
|
this.checkFallDamage(movement.y, this.onGround(), effectState, effectPos);
|
|
}
|
|
|
|
@@ -1664,7 +1664,7 @@ public abstract class Entity
|
|
return colliders.isEmpty() ? maxDistance : -Shapes.collide(Direction.Axis.Y, aabb, colliders, -maxDistance);
|
|
}
|
|
|
|
- private Vec3 collide(final Vec3 movement) {
|
|
+ public Vec3 collide(final Vec3 movement) { // Leaves - private -> public
|
|
// Paper start - optimise collisions
|
|
final boolean xZero = movement.x == 0.0;
|
|
final boolean yZero = movement.y == 0.0;
|
|
diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java
|
|
index cb1589e3aa663ca058fb5c3a24da700d4482cf35..d64c68651b7142869a06ce0200fb625cd45ae235 100644
|
|
--- a/net/minecraft/world/entity/LivingEntity.java
|
|
+++ b/net/minecraft/world/entity/LivingEntity.java
|
|
@@ -3348,7 +3348,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
private void travelRidden(final Player controller, final Vec3 selfInput) {
|
|
Vec3 riddenInput = this.getRiddenInput(controller, selfInput);
|
|
this.tickRidden(controller, riddenInput);
|
|
- if (this.canSimulateMovement()) {
|
|
+ if (this.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves - Fakeplayer
|
|
this.setSpeed(this.getRiddenSpeed(controller));
|
|
this.travel(riddenInput);
|
|
} else {
|
|
@@ -4280,7 +4280,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
// Paper start - lag compensate eating
|
|
// we add 1 to the expected time to avoid lag compensating when we should not
|
|
final boolean shouldLagCompensate = this.useItem.has(DataComponents.FOOD) && this.eatStartTime != -1 && (System.nanoTime() - this.eatStartTime) > ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L));
|
|
- if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide() && !useItem.useOnRelease()) {
|
|
+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !(this instanceof org.leavesmc.leaves.bot.ServerBot) && !this.level().isClientSide() && !useItem.useOnRelease()) {
|
|
this.useItemRemaining = 0;
|
|
// Paper end - lag compensate eating
|
|
this.completeUsingItem();
|
|
@@ -4469,6 +4469,23 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin
|
|
this.stopUsingItem();
|
|
}
|
|
|
|
+ // Leaves start - Fakeplayer
|
|
+ public boolean releaseUsingItemWithResult() {
|
|
+ ItemStack itemInHand = this.getItemInHand(this.getUsedItemHand());
|
|
+ boolean result = false;
|
|
+ if (!this.useItem.isEmpty() && ItemStack.isSameItem(itemInHand, this.useItem)) {
|
|
+ this.useItem = itemInHand;
|
|
+ result = this.useItem.releaseUsingWithResult(this.level(), this, this.getUseItemRemainingTicks());
|
|
+ if (this.useItem.useOnRelease()) {
|
|
+ this.updatingUsingItem();
|
|
+ }
|
|
+ }
|
|
+
|
|
+ this.stopUsingItem();
|
|
+ return result;
|
|
+ }
|
|
+ // Leaves end - Fakeplayer
|
|
+
|
|
public void stopUsingItem() {
|
|
if (!this.level().isClientSide()) {
|
|
boolean wasUsingItem = this.isUsingItem();
|
|
diff --git a/net/minecraft/world/entity/player/Player.java b/net/minecraft/world/entity/player/Player.java
|
|
index c6fa9dff800b1491b1e0fc5d7e1dc16b99b8c7db..f063e9b7601480d0e66da22ea8e5bec2e8619fee 100644
|
|
--- a/net/minecraft/world/entity/player/Player.java
|
|
+++ b/net/minecraft/world/entity/player/Player.java
|
|
@@ -156,7 +156,7 @@ public abstract class Player extends Avatar implements ContainerUser {
|
|
protected FoodData foodData = new FoodData();
|
|
protected int jumpTriggerTime;
|
|
public int takeXpDelay;
|
|
- private int sleepCounter = 0;
|
|
+ protected int sleepCounter = 0;
|
|
protected boolean wasUnderwater;
|
|
private final Abilities abilities = new Abilities();
|
|
public int experienceLevel = 0;
|
|
@@ -167,7 +167,7 @@ public abstract class Player extends Avatar implements ContainerUser {
|
|
private int lastLevelUpTime;
|
|
public GameProfile gameProfile;
|
|
private boolean reducedDebugInfo;
|
|
- private ItemStack lastItemInMainHand = ItemStack.EMPTY;
|
|
+ protected ItemStack lastItemInMainHand = ItemStack.EMPTY; // Leaves - fakeplayer
|
|
private final ItemCooldowns cooldowns = this.createItemCooldowns();
|
|
private Optional<GlobalPos> lastDeathLocation = Optional.empty();
|
|
public me.earthme.luminol.functions.bars.TickableStatusBarList statusBarList = new me.earthme.luminol.functions.bars.TickableStatusBarList(this); // Luminol status bars
|
|
@@ -345,6 +345,12 @@ public abstract class Player extends Avatar implements ContainerUser {
|
|
this.updatePlayerPose();
|
|
}
|
|
|
|
+ // Leaves start - fakeplayer
|
|
+ protected void livingEntityTick() {
|
|
+ super.tick();
|
|
+ }
|
|
+ // Leaves end - fakeplayer
|
|
+
|
|
@Override
|
|
protected float getMaxHeadRotationRelativeToBody() {
|
|
return this.isBlocking() ? 15.0F : super.getMaxHeadRotationRelativeToBody();
|
|
@@ -570,7 +576,7 @@ public abstract class Player extends Avatar implements ContainerUser {
|
|
public void removeEntitiesOnShoulder() {
|
|
}
|
|
|
|
- private void touch(final Entity entity) {
|
|
+ public void touch(final Entity entity) { // Leaves - private -> public
|
|
entity.playerTouch(this);
|
|
}
|
|
|
|
@@ -1270,7 +1276,7 @@ public abstract class Player extends Avatar implements ContainerUser {
|
|
// Paper end - Configurable sprint interruption on attack
|
|
}
|
|
|
|
- if (entity instanceof ServerPlayer serverPlayer && entity.hurtMarked) {
|
|
+ if ((entity instanceof ServerPlayer serverPlayer && !(entity instanceof org.leavesmc.leaves.bot.ServerBot)) && entity.hurtMarked) { // Leaves - bot knockback
|
|
// CraftBukkit start - Add Velocity Event
|
|
boolean cancelled = false;
|
|
org.bukkit.entity.Player player = (org.bukkit.entity.Player) entity.getBukkitEntity();
|
|
diff --git a/net/minecraft/world/entity/projectile/FishingHook.java b/net/minecraft/world/entity/projectile/FishingHook.java
|
|
index d7217fd075c6d6fae3622c56e940e247008dcc27..0958e7f93494766e97e87ed4d39c8e4550a641f6 100644
|
|
--- a/net/minecraft/world/entity/projectile/FishingHook.java
|
|
+++ b/net/minecraft/world/entity/projectile/FishingHook.java
|
|
@@ -59,7 +59,7 @@ public class FishingHook extends Projectile {
|
|
private static final EntityDataAccessor<Integer> DATA_HOOKED_ENTITY = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.INT);
|
|
private static final EntityDataAccessor<Boolean> DATA_BITING = SynchedEntityData.defineId(FishingHook.class, EntityDataSerializers.BOOLEAN);
|
|
private int life;
|
|
- private int nibble;
|
|
+ public int nibble; // Leaves - private -> public
|
|
public int timeUntilLured;
|
|
public int timeUntilHooked;
|
|
public float fishAngle;
|
|
diff --git a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
|
index 9b887b40236a212de513e3ceece1abfec5372ae2..2f8f8fa1bef9f333978b47c2ce729c291bec66fb 100644
|
|
--- a/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
|
+++ b/net/minecraft/world/entity/vehicle/boat/AbstractBoat.java
|
|
@@ -270,6 +270,11 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
|
}
|
|
|
|
this.move(MoverType.SELF, this.getDeltaMovement());
|
|
+ } else if (this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot) { // Leaves start - Fakeplayer
|
|
+ this.floatBoat();
|
|
+ this.controlBoat();
|
|
+ this.move(MoverType.SELF, this.getDeltaMovement());
|
|
+ // Leaves end - Fakeplayer
|
|
} else {
|
|
this.setDeltaMovement(Vec3.ZERO);
|
|
}
|
|
@@ -380,6 +385,13 @@ public abstract class AbstractBoat extends VehicleEntity implements Leashable {
|
|
}
|
|
}
|
|
|
|
+ // Leaves start - Fakeplayer
|
|
+ @Override
|
|
+ public boolean canSimulateMovement() {
|
|
+ return super.canSimulateMovement() || this.getControllingPassenger() instanceof org.leavesmc.leaves.bot.ServerBot;
|
|
+ }
|
|
+ // Leaves end - Fakeplayer
|
|
+
|
|
protected @Nullable SoundEvent getPaddleSound() {
|
|
return switch (this.getStatus()) {
|
|
case IN_WATER, UNDER_WATER, UNDER_FLOWING_WATER -> SoundEvents.BOAT_PADDLE_WATER;
|
|
diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
|
index f6d37cba8ab5688501be9170720a0b6ded810819..fdd03c9d73a8a0527d0ead3fbbba20083c617e2c 100644
|
|
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
|
|
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
|
|
@@ -406,6 +406,7 @@ public abstract class AbstractContainerMenu {
|
|
|
|
private void doClick(final int slotIndex, final int buttonNum, final ContainerInput containerInput, final Player player) {
|
|
Inventory inventory = player.getInventory();
|
|
+ if (!doClickCheck(slotIndex, buttonNum, containerInput, player)) return; // Leaves - doClick check
|
|
if (containerInput == ContainerInput.QUICK_CRAFT) {
|
|
int expectedStatus = this.quickcraftStatus;
|
|
this.quickcraftStatus = getQuickcraftHeader(buttonNum);
|
|
@@ -680,6 +681,22 @@ public abstract class AbstractContainerMenu {
|
|
}
|
|
}
|
|
|
|
+ // Leaves start - doClick check
|
|
+ private boolean doClickCheck(int slotIndex, int buttonNum, ContainerInput containerInput, Player player) {
|
|
+ if (slotIndex < 0) {
|
|
+ return true;
|
|
+ }
|
|
+
|
|
+ Slot slot = getSlot(slotIndex);
|
|
+ ItemStack itemStack = slot.getItem();
|
|
+ net.minecraft.world.item.component.CustomData customData = itemStack.get(net.minecraft.core.component.DataComponents.CUSTOM_DATA);
|
|
+ if (customData != null && customData.contains("Leaves.Gui.Placeholder")) {
|
|
+ return !customData.copyTag().getBoolean("Leaves.Gui.Placeholder").orElse(false);
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ // Leaves end - doClick check
|
|
+
|
|
private boolean tryItemClickBehaviourOverride(
|
|
final Player player, final ClickAction clickAction, final Slot slot, final ItemStack clicked, final ItemStack carried
|
|
) {
|
|
diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
|
|
index 92149f9bf679cf4a486b24b5197470de68e0f424..9cb7f4a5e7677ee4b66416e13045f0f7dda4cc1c 100644
|
|
--- a/net/minecraft/world/item/ItemStack.java
|
|
+++ b/net/minecraft/world/item/ItemStack.java
|
|
@@ -458,7 +458,7 @@ public final class ItemStack implements DataComponentHolder, ItemInstance, Chang
|
|
placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(level, player, hand, capturedBlockStates.getFirst(), pos);
|
|
}
|
|
|
|
- if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
|
|
+ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild()) && (!(player instanceof org.leavesmc.leaves.bot.ServerBot))) { // Leaves - Fakeplayer skip this check
|
|
result = InteractionResult.FAIL; // cancel placement
|
|
// PAIL: Remove this when MC-99075 fixed
|
|
player.containerMenu.forceHeldSlot(hand);
|
|
@@ -962,6 +962,20 @@ public final class ItemStack implements DataComponentHolder, ItemInstance, Chang
|
|
}
|
|
}
|
|
|
|
+ // Leaves start - Fakeplayer
|
|
+ public boolean releaseUsingWithResult(Level level, LivingEntity livingEntity, int timeLeft) {
|
|
+ ItemStack itemStack = this.copy();
|
|
+ if (this.getItem().releaseUsing(this, level, livingEntity, timeLeft)) {
|
|
+ ItemStack itemStack1 = this.applyAfterUseComponentSideEffects(livingEntity, itemStack);
|
|
+ if (itemStack1 != this) {
|
|
+ livingEntity.setItemInHand(livingEntity.getUsedItemHand(), itemStack1);
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+ // Leaves end - Fakeplayer
|
|
+
|
|
public boolean useOnRelease() {
|
|
return this.getItem().useOnRelease(this);
|
|
}
|
|
diff --git a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
|
index 8d761640af4ce3afb4de5b46d3627614fff0ece9..15605dacaec3860e476a70dbdd3743e4197f67a6 100644
|
|
--- a/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
|
+++ b/net/minecraft/world/level/block/piston/PistonMovingBlockEntity.java
|
|
@@ -152,7 +152,7 @@ public class PistonMovingBlockEntity extends BlockEntity {
|
|
break;
|
|
}
|
|
|
|
- if (!(entity instanceof ServerPlayer)) {
|
|
+ if (!(entity instanceof ServerPlayer) || (entity instanceof org.leavesmc.leaves.bot.ServerBot)) { // Leaves - bot slime block
|
|
Vec3 deltaMovement = entity.getDeltaMovement();
|
|
double dx = deltaMovement.x;
|
|
double dy = deltaMovement.y;
|
|
diff --git a/net/minecraft/world/level/levelgen/PhantomSpawner.java b/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
|
index db0324595d7f5b6f92bd7724daf181b0903e1da4..ec3a437bd8a7d0e95e1e5fa0ff4462a70391ecf9 100644
|
|
--- a/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
|
+++ b/net/minecraft/world/level/levelgen/PhantomSpawner.java
|
|
@@ -49,6 +49,10 @@ public class PhantomSpawner implements CustomSpawner {
|
|
ServerStatsCounter stats = player.getStats();
|
|
int value = Mth.clamp(stats.getValue(Stats.CUSTOM.get(Stats.TIME_SINCE_REST)), 1, Integer.MAX_VALUE);
|
|
int dayLength = 24000;
|
|
+ if (player instanceof org.leavesmc.leaves.bot.ServerBot bot && bot.getConfigValue(org.leavesmc.leaves.bot.agent.Configs.SPAWN_PHANTOM)) {
|
|
+ dayLength = Math.max(bot.notSleepTicks, 1);
|
|
+ }
|
|
+ // Leaves end - fakeplayer spawn
|
|
if (random.nextInt(value) >= level.paperConfig().entities.behavior.playerInsomniaStartTicks) { // Paper - Ability to control player's insomnia and phantoms
|
|
BlockPos spawnPos = playerPos.above(20 + random.nextInt(15))
|
|
.east(-10 + random.nextInt(21))
|