diff --git a/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/Bot.java b/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/Bot.java index ed54a9a..cbb6a21 100644 --- a/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/Bot.java +++ b/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/Bot.java @@ -39,9 +39,9 @@ public interface Bot extends Player { /** * Gets the fakeplayer name without prefix and suffix * - * @return fakeplayer real name + * @return fakeplayer raw name */ - @NotNull String getRealName(); + @NotNull String getRawName(); /** * Gets the creator's UUID of the fakeplayer @@ -91,4 +91,13 @@ public interface Bot extends Player { * @return success */ boolean remove(boolean save); + + /** + * Remove the fakeplayer + * + * @param save should save + * @param resume should resume at next server start + * @return success + */ + boolean remove(boolean save, boolean resume); } diff --git a/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotCreator.java b/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotCreator.java index dd894be..f541b2b 100644 --- a/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotCreator.java +++ b/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotCreator.java @@ -27,8 +27,8 @@ import java.util.function.Consumer; public interface BotCreator { - static BotCreator of(String realName, Location location) { - return Bukkit.getBotManager().botCreator(realName, location); + static BotCreator of(String rawName, Location location) { + return Bukkit.getBotManager().botCreator(rawName, location); } BotCreator name(String name); diff --git a/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotManager.java b/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotManager.java index edc1bf9..da349e6 100644 --- a/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotManager.java +++ b/lophine-api/src/main/java/org/leavesmc/leaves/entity/bot/BotManager.java @@ -61,5 +61,5 @@ public interface BotManager { */ > T newAction(@NotNull Class type); - BotCreator botCreator(@NotNull String realName, @NotNull Location location); + BotCreator botCreator(@NotNull String rawName, @NotNull Location location); } diff --git a/lophine-server/minecraft-patches/features/0021-Spawn-invulnerable-time.patch b/lophine-server/minecraft-patches/features/0021-Spawn-invulnerable-time.patch index 84bb5ab..69160c4 100644 --- a/lophine-server/minecraft-patches/features/0021-Spawn-invulnerable-time.patch +++ b/lophine-server/minecraft-patches/features/0021-Spawn-invulnerable-time.patch @@ -5,14 +5,14 @@ Subject: [PATCH] Spawn invulnerable time diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index 93bc76af4d0abbe1c526434991e74c4465764ac6..1a43bdcb4c37df4ad1c4dfe6ebb84470832e910f 100644 +index 93bc76af4d0abbe1c526434991e74c4465764ac6..7b8dc8db175d905790462bbf6d0802ca416d7b36 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -240,6 +240,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc private int lastSentFood = -99999999; private boolean lastFoodSaturationZero = true; public int lastSentExp = -99999999; -+ private int spawnInvulnerableTime = 60; // Lophine - spawn invulnerable time ++ protected int spawnInvulnerableTime = 60; // Lophine - spawn invulnerable time private ChatVisiblity chatVisibility = ChatVisiblity.FULL; public ParticleStatus particleStatus = ParticleStatus.ALL; private boolean canChatColor = true; diff --git a/lophine-server/minecraft-patches/features/0022-Leaves-Fakeplayer.patch b/lophine-server/minecraft-patches/features/0022-Leaves-Fakeplayer.patch index 665002f..0a37863 100644 --- a/lophine-server/minecraft-patches/features/0022-Leaves-Fakeplayer.patch +++ b/lophine-server/minecraft-patches/features/0022-Leaves-Fakeplayer.patch @@ -33,7 +33,7 @@ index d5e604bf18a223aa434bc9f78274e1f3ff7f203d..715976a49ca621ba40d9353b18d41d34 private boolean encrypted; 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 diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index f04352738e4f703d28f3c06ff884aee7d980542c..0990879441a7d1ef97681115a6427e18eae7adef 100644 +index f04352738e4f703d28f3c06ff884aee7d980542c..744b780075bf76fa0fa5e27699a146701289e0d8 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -425,6 +425,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) { + this.playerList.saveAll(playerSaveInterval); ++ org.leavesmc.leaves.bot.BotList.INSTANCE.saveAllResumeBots(playerSaveInterval); // Leaves - resident fakeplayer + } + for (final ServerLevel level : (region == null ? this.getAllLevels() : Arrays.asList(region.world))) { // Folia - region threading + if (level.paperConfig().chunks.autoSaveInterval.value() > 0) { +@@ -2020,6 +2028,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop 0) --this.spawnInvulnerableTime; // Lophine - spawn invulnerable time -@@ -2134,6 +2139,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +- 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) +@@ -2134,6 +2134,11 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc this.lastSentHealth = -1.0F; this.lastSentFood = -1; this.teleportSpectators(teleportTransition, serverLevel); @@ -365,40 +354,73 @@ index 1a43bdcb4c37df4ad1c4dfe6ebb84470832e910f..daff493e4ea944afa91ce99a3596931a // CraftBukkit start org.bukkit.event.player.PlayerChangedWorldEvent changeEvent = new org.bukkit.event.player.PlayerChangedWorldEvent(this.getBukkitEntity(), serverLevel.getWorld()); this.level().getCraftServer().getPluginManager().callEvent(changeEvent); -@@ -3728,4 +3738,31 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc - return (org.bukkit.craftbukkit.entity.CraftPlayer) super.getBukkitEntity(); +diff --git a/net/minecraft/server/players/CachedUserNameToIdResolver.java b/net/minecraft/server/players/CachedUserNameToIdResolver.java +index 345bdb0ff82b8cd8c63e5ff1f2dabb68a1e54b77..c9a7c1c37155e0d339b880179a5988c9a6cb3797 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 get(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 string = name.toLowerCase(Locale.ROOT); + boolean stateLocked = true; try { this.stateLock.lock(); // Paper - Fix GameProfileCache concurrency + CachedUserNameToIdResolver.GameProfileInfo gameProfileInfo = this.profilesByName.get(string); +diff --git a/net/minecraft/server/players/NameAndId.java b/net/minecraft/server/players/NameAndId.java +index 05b4a75f6597e8613c91344d100bb7f005d169a7..9a5006362c12e972d031c48be4d30362d88d1c00 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 CODEC = RecordCodecBuilder.create( + instance -> instance.group(UUIDUtil.STRING_CODEC.fieldOf("id").forGetter(NameAndId::id), Codec.STRING.fieldOf("name").forGetter(NameAndId::name)) + .apply(instance, NameAndId::new) + ); + + public NameAndId(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 } - // CraftBukkit end -+ -+ // Leaves start - player operation limiter -+ protected void resetOperationCountPerTick() { -+ instaBreakCountPerTick = 0; -+ placeBlockCountPerTick = 0; + + public NameAndId(com.mojang.authlib.yggdrasil.response.NameAndId nameAndId) { +- this(nameAndId.id(), nameAndId.name()); ++ this(nameAndId.id(), nameAndId.name(), false); // Leaves - fakeplayer + } + -+ public int getInstaBreakCountPerTick() { -+ return instaBreakCountPerTick; -+ } -+ -+ public int getPlaceBlockCountPerTick() { -+ return placeBlockCountPerTick; -+ } -+ -+ public void addInstaBreakCountPerTick() { -+ ++instaBreakCountPerTick; -+ } -+ -+ public void addPlaceBlockCountPerTick() { -+ ++placeBlockCountPerTick; -+ } -+ -+ public boolean allowOperation() { -+ return (instaBreakCountPerTick == 0 || placeBlockCountPerTick == 0) && (instaBreakCountPerTick <= 1 && placeBlockCountPerTick <= 2); -+ } -+ // Leaves end - player operation limiter - } ++ public NameAndId(UUID uuid, String name) { ++ this(uuid, name, false); // Leaves - fakeplayer + } + + public static @Nullable NameAndId fromJson(JsonObject json) { +@@ -33,7 +37,7 @@ public record NameAndId(UUID id, String name) { + return null; + } + +- return new NameAndId(uuid, json.get("name").getAsString()); ++ return new NameAndId(uuid, json.get("name").getAsString(), false); // Leaves - fakeplayer + } else { + return null; + } +@@ -46,7 +50,7 @@ public record NameAndId(UUID id, String name) { + + public static NameAndId createOffline(String name) { + UUID uuid = UUIDUtil.createOfflinePlayerUUID(name); +- return new NameAndId(uuid, name); ++ return new NameAndId(uuid, 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 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..293b154dc027694acd2dceaf00c61b3e42cf7a1c 100644 +index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..3a5319739f0687fc6f09b2ac8ee31716593fe0de 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -317,6 +317,19 @@ public abstract class PlayerList { @@ -409,7 +431,7 @@ index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..293b154dc027694acd2dceaf00c61b3e + 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, true); ++ 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); @@ -421,7 +443,7 @@ index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..293b154dc027694acd2dceaf00c61b3e 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,13 @@ public abstract class PlayerList { +@@ -791,6 +804,12 @@ public abstract class PlayerList { ).callEvent(); // Paper end @@ -430,12 +452,11 @@ index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..293b154dc027694acd2dceaf00c61b3e + this.server.getBotList().bots.forEach(bot -> bot.sendFakeDataIfNeed(serverPlayer, true)); // Leaves - render bot + } + // Leaves end - bot support -+ + return serverPlayer; } -@@ -892,11 +912,16 @@ public abstract class PlayerList { +@@ -892,11 +911,16 @@ public abstract class PlayerList { public String[] getPlayerNamesArray() { List players = new java.util.ArrayList<>(this.players); // Folia - region threading @@ -453,7 +474,7 @@ index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..293b154dc027694acd2dceaf00c61b3e return strings; } -@@ -1016,7 +1041,14 @@ public abstract class PlayerList { +@@ -1016,7 +1040,14 @@ public abstract class PlayerList { } public @Nullable ServerPlayer getPlayerByName(String username) { @@ -469,7 +490,7 @@ index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..293b154dc027694acd2dceaf00c61b3e } public void broadcast(@Nullable Player except, double x, double y, double z, double radius, ResourceKey dimension, Packet packet) { -@@ -1353,7 +1385,13 @@ public abstract class PlayerList { +@@ -1353,7 +1384,13 @@ public abstract class PlayerList { } public @Nullable ServerPlayer getPlayer(UUID playerUUID) { @@ -485,7 +506,7 @@ index 0d322ef4aa3e70c9edbb9fa8ba368bef916eb93d..293b154dc027694acd2dceaf00c61b3e public @Nullable ServerPlayer getPlayer(String name) { diff --git a/net/minecraft/server/waypoints/ServerWaypointManager.java b/net/minecraft/server/waypoints/ServerWaypointManager.java -index f76d3a404eb7077f1db2374303eb265cb513d848..2e0e17a59fa2864dc9a2f2dafd18158cae6dae04 100644 +index bd1d4a832eec4c89a7f8bdd5d066b6074f206d81..d7224c2297eb5d580349da3b2770895fba6c3e08 100644 --- a/net/minecraft/server/waypoints/ServerWaypointManager.java +++ b/net/minecraft/server/waypoints/ServerWaypointManager.java @@ -24,6 +24,11 @@ public class ServerWaypointManager implements WaypointManager ((1L + this.totalEatTimeTicks) * 50L * (1000L * 1000L)); - if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !this.level().isClientSide() && !usingItem.useOnRelease()) { -+ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !(this instanceof org.leavesmc.leaves.bot.ServerBot) && !this.level().isClientSide() && !usingItem.useOnRelease()) { // Leaves - Fakeplayer skip this check ++ if ((--this.useItemRemaining == 0 || shouldLagCompensate) && !(this instanceof org.leavesmc.leaves.bot.ServerBot) && !this.level().isClientSide() && !usingItem.useOnRelease()) { this.useItemRemaining = 0; // Paper end - lag compensate eating this.completeUsingItem(); @@ -778,16 +799,3 @@ index bef794c3f58c41d910aa0bcc63fbdeea7225fddf..a601da588e6973cc5b87d3e3eeba49b5 this.id = id; } -diff --git a/net/minecraft/world/level/storage/PlayerDataStorage.java b/net/minecraft/world/level/storage/PlayerDataStorage.java -index b8ef50bc3d07890c9da2c98d5f009a3adc52f4b0..f37de9384005f53631cc3e122c74e4793dff4be0 100644 ---- a/net/minecraft/world/level/storage/PlayerDataStorage.java -+++ b/net/minecraft/world/level/storage/PlayerDataStorage.java -@@ -19,7 +19,7 @@ import net.minecraft.util.datafix.DataFixTypes; - import net.minecraft.world.entity.player.Player; - import org.slf4j.Logger; - --public class PlayerDataStorage { -+public class PlayerDataStorage implements org.leavesmc.leaves.bot.IPlayerDataStorage { - private static final Logger LOGGER = LogUtils.getLogger(); - private final File playerDir; - protected final DataFixer fixerUpper; diff --git a/lophine-server/minecraft-patches/features/0026-Leaves-Jade-Protocol.patch b/lophine-server/minecraft-patches/features/0026-Leaves-Jade-Protocol.patch index 6ffde65..d2e78d1 100644 --- a/lophine-server/minecraft-patches/features/0026-Leaves-Jade-Protocol.patch +++ b/lophine-server/minecraft-patches/features/0026-Leaves-Jade-Protocol.patch @@ -9,10 +9,10 @@ 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/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index daff493e4ea944afa91ce99a3596931a487304a3..f79735abf21b6eecc02e5b5f1ce3140dfef3ede9 100644 +index b644a786d6b4596109efa6e951d46e5d0b808f00..4ca7cf022f4e213bcd5a310dfd8b2db293c441b8 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java -@@ -1458,7 +1458,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -1453,7 +1453,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc } else if (fun.bm.lophine.config.modules.experiment.EntityDamageSourceTraceConfig.enabled) { final LivingEntity entitylivingnew = this.getKillCreditOrigin(); if (entitylivingnew != null) { @@ -22,7 +22,7 @@ index daff493e4ea944afa91ce99a3596931a487304a3..f79735abf21b6eecc02e5b5f1ce3140d // Luminol End - Cross Region Damage trace } diff --git a/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/net/minecraft/server/network/ServerGamePacketListenerImpl.java -index 5c81be29f7ecc3389b5b578f85774035def96e26..98d641b2e8ca340cb10fe0448f8a8b4f8446f616 100644 +index 12862190a59af38e3cf828e4ac9e66a64d2d2215..8f554cb8cb79fa669f3ee9254c87cde1de674fb3 100644 --- a/net/minecraft/server/network/ServerGamePacketListenerImpl.java +++ b/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -3798,7 +3798,7 @@ public class ServerGamePacketListenerImpl diff --git a/lophine-server/minecraft-patches/features/0027-Leaves-Xaero-Map-Protocol.patch b/lophine-server/minecraft-patches/features/0027-Leaves-Xaero-Map-Protocol.patch index 4357a76..d92f805 100644 --- a/lophine-server/minecraft-patches/features/0027-Leaves-Xaero-Map-Protocol.patch +++ b/lophine-server/minecraft-patches/features/0027-Leaves-Xaero-Map-Protocol.patch @@ -8,10 +8,10 @@ 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/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 293b154dc027694acd2dceaf00c61b3e42cf7a1c..63e0c4f64f99b230c5779095382f93fad0ac2cf6 100644 +index 3a5319739f0687fc6f09b2ac8ee31716593fe0de..36cd1a0307ff1a734eb5f4f3cc013781692e7ad8 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java -@@ -1127,6 +1127,7 @@ public abstract class PlayerList { +@@ -1126,6 +1126,7 @@ public abstract class PlayerList { //player.connection.send(new ClientboundSetChunkCacheRadiusPacket(io.papermc.paper.FeatureHooks.getViewDistance(level))); // Paper - rewrite chunk system //player.connection.send(new ClientboundSetSimulationDistancePacket(io.papermc.paper.FeatureHooks.getSimulationDistance(level))); // Paper - rewrite chunk system // Paper end - view distances diff --git a/lophine-server/minecraft-patches/features/0029-Leaves-Wool-Hopper-Counter.patch b/lophine-server/minecraft-patches/features/0029-Leaves-Wool-Hopper-Counter.patch index 817fc7a..0b47fbf 100644 --- a/lophine-server/minecraft-patches/features/0029-Leaves-Wool-Hopper-Counter.patch +++ b/lophine-server/minecraft-patches/features/0029-Leaves-Wool-Hopper-Counter.patch @@ -10,7 +10,7 @@ Licensed under: MIT This patch is Powered by fabric-carpet(https://github.com/gnembon/fabric-carpet) diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java -index 6a51bace3151646afae9de820d9c8977a0221df4..8dd50507bbc9f61c9ae019eecc5e9338d20addff 100644 +index 6a51bace3151646afae9de820d9c8977a0221df4..474ca0ce0d3095fc586f8f9e9a584ed4f7c91471 100644 --- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java @@ -229,8 +229,30 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -72,7 +72,7 @@ index 6a51bace3151646afae9de820d9c8977a0221df4..8dd50507bbc9f61c9ae019eecc5e9338 + for (int i = 0; i < container.getContainerSize(); ++i) { + if (!container.getItem(i).isEmpty()) { + ItemStack itemstack = container.getItem(i); -+ org.leavesmc.leaves.util.HopperCounter.getCounter(woolColor).add(level, itemstack); ++ org.leavesmc.leaves.util.HopperCounter.getCounter(woolColor).add(level.getServer(), itemstack); + container.setItem(i, ItemStack.EMPTY); + } + } diff --git a/lophine-server/minecraft-patches/features/0031-Leaves-Replay-Mod-API.patch b/lophine-server/minecraft-patches/features/0031-Leaves-Replay-Mod-API.patch index 0466237..690a769 100644 --- a/lophine-server/minecraft-patches/features/0031-Leaves-Replay-Mod-API.patch +++ b/lophine-server/minecraft-patches/features/0031-Leaves-Replay-Mod-API.patch @@ -84,10 +84,10 @@ index af71e0e1eb1c93745f3e4954ecc8fbd2ad4808a3..f3829564681faff3ae8971ed90b947b4 players.add(serverPlayer1); if (players.size() >= resultLimit) { diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 324f9d259c6e0fd814ffe11b62d07fb4d2197da3..9d334ed3307f3c4c82bb5300219a465408bf341a 100644 +index 744b780075bf76fa0fa5e27699a146701289e0d8..c8f2f98ebc145063505b73ef7c723f2878d34ea3 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1894,7 +1894,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop { // Folia - region threading // Paper start - Expand PlayerGameModeChangeEvent org.bukkit.event.player.PlayerGameModeChangeEvent event = player.setGameMode(gameMode, org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null); // Folia - region threading -@@ -2492,7 +2492,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop sender.canSee(ep.getBukkitEntity())).collect(java.util.stream.Collectors.toList()); diff --git a/net/minecraft/server/commands/OpCommand.java b/net/minecraft/server/commands/OpCommand.java -index 3798c1ea92ead20b3b7e67d88d2405f29e324d2c..922383a284c8fb3c183d8a15dc41d813451adfb3 100644 +index 590891d70a71ab30ceae3a3cf1923745e7c20b26..0ede1e5c73a0071e854de70f81ae1fc6a1d6dc59 100644 --- a/net/minecraft/server/commands/OpCommand.java +++ b/net/minecraft/server/commands/OpCommand.java @@ -25,7 +25,7 @@ public class OpCommand { @@ -306,7 +306,7 @@ index c09af6b81987df8e681689ecce9932a2e39af1a3..b3c593474e889d254f59813e7f42299b } // Leaves end - skip diff --git a/net/minecraft/server/level/ServerPlayer.java b/net/minecraft/server/level/ServerPlayer.java -index f79735abf21b6eecc02e5b5f1ce3140dfef3ede9..04a600d96f4ae7c08d06dc4fb8f71b3f0eb1be07 100644 +index 4ca7cf022f4e213bcd5a310dfd8b2db293c441b8..8ea3c580b506e214664135a2c10722b56ab8e439 100644 --- a/net/minecraft/server/level/ServerPlayer.java +++ b/net/minecraft/server/level/ServerPlayer.java @@ -202,7 +202,7 @@ import org.jspecify.annotations.Nullable; @@ -318,7 +318,7 @@ index f79735abf21b6eecc02e5b5f1ce3140dfef3ede9..04a600d96f4ae7c08d06dc4fb8f71b3f public static final long LAST_SAVE_ABSENT = Long.MIN_VALUE; public long lastSave = LAST_SAVE_ABSENT; // Paper // Folia - threaded regions - changed to nanoTime private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_XZ = 32; private static final int NEUTRAL_MOB_DEATH_NOTIFICATION_RADII_Y = 10; -@@ -673,7 +673,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc +@@ -669,7 +669,7 @@ public class ServerPlayer extends Player implements ca.spottedleaf.moonrise.patc // Paper start - Expand PlayerGameModeChangeEvent this.loadGameTypes(input); } @@ -328,7 +328,7 @@ index f79735abf21b6eecc02e5b5f1ce3140dfef3ede9..04a600d96f4ae7c08d06dc4fb8f71b3f if (new org.bukkit.event.player.PlayerGameModeChangeEvent(this.getBukkitEntity(), org.bukkit.GameMode.getByValue(this.server.getDefaultGameType().getId()), org.bukkit.event.player.PlayerGameModeChangeEvent.Cause.DEFAULT_GAMEMODE, null).callEvent()) { this.gameMode.setGameModeForPlayer(this.server.getForcedGameType(), GameType.DEFAULT_MODE); diff --git a/net/minecraft/server/players/PlayerList.java b/net/minecraft/server/players/PlayerList.java -index 98f2ced8e6afdf0074ade94e0bbf5498bd6c505f..4dcb90709200b33fc9155f6dea4281ed32427889 100644 +index 36cd1a0307ff1a734eb5f4f3cc013781692e7ad8..e38f5ae03f184696a3d68542c0bde3b1091dfd2e 100644 --- a/net/minecraft/server/players/PlayerList.java +++ b/net/minecraft/server/players/PlayerList.java @@ -130,6 +130,7 @@ public abstract class PlayerList { @@ -405,7 +405,7 @@ index 98f2ced8e6afdf0074ade94e0bbf5498bd6c505f..4dcb90709200b33fc9155f6dea4281ed + 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); ++ 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); @@ -532,7 +532,7 @@ index 98f2ced8e6afdf0074ade94e0bbf5498bd6c505f..4dcb90709200b33fc9155f6dea4281ed this.playersByName.remove(player.getScoreboardName().toLowerCase(java.util.Locale.ROOT)); // Spigot this.server.getCustomBossEvents().onPlayerDisconnect(player); UUID uuid = player.getUUID(); -@@ -911,15 +1070,15 @@ public abstract class PlayerList { +@@ -910,15 +1069,15 @@ public abstract class PlayerList { } public String[] getPlayerNamesArray() { @@ -553,7 +553,7 @@ index 98f2ced8e6afdf0074ade94e0bbf5498bd6c505f..4dcb90709200b33fc9155f6dea4281ed // Leaves end - fakeplayer support diff --git a/net/minecraft/world/entity/LivingEntity.java b/net/minecraft/world/entity/LivingEntity.java -index f80f5533c1c3c64ee1b8b2c43e2bc2dea8ab567f..aa9cbb5f02b87789fd94521792aefac5c840c95a 100644 +index c89a2de1e1959c1275d39003c1b6b49f165df60f..99915b37331da819fd72c34b25773ab3e63f1775 100644 --- a/net/minecraft/world/entity/LivingEntity.java +++ b/net/minecraft/world/entity/LivingEntity.java @@ -262,7 +262,7 @@ public abstract class LivingEntity extends Entity implements Attackable, Waypoin diff --git a/lophine-server/minecraft-patches/features/0032-Leaves-Catch-update-suppression-crash.patch b/lophine-server/minecraft-patches/features/0032-Leaves-Catch-update-suppression-crash.patch index feeaf8e..289ea81 100644 --- a/lophine-server/minecraft-patches/features/0032-Leaves-Catch-update-suppression-crash.patch +++ b/lophine-server/minecraft-patches/features/0032-Leaves-Catch-update-suppression-crash.patch @@ -46,10 +46,10 @@ index ab80a66646a7ebe2862221ac342b06c14fcfc734..7834f3da4d0ff4a5cdec46b023d73483 fillCrashReport(reportedException.getReport(), packetListener, packet); return reportedException; diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java -index 9d334ed3307f3c4c82bb5300219a465408bf341a..f2f57cfcd7739a951123c81f82cac1c2bbd3a3bd 100644 +index c8f2f98ebc145063505b73ef7c723f2878d34ea3..56160853050cd131718d16e21a0bb6c9780e2658 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java -@@ -1973,8 +1973,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop consumer) { - Bukkit.getRegionScheduler().execute( - MinecraftInternalPlugin.INSTANCE, - location.getWorld(), - location.getBlockX() >> 4, - location.getBlockZ() >> 4, - () -> { - this.mojangAPISkin(); - Bukkit.getRegionScheduler().execute( - MinecraftInternalPlugin.INSTANCE, - location.getWorld(), - location.getBlockX() >> 4, - location.getBlockZ() >> 4, - () -> { - CraftBot bot = this.spawn(); - if (bot != null && consumer != null) { - consumer.accept(bot); - } - } - ); - } - ); + Bukkit.getAsyncScheduler().runNow(MinecraftInternalPlugin.INSTANCE, (task0) -> { + this.mojangAPISkin(); + Bukkit.getRegionScheduler().execute( + MinecraftInternalPlugin.INSTANCE, + location.getWorld(), + location.getBlockX() >> 4, + location.getBlockZ() >> 4, + () -> { + CraftBot bot = this.spawn(); + if (bot != null && consumer != null) { + consumer.accept(bot); + } + }); + }); } @Nullable diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotDataStorage.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotDataStorage.java index 066a47c..1cd9b1b 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotDataStorage.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotDataStorage.java @@ -36,10 +36,7 @@ import java.io.File; import java.io.IOException; import java.util.Optional; -public class BotDataStorage implements IPlayerDataStorage { - - private static final LevelResource BOT_DATA_DIR = new LevelResource("fakeplayerdata"); - private static final LevelResource BOT_LIST_FILE = new LevelResource("fakeplayer.dat"); +public class BotDataStorage { private static final Logger LOGGER = LogUtils.getLogger(); private final File botDir; @@ -47,9 +44,9 @@ public class BotDataStorage implements IPlayerDataStorage { private CompoundTag savedBotList; - public BotDataStorage(LevelStorageSource.@NotNull LevelStorageAccess session) { - this.botDir = session.getLevelPath(BOT_DATA_DIR).toFile(); - this.botListFile = session.getLevelPath(BOT_LIST_FILE).toFile(); + public BotDataStorage(LevelStorageSource.@NotNull LevelStorageAccess session, String dataDir, String listFileName) { + this.botDir = session.getLevelPath(new LevelResource(dataDir)).toFile(); + this.botListFile = session.getLevelPath(new LevelResource(listFileName)).toFile(); this.botDir.mkdirs(); this.savedBotList = new CompoundTag(); @@ -62,7 +59,6 @@ public class BotDataStorage implements IPlayerDataStorage { } } - @Override public void save(Player player) { boolean flag = true; try { @@ -85,22 +81,27 @@ public class BotDataStorage implements IPlayerDataStorage { if (flag && player instanceof ServerBot bot) { CompoundTag nbt = new CompoundTag(); - nbt.putString("name", bot.createState.name()); + nbt.putString("name", bot.createState.fullName()); nbt.store("uuid", UUIDUtil.CODEC, bot.getUUID()); nbt.putBoolean("resume", bot.resume); - this.savedBotList.put(bot.createState.realName(), nbt); + this.savedBotList.put(bot.createState.fullName(), nbt); this.saveBotList(); } } - public Optional load(Player player, ProblemReporter reporter) { - return this.load(player.getScoreboardName(), player.getStringUUID()).map(nbt -> { - ValueInput valueInput = TagValueInput.create(reporter, player.registryAccess(), nbt); - player.load(valueInput); + + public Optional load(@NotNull ServerBot bot, ProblemReporter reporter) { + return this.load(bot.nameAndId().name(), bot.nameAndId().id().toString()).map(nbt -> { + ValueInput valueInput = TagValueInput.create(reporter, bot.registryAccess(), nbt); + bot.load(valueInput); return valueInput; }); } + public void removeSavedData(@NotNull ServerBot bot) { + this.load(bot.nameAndId().name(), bot.nameAndId().id().toString()); + } + private Optional load(String name, String uuid) { File file = new File(this.botDir, uuid + ".dat"); diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotList.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotList.java index 62d6712..0866dd9 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotList.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotList.java @@ -21,13 +21,14 @@ import ca.spottedleaf.moonrise.common.util.TickThread; import com.google.common.collect.Maps; import com.mojang.authlib.GameProfile; import com.mojang.authlib.properties.Property; -import com.mojang.authlib.properties.PropertyMap; import com.mojang.logging.LogUtils; import fun.bm.lophine.config.modules.function.FakeplayerConfig; +import fun.bm.lophine.config.modules.function.OldFeatureConfig; import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.profile.MutablePropertyMap; import io.papermc.paper.threadedregions.RegionizedServer; import io.papermc.paper.threadedregions.scheduler.FoliaGlobalRegionScheduler; +import io.papermc.paper.util.MCUtil; import net.kyori.adventure.text.format.NamedTextColor; import net.kyori.adventure.text.format.Style; import net.minecraft.nbt.CompoundTag; @@ -46,10 +47,10 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.storage.ValueInput; import org.bukkit.Bukkit; import org.bukkit.Location; -import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.event.entity.EntityRemoveEvent; +import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.leavesmc.leaves.event.bot.*; @@ -68,23 +69,48 @@ public class BotList { private final MinecraftServer server; public final List bots = new CopyOnWriteArrayList<>(); - private final BotDataStorage dataStorage; + private final BotDataStorage manualSaveDataStorage; + private final BotDataStorage resumeDataStorage; private final Map botsByUUID = Maps.newHashMap(); private final Map botsByName = Maps.newHashMap(); private final Map> botsNameByWorldUuid = Maps.newHashMap(); + private final Map> legacyBotsNameByWorldUuid = Maps.newHashMap(); public boolean forceShutdown = false; - public BotList(MinecraftServer server) { + public BotList(@NotNull MinecraftServer server) { this.server = server; - this.dataStorage = new BotDataStorage(server.storageSource); + this.manualSaveDataStorage = new BotDataStorage(server.storageSource, "fakeplayerdata", "fakeplayer.dat"); + this.resumeDataStorage = new BotDataStorage(server.storageSource, "resume_fakeplayerdata", "resume_fakeplayer.dat"); INSTANCE = this; } - public ServerBot createNewBot(BotCreateState state) { - BotCreateEvent event = new BotCreateEvent(state.name(), state.skinName(), state.location(), state.createReason(), state.creator()); - event.setCancelled(!BotUtil.isCreateLegal(state.name())); + public void saveAllResumeBots(final int interval) { + MCUtil.ensureMain("Save Bots", () -> { + final long now = System.currentTimeMillis() / 50; + for (ServerBot bot : bots) { + if (interval == -1 || now - bot.lastSave >= interval) { + this.resumeDataStorage.save(bot); + bot.lastSave = now; + } + } + return null; + }); + } + + public void saveAllResumeBots() { + if (!FakeplayerConfig.enable || !FakeplayerConfig.canResident) { + return; + } + for (ServerBot bot : this.bots) { + this.resumeDataStorage.save(bot); + } + } + + public ServerBot createNewBot(@NotNull BotCreateState state) { + BotCreateEvent event = new BotCreateEvent(state.fullName(), state.skinName(), state.location(), state.createReason(), state.creator()); + event.setCancelled(!BotUtil.isCreateLegal(state.fullName())); this.server.server.getPluginManager().callEvent(event); if (event.isCancelled()) { @@ -94,7 +120,7 @@ public class BotList { Location location = event.getCreateLocation(); ServerLevel world = ((CraftWorld) location.getWorld()).getHandle(); - GameProfile profile = setProfile(BotUtil.getBotUUID(state), state.name(), state.skin()); + GameProfile profile = createBotProfile(BotUtil.getBotUUID(state), state.fullName(), state.skin()); ServerBot bot = new ServerBot(this.server, world, profile); bot.createState = state; if (event.getCreator() instanceof org.bukkit.entity.Player player) { @@ -104,56 +130,58 @@ public class BotList { return this.placeNewBot(bot, world, location, null); } - public ServerBot loadNewBot(String realName) { - try { - return this.loadNewBot(realName, this.dataStorage); - } catch (Exception e) { - LOGGER.error("Failed to load bot {}", realName, e); - return null; - } + public ServerBot loadNewManualSavedBot(String fullName) { + return this.loadNewBot(fullName, this.manualSaveDataStorage); } - public ServerBot loadNewBot(String realName, IPlayerDataStorage playerIO) { - UUID uuid = BotUtil.getBotUUID(realName); + public ServerBot loadNewResumeBot(String fullName) { + return this.loadNewBot(fullName, this.resumeDataStorage); + } - BotLoadEvent event = new BotLoadEvent(realName, uuid); - this.server.server.getPluginManager().callEvent(event); - if (event.isCancelled()) { + public ServerBot loadNewBot(String fullName, BotDataStorage storage) { + if (botsByName.containsKey(fullName)) { return null; } + try { + UUID uuid = BotUtil.getBotUUID(fullName); - ServerBot bot = new ServerBot(this.server, this.server.getLevel(Level.OVERWORLD), new GameProfile(uuid, realName)); - bot.connection = new ServerBotPacketListenerImpl(this.server, bot, new ServerBotPacketListenerImpl.BotConnection()); - bot.connection.markClientLoaded(); - Optional optional; - if (playerIO instanceof BotDataStorage botIO) { + BotLoadEvent event = new BotLoadEvent(fullName, uuid); + this.server.server.getPluginManager().callEvent(event); + if (event.isCancelled()) { + return null; + } + + ServerBot bot = new ServerBot(this.server, this.server.getLevel(Level.OVERWORLD), new GameProfile(uuid, fullName)); + bot.connection = new ServerBotPacketListenerImpl(this.server, bot); + Optional optional; try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(bot.problemPath(), LOGGER)) { - optional = botIO.load(bot, scopedCollector); + optional = storage.load(bot, scopedCollector); } catch (Exception e) { throw new RuntimeException(e); } - } else { - optional = Optional.empty(); - } - if (optional.isEmpty()) { - return null; - } - ValueInput nbt = optional.get(); - - ResourceKey resourcekey = null; - if (nbt.getLong("WorldUUIDMost").isPresent() && nbt.getLong("WorldUUIDLeast").isPresent()) { - World bWorld = Bukkit.getServer().getWorld(new UUID(nbt.getLong("WorldUUIDMost").orElseThrow(), nbt.getLong("WorldUUIDLeast").orElseThrow())); - if (bWorld != null) { - resourcekey = ((CraftWorld) bWorld).getHandle().dimension(); + if (optional.isEmpty()) { + return null; } - } - if (resourcekey == null) { + ValueInput nbt = optional.get(); + + ResourceKey resourcekey = null; + if (nbt.getLong("WorldUUIDMost").isPresent() && nbt.getLong("WorldUUIDLeast").isPresent()) { + org.bukkit.World bWorld = Bukkit.getServer().getWorld(new UUID(nbt.getLong("WorldUUIDMost").orElseThrow(), nbt.getLong("WorldUUIDLeast").orElseThrow())); + if (bWorld != null) { + resourcekey = ((CraftWorld) bWorld).getHandle().dimension(); + } + } + if (resourcekey == null) { + return null; + } + + ServerLevel world = this.server.getLevel(resourcekey); + return this.placeNewBot(bot, world, bot.getLocation(), nbt); + } catch (Exception e) { + LOGGER.error("Failed to load bot {}", fullName, e); return null; } - - ServerLevel world = this.server.getLevel(resourcekey); - return this.placeNewBot(bot, world, bot.getLocation(), nbt); } public ServerBot placeNewBot(@NotNull ServerBot bot, ServerLevel world, Location location, ValueInput save) { @@ -161,7 +189,7 @@ public class BotList { bot.isRealPlayer = true; bot.loginTime = System.currentTimeMillis(); - bot.connection = new ServerBotPacketListenerImpl(this.server, bot, new ServerBotPacketListenerImpl.BotConnection()); + bot.connection = new ServerBotPacketListenerImpl(this.server, bot); bot.connection.markClientLoaded(); bot.setServerLevel(world); @@ -188,60 +216,56 @@ public class BotList { bot.loadAndSpawnParentVehicle(nbt); }); + Runnable task = () -> { + world.getCurrentWorldData().connections.add(bot.connection.connection); + world.addNewPlayer(bot); + BotJoinEvent event1 = new BotJoinEvent(bot.getBukkitEntity(), PaperAdventure.asAdventure(Component.translatable("multiplayer.player.joined", bot.getDisplayName())).style(Style.style(NamedTextColor.YELLOW))); + this.server.server.getPluginManager().callEvent(event1); + + net.kyori.adventure.text.Component joinMessage = event1.joinMessage(); + if (joinMessage != null && !joinMessage.equals(net.kyori.adventure.text.Component.empty())) { + this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(joinMessage), false); + } + + bot.renderInfo(); + bot.suppressTrackerForLogin = false; + + bot.level().getChunkSource().chunkMap.addEntity(bot); + bot.renderData(); + bot.initInventoryMenu(); + botsNameByWorldUuid + .computeIfAbsent(bot.level().uuid.toString(), (k) -> new HashSet<>()) + .add(bot.getBukkitEntity().getName()); + BotList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", bot.getName().getString(), "Local", bot.getId(), bot.level().serverLevelData.getLevelName(), bot.getX(), bot.getY(), bot.getZ()); + }; if (TickThread.isTickThreadFor(world, location.blockX() >> 4, location.blockZ() >> 4)) { - summonBot(bot, world); + task.run(); } else { RegionizedServer.getInstance().taskQueue.queueTickTaskQueue( world, location.getBlockX() >> 4, location.blockZ() >> 4, - () -> summonBot(bot, world)); + task::run); } return bot; } - private ServerBot summonBot(ServerBot bot, ServerLevel world) { - world.getCurrentWorldData().connections.add(bot.connection.connection); - world.addNewPlayer(bot); - - BotJoinEvent event1 = new BotJoinEvent(bot.getBukkitEntity(), PaperAdventure.asAdventure(Component.translatable("multiplayer.player.joined", bot.getDisplayName())).style(Style.style(NamedTextColor.YELLOW))); - this.server.server.getPluginManager().callEvent(event1); - - net.kyori.adventure.text.Component joinMessage = event1.joinMessage(); - if (joinMessage != null && !joinMessage.equals(net.kyori.adventure.text.Component.empty())) { - this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(joinMessage), false); - } - - bot.renderInfo(); - bot.suppressTrackerForLogin = false; - - bot.level().getChunkSource().chunkMap.addEntity(bot); - bot.renderData(); - bot.initInventoryMenu(); - botsNameByWorldUuid - .computeIfAbsent(bot.level().uuid.toString(), (k) -> new HashSet<>()) - .add(bot.getBukkitEntity().getRealName()); - BotList.LOGGER.info("{}[{}] logged in with entity id {} at ([{}]{}, {}, {})", bot.getName().getString(), "Local", bot.getId(), bot.level().serverLevelData.getLevelName(), bot.getX(), bot.getY(), bot.getZ()); - return bot; - } - /* * return true if async */ - public boolean removeBot(@NotNull ServerBot bot, @NotNull BotRemoveEvent.RemoveReason reason, @Nullable CommandSender remover, boolean saved, boolean async) { + public boolean removeBot(@NotNull ServerBot bot, @NotNull BotRemoveEvent.RemoveReason reason, @Nullable CommandSender remover, boolean save, boolean resume, boolean async) { if (async && !TickThread.isTickThreadFor(bot.level(), bot.getX(), bot.getZ())) { - bot.getBukkitEntity().taskScheduler.schedule((Entity unused) -> this.removeBot(bot, reason, remover, saved), null, 1L); - return true; + bot.getBukkitEntity().taskScheduler.schedule((Entity unused) -> this.removeBot(bot, reason, remover, save, resume), null, 1L); + return true; // async always return true } - this.removeBot(bot, reason, remover, saved); - return false; + return this.removeBot(bot, remover, reason, save, resume); } - public boolean removeBot(@NotNull ServerBot bot, @NotNull BotRemoveEvent.RemoveReason reason, @Nullable CommandSender remover, boolean saved) { - return this.removeBot(bot, reason, remover, saved, this.dataStorage); + public boolean removeBot(@NotNull ServerBot bot, @NotNull BotRemoveEvent.RemoveReason reason, @Nullable CommandSender remover, boolean save, boolean resume) { + return this.removeBot(bot, reason, remover, save, resume, true); } - public boolean removeBot(@NotNull ServerBot bot, @NotNull BotRemoveEvent.RemoveReason reason, @Nullable CommandSender remover, boolean saved, IPlayerDataStorage playerIO) { - BotRemoveEvent event = new BotRemoveEvent(bot.getBukkitEntity(), reason, remover, PaperAdventure.asAdventure(Component.translatable("multiplayer.player.left", bot.getDisplayName())).style(Style.style(NamedTextColor.YELLOW)), saved); + public boolean removeBot(@NotNull ServerBot bot, @Nullable CommandSender remover, @NotNull BotRemoveEvent.RemoveReason reason, boolean save, boolean resume) { + BotRemoveEvent event = new BotRemoveEvent(bot.getBukkitEntity(), reason, remover, PaperAdventure.asAdventure(Component.translatable("multiplayer.player.left", bot.getDisplayName())).style(Style.style(NamedTextColor.YELLOW)), save); this.server.server.getPluginManager().callEvent(event); if (event.isCancelled() && event.getReason() != BotRemoveEvent.RemoveReason.INTERNAL) { @@ -255,11 +279,16 @@ public class BotList { bot.disconnect(); + this.resumeDataStorage.removeSavedData(bot); if (event.shouldSave()) { - playerIO.save(bot); + if (resume) { + this.resumeDataStorage.save(bot); + } else { + this.manualSaveDataStorage.save(bot); + } } else { bot.dropAll(true); - botsNameByWorldUuid.getOrDefault(bot.level().uuid.toString(), new HashSet<>()).remove(bot.getBukkitEntity().getRealName()); + botsNameByWorldUuid.getOrDefault(bot.level().uuid.toString(), new HashSet<>()).remove(bot.getBukkitEntity().getName()); } if (bot.isPassenger() && event.shouldSave()) { @@ -267,7 +296,7 @@ public class BotList { if (entity.hasExactlyOnePlayerPassenger()) { bot.stopRiding(); entity.getPassengersAndSelf().forEach((entity1) -> { - if (entity1 instanceof AbstractVillager villager) { + if (!OldFeatureConfig.villagerVoidTrade && entity1 instanceof AbstractVillager villager) { final Player human = villager.getTradingPlayer(); if (human != null) { villager.setTradingPlayer(null); @@ -312,15 +341,14 @@ public class BotList { if (removeMessage != null && !removeMessage.equals(net.kyori.adventure.text.Component.empty())) { this.server.getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(removeMessage), false); } - return true; } public void removeAllIn(String worldUuid) { - for (String realName : this.botsNameByWorldUuid.getOrDefault(worldUuid, new HashSet<>())) { - ServerBot bot = this.getBotByName(realName); + for (String fullName : this.botsNameByWorldUuid.getOrDefault(worldUuid, new HashSet<>())) { + ServerBot bot = this.getBotByName(fullName); if (bot != null) { - this.removeBot(bot, BotRemoveEvent.RemoveReason.INTERNAL, null, FakeplayerConfig.canResident); + this.removeBot(bot, BotRemoveEvent.RemoveReason.INTERNAL, null, FakeplayerConfig.canResident, FakeplayerConfig.canResident); } } } @@ -332,7 +360,7 @@ public class BotList { for (ServerBot bot : this.bots) { bot.resume = FakeplayerConfig.canResident; if (TickThread.isTickThreadFor(bot.level(), bot.getX(), bot.getZ())) { - this.removeBot(bot, BotRemoveEvent.RemoveReason.INTERNAL, null, FakeplayerConfig.canResident); + this.removeBot(bot, BotRemoveEvent.RemoveReason.INTERNAL, null, FakeplayerConfig.canResident, FakeplayerConfig.canResident); } else { finished = false; check.getAndIncrement(); @@ -349,7 +377,7 @@ public class BotList { } counter.getAndIncrement(); try { - this.removeBot(bot, BotRemoveEvent.RemoveReason.INTERNAL, null, FakeplayerConfig.canResident); + this.removeBot(bot, BotRemoveEvent.RemoveReason.INTERNAL, null, FakeplayerConfig.canResident, FakeplayerConfig.canResident); received.getAndIncrement(); } catch (Exception e) { this.removeBot(bot, check, received, counter); @@ -361,24 +389,39 @@ public class BotList { }, null, 1L); } - public void loadBotInfo() { + public void loadResumeBotInfo() { if (!FakeplayerConfig.enable || !FakeplayerConfig.canResident) { return; } - CompoundTag savedBotList = this.getSavedBotList().copy(); - for (String realName : savedBotList.keySet()) { - CompoundTag nbt = savedBotList.getCompound(realName).orElseThrow(); - if (!nbt.getBoolean("resume").orElse(false)) { - continue; - } - UUID levelUuid = BotUtil.getBotLevel(realName, this.dataStorage); + CompoundTag savedBotList = this.getResumeBotList().copy(); + for (String fullName : savedBotList.keySet()) { + UUID levelUuid = BotUtil.getBotLevel(fullName, this.resumeDataStorage); if (levelUuid == null) { - LOGGER.warn("Bot {} has no world UUID, skipping loading.", realName); + LOGGER.warn("Bot {} has no world UUID, skipping loading.", fullName); continue; } this.botsNameByWorldUuid .computeIfAbsent(levelUuid.toString(), (k) -> new HashSet<>()) - .add(realName); + .add(fullName); + } + loadLegacyResumeBotInfo(); + } + + private void loadLegacyResumeBotInfo() { + CompoundTag savedBotList = this.getManualSavedBotList().copy(); + for (String fullName : savedBotList.keySet()) { + CompoundTag nbt = savedBotList.getCompound(fullName).orElseThrow(); + if (!nbt.getBoolean("resume").orElse(false)) { + continue; + } + UUID levelUuid = BotUtil.getBotLevel(fullName, this.manualSaveDataStorage); + if (levelUuid == null) { + LOGGER.warn("Bot {} has no world UUID, skipping loading.", fullName); + continue; + } + this.legacyBotsNameByWorldUuid + .computeIfAbsent(levelUuid.toString(), (k) -> new HashSet<>()) + .add(fullName); } } @@ -386,23 +429,19 @@ public class BotList { if (!FakeplayerConfig.enable || !FakeplayerConfig.canResident) { return; } - Set bots = this.botsNameByWorldUuid.get(worldUuid); - if (bots == null) { - return; - } - Set botsCopy = new HashSet<>(bots); - botsCopy.forEach(this::loadNewBot); + new HashSet<>(this.botsNameByWorldUuid.getOrDefault(worldUuid, new HashSet<>())).forEach(this::loadNewResumeBot); + new HashSet<>(this.legacyBotsNameByWorldUuid.getOrDefault(worldUuid, new HashSet<>())).forEach(this::loadNewManualSavedBot); } - public void updateBotLevel(ServerBot bot, ServerLevel level) { + public void updateBotLevel(@NotNull ServerBot bot, @NotNull ServerLevel level) { String prevUuid = bot.level().uuid.toString(); String newUuid = level.uuid.toString(); this.botsNameByWorldUuid .computeIfAbsent(newUuid, (k) -> new HashSet<>()) - .add(bot.getBukkitEntity().getRealName()); + .add(bot.getBukkitEntity().getName()); this.botsNameByWorldUuid .computeIfAbsent(prevUuid, (k) -> new HashSet<>()) - .remove(bot.getBukkitEntity().getRealName()); + .remove(bot.getBukkitEntity().getName()); } public void networkTick() { @@ -419,15 +458,25 @@ public class BotList { return this.botsByName.get(name.toLowerCase(Locale.ROOT)); } - public CompoundTag getSavedBotList() { - return this.dataStorage.getSavedBotList(); + public CompoundTag getManualSavedBotList() { + return this.getSavedBotList(this.manualSaveDataStorage); } - public GameProfile setProfile(UUID uuid, String name, String[] skin) { - GameProfile profile = new GameProfile(uuid, name); - if (skin == null) return profile; - PropertyMap profileMap = new MutablePropertyMap(profile.properties()); - profileMap.put("textures", new Property("textures", skin[0], skin[1])); - return new GameProfile(uuid, name, profileMap); + public CompoundTag getResumeBotList() { + return this.getSavedBotList(this.resumeDataStorage); + } + + public CompoundTag getSavedBotList(@NotNull BotDataStorage storage) { + return storage.getSavedBotList(); + } + + @Contract("_, _, _ -> new") + public static @NotNull GameProfile createBotProfile(UUID uuid, String name, String[] skin) { + GameProfile profile = new GameProfile(uuid, name, new MutablePropertyMap()); + profile.properties().put("is_bot", new Property("is_bot", "true")); + if (skin != null) { + profile.properties().put("textures", new Property("textures", skin[0], skin[1])); + } + return profile; } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotStatsCounter.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotStatsCounter.java index 7296d14..1d490a0 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotStatsCounter.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotStatsCounter.java @@ -24,6 +24,7 @@ import net.minecraft.stats.ServerStatsCounter; import net.minecraft.stats.Stat; import net.minecraft.world.entity.player.Player; import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NonNull; import java.io.File; @@ -44,7 +45,7 @@ public class BotStatsCounter extends ServerStatsCounter { } @Override - public void parse(@NotNull DataFixer dataFixer, @NotNull JsonElement json) { + public void parse(@NonNull DataFixer fixerUpper, @NonNull JsonElement json) { } @Override diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotUtil.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotUtil.java index c72c5b0..9ab354c 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotUtil.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/BotUtil.java @@ -85,15 +85,15 @@ public class BotUtil { @NotNull public static UUID getBotUUID(@NotNull BotCreateState state) { - return getBotUUID(state.realName()); + return getBotUUID(state.fullName()); } - public static UUID getBotUUID(@NotNull String realName) { - return UUID.nameUUIDFromBytes(("Fakeplayer:" + realName).getBytes(Charsets.UTF_8)); + public static UUID getBotUUID(@NotNull String fullName) { + return UUID.nameUUIDFromBytes(("Fakeplayer:" + fullName).getBytes(Charsets.UTF_8)); } - public static UUID getBotLevel(@NotNull String realName, BotDataStorage botDataStorage) { - UUID uuid = BotUtil.getBotUUID(realName); + public static UUID getBotLevel(@NotNull String fullName, BotDataStorage botDataStorage) { + UUID uuid = getBotUUID(fullName); Optional tagOptional = botDataStorage.read(uuid.toString()); if (tagOptional.isEmpty()) { return null; diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/IPlayerDataStorage.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/IPlayerDataStorage.java deleted file mode 100644 index dd4c9e5..0000000 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/IPlayerDataStorage.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * This file is part of Leaves (https://github.com/LeavesMC/Leaves) - * - * Leaves is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Leaves is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Leaves. If not, see . - */ - -package org.leavesmc.leaves.bot; - -import net.minecraft.world.entity.player.Player; - -public interface IPlayerDataStorage { - - void save(Player player); - -// Optional load(Player player, ProblemReporter reporter); -} diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java index 7744140..c126d76 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBot.java @@ -19,7 +19,7 @@ package org.leavesmc.leaves.bot; import com.google.common.collect.ImmutableMap; import com.mojang.authlib.GameProfile; -import com.mojang.logging.LogUtils; +import fun.bm.lophine.LophineLogger; import fun.bm.lophine.config.modules.function.FakeplayerConfig; import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.event.entity.EntityKnockbackEvent; @@ -77,16 +77,16 @@ import org.leavesmc.leaves.entity.bot.CraftBot; import org.leavesmc.leaves.event.bot.*; import org.leavesmc.leaves.plugin.MinecraftInternalPlugin; import org.leavesmc.leaves.util.MathUtils; -import org.slf4j.Logger; import java.util.*; import java.util.function.Predicate; +import static net.minecraft.server.MinecraftServer.getServer; + public class ServerBot extends ServerPlayer { private final List> actions; - private final Map> configs; - private static final Logger LOGGER = LogUtils.getClassLogger(); + private final Map> configs; public boolean resume = false; public BotCreateState createState; @@ -108,8 +108,8 @@ public class ServerBot extends ServerPlayer { this.gameMode = new ServerBotGameMode(this); this.actions = new ArrayList<>(); - ImmutableMap.Builder> configBuilder = ImmutableMap.builder(); - for (AbstractBotConfig config : Configs.getConfigs()) { + ImmutableMap.Builder> configBuilder = ImmutableMap.builder(); + for (AbstractBotConfig config : Configs.getConfigs()) { configBuilder.put(config.getName(), config.create().setBot(this)); } this.configs = configBuilder.build(); @@ -139,7 +139,7 @@ public class ServerBot extends ServerPlayer { this.joining = false; } - this.resetOperationCountPerTick(); // Leaves - player operation limiter +// this.resetOperationCountPerTick(); // Leaves - player operation limiter this.wardenSpawnTracker.tick(); if (this.invulnerableTime > 0) { this.invulnerableTime--; @@ -213,17 +213,7 @@ public class ServerBot extends ServerPlayer { this.updateIsUnderwater(); if (this.getConfigValue(Configs.TICK_TYPE) == TickType.NETWORK) { - try { - Bukkit.getRegionScheduler().execute( - MinecraftInternalPlugin.INSTANCE, - this.level().getWorld(), - this.getBlockX() >> 4, - this.getBlockZ() >> 4, - this::runAction - ); - } catch (Exception e) { - this.runAction(); - } + getServer().scheduleOnMain(this::runAction); } this.livingEntityTick(); @@ -305,6 +295,18 @@ public class ServerBot extends ServerPlayer { teleportTransition.postTeleportTransition().onTransition(this); this.isChangingDimension = false; + // Lophine - We don't have this +/* if (LeavesConfig.modify.netherPortalFix) { + final ResourceKey fromDim = fromLevel.dimension(); + final ResourceKey toDim = level().dimension(); + if (!((fromDim != Level.OVERWORLD || toDim != Level.NETHER) && (fromDim != Level.NETHER || toDim != Level.OVERWORLD))) { + BlockPos fromPortal = org.leavesmc.leaves.util.ReturnPortalManager.findPortalAt(this, fromDim, lastPos); + BlockPos toPos = this.blockPosition(); + if (fromPortal != null) { + org.leavesmc.leaves.util.ReturnPortalManager.storeReturnPortal(this, toDim, toPos, fromPortal); + } + } + }*/ if (this.isBlocking()) { this.stopUsingItem(); } @@ -350,7 +352,7 @@ public class ServerBot extends ServerPlayer { if (FakeplayerConfig.canOpenInventory) { if (player instanceof ServerPlayer player1 && player.getMainHandItem().isEmpty()) { BotInventoryOpenEvent event = new BotInventoryOpenEvent(this.getBukkitEntity(), player1.getBukkitEntity()); - MinecraftServer.getServer().server.getPluginManager().callEvent(event); + getServer().server.getPluginManager().callEvent(event); if (!event.isCancelled()) { player.openMenu(new SimpleMenuProvider((i, inventory, p) -> ChestMenu.sixRows(i, inventory, this.container), this.getDisplayName())); return InteractionResult.SUCCESS; @@ -372,8 +374,8 @@ public class ServerBot extends ServerPlayer { nbt.putBoolean("isShiftKeyDown", this.isShiftKeyDown()); CompoundTag createNbt = new CompoundTag(); - createNbt.putString("realName", this.createState.realName()); - createNbt.putString("name", this.createState.name()); + createNbt.putString("rawName", this.createState.rawName()); + createNbt.putString("name", this.createState.fullName()); createNbt.putString("skinName", this.createState.skinName()); if (this.createState.skin() != null) { @@ -395,7 +397,7 @@ public class ServerBot extends ServerPlayer { if (!this.configs.isEmpty()) { ValueOutput.TypedOutputList configNbt = nbt.list("configs", CompoundTag.CODEC); - for (AbstractBotConfig config : this.configs.values()) { + for (AbstractBotConfig config : this.configs.values()) { configNbt.add(config.save(new CompoundTag())); } } @@ -407,7 +409,11 @@ public class ServerBot extends ServerPlayer { this.setShiftKeyDown(nbt.getBooleanOr("isShiftKeyDown", false)); CompoundTag createNbt = nbt.read("createStatus", CompoundTag.CODEC).orElseThrow(); - BotCreateState.Builder createBuilder = BotCreateState.builder(createNbt.getString("realName").orElseThrow(), null).name(createNbt.getString("name").orElseThrow()); + BotCreateState.Builder createBuilder = BotCreateState + .builder(createNbt.getString("rawName") + .orElseGet(() -> createNbt.getString("realName") + .orElseThrow()), null) // Convert from legacy version, consider to use ca.spottedleaf.dataconverter.minecraft.MCDataConverter instead for release version + .name(createNbt.getString("name").orElseThrow()); String[] skin = null; if (createNbt.contains("skin")) { @@ -422,7 +428,7 @@ public class ServerBot extends ServerPlayer { createBuilder.createReason(BotCreateEvent.CreateReason.INTERNAL).creator(null); this.createState = createBuilder.build(); - this.gameProfile = BotList.INSTANCE.setProfile(this.getUUID(), this.createState.name(), this.createState.skin()); + this.gameProfile = BotList.createBotProfile(this.getUUID(), this.createState.fullName(), this.createState.skin()); if (nbt.list("actions", CompoundTag.CODEC).isPresent()) { @@ -440,8 +446,9 @@ public class ServerBot extends ServerPlayer { if (nbt.list("configs", CompoundTag.CODEC).isPresent()) { ValueInput.TypedInputList configNbt = nbt.list("configs", CompoundTag.CODEC).orElseThrow(); for (CompoundTag configTag : configNbt) { - AbstractBotConfig config = Configs.getConfig(configTag.getString("configName").orElseThrow()); + AbstractBotConfig config = Configs.getConfig(configTag.getString("configName").orElseThrow()); if (config != null) { + config.setBot(this); config.load(configTag); } } @@ -466,30 +473,30 @@ public class ServerBot extends ServerPlayer { ChunkMap.TrackedEntity entityTracker = this.moonrise$getTrackedEntity(); if (entityTracker == null) { - LOGGER.warn("Fakeplayer cant get entity tracker for {}", this.getId()); + LophineLogger.LOGGER.warn("Fakeplayer cant get entity tracker for {}", this.getId()); return; } playerConnection.send(this.getAddEntityPacket(entityTracker.serverEntity)); if (login) { - Bukkit.getGlobalRegionScheduler().runDelayed(MinecraftInternalPlugin.INSTANCE, (unused) -> playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))), 10); + Bukkit.getGlobalRegionScheduler().runDelayed(MinecraftInternalPlugin.INSTANCE, (task) -> playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))), 10); } else { playerConnection.send(new ClientboundRotateHeadPacket(this, (byte) ((getYRot() * 256f) / 360f))); } } public void renderInfo() { - MinecraftServer.getServer().getPlayerList().getPlayers().forEach(this::sendPlayerInfo); + getServer().getPlayerList().getPlayers().forEach(this::sendPlayerInfo); } public void renderData() { - MinecraftServer.getServer().getPlayerList().getPlayers().forEach( + getServer().getPlayerList().getPlayers().forEach( player -> this.sendFakeDataIfNeed(player, false) ); } private void sendPacket(Packet packet) { - MinecraftServer.getServer().getPlayerList().getPlayers().forEach(player -> player.connection.send(packet)); + getServer().getPlayerList().getPlayers().forEach(player -> player.connection.send(packet)); } @Override @@ -498,7 +505,7 @@ public class ServerBot extends ServerPlayer { Component defaultMessage = this.getCombatTracker().getDeathMessage(); BotDeathEvent event = new BotDeathEvent(this.getBukkitEntity(), PaperAdventure.asAdventure(defaultMessage), flag); - MinecraftServer.getServer().server.getPluginManager().callEvent(event); + getServer().server.getPluginManager().callEvent(event); if (event.isCancelled()) { if (this.getHealth() <= 0) { @@ -511,18 +518,23 @@ public class ServerBot extends ServerPlayer { net.kyori.adventure.text.Component deathMessage = event.deathMessage(); if (event.isSendDeathMessage() && deathMessage != null && !deathMessage.equals(net.kyori.adventure.text.Component.empty())) { - MinecraftServer.getServer().getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(deathMessage), false); + getServer().getPlayerList().broadcastSystemMessage(PaperAdventure.asVanilla(deathMessage), false); } - MinecraftServer.getServer().getBotList().removeBot(this, BotRemoveEvent.RemoveReason.DEATH, null, false); + // TODO: separate die and remove logic, call super.die here + this.removeEntitiesOnShoulder(); + if (this.level().getGameRules().get(GameRules.FORGIVE_DEAD_PLAYERS)) { + this.tellNeutralMobsThatIDied(); + } + getServer().getBotList().removeBot(this, BotRemoveEvent.RemoveReason.DEATH, null, false, false); } @Override - public boolean startRiding(Entity entity, boolean force, boolean triggerEvents) { - if (super.startRiding(entity, force, triggerEvents)) { - if (entity.getControllingPassenger() == this) { // see net.minecraft.server.networkServerGamePacketListenerImpl#handleMoveVehicle + public boolean startRiding(@NotNull Entity vehicle, boolean force, boolean sendGameEvent) { + if (super.startRiding(vehicle, force, sendGameEvent)) { + if (vehicle.getControllingPassenger() == this) { // see net.minecraft.server.networkServerGamePacketListenerImpl#handleMoveVehicle this.setDeltaMovement(Vec3.ZERO); - this.setYRot(entity.yRotO); + this.setYRot(vehicle.yRotO); } return true; } else { @@ -669,15 +681,15 @@ public class ServerBot extends ServerPlayer { } @SuppressWarnings("unchecked") - public > AbstractBotConfig getConfig(@NotNull AbstractBotConfig config) { - return (AbstractBotConfig) Objects.requireNonNull(this.configs.get(config.getName())); + public > AbstractBotConfig getConfig(@NotNull AbstractBotConfig config) { + return (AbstractBotConfig) Objects.requireNonNull(this.configs.get(config.getName())); } - public Collection> getAllConfigs() { + public Collection> getAllConfigs() { return configs.values(); } - public > O getConfigValue(@NotNull AbstractBotConfig config) { + public > T getConfigValue(@NotNull AbstractBotConfig config) { return this.getConfig(config).getValue(); } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java index 028e68c..e634f91 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotGameMode.java @@ -79,7 +79,7 @@ public class ServerBotGameMode extends ServerPlayerGameMode { this.level.sendBlockUpdated(pos, blockState, blockState, 3); return false; } else { - BlockState blockState1 = block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update + BlockState blockState1 = /*isNoBlockUpdate() ? blockState : */block.playerWillDestroy(this.level, pos, blockState, this.player); // Leaves - no block update boolean flag = this.level.removeBlock(pos, false); if (flag) { block.destroy(this.level, pos, blockState1); diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotPacketListenerImpl.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotPacketListenerImpl.java index bcb8ba8..053a704 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotPacketListenerImpl.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/ServerBotPacketListenerImpl.java @@ -29,12 +29,9 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class ServerBotPacketListenerImpl extends ServerGamePacketListenerImpl { - public final Connection fakeConnection; - public ServerBotPacketListenerImpl(MinecraftServer server, ServerBot bot, BotConnection botConnection) { - super(server, botConnection, bot, CommonListenerCookie.createInitial(bot.gameProfile, false)); - this.fakeConnection = botConnection; - this.fakeConnection.packetListener = this; + public ServerBotPacketListenerImpl(MinecraftServer server, ServerBot bot) { + super(server, BotConnection.INSTANCE, bot, CommonListenerCookie.createInitial(bot.gameProfile, false)); } @Override @@ -56,6 +53,8 @@ public class ServerBotPacketListenerImpl extends ServerGamePacketListenerImpl { public static class BotConnection extends Connection { + private static final BotConnection INSTANCE = new BotConnection(); + public BotConnection() { super(PacketFlow.SERVERBOUND); } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java index 7ca24df..8ef19d7 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/Configs.java @@ -28,7 +28,7 @@ import java.util.Map; @SuppressWarnings({"unused"}) public class Configs { - private static final Map, AbstractBotConfig> configs = new HashMap<>(); + private static final Map, AbstractBotConfig> configs = new HashMap<>(); public static final SkipSleepConfig SKIP_SLEEP = register(new SkipSleepConfig()); public static final AlwaysSendDataConfig ALWAYS_SEND_DATA = register(new AlwaysSendDataConfig()); @@ -38,7 +38,7 @@ public class Configs { public static final LocatorBarConfig ENABLE_LOCATOR_BAR = register(new LocatorBarConfig()); @Nullable - public static AbstractBotConfig getConfig(String name) { + public static AbstractBotConfig getConfig(String name) { return configs.values().stream() .filter(config -> config.getName().equals(name)) .findFirst() @@ -47,12 +47,12 @@ public class Configs { @NotNull @Contract(pure = true) - public static Collection> getConfigs() { + public static Collection> getConfigs() { return configs.values(); } @SuppressWarnings("unchecked") - private static > @NotNull E register(AbstractBotConfig instance) { + private static > @NotNull E register(AbstractBotConfig instance) { configs.put(instance.getClass(), instance); return (E) instance; } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/ExtraData.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/ExtraData.java new file mode 100644 index 0000000..46c852a --- /dev/null +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/ExtraData.java @@ -0,0 +1,11 @@ +package org.leavesmc.leaves.bot.agent; + +import org.apache.commons.lang3.tuple.Pair; + +import java.util.List; + +public record ExtraData(List> raw) { + public void add(String key, String value) { + raw.add(Pair.of(key, value)); + } +} diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractBotAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractBotAction.java index 69761d3..b7e0912 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractBotAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractBotAction.java @@ -19,18 +19,18 @@ package org.leavesmc.leaves.bot.agent.actions; import com.mojang.brigadier.arguments.ArgumentType; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.logging.LogUtils; +import fun.bm.lophine.LophineLogger; import net.minecraft.core.UUIDUtil; import net.minecraft.nbt.CompoundTag; import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.bot.agent.ExtraData; import org.leavesmc.leaves.command.CommandContext; import org.leavesmc.leaves.command.WrappedArgument; import org.leavesmc.leaves.event.bot.BotActionExecuteEvent; import org.leavesmc.leaves.event.bot.BotActionStopEvent; import org.leavesmc.leaves.util.UpdateSuppressionException; -import org.slf4j.Logger; import java.util.*; import java.util.function.Consumer; @@ -56,7 +56,6 @@ public abstract class AbstractBotAction> { private Consumer onFail; private Consumer onSuccess; private Consumer onStop; - private static final Logger LOGGER = LogUtils.getClassLogger(); public AbstractBotAction(String name, Supplier creator) { this.name = name; @@ -74,13 +73,12 @@ public abstract class AbstractBotAction> { public abstract Object asCraft(); - public void provideActionData(@NotNull ActionData data) { + public String getActionDataString() { + return getActionDataString(new ExtraData(new ArrayList<>())); } - public String getActionDataString() { - ActionData data = new ActionData(new ArrayList<>()); - provideActionData(data); - return data.raw.stream() + public String getActionDataString(@NotNull ExtraData data) { + return data.raw().stream() .map(pair -> pair.getLeft() + "=" + pair.getRight()) .reduce((a, b) -> a + ", " + b) .orElse("No arguments"); @@ -141,7 +139,7 @@ public abstract class AbstractBotAction> { e.providePlayer(bot); e.consume(); } catch (Exception e) { - LOGGER.warn("An error occurred while executing bot " + bot.displayName + ", action " + this.name, e); + LophineLogger.LOGGER.error("An error occurred while executing bot {}, action {}", bot.displayName, this.name, e); } if (result) { @@ -179,12 +177,12 @@ public abstract class AbstractBotAction> { public void load(@NotNull CompoundTag nbt) { this.uuid = nbt.read("actionUUID", UUIDUtil.CODEC).orElse(UUID.randomUUID()); - this.initialTickDelay = nbt.getInt("initialTickDelay").orElse(0); - this.initialTickInterval = nbt.getInt("initialTickInterval").orElse(0); - this.initialNumber = nbt.getInt("initialNumber").orElse(0); + this.initialTickDelay = nbt.getIntOr("initialTickDelay", 0); + this.initialTickInterval = nbt.getIntOr("initialTickInterval", 0); + this.initialNumber = nbt.getIntOr("initialNumber", 0); - this.tickToNext = nbt.getInt("tickToNext").orElse(0); - this.numberRemaining = nbt.getInt("numberRemaining").orElse(0); + this.tickToNext = nbt.getIntOr("tickToNext", 0); + this.numberRemaining = nbt.getIntOr("numberRemaining", 0); } public void stop(@NotNull ServerBot bot, BotActionStopEvent.Reason reason) { @@ -263,12 +261,4 @@ public abstract class AbstractBotAction> { public void setOnStop(Consumer onStop) { this.onStop = onStop; } - - public record ActionData( - List> raw - ) { - public void add(String key, String value) { - raw.add(Pair.of(key, value)); - } - } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractStateBotAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractStateBotAction.java index e7acdd5..1cd4837 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractStateBotAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractStateBotAction.java @@ -20,7 +20,6 @@ package org.leavesmc.leaves.bot.agent.actions; import java.util.function.Supplier; public abstract class AbstractStateBotAction> extends AbstractBotAction { - public AbstractStateBotAction(String name, Supplier creator) { super(name, creator); this.setDoNumber(-1); diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractTimerBotAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractTimerBotAction.java index fb82be7..6d30aeb 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractTimerBotAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractTimerBotAction.java @@ -19,6 +19,7 @@ package org.leavesmc.leaves.bot.agent.actions; import net.minecraft.network.chat.Component; import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.bot.agent.ExtraData; import org.leavesmc.leaves.command.CommandContext; import java.util.function.Supplier; @@ -30,12 +31,8 @@ public abstract class AbstractTimerBotAction public AbstractTimerBotAction(String name, Supplier creator) { super(name, creator); - this.addArgument("delay", integer(0)) - .suggests(strings("0", "5", "10", "20")) - .setOptional(true); - this.addArgument("interval", integer(0)) - .suggests(strings("20", "0", "5", "10")) - .setOptional(true); + this.addArgument("delay", integer(0)).suggests(strings("0", "5", "10", "20")).setOptional(true); + this.addArgument("interval", integer(0)).suggests(strings("20", "0", "5", "10")).setOptional(true); this.addArgument("do_number", integer(-1)) .suggests(((context, builder) -> builder.suggest("-1", Component.literal("do infinite times")))) .setOptional(true); @@ -49,11 +46,11 @@ public abstract class AbstractTimerBotAction } @Override - public void provideActionData(@NotNull ActionData data) { - super.provideActionData(data); + public String getActionDataString(@NotNull ExtraData data) { data.add("delay", String.valueOf(this.getStartDelayTick())); data.add("interval", String.valueOf(this.getDoIntervalTick())); data.add("do_number", String.valueOf(this.getDoNumber())); data.add("remaining_do_number", String.valueOf(this.getDoNumberRemaining())); + return super.getActionDataString(data); } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractUseBotAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractUseBotAction.java index 38403cf..00996cd 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractUseBotAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/AbstractUseBotAction.java @@ -22,6 +22,7 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionResult; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.bot.agent.ExtraData; import org.leavesmc.leaves.command.CommandContext; import org.leavesmc.leaves.event.bot.BotActionStopEvent; @@ -115,10 +116,10 @@ public abstract class AbstractUseBotAction> ex } @Override - public void provideActionData(@NotNull ActionData data) { - super.provideActionData(data); + public String getActionDataString(@NotNull ExtraData data) { data.add("use_timeout", String.valueOf(this.useTickTimeout)); data.add("already_used_tick", String.valueOf(this.alreadyUsedTick)); + return super.getActionDataString(data); } @Override @@ -133,9 +134,9 @@ public abstract class AbstractUseBotAction> ex @Override public void load(@NotNull CompoundTag nbt) { super.load(nbt); - this.useTickTimeout = nbt.getInt("useTick").orElseThrow(); + this.useTickTimeout = nbt.getIntOr("useTick", this.useTickTimeout); this.alreadyUsedTick = nbt.getInt("alreadyUsedTick").orElseGet( - () -> this.useTickTimeout - nbt.getInt("tickToRelease").orElseThrow() + () -> nbt.getInt("tickToRelease").map(tickToRelease -> this.useTickTimeout - tickToRelease).orElse(this.alreadyUsedTick) ); } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerFishAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerFishAction.java index 8a8f022..6f0464d 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerFishAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerFishAction.java @@ -55,8 +55,8 @@ public class ServerFishAction extends AbstractTimerBotAction { @Override public void load(@NotNull CompoundTag nbt) { super.load(nbt); - this.initialFishInterval = nbt.getInt("initialFishInterval").orElseThrow(); - this.tickToNextFish = nbt.getInt("tickToNextFish").orElseThrow(); + this.initialFishInterval = nbt.getIntOr("initialFishInterval", this.initialFishInterval); + this.tickToNextFish = nbt.getIntOr("tickToNextFish", this.tickToNextFish); } @Override diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerLookAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerLookAction.java index b694f02..9e71281 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerLookAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerLookAction.java @@ -18,15 +18,15 @@ package org.leavesmc.leaves.bot.agent.actions; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.EntityArgument; -import net.minecraft.commands.arguments.coordinates.Coordinates; -import net.minecraft.commands.arguments.coordinates.Vec3Argument; -import net.minecraft.commands.arguments.selector.EntitySelector; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.argument.ArgumentTypes; +import io.papermc.paper.command.brigadier.argument.resolvers.FinePositionResolver; +import io.papermc.paper.command.brigadier.argument.resolvers.selector.PlayerSelectorArgumentResolver; import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerPlayer; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.phys.Vec3; +import org.bukkit.command.CommandSender; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.entity.Entity; import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; @@ -42,35 +42,28 @@ public class ServerLookAction extends AbstractBotAction { public ServerLookAction() { super("look", ServerLookAction::new); - declarePlayerBranch(); - declareLocationBranch(); - } - - private void declarePlayerBranch() { - this.fork(0); - this.addArgument("player", EntityArgument.player()) - .setOptional(true); - } - - private void declareLocationBranch() { + this.addArgument("player", ArgumentTypes.player()).setOptional(true); this.fork(1); - this.addArgument("location", Vec3Argument.vec3(false)); + this.addArgument("location", ArgumentTypes.finePosition()); } @Override public void loadCommand(@NotNull CommandContext context) throws CommandSyntaxException { - EntitySelector selector = context.getArgumentOrDefault("player", EntitySelector.class, null); - Coordinates location = context.getArgumentOrDefault("location", Coordinates.class, null); + PlayerSelectorArgumentResolver playerSelectorResolver = context.getArgumentOrDefault("player", PlayerSelectorArgumentResolver.class, null); + FinePositionResolver positionResolver = context.getArgumentOrDefault("location", FinePositionResolver.class, null); CommandSourceStack source = context.getSource(); - if (selector == null && location == null) { - Entity sender = source.getEntityOrException(); - this.setPos(new Vector(sender.getX(), sender.getY(), sender.getZ())); - } else if (selector != null) { - ServerPlayer player = selector.findSinglePlayer(source); - this.setTarget(player); + if (playerSelectorResolver == null && positionResolver == null) { + CommandSender sender = context.getSender(); + if (sender instanceof Entity entity) { + this.setPos(entity.getLocation().toVector()); + } else { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownCommand().create(); + } + } else if (playerSelectorResolver != null) { + CraftPlayer player = (CraftPlayer) playerSelectorResolver.resolve(source).getFirst(); + this.setTarget(player.getHandle()); } else { - Vec3 vector = location.getPosition(source); - this.setPos(new Vector(vector.x, vector.y, vector.z)); + this.setPos(positionResolver.resolve(source).toVector()); } } @@ -115,16 +108,6 @@ public class ServerLookAction extends AbstractBotAction { return target; } - @Override - public void provideActionData(@NotNull ActionData data) { - super.provideActionData(data); - if (target != null) { - data.add("target", target.getName().getString()); - } else { - data.add("position", String.format("(%.2f, %.2f, %.2f)", pos.getX(), pos.getY(), pos.getZ())); - } - } - @Override public boolean doTick(@NotNull ServerBot bot) { if (target != null) { diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMountAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMountAction.java index b879e46..058704d 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMountAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMountAction.java @@ -17,9 +17,8 @@ package org.leavesmc.leaves.bot.agent.actions; -import net.minecraft.world.entity.Entity; import org.bukkit.Location; -import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftVehicle; import org.bukkit.entity.Vehicle; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; @@ -39,14 +38,17 @@ public class ServerMountAction extends AbstractBotAction { Location center = bot.getBukkitEntity().getLocation(); List vehicles = center.getNearbyEntitiesByType( Vehicle.class, - 4, - vehicle -> manhattanDistance(bot, ((CraftEntity) vehicle).getHandle()) <= 3 + bot.entityInteractionRange() ).stream().sorted(Comparator.comparingDouble( (vehicle) -> center.distanceSquared(vehicle.getLocation()) )).toList(); for (Vehicle vehicle : vehicles) { - if (bot.startRiding(((CraftEntity) vehicle).getHandle(), false, true)) { + CraftVehicle craftVehicle = (CraftVehicle) vehicle; + if (!bot.hasLineOfSight(craftVehicle.getHandle())) { + continue; + } + if (bot.startRiding(craftVehicle.getHandle())) { return true; } } @@ -58,10 +60,4 @@ public class ServerMountAction extends AbstractBotAction { public Object asCraft() { return new CraftMountAction(this); } - - private double manhattanDistance(@NotNull Entity entity1, @NotNull Entity entity2) { - return Math.abs(entity1.getX() - entity2.getX()) + - Math.abs(entity1.getY() - entity2.getY()) + - Math.abs(entity1.getZ() - entity2.getZ()); - } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMoveAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMoveAction.java index 439d130..8775a92 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMoveAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerMoveAction.java @@ -17,46 +17,26 @@ package org.leavesmc.leaves.bot.agent.actions; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.bot.agent.ExtraData; import org.leavesmc.leaves.command.CommandContext; +import org.leavesmc.leaves.command.arguments.EnumArgumentType; import org.leavesmc.leaves.entity.bot.action.MoveAction.MoveDirection; import org.leavesmc.leaves.entity.bot.actions.CraftMoveAction; import org.leavesmc.leaves.event.bot.BotActionStopEvent; -import java.util.Arrays; -import java.util.Map; - -import static java.util.stream.Collectors.toMap; -import static org.leavesmc.leaves.command.ArgumentNode.ArgumentSuggestions.strings; - public class ServerMoveAction extends AbstractStateBotAction { - private static final Map NAME_TO_DIRECTION = Arrays.stream(MoveDirection.values()).collect(toMap( - it -> it.name, - it -> it - )); private MoveDirection direction = MoveDirection.FORWARD; public ServerMoveAction() { super("move", ServerMoveAction::new); - this.addArgument("direction", StringArgumentType.word()) - .suggests(strings( - Arrays.stream(MoveDirection.values()) - .map((it) -> it.name) - .toList() - )); + this.addArgument("direction", EnumArgumentType.fromEnum(MoveDirection.class)); } @Override - public void loadCommand(@NotNull CommandContext context) throws CommandSyntaxException { - String raw = context.getArgument("direction", String.class); - MoveDirection direction = NAME_TO_DIRECTION.get(raw); - if (direction == null) { - throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); - } - this.direction = direction; + public void loadCommand(@NotNull CommandContext context) { + this.direction = context.getArgument("direction", MoveDirection.class); } @Override @@ -82,9 +62,9 @@ public class ServerMoveAction extends AbstractStateBotAction { } @Override - public void provideActionData(@NotNull ActionData data) { - super.provideActionData(data); + public String getActionDataString(@NotNull ExtraData data) { data.add("direction", direction.name); + return super.getActionDataString(data); } public MoveDirection getDirection() { diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerRotationAction.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerRotationAction.java index cfa4383..bfc28b0 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerRotationAction.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/actions/ServerRotationAction.java @@ -18,11 +18,13 @@ package org.leavesmc.leaves.bot.agent.actions; import com.mojang.brigadier.arguments.FloatArgumentType; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Entity; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.bot.agent.ExtraData; import org.leavesmc.leaves.command.CommandContext; import org.leavesmc.leaves.entity.bot.actions.CraftRotationAction; @@ -35,16 +37,26 @@ public class ServerRotationAction extends AbstractBotAction builder.suggest( - DF.format(context.getSource().getEntityOrException().getYRot()), - Component.literal("current player yaw") - )) + .suggests((context, builder) -> { + CommandSender sender = context.getSender(); + if (sender instanceof Entity entity) { + builder.suggest( + DF.format(entity.getYaw()), + Component.literal("current player yaw") + ); + } + }) .setOptional(true); this.addArgument("pitch", FloatArgumentType.floatArg(-90, 90)) - .suggests((context, builder) -> builder.suggest( - DF.format(context.getSource().getEntityOrException().getXRot()), - Component.literal("current player pitch") - )) + .suggests((context, builder) -> { + CommandSender sender = context.getSender(); + if (sender instanceof Entity entity) { + builder.suggest( + DF.format(entity.getPitch()), + Component.literal("current player pitch") + ); + } + }) .setOptional(true); } @@ -52,9 +64,14 @@ public class ServerRotationAction extends AbstractBotAction> { +public abstract class AbstractBotConfig> { private final String name; - private final WrappedArgument argument; + private final WrappedArgument argument; private final Supplier creator; protected ServerBot bot; - public AbstractBotConfig(String name, ArgumentType type, Supplier creator) { + public AbstractBotConfig(String name, ArgumentType type, Supplier creator) { this.name = name; this.argument = new WrappedArgument<>(name, type); if (shouldApplySuggestions()) { @@ -56,7 +54,7 @@ public abstract class AbstractBotConfig setBot(ServerBot bot) { + public AbstractBotConfig setBot(ServerBot bot) { this.bot = bot; return this; } @@ -65,34 +63,32 @@ public abstract class AbstractBotConfig> getExtraData() { - return List.of(); - } + public abstract T loadFromCommand(@NotNull CommandContext context) throws CommandSyntaxException; public String getName() { return name; } public Component getNameComponent() { - Component result = text(getName(), AQUA); - if (!getExtraData().isEmpty()) { - result = result.hoverEvent(showText( - getExtraData().stream() - .map(pair -> text(pair.getKey() + "=" + pair.getValue())) - .reduce((a, b) -> a.append(text(", ")).append(b)) - .orElseGet(() -> text("")) - )); - } - return result; + return Component.text(getName(), NamedTextColor.AQUA).hoverEvent(HoverEvent.showText(Component.text(getExtraDataString()))); } - public WrappedArgument getArgument() { + public String getExtraDataString() { + return getExtraDataString(new ExtraData(new ArrayList<>())); + } + + public String getExtraDataString(@NotNull ExtraData data) { + return data.raw().stream() + .map(pair -> pair.getLeft() + "=" + pair.getRight()) + .reduce((a, b) -> a + ", " + b) + .orElse("No data"); + } + + public WrappedArgument getArgument() { return argument; } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/AlwaysSendDataConfig.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/AlwaysSendDataConfig.java index 6f667ef..b9c951b 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/AlwaysSendDataConfig.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/AlwaysSendDataConfig.java @@ -23,7 +23,7 @@ import net.minecraft.nbt.CompoundTag; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.command.CommandContext; -public class AlwaysSendDataConfig extends AbstractBotConfig { +public class AlwaysSendDataConfig extends AbstractBotConfig { private boolean value; public AlwaysSendDataConfig() { diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/LocatorBarConfig.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/LocatorBarConfig.java index 94323b3..7b5963a 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/LocatorBarConfig.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/LocatorBarConfig.java @@ -18,6 +18,7 @@ package org.leavesmc.leaves.bot.agent.configs; import com.mojang.brigadier.arguments.BoolArgumentType; +import fun.bm.lophine.LophineLogger; import fun.bm.lophine.config.modules.experiment.CommandConfig; import fun.bm.lophine.config.modules.function.FakeplayerConfig; import me.earthme.luminol.utils.NullPlugin; @@ -25,10 +26,9 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.waypoints.ServerWaypointManager; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; -import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.command.CommandContext; -public class LocatorBarConfig extends AbstractBotConfig { +public class LocatorBarConfig extends AbstractBotConfig { private boolean value; public LocatorBarConfig() { @@ -43,20 +43,24 @@ public class LocatorBarConfig extends AbstractBotConfig setValue(value), 20); - } else { - setValue(value, this.bot); - } + setValue(value, 0); } - public void setValue(@NotNull Boolean value, ServerBot bot) throws IllegalArgumentException { - this.value = value; - ServerWaypointManager manager = bot.level().getWaypointManager(); - if (value) { - manager.trackWaypoint(bot); + public void setValue(@NotNull Boolean value, int count) throws IllegalArgumentException { + if (count > 60) { + LophineLogger.LOGGER.error("Failed to set locator bar for a fakeplayer after 60 attempts"); + return; + } + if (this.bot != null) { + this.value = value; + ServerWaypointManager manager = this.bot.level().getWaypointManager(); + if (value) { + manager.trackWaypoint(this.bot); + } else { + manager.untrackWaypoint(this.bot); + } } else { - manager.untrackWaypoint(bot); + Bukkit.getGlobalRegionScheduler().runDelayed(new NullPlugin(), (task0) -> setValue(value, count + 1), 20); } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SimulationDistanceConfig.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SimulationDistanceConfig.java index 24bce40..061e791 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SimulationDistanceConfig.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SimulationDistanceConfig.java @@ -19,6 +19,7 @@ package org.leavesmc.leaves.bot.agent.configs; import com.mojang.brigadier.arguments.IntegerArgumentType; import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import fun.bm.lophine.LophineLogger; import fun.bm.lophine.config.modules.function.FakeplayerConfig; import me.earthme.luminol.utils.NullPlugin; import net.minecraft.nbt.CompoundTag; @@ -28,7 +29,7 @@ import org.leavesmc.leaves.command.CommandContext; import static net.minecraft.network.chat.Component.literal; -public class SimulationDistanceConfig extends AbstractBotConfig { +public class SimulationDistanceConfig extends AbstractBotConfig { public SimulationDistanceConfig() { super("simulation_distance", IntegerArgumentType.integer(2, 32), SimulationDistanceConfig::new); @@ -68,10 +69,18 @@ public class SimulationDistanceConfig extends AbstractBotConfig load(nbt), 20); - } else { + load(nbt, 0); + } + + public void load(@NotNull CompoundTag nbt, int count) { + if (count > 60) { + LophineLogger.LOGGER.error("Failed to load simulation distance for a fakeplayer after 60 attempts"); + return; + } + if (this.bot != null) { this.setValue(nbt.getIntOr(getName(), FakeplayerConfig.getSimulationDistance(this.bot))); + } else { + Bukkit.getGlobalRegionScheduler().runDelayed(new NullPlugin(), (task0) -> load(nbt, count + 1), 20); } } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SkipSleepConfig.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SkipSleepConfig.java index 53c2b97..f8a8737 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SkipSleepConfig.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SkipSleepConfig.java @@ -18,15 +18,15 @@ package org.leavesmc.leaves.bot.agent.configs; import com.mojang.brigadier.arguments.BoolArgumentType; +import fun.bm.lophine.LophineLogger; import fun.bm.lophine.config.modules.function.FakeplayerConfig; import me.earthme.luminol.utils.NullPlugin; import net.minecraft.nbt.CompoundTag; import org.bukkit.Bukkit; import org.jetbrains.annotations.NotNull; -import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.command.CommandContext; -public class SkipSleepConfig extends AbstractBotConfig { +public class SkipSleepConfig extends AbstractBotConfig { public SkipSleepConfig() { super("skip_sleep", BoolArgumentType.bool(), SkipSleepConfig::new); @@ -38,16 +38,20 @@ public class SkipSleepConfig extends AbstractBotConfig setValue(value), 20); - } else { - setValue(value, this.bot); - } + public void setValue(Boolean value) throws IllegalArgumentException { + setValue(value, 0); } - public void setValue(@NotNull Boolean value, ServerBot bot) throws IllegalArgumentException { - bot.fauxSleeping = value; + public void setValue(Boolean value, int count) throws IllegalArgumentException { + if (count > 60) { + LophineLogger.LOGGER.error("Failed to set skip sleep config for a fakeplayer after 60 attempts."); + return; + } + if (this.bot != null) { + bot.fauxSleeping = value; + } else { + Bukkit.getGlobalRegionScheduler().runDelayed(new NullPlugin(), (task0) -> setValue(value, count + 1), 20); + } } @Override diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SpawnPhantomConfig.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SpawnPhantomConfig.java index 986c389..7e55bdd 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SpawnPhantomConfig.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/SpawnPhantomConfig.java @@ -20,13 +20,11 @@ package org.leavesmc.leaves.bot.agent.configs; import com.mojang.brigadier.arguments.BoolArgumentType; import fun.bm.lophine.config.modules.function.FakeplayerConfig; import net.minecraft.nbt.CompoundTag; -import org.apache.commons.lang3.tuple.Pair; import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.bot.agent.ExtraData; import org.leavesmc.leaves.command.CommandContext; -import java.util.List; - -public class SpawnPhantomConfig extends AbstractBotConfig { +public class SpawnPhantomConfig extends AbstractBotConfig { private boolean value; public SpawnPhantomConfig() { @@ -45,8 +43,9 @@ public class SpawnPhantomConfig extends AbstractBotConfig> getExtraData() { - return List.of(Pair.of("not_sleeping_ticks", String.valueOf(bot.notSleepTicks))); + public String getExtraDataString(@NotNull ExtraData data) { + data.add("not_sleeping_ticks", String.valueOf(bot.notSleepTicks)); + return super.getExtraDataString(data); } @Override diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/TickTypeConfig.java b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/TickTypeConfig.java index 36bcdaf..69ac1ea 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/TickTypeConfig.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/bot/agent/configs/TickTypeConfig.java @@ -17,37 +17,26 @@ package org.leavesmc.leaves.bot.agent.configs; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; import fun.bm.lophine.config.modules.function.FakeplayerConfig; import net.minecraft.nbt.CompoundTag; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.command.CommandContext; +import org.leavesmc.leaves.command.arguments.EnumArgumentType; -public class TickTypeConfig extends AbstractBotConfig { +import java.util.Locale; + +public class TickTypeConfig extends AbstractBotConfig { private ServerBot.TickType value; public TickTypeConfig() { - super("tick_type", StringArgumentType.word(), TickTypeConfig::new); + super("tick_type", EnumArgumentType.fromEnum(ServerBot.TickType.class), TickTypeConfig::new); this.value = FakeplayerConfig.tickType; } @Override - public void applySuggestions(CommandContext context, @NotNull SuggestionsBuilder builder) { - builder.suggest("network"); - builder.suggest("entity_list"); - } - - @Override - public ServerBot.TickType loadFromCommand(@NotNull CommandContext context) throws CommandSyntaxException { - String raw = context.getString(getName()); - return switch (raw) { - case "network" -> ServerBot.TickType.NETWORK; - case "entity_list" -> ServerBot.TickType.ENTITY_LIST; - default -> throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); - }; + public ServerBot.TickType loadFromCommand(@NotNull CommandContext context) { + return context.getArgument("tick_type", ServerBot.TickType.class); } @Override @@ -64,14 +53,14 @@ public class TickTypeConfig extends AbstractBotConfig ServerBot.TickType.NETWORK; case "entity_list" -> ServerBot.TickType.ENTITY_LIST; default -> throw new IllegalStateException("Unexpected bot tick type value: " + raw); diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/arguments/BotArgumentType.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/arguments/BotArgumentType.java new file mode 100644 index 0000000..b460a3e --- /dev/null +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/arguments/BotArgumentType.java @@ -0,0 +1,71 @@ +/* + * This file is part of Leaves (https://github.com/LeavesMC/Leaves) + * + * Leaves is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Leaves is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Leaves. If not, see . + */ + +package org.leavesmc.leaves.command.arguments; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.NotNull; +import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.ServerBot; + +import java.util.Collection; +import java.util.concurrent.CompletableFuture; + +public class BotArgumentType implements CustomArgumentType.Converted<@NotNull ServerBot, @NotNull String> { + + private BotArgumentType() { + } + + public static @NotNull BotArgumentType bot() { + return new BotArgumentType(); + } + + @Override + public @NotNull CompletableFuture listSuggestions(com.mojang.brigadier.context.@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) { + Collection bots = BotList.INSTANCE.bots; + if (bots.isEmpty()) { + return builder + .suggest("", Component.literal("There are no bots in the server, create one first.")) + .buildFuture(); + } + bots.stream().map(ServerBot::getScoreboardName).forEach(builder::suggest); + return builder.buildFuture(); + } + + @Override + public ServerBot convert(String nativeType) throws CommandSyntaxException { + ServerBot bot = BotList.INSTANCE.getBotByName(nativeType); + if (bot == null) { + throw new CommandSyntaxException( + CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), + Component.literal("Bot with name '" + nativeType + "' does not exist") + ); + } + return bot; + } + + @Override + public @NotNull ArgumentType<@NotNull String> getNativeType() { + return StringArgumentType.word(); + } +} diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/arguments/EnumArgumentType.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/arguments/EnumArgumentType.java new file mode 100644 index 0000000..38fd7e4 --- /dev/null +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/arguments/EnumArgumentType.java @@ -0,0 +1,98 @@ +/* + * This file is part of Leaves (https://github.com/LeavesMC/Leaves) + * + * Leaves is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Leaves is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Leaves. If not, see . + */ + +package org.leavesmc.leaves.command.arguments; + +import com.mojang.brigadier.arguments.ArgumentType; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.Suggestions; +import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import io.papermc.paper.command.brigadier.argument.CustomArgumentType; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; +import java.util.concurrent.CompletableFuture; + +@SuppressWarnings("ClassCanBeRecord") +public final class EnumArgumentType> implements CustomArgumentType.Converted<@NotNull T, @NotNull String> { + private final Class enumClass; + + @Contract(value = "_ -> new", pure = true) + public static > @NotNull EnumArgumentType fromEnum(Class enumClass) { + return new EnumArgumentType<>(enumClass); + } + + private EnumArgumentType(Class enumClass) { + this.enumClass = enumClass; + } + + @Override + public @NotNull T convert(@NotNull String nativeType) throws CommandSyntaxException { + try { + return Enum.valueOf(enumClass, nativeType.toUpperCase()); + } catch (IllegalArgumentException e) { + throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); + } + } + + @Override + public @NotNull CompletableFuture listSuggestions(@NotNull CommandContext context, @NotNull SuggestionsBuilder builder) { + for (Enum value : enumClass.getEnumConstants()) { + String name = value.name().toLowerCase(); + if (name.startsWith(builder.getRemainingLowerCase())) { + builder.suggest(name); + } + } + return builder.buildFuture(); + } + + @Override + public @NotNull ArgumentType<@NotNull String> getNativeType() { + return StringArgumentType.word(); + } + + public Class enumClass() { + return enumClass; + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj == null || obj.getClass() != this.getClass()) { + return false; + } + EnumArgumentType that = (EnumArgumentType) obj; + return Objects.equals(this.enumClass, that.enumClass); + } + + @Override + public int hashCode() { + return Objects.hash(enumClass); + } + + @Override + public String toString() { + return "EnumArgumentType[" + + "enumClass=" + enumClass + ']'; + } + +} diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotArgument.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotArgument.java deleted file mode 100644 index 792e098..0000000 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotArgument.java +++ /dev/null @@ -1,46 +0,0 @@ -package org.leavesmc.leaves.command.bot; - -import com.mojang.brigadier.arguments.ArgumentType; -import com.mojang.brigadier.arguments.StringArgumentType; -import com.mojang.brigadier.exceptions.CommandSyntaxException; -import com.mojang.brigadier.suggestion.Suggestions; -import com.mojang.brigadier.suggestion.SuggestionsBuilder; -import net.minecraft.network.chat.Component; -import org.leavesmc.leaves.bot.BotList; -import org.leavesmc.leaves.bot.ServerBot; -import org.leavesmc.leaves.command.CommandContext; -import org.leavesmc.leaves.command.CustomArgumentType; - -import java.util.Collection; -import java.util.concurrent.CompletableFuture; - -public class BotArgument implements CustomArgumentType { - @Override - public ArgumentType getBaseArgumentType() { - return StringArgumentType.word(); - } - - @Override - public ServerBot transform(String value) throws CommandSyntaxException { - ServerBot bot = BotList.INSTANCE.getBotByName(value); - if (bot == null) { - throw new CommandSyntaxException( - CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument(), - Component.literal("Bot with name '" + value + "' does not exist") - ); - } - return bot; - } - - @Override - public CompletableFuture getSuggestions(CommandContext context, SuggestionsBuilder builder) throws CommandSyntaxException { - Collection bots = BotList.INSTANCE.bots; - if (bots.isEmpty()) { - return builder - .suggest("", Component.literal("There are no bots in the server, create one first.")) - .buildFuture(); - } - bots.stream().map(ServerBot::getScoreboardName).forEach(builder::suggest); - return builder.buildFuture(); - } -} diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotCommand.java index b4dfc24..29e6280 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotCommand.java @@ -18,7 +18,7 @@ package org.leavesmc.leaves.command.bot; import com.mojang.brigadier.builder.ArgumentBuilder; -import net.minecraft.commands.CommandSourceStack; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.command.RootNode; @@ -52,7 +52,7 @@ public class BotCommand extends RootNode { return sender.hasPermission(PERM_BASE); } - public static boolean hasPermission(@NotNull CommandSender sender, String... subcommand) { - return hasPermission(PERM_BASE, sender, subcommand); + public static boolean hasPermission(@NotNull CommandSender sender, String subcommand) { + return sender.hasPermission(PERM_BASE) || sender.hasPermission(PERM_BASE + "." + subcommand); } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotSubcommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotSubcommand.java index 4c4ebda..f09bddf 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotSubcommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/BotSubcommand.java @@ -17,12 +17,11 @@ package org.leavesmc.leaves.command.bot; -import net.minecraft.commands.CommandSourceStack; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.command.LiteralNode; public abstract class BotSubcommand extends LiteralNode { - protected BotSubcommand(String name) { super(name); } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ActionCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ActionCommand.java index 09691e5..f893d0e 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ActionCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ActionCommand.java @@ -17,13 +17,13 @@ package org.leavesmc.leaves.command.bot.subcommands; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import fun.bm.lophine.config.modules.function.FakeplayerConfig; -import net.minecraft.commands.CommandSourceStack; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.command.ArgumentNode; import org.leavesmc.leaves.command.CommandContext; -import org.leavesmc.leaves.command.CustomArgumentNode; +import org.leavesmc.leaves.command.arguments.BotArgumentType; import org.leavesmc.leaves.command.bot.BotSubcommand; import org.leavesmc.leaves.command.bot.subcommands.action.ListCommand; import org.leavesmc.leaves.command.bot.subcommands.action.StartCommand; @@ -41,10 +41,10 @@ public class ActionCommand extends BotSubcommand { return FakeplayerConfig.canUseAction && super.requires(source); } - public static class BotArgument extends CustomArgumentNode { + public static class BotArgument extends ArgumentNode { private BotArgument() { - super("bot", new org.leavesmc.leaves.command.bot.BotArgument()); + super("bot", BotArgumentType.bot()); children( StartCommand::new, StopCommand::new, @@ -52,8 +52,8 @@ public class ActionCommand extends BotSubcommand { ); } - public static @NotNull ServerBot getBot(@NotNull CommandContext context) throws CommandSyntaxException { - return context.getCustomArgument(BotArgument.class); + public static @NotNull ServerBot getBot(@NotNull CommandContext context) { + return context.getArgument(BotArgument.class); } } } \ No newline at end of file diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ConfigCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ConfigCommand.java index 6c66d2c..767b7c6 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ConfigCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ConfigCommand.java @@ -21,16 +21,17 @@ import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.builder.RequiredArgumentBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; import fun.bm.lophine.config.modules.function.FakeplayerConfig; -import net.minecraft.commands.CommandSourceStack; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.bot.agent.Configs; import org.leavesmc.leaves.bot.agent.configs.AbstractBotConfig; +import org.leavesmc.leaves.command.ArgumentNode; import org.leavesmc.leaves.command.CommandContext; -import org.leavesmc.leaves.command.CustomArgumentNode; import org.leavesmc.leaves.command.LiteralNode; +import org.leavesmc.leaves.command.arguments.BotArgumentType; import org.leavesmc.leaves.command.bot.BotSubcommand; import java.util.Collection; @@ -55,35 +56,33 @@ public class ConfigCommand extends BotSubcommand { return FakeplayerConfig.canModifyConfig && super.requires(source); } - private static class BotArgument extends CustomArgumentNode { + private static class BotArgument extends ArgumentNode { private BotArgument() { - super("bot", new org.leavesmc.leaves.command.bot.BotArgument()); - Configs.getConfigs().stream() - .map(this::configNodeCreator) - .forEach(this::children); + super("bot", BotArgumentType.bot()); + Configs.getConfigs().stream().map(this::configNodeCreator).forEach(this::children); } @Contract(pure = true) - private @NotNull Supplier configNodeCreator(AbstractBotConfig config) { + private @NotNull Supplier configNodeCreator(AbstractBotConfig config) { return () -> new ConfigNode<>(config); } - public static @NotNull ServerBot getBot(@NotNull CommandContext context) throws CommandSyntaxException { - return context.getCustomArgument(BotArgument.class); + public static @NotNull ServerBot getBot(@NotNull CommandContext context) { + return context.getArgument(BotArgument.class); } @Override - protected boolean execute(CommandContext context) throws CommandSyntaxException { + protected boolean execute(CommandContext context) { ServerBot bot = BotArgument.getBot(context); CommandSender sender = context.getSender(); - Collection> botConfigs = bot.getAllConfigs(); + Collection> botConfigs = bot.getAllConfigs(); sender.sendMessage(join(spaces(), text("Bot", GRAY), asAdventure(bot.getDisplayName()).append(text("'s", GRAY)), text("configs:", GRAY) )); - for (AbstractBotConfig botConfig : botConfigs) { + for (AbstractBotConfig botConfig : botConfigs) { sender.sendMessage(join(spaces(), botConfig.getNameComponent(), text("=", GRAY), @@ -94,10 +93,10 @@ public class ConfigCommand extends BotSubcommand { } } - private static class ConfigNode extends LiteralNode { - private final AbstractBotConfig config; + private static class ConfigNode extends LiteralNode { + private final AbstractBotConfig config; - private ConfigNode(@NotNull AbstractBotConfig config) { + private ConfigNode(@NotNull AbstractBotConfig config) { super(config.getName()); this.config = config; } @@ -110,14 +109,13 @@ public class ConfigCommand extends BotSubcommand { CommandContext ctx = new CommandContext(mojangCtx); return executeSet(ctx) ? 1 : 0; }); - return super.compileBase() - .then(argument); + return super.compileBase().then(argument); } @Override - protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException { + protected boolean execute(@NotNull CommandContext context) { ServerBot bot = BotArgument.getBot(context); - AbstractBotConfig botConfig = bot.getConfig(config); + AbstractBotConfig botConfig = bot.getConfig(config); context.getSender().sendMessage(join(spaces(), text("Bot", GRAY), asAdventure(bot.getDisplayName()).append(text("'s", GRAY)), @@ -131,7 +129,7 @@ public class ConfigCommand extends BotSubcommand { private boolean executeSet(CommandContext context) throws CommandSyntaxException { ServerBot bot = BotArgument.getBot(context); - AbstractBotConfig botConfig = bot.getConfig(config); + AbstractBotConfig botConfig = bot.getConfig(config); try { botConfig.setValue(botConfig.loadFromCommand(context)); } catch (ClassCastException e) { diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/CreateCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/CreateCommand.java index 68d7b56..7ef7564 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/CreateCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/CreateCommand.java @@ -20,29 +20,27 @@ package org.leavesmc.leaves.command.bot.subcommands; import com.mojang.brigadier.arguments.StringArgumentType; import com.mojang.brigadier.exceptions.CommandSyntaxException; import fun.bm.lophine.config.modules.function.FakeplayerConfig; +import io.papermc.paper.command.brigadier.CommandSourceStack; +import io.papermc.paper.command.brigadier.argument.ArgumentTypes; +import io.papermc.paper.command.brigadier.argument.resolvers.FinePositionResolver; import net.kyori.adventure.text.format.NamedTextColor; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.commands.arguments.DimensionArgument; -import net.minecraft.commands.arguments.coordinates.Coordinates; -import net.minecraft.commands.arguments.coordinates.Vec3Argument; -import net.minecraft.resources.Identifier; -import net.minecraft.world.phys.Vec3; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.command.CommandSender; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.entity.Entity; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.BotCreateState; import org.leavesmc.leaves.bot.BotList; +import org.leavesmc.leaves.bot.BotUtil; import org.leavesmc.leaves.command.ArgumentNode; import org.leavesmc.leaves.command.CommandContext; import org.leavesmc.leaves.command.bot.BotSubcommand; import org.leavesmc.leaves.event.bot.BotCreateEvent; import static net.kyori.adventure.text.Component.text; -import static net.minecraft.commands.arguments.DimensionArgument.getDimension; public class CreateCommand extends BotSubcommand { @@ -54,15 +52,16 @@ public class CreateCommand extends BotSubcommand { protected static boolean handleCreateCommand(@NotNull CommandContext context) throws CommandSyntaxException { CommandSender sender = context.getSender(); - String name = context.getArgument(NameArgument.class); - if (!canCreate(sender, name)) { + String rawName = context.getArgument(NameArgument.class); + String fullName = BotUtil.getFullName(rawName); + if (!canCreate(sender, fullName)) { // Check full name return false; } - String skinName = context.getArgumentOrDefault(SkinNameArgument.class, name); + String skinName = context.getArgumentOrDefault(SkinNameArgument.class, rawName); // Use raw name for correct skin World world; try { - world = getDimension(context.getMojangContext(), "world").getWorld(); + world = context.getArgument(WorldArgument.class); } catch (IllegalArgumentException e) { if (!(sender instanceof Entity entity)) { sender.sendMessage(text("Must specify world and location when executed by console", NamedTextColor.RED)); @@ -72,16 +71,16 @@ public class CreateCommand extends BotSubcommand { } Location location = Bukkit.getWorlds().getFirst().getSpawnLocation(); - Coordinates coords = context.getArgumentOrDefault(LocationArgument.class, null); - if (coords != null) { - Vec3 vec3 = coords.getPosition(context.getSource()); - location = new Location(world, vec3.x, vec3.y, vec3.z); + FinePositionResolver positionResolver = context.getArgumentOrDefault(LocationArgument.class, null); + if (positionResolver != null) { + Vector vec3 = positionResolver.resolve(context.getSource()).toVector(); + location = new Location(world, vec3.getX(), vec3.getY(), vec3.getZ()); } else if (sender instanceof Entity entity) { location = entity.getLocation(); } BotCreateState - .builder(name, location) + .builder(rawName, location) .createReason(BotCreateEvent.CreateReason.COMMAND) .skinName(skinName) .creator(sender) @@ -116,7 +115,6 @@ public class CreateCommand extends BotSubcommand { } private static class NameArgument extends ArgumentNode { - private NameArgument() { super("name", StringArgumentType.word()); children(SkinNameArgument::new); @@ -129,7 +127,6 @@ public class CreateCommand extends BotSubcommand { } private static class SkinNameArgument extends ArgumentNode { - private SkinNameArgument() { super("skin_name", StringArgumentType.word()); children(WorldArgument::new); @@ -141,10 +138,9 @@ public class CreateCommand extends BotSubcommand { } } - private static class WorldArgument extends ArgumentNode { - + private static class WorldArgument extends ArgumentNode { private WorldArgument() { - super("world", DimensionArgument.dimension()); + super("world", ArgumentTypes.world()); children(LocationArgument::new); } @@ -154,10 +150,9 @@ public class CreateCommand extends BotSubcommand { } } - private static class LocationArgument extends ArgumentNode { - + private static class LocationArgument extends ArgumentNode { private LocationArgument() { - super("location", Vec3Argument.vec3(true)); + super("location", ArgumentTypes.finePosition()); } @Override diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ListCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ListCommand.java index 5008032..5287449 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ListCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/ListCommand.java @@ -20,10 +20,8 @@ package org.leavesmc.leaves.command.bot.subcommands; import com.mojang.brigadier.exceptions.CommandSyntaxException; import fun.bm.lophine.config.modules.function.FakeplayerConfig; import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.command.brigadier.argument.ArgumentTypes; import net.kyori.adventure.text.Component; -import net.minecraft.commands.arguments.DimensionArgument; -import net.minecraft.resources.Identifier; -import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.player.Player; import org.bukkit.Bukkit; import org.bukkit.World; @@ -45,8 +43,6 @@ import static net.kyori.adventure.text.Component.text; import static net.kyori.adventure.text.JoinConfiguration.noSeparators; import static net.kyori.adventure.text.event.HoverEvent.showText; import static net.kyori.adventure.text.format.NamedTextColor.*; -import static net.minecraft.commands.arguments.DimensionArgument.getDimension; - public class ListCommand extends BotSubcommand { @@ -93,16 +89,16 @@ public class ListCommand extends BotSubcommand { ); } - private static class WorldArgument extends ArgumentNode { + private static class WorldArgument extends ArgumentNode { private WorldArgument() { - super("world", DimensionArgument.dimension()); + super("world", ArgumentTypes.world()); } @Override - protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException { - ServerLevel dimension = getDimension(context.getMojangContext(), "world"); - Component botListMessage = getBotListMessage(dimension.getWorld()); + protected boolean execute(@NotNull CommandContext context) { + World world = context.getArgument(WorldArgument.class); + Component botListMessage = getBotListMessage(world); CommandSender sender = context.getSender(); if (botListMessage == null) { sender.sendMessage(text("No bots in that world", RED)); diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/LoadCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/LoadCommand.java index 31c8884..964fd4a 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/LoadCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/LoadCommand.java @@ -22,8 +22,8 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; import fun.bm.lophine.config.modules.function.FakeplayerConfig; +import io.papermc.paper.command.brigadier.CommandSourceStack; import net.kyori.adventure.text.format.NamedTextColor; -import net.minecraft.commands.CommandSourceStack; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.BotList; @@ -63,27 +63,27 @@ public class LoadCommand extends BotSubcommand { String botName = context.getArgument(BotNameArgument.class); BotList botList = BotList.INSTANCE; CommandSender sender = context.getSender(); - if (!botList.getSavedBotList().contains(botName)) { + if (!botList.getManualSavedBotList().contains(botName)) { throw CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherUnknownArgument().create(); } + if (botList.getBotByName(botName) != null) { + sender.sendMessage(text("Bot with name " + botName + " already exists!", NamedTextColor.RED)); + return false; + } - ServerBot bot = botList.loadNewBot(botName); + ServerBot bot = botList.loadNewManualSavedBot(botName); if (bot == null) { sender.sendMessage(text("Failed to load bot, please check log", NamedTextColor.RED)); return false; } - sender.sendMessage(join( - spaces(), - text("Successfully loaded bot", NamedTextColor.GRAY), - asAdventure(bot.getDisplayName()) - )); + sender.sendMessage(join(spaces(), text("Successfully loaded bot", NamedTextColor.GRAY), asAdventure(bot.getDisplayName()))); return true; } @Override protected CompletableFuture getSuggestions(CommandContext context, @NotNull SuggestionsBuilder builder) { BotList botList = BotList.INSTANCE; - Set bots = botList.getSavedBotList().keySet(); + Set bots = botList.getManualSavedBotList().keySet(); if (bots.isEmpty()) { return builder .suggest("", net.minecraft.network.chat.Component.literal("There are no bots saved before, save one first.")) diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/RemoveCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/RemoveCommand.java index 35a7b35..2bdf131 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/RemoveCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/RemoveCommand.java @@ -30,7 +30,7 @@ import org.leavesmc.leaves.bot.BotList; import org.leavesmc.leaves.bot.ServerBot; import org.leavesmc.leaves.command.ArgumentNode; import org.leavesmc.leaves.command.CommandContext; -import org.leavesmc.leaves.command.CustomArgumentNode; +import org.leavesmc.leaves.command.arguments.BotArgumentType; import org.leavesmc.leaves.command.bot.BotSubcommand; import org.leavesmc.leaves.event.bot.BotRemoveEvent; import org.leavesmc.leaves.plugin.MinecraftInternalPlugin; @@ -65,7 +65,7 @@ public class RemoveCommand extends BotSubcommand { } private static boolean removeBotOrigin(@NotNull ServerBot bot, @Nullable CommandSender sender) { - boolean success = BotList.INSTANCE.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false); + boolean success = BotList.INSTANCE.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, false, false); if (!success) { sender = sender == null ? Bukkit.getConsoleSender() : sender; sender.sendMessage(text("Bot remove canceled by a plugin", RED)); @@ -73,16 +73,15 @@ public class RemoveCommand extends BotSubcommand { return success; } - private static class BotArgument extends CustomArgumentNode { - + private static class BotArgument extends ArgumentNode { private BotArgument() { - super("bot", new org.leavesmc.leaves.command.bot.BotArgument()); + super("bot", BotArgumentType.bot()); children(RemoveTimeArgument::new); } @Override - protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException { - ServerBot bot = context.getCustomArgument(BotArgument.class); + protected boolean execute(@NotNull CommandContext context) { + ServerBot bot = context.getArgument(BotArgument.class); return removeBot(bot, context.getSender()); } } @@ -97,7 +96,7 @@ public class RemoveCommand extends BotSubcommand { protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException { String removeTimeStr = context.getArgument("remove_time", String.class); int removeTimeSeconds = parseRemoveTime(removeTimeStr); - ServerBot bot = context.getCustomArgument(BotArgument.class); + ServerBot bot = context.getArgument(BotArgument.class); CommandSender sender = context.getSender(); boolean isReschedule = bot.removeTaskId != -1; @@ -141,22 +140,25 @@ public class RemoveCommand extends BotSubcommand { } Matcher matcher = Pattern.compile("(\\d+)([hmsHMS])").matcher(timeStr); - int seconds = 0; + long seconds = 0; boolean foundMatch = false; while (matcher.find()) { foundMatch = true; - int value = Integer.parseInt(matcher.group(1)); + long value; + try { + value = Long.parseLong(matcher.group(1)); + } catch (NumberFormatException e) { + throw new CommandSyntaxException( + CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException(), + literal("Number too large: " + matcher.group(1)) + ); + } + switch (matcher.group(2).toLowerCase()) { - case "h": - seconds += value * 3600; - break; - case "m": - seconds += value * 60; - break; - case "s": - seconds += value; - break; + case "h" -> seconds += value * 3600; + case "m" -> seconds += value * 60; + case "s" -> seconds += value; } } @@ -167,7 +169,14 @@ public class RemoveCommand extends BotSubcommand { ); } - return seconds; + if (seconds > Integer.MAX_VALUE) { + throw new CommandSyntaxException( + CommandSyntaxException.BUILT_IN_EXCEPTIONS.dispatcherParseException(), + literal("Total time exceeds maximum limit") + ); + } + + return (int) seconds; } private static @NotNull String formatSeconds(int totalSeconds) { diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/SaveCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/SaveCommand.java index 5feda17..7c53f76 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/SaveCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/SaveCommand.java @@ -17,17 +17,16 @@ package org.leavesmc.leaves.command.bot.subcommands; -import com.mojang.brigadier.exceptions.CommandSyntaxException; import fun.bm.lophine.config.modules.function.FakeplayerConfig; +import io.papermc.paper.command.brigadier.CommandSourceStack; import net.kyori.adventure.text.format.NamedTextColor; -import net.minecraft.commands.CommandSourceStack; -import net.minecraft.world.entity.LivingEntity; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.NotNull; import org.leavesmc.leaves.bot.BotList; import org.leavesmc.leaves.bot.ServerBot; +import org.leavesmc.leaves.command.ArgumentNode; import org.leavesmc.leaves.command.CommandContext; -import org.leavesmc.leaves.command.CustomArgumentNode; +import org.leavesmc.leaves.command.arguments.BotArgumentType; import org.leavesmc.leaves.command.bot.BotSubcommand; import org.leavesmc.leaves.event.bot.BotRemoveEvent; @@ -48,40 +47,24 @@ public class SaveCommand extends BotSubcommand { return FakeplayerConfig.canManualSaveAndLoad && super.requires(source); } - private static class BotArgument extends CustomArgumentNode { + private static class BotArgument extends ArgumentNode { private BotArgument() { - super("bot", new org.leavesmc.leaves.command.bot.BotArgument()); + super("bot", BotArgumentType.bot()); } @Override - protected boolean execute(@NotNull CommandContext context) throws CommandSyntaxException { - save(context.getCustomArgument(BotArgument.class), context.getSender()); - return true; - } - - private boolean save(ServerBot bot, CommandSender sender) { - return save(bot, sender, true); - } - - private boolean save(ServerBot bot, CommandSender sender, boolean taskQueue) { - if (taskQueue) { - bot.getBukkitEntity().taskScheduler.schedule((LivingEntity nmsEntity) -> saveOrigin(bot, sender), null, 1L); - } else { - saveOrigin(bot, sender); - } - return true; - } - - private boolean saveOrigin(ServerBot bot, CommandSender sender) { + protected boolean execute(@NotNull CommandContext context) { + ServerBot bot = context.getArgument(BotArgument.class); + CommandSender sender = context.getSender(); BotList botList = BotList.INSTANCE; - boolean success = botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, true); + boolean success = botList.removeBot(bot, BotRemoveEvent.RemoveReason.COMMAND, sender, true, false); if (success) { sender.sendMessage(join(spaces(), text("Successfully saved bot", NamedTextColor.GRAY), asAdventure(bot.getDisplayName()), - text("as " + bot.createState.realName(), NamedTextColor.GRAY) + text("as " + bot.createState.fullName(), NamedTextColor.GRAY) )); } else { sender.sendMessage(text("Bot save canceled by a plugin", NamedTextColor.RED)); diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/ListCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/ListCommand.java index 3c65fa4..57a0261 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/ListCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/ListCommand.java @@ -53,10 +53,7 @@ public class ListCommand extends LiteralNode { return true; } - sender.sendMessage( - asAdventure(bot.getDisplayName()) - .append(text("'s action list:", GRAY)) - ); + sender.sendMessage(asAdventure(bot.getDisplayName()).append(text("'s action list:", GRAY))); for (int i = 0; i < actions.size(); i++) { AbstractBotAction action = actions.get(i); sender.sendMessage(join(spaces(), diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/StartCommand.java b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/StartCommand.java index 2ef4faa..402e9b0 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/StartCommand.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/command/bot/subcommands/action/StartCommand.java @@ -20,7 +20,7 @@ package org.leavesmc.leaves.command.bot.subcommands.action; import com.mojang.brigadier.Command; import com.mojang.brigadier.builder.ArgumentBuilder; import com.mojang.brigadier.exceptions.CommandSyntaxException; -import net.minecraft.commands.CommandSourceStack; +import io.papermc.paper.command.brigadier.CommandSourceStack; import org.apache.commons.lang3.tuple.Pair; import org.bukkit.command.CommandSender; import org.jetbrains.annotations.Contract; @@ -49,10 +49,7 @@ public class StartCommand extends LiteralNode { public StartCommand() { super("start"); - Actions.getAll() - .stream() - .map(this::actionNodeCreator) - .forEach(this::children); + Actions.getAll().stream().map(this::actionNodeCreator).forEach(this::children); } private boolean handleStartCommand(CommandContext context, @NotNull AbstractBotAction action) throws CommandSyntaxException { diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java b/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java index 6b7c489..229a757 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBot.java @@ -46,8 +46,8 @@ public class CraftBot extends CraftPlayer implements Bot { } @Override - public @NotNull String getRealName() { - return this.getHandle().createState.realName(); + public @NotNull String getRawName() { + return this.getHandle().createState.rawName(); } @Override @@ -92,7 +92,12 @@ public class CraftBot extends CraftPlayer implements Bot { @Override public boolean remove(boolean save) { - return BotList.INSTANCE.removeBot(this.getHandle(), BotRemoveEvent.RemoveReason.PLUGIN, null, save); + return BotList.INSTANCE.removeBot(this.getHandle(), BotRemoveEvent.RemoveReason.PLUGIN, null, save, false); + } + + @Override + public boolean remove(boolean save, boolean resume) { + return BotList.INSTANCE.removeBot(this.getHandle(), BotRemoveEvent.RemoveReason.PLUGIN, null, save, resume); } @Override diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBotManager.java b/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBotManager.java index 67cbcca..5a6f23b 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBotManager.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/entity/bot/CraftBotManager.java @@ -85,7 +85,7 @@ public class CraftBotManager implements BotManager { } @Override - public BotCreator botCreator(@NotNull String realName, @NotNull Location location) { - return BotCreateState.builder(realName, location).createReason(BotCreateEvent.CreateReason.PLUGIN); + public BotCreator botCreator(@NotNull String rawName, @NotNull Location location) { + return BotCreateState.builder(rawName, location).createReason(BotCreateEvent.CreateReason.PLUGIN); } } diff --git a/lophine-server/src/main/java/org/leavesmc/leaves/util/HopperCounter.java b/lophine-server/src/main/java/org/leavesmc/leaves/util/HopperCounter.java index 917fdf5..8d10f1f 100644 --- a/lophine-server/src/main/java/org/leavesmc/leaves/util/HopperCounter.java +++ b/lophine-server/src/main/java/org/leavesmc/leaves/util/HopperCounter.java @@ -81,32 +81,32 @@ public class HopperCounter { this.coloredName = Component.text(color.getName(), TextColor.color(color.getTextColor())); } - public void add(Level level, ItemStack stack) { + public void add(MinecraftServer server, ItemStack stack) { if (startTick < 0) { - startTick = level.getGameTime(); + startTick = server.overworld().getGameTime(); startMillis = System.currentTimeMillis(); } Item item = stack.getItem(); counter.put(item, counter.getLong(item) + stack.getCount()); } - public void reset(Level level) { + public void reset(MinecraftServer server) { counter.clear(); - startTick = level.getGameTime(); + startTick = server.overworld().getGameTime(); startMillis = System.currentTimeMillis(); } - public static void resetAll(Level level, boolean fresh) { + public static void resetAll(MinecraftServer server, boolean fresh) { for (HopperCounter counter : COUNTERS.values()) { - counter.reset(level); + counter.reset(server); if (fresh) { counter.startTick = -1; } } } - public List format(MinecraftServer server, Level level, boolean realTime) { - long ticks = Math.max(realTime ? (System.currentTimeMillis() - startMillis) / 50 : level.getGameTime() - startTick, -1); + public List format(MinecraftServer server, boolean realTime) { + long ticks = Math.max(realTime ? (System.currentTimeMillis() - startMillis) / 50 : server.overworld().getGameTime() - startTick, -1); if (startTick < 0 || ticks == -1) { return Collections.singletonList(Component.text().append(coloredName, Component.text(" hasn't started counting yet")).build());