From 272900d52ea1cf0a45ff0061aa1e15798efd222c Mon Sep 17 00:00:00 2001 From: Anon Date: Fri, 23 Jun 2023 16:25:18 +0200 Subject: [PATCH] Added slab handling for 1.20/.1 Added Farm bot crops handling for 1.20/.1 Added utilities for Containers/Inventories Added bot movement lock to prevent multiple bots that use movements from running at the same time. General code improvements. --- MinecraftClient/ChatBots/AntiAFK.cs | 51 +- MinecraftClient/ChatBots/Farmer.cs | 670 +++++++-------- MinecraftClient/ChatBots/FollowPlayer.cs | 71 +- MinecraftClient/ChatBots/ItemsCollector.cs | 21 +- MinecraftClient/ChatBots/WebSocketBot.cs | 2 +- .../Inventory/ContainerExtensions.cs | 58 ++ MinecraftClient/Mapping/BlockExtension.cs | 798 ++++++++++-------- .../Protocol/Handlers/Protocol18.cs | 12 + .../Translations/Translations.Designer.cs | 14 +- .../Resources/Translations/Translations.resx | 6 + MinecraftClient/Scripting/BotMovementLock.cs | 35 + 11 files changed, 941 insertions(+), 797 deletions(-) create mode 100644 MinecraftClient/Inventory/ContainerExtensions.cs create mode 100644 MinecraftClient/Scripting/BotMovementLock.cs diff --git a/MinecraftClient/ChatBots/AntiAFK.cs b/MinecraftClient/ChatBots/AntiAFK.cs index bb43045d59..30d47189e5 100644 --- a/MinecraftClient/ChatBots/AntiAFK.cs +++ b/MinecraftClient/ChatBots/AntiAFK.cs @@ -8,7 +8,6 @@ namespace MinecraftClient.ChatBots /// /// This bot sends a command every 60 seconds in order to stay non-afk. /// - public class AntiAFK : ChatBot { public static Configs Config = new(); @@ -16,8 +15,7 @@ public class AntiAFK : ChatBot [TomlDoNotInlineObject] public class Configs { - [NonSerialized] - private const string BotName = "AntiAFK"; + [NonSerialized] private const string BotName = "AntiAFK"; public bool Enabled = false; @@ -99,6 +97,13 @@ public override void Initialize() { LogToConsole(Translations.bot_antiafk_not_using_terrain_handling); } + else + { + var movementLock = BotMovementLock.Instance; + if (movementLock is { IsLocked: true }) + LogToConsole( + $"§§6§1§0{string.Format(Translations.bot_antiafk_may_not_move, movementLock.LockedBy)}"); + } } } @@ -106,25 +111,22 @@ public override void Update() { count++; - if (count >= nextrun) - { - DoAntiAfkStuff(); - count = 0; - nextrun = random.Next(Settings.DoubleToTick(Config.Delay.min), Settings.DoubleToTick(Config.Delay.max)); - } - + if (count < nextrun) return; + DoAntiAfkStuff(); + count = 0; + nextrun = random.Next(Settings.DoubleToTick(Config.Delay.min), Settings.DoubleToTick(Config.Delay.max)); } private void DoAntiAfkStuff() { - if (Config.Use_Terrain_Handling && GetTerrainEnabled()) + var isMovementLocked = BotMovementLock.Instance; + if (Config.Use_Terrain_Handling && GetTerrainEnabled() && isMovementLocked is {IsLocked: false}) { - Location currentLocation = GetCurrentLocation(); - Location goal; + var currentLocation = GetCurrentLocation(); - bool moved = false; - bool useAlternativeMethod = false; - int triesCounter = 0; + var moved = false; + var useAlternativeMethod = false; + var triesCounter = 0; while (!moved) { @@ -134,10 +136,11 @@ private void DoAntiAfkStuff() break; } - goal = GetRandomLocationWithinRangeXZ(currentLocation, Config.Walk_Range); + var goal = GetRandomLocationWithinRangeXZ(currentLocation, Config.Walk_Range); // Prevent getting the same location - while ((currentLocation.X == goal.X) && (currentLocation.Y == goal.Y) && (currentLocation.Z == goal.Z)) + while ((currentLocation.X == goal.X) && (currentLocation.Y == goal.Y) && + (currentLocation.Z == goal.Z)) { LogToConsole("Same location!, generating new one"); goal = GetRandomLocationWithinRangeXZ(currentLocation, Config.Walk_Range); @@ -148,10 +151,8 @@ private void DoAntiAfkStuff() useAlternativeMethod = true; break; } - else - { - moved = MoveToLocation(goal, allowUnsafe: false, allowDirectTeleport: false); - } + + moved = MoveToLocation(goal, allowUnsafe: false, allowDirectTeleport: false); } if (!useAlternativeMethod && Config.Use_Sneak) @@ -169,12 +170,14 @@ private void DoAntiAfkStuff() Sneak(previousSneakState); previousSneakState = !previousSneakState; } + count = 0; } private Location GetRandomLocationWithinRangeXZ(Location currentLocation, int range) { - return new Location(currentLocation.X + random.Next(range * -1, range), currentLocation.Y, currentLocation.Z + random.Next(range * -1, range)); + return new Location(currentLocation.X + random.Next(range * -1, range), currentLocation.Y, + currentLocation.Z + random.Next(range * -1, range)); } } -} +} \ No newline at end of file diff --git a/MinecraftClient/ChatBots/Farmer.cs b/MinecraftClient/ChatBots/Farmer.cs index 24d03e312e..5723225343 100644 --- a/MinecraftClient/ChatBots/Farmer.cs +++ b/MinecraftClient/ChatBots/Farmer.cs @@ -7,6 +7,7 @@ using Brigadier.NET.Builder; using MinecraftClient.CommandHandler; using MinecraftClient.CommandHandler.Patch; +using MinecraftClient.Commands; using MinecraftClient.Inventory; using MinecraftClient.Mapping; using MinecraftClient.Protocol.Handlers; @@ -24,8 +25,7 @@ public class Farmer : ChatBot [TomlDoNotInlineObject] public class Configs { - [NonSerialized] - private const string BotName = "Farmer"; + [NonSerialized] private const string BotName = "Farmer"; public bool Enabled = false; @@ -39,12 +39,12 @@ public void OnSettingUpdate() } } - public enum State + private enum State { SearchingForCropsToBreak = 0, SearchingForFarmlandToPlant, - PlantingCrops, - BonemealingCrops + BoneMealingCrops, + CollectingItems } public enum CropType @@ -52,7 +52,7 @@ public enum CropType Beetroot, Carrot, Melon, - Netherwart, + NetherWart, Pumpkin, Potato, Wheat @@ -66,9 +66,10 @@ public enum CropType private bool allowTeleport = false; private bool debugEnabled = false; - public int Delay_Between_Tasks_Millisecond => (int)Math.Round(Config.Delay_Between_Tasks * 1000); + private int Delay_Between_Tasks_Millisecond => (int)Math.Round(Config.Delay_Between_Tasks * 1000); - private const string commandDescription = "farmer [radius:] [unsafe:] [teleport:] [debug:]|stop>"; + private const string commandDescription = + "farmer [radius:] [unsafe:] [teleport:] [debug:]|stop>"; public override void Initialize() { @@ -103,7 +104,8 @@ public override void Initialize() .Then(l => l.Argument("CropType", MccArguments.FarmerCropType()) .Executes(r => OnCommandStart(r.Source, MccArguments.GetFarmerCropType(r, "CropType"), null)) .Then(l => l.Argument("OtherArgs", Arguments.GreedyString()) - .Executes(r => OnCommandStart(r.Source, MccArguments.GetFarmerCropType(r, "CropType"), Arguments.GetString(r, "OtherArgs")))))) + .Executes(r => OnCommandStart(r.Source, MccArguments.GetFarmerCropType(r, "CropType"), + Arguments.GetString(r, "OtherArgs")))))) .Then(l => l.Literal("_help") .Executes(r => OnCommandHelp(r.Source, string.Empty)) .Redirect(McClient.dispatcher.GetRoot().GetChild("help").GetChild(CommandName))) @@ -112,6 +114,8 @@ public override void Initialize() public override void OnUnload() { + running = false; + BotMovementLock.Instance?.UnLock("Farmer"); McClient.dispatcher.Unregister(CommandName); McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } @@ -145,7 +149,12 @@ private int OnCommandStart(CmdResult r, CropType whatToFarm, string? otherArgs) if (running) return r.SetAndReturn(CmdResult.Status.Fail, Translations.bot_farmer_already_running); - int radius = 30; + var movementLock = BotMovementLock.Instance; + if (movementLock is { IsLocked: true }) + return r.SetAndReturn(CmdResult.Status.Fail, + string.Format(Translations.bot_common_movement_lock_held, "Farmer", movementLock.LockedBy)); + + var radius = 30; state = State.SearchingForFarmlandToPlant; cropType = whatToFarm; @@ -155,20 +164,22 @@ private int OnCommandStart(CmdResult r, CropType whatToFarm, string? otherArgs) if (!string.IsNullOrWhiteSpace(otherArgs)) { - string[] args = otherArgs.ToLower().Split(' ', StringSplitOptions.TrimEntries); - foreach (string currentArg in args) + var args = otherArgs.ToLower().Split(' ', StringSplitOptions.TrimEntries); + foreach (var currentArg in args) { if (!currentArg.Contains(':')) { - LogToConsole("§§6§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); + LogToConsole( + $"§§6§1§0{string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)}"); continue; } - string[] parts = currentArg.Split(":", StringSplitOptions.TrimEntries); + var parts = currentArg.Split(":", StringSplitOptions.TrimEntries); if (parts.Length != 2) { - LogToConsole("§§6§1§0" + string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)); + LogToConsole( + $"§§6§1§0{string.Format(Translations.bot_farmer_warining_invalid_parameter, currentArg)}"); continue; } @@ -177,11 +188,11 @@ private int OnCommandStart(CmdResult r, CropType whatToFarm, string? otherArgs) case "r": case "radius": if (!int.TryParse(parts[1], NumberStyles.Any, CultureInfo.CurrentCulture, out radius)) - LogToConsole("§§6§1§0" + Translations.bot_farmer_invalid_radius); + LogToConsole($"§§6§1§0{Translations.bot_farmer_invalid_radius}"); if (radius <= 0) { - LogToConsole("§§6§1§0" + Translations.bot_farmer_invalid_radius); + LogToConsole($"§§6§1§0{Translations.bot_farmer_invalid_radius}"); radius = 30; } @@ -194,7 +205,7 @@ private int OnCommandStart(CmdResult r, CropType whatToFarm, string? otherArgs) if (parts[1].Equals("true") || parts[1].Equals("1")) { - LogToConsole("§§6§1§0" + Translations.bot_farmer_warining_force_unsafe); + LogToConsole($"§§6§1§0{Translations.bot_farmer_warining_force_unsafe}"); allowUnsafe = true; } else allowUnsafe = false; @@ -208,7 +219,7 @@ private int OnCommandStart(CmdResult r, CropType whatToFarm, string? otherArgs) if (parts[1].Equals("true") || parts[1].Equals("1")) { - LogToConsole("§§4§1§f" + Translations.bot_farmer_warining_allow_teleport); + LogToConsole($"§§4§1§f{Translations.bot_farmer_warining_allow_teleport}"); allowTeleport = true; } else allowTeleport = false; @@ -234,27 +245,57 @@ private int OnCommandStart(CmdResult r, CropType whatToFarm, string? otherArgs) farmingRadius = radius; running = true; - new Thread(() => MainPorcess()).Start(); + new Thread(() => MainProcess()).Start(); return r.SetAndReturn(CmdResult.Status.Done); } public override void AfterGameJoined() { + BotMovementLock.Instance?.UnLock("Farmer"); running = false; } public override bool OnDisconnect(DisconnectReason reason, string message) { + BotMovementLock.Instance?.UnLock("Farmer"); running = false; return true; } - private void MainPorcess() + private void MainProcess() { - LogToConsole("§§2§1§f" + Translations.bot_farmer_started); - LogToConsole("§§2§1§f " + Translations.bot_farmer_crop_type + ": " + cropType); - LogToConsole("§§2§1§f " + Translations.bot_farmer_radius + ": " + farmingRadius); + var movementLock = BotMovementLock.Instance; + switch (movementLock) + { + case { IsLocked: false }: + if (!movementLock.Lock("Farmer")) + { + running = false; + LogToConsole($"§§6§1§0Farmer bot failed to obtain the movement lock for some reason!"); + LogToConsole($"§§6§1§0Disable other bots who have movement mechanics, and try again!"); + return; + } + + LogDebug($"Locked the movement for other bots!"); + break; + case { IsLocked: true }: + running = false; + LogToConsole($"§§6§1§0Farmer bot failed to obtain the movement lock for some reason!"); + LogToConsole($"§§6§1§0Disable other bots who have movement mechanics, and try again!"); + return; + } + + LogToConsole($"§§2§1§f{Translations.bot_farmer_started}"); + LogToConsole($"§§2§1§f {Translations.bot_farmer_crop_type}: {cropType}"); + LogToConsole($"§§2§1§f {Translations.bot_farmer_radius}: {farmingRadius}"); + + var itemTypes = new List + { + GetSeedItemTypeForCropType(cropType), + GetCropItemTypeForCropType(cropType) + }; + itemTypes = itemTypes.Distinct().ToList(); while (running) { @@ -271,9 +312,9 @@ private void MainPorcess() case State.SearchingForFarmlandToPlant: LogDebug("Looking for farmland..."); - ItemType cropTypeToPlant = GetSeedItemTypeForCropType(cropType); + var cropTypeToPlant = GetSeedItemTypeForCropType(cropType); - // If we don't have any seeds on our hotbar, skip this step and try collecting some + // If we don't have any seeds on our hot bar, skip this step and try collecting some if (!SwitchToItem(cropTypeToPlant)) { LogDebug("No seeds, trying to find some crops to break"); @@ -282,7 +323,7 @@ private void MainPorcess() continue; } - List farmlandToPlantOn = findEmptyFarmland(farmingRadius); + var farmlandToPlantOn = FindEmptyFarmland(farmingRadius); if (farmlandToPlantOn.Count == 0) { @@ -292,11 +333,9 @@ private void MainPorcess() continue; } - int i = 0; - foreach (Location location in farmlandToPlantOn) + var i = 0; + foreach (var location in farmlandToPlantOn.TakeWhile(location => running)) { - if (!running) break; - // Check only every second iteration, minor optimization xD if (i % 2 == 0) { @@ -309,14 +348,15 @@ private void MainPorcess() } } - double yValue = Math.Floor(location.Y) + 1; + var yValue = Math.Floor(location.Y) + 1; // TODO: Figure out why this is not working. // Why we need this: sometimes the server kicks the player for "invalid movement" packets. - /*if (cropType == CropType.Netherwart) + /*if (cropType == CropType.NetherWart) yValue = (double)(Math.Floor(location.Y) - 1.0) + (double)0.87500;*/ - Location location2 = new Location(Math.Floor(location.X) + 0.5, yValue, Math.Floor(location.Z) + 0.5); + var location2 = new Location(Math.Floor(location.X) + 0.5, yValue, + Math.Floor(location.Z) + 0.5); if (WaitForMoveToLocation(location2)) { @@ -329,7 +369,8 @@ private void MainPorcess() break; } - Location loc = new Location(Math.Floor(location.X), Math.Floor(location2.Y), Math.Floor(location.Z)); + var loc = new Location(Math.Floor(location.X), Math.Floor(location2.Y), + Math.Floor(location.Z)); LogDebug("Sending placeblock to: " + loc); SendPlaceBlock(loc, Direction.Up); @@ -347,21 +388,21 @@ private void MainPorcess() case State.SearchingForCropsToBreak: LogDebug("Searching for crops to break..."); - List cropsToCollect = findCrops(farmingRadius, cropType, true); + var cropsToCollect = findCrops(farmingRadius, cropType, true); if (cropsToCollect.Count == 0) { - LogToConsole("No crops to break, trying to bonemeal ungrown ones"); - state = State.BonemealingCrops; + LogToConsole("No crops to break, trying to bone meal un-grown ones"); + state = State.BoneMealingCrops; Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } // Switch to an axe for faster breaking if the bot has one in his inventory - if (cropType == CropType.Melon || cropType == CropType.Pumpkin) + if (cropType is CropType.Melon or CropType.Pumpkin) { // Start from Diamond axe, if not found, try a tier lower axe - bool switched = SwitchToItem(ItemType.DiamondAxe); + var switched = SwitchToItem(ItemType.DiamondAxe); if (!switched) switched = SwitchToItem(ItemType.IronAxe); @@ -373,12 +414,10 @@ private void MainPorcess() SwitchToItem(ItemType.StoneAxe); } - foreach (Location location in cropsToCollect) + foreach (var location in cropsToCollect.TakeWhile(location => running)) { - if (!running) break; - // God damn C# rounding it to 0.94 - // This will be needed when bot bonemeals carrots or potatoes which are at the first stage of growth, + // This will be needed when bot bone meals carrots or potatoes which are at the first stage of growth, // because sometimes the bot walks over crops and breaks them // TODO: Figure out a fix // new Location(Math.Floor(location.X) + 0.5, (double)((location.Y - 1) + (double)0.93750), Math.Floor(location.Z) + 0.5) @@ -387,46 +426,44 @@ private void MainPorcess() WaitForDigBlock(location); // Allow some time to pickup the item - Thread.Sleep(cropType == CropType.Melon || cropType == CropType.Pumpkin ? 400 : 200); + Thread.Sleep(cropType is CropType.Melon or CropType.Pumpkin ? 400 : 200); } LogDebug("Finished breaking crops!"); - state = State.BonemealingCrops; + state = State.BoneMealingCrops; break; - case State.BonemealingCrops: - // Can't be bonemealed - if (cropType == CropType.Netherwart) + case State.BoneMealingCrops: + // Can't be bone mealed + if (cropType == CropType.NetherWart) { state = State.SearchingForFarmlandToPlant; Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } - // If we don't have any bonemeal on our hotbar, skip this step + // If we don't have any bone meal on our hot bar, skip this step if (!SwitchToItem(ItemType.BoneMeal)) { - LogDebug("No bonemeal, searching for some farmland to plant seeds on"); + LogDebug("No bone meal, searching for some farmland to plant seeds on"); state = State.SearchingForFarmlandToPlant; Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } - List cropsToBonemeal = findCrops(farmingRadius, cropType, false); + var cropsToBonemeal = findCrops(farmingRadius, cropType, false); if (cropsToBonemeal.Count == 0) { - LogDebug("No crops to bonemeal, searching for farmland to plant seeds on"); + LogDebug("No crops to bone meal, searching for farmland to plant seeds on"); state = State.SearchingForFarmlandToPlant; Thread.Sleep(Delay_Between_Tasks_Millisecond); continue; } - int i2 = 0; - foreach (Location location in cropsToBonemeal) + var i2 = 0; + foreach (var location in cropsToBonemeal.TakeWhile(location => running)) { - if (!running) break; - // Check only every second iteration, minor optimization xD if (i2 % 2 == 0) { @@ -441,18 +478,21 @@ private void MainPorcess() if (WaitForMoveToLocation(location)) { - // Stop if we do not have any more bonemeal left + // Stop if we do not have any more bone meal left if (!SwitchToItem(ItemType.BoneMeal)) { - LogDebug("No bonemeal, searching for some farmland to plant seeds on..."); + LogDebug("No bone meal, searching for some farmland to plant seeds on..."); break; } - Location location2 = new Location(Math.Floor(location.X) + 0.5, location.Y, Math.Floor(location.Z) + 0.5); - LogDebug("Trying to bonemeal: " + location2); + var location2 = new Location(Math.Floor(location.X) + 0.5, location.Y, + Math.Floor(location.Z) + 0.5); + LogDebug("Trying to bone meal: " + location2); - // Send like 4 bonemeal attempts, it should do the job with 2-3, but sometimes doesn't do - for (int boneMealTimes = 0; boneMealTimes < (cropType == CropType.Beetroot ? 6 : 5); boneMealTimes++) + // Send like 4 bone meal attempts, it should do the job with 2-3, but sometimes doesn't do + for (var boneMealTimes = 0; + boneMealTimes < (cropType == CropType.Beetroot ? 6 : 5); + boneMealTimes++) { // TODO: Do a check if the carrot/potato is on the first growth stage // if so, use: new Location(location.X, (double)(location.Y - 1) + (double)0.93750, location.Z) @@ -465,100 +505,118 @@ private void MainPorcess() i2++; } - LogDebug("Finished bonemealing crops!"); + LogDebug("Finished bone mealing crops!"); + state = State.CollectingItems; + break; + + case State.CollectingItems: + LogDebug("Searching for items to collect..."); + + var currentLocation = GetCurrentLocation(); + var items = GetEntities() + .Where(x => + x.Value.Type == EntityType.Item && + x.Value.Location.Distance(currentLocation) <= farmingRadius && + itemTypes.Contains(x.Value.Item.Type)) + .Select(x => x.Value) + .ToList(); + items = items.OrderBy(x => x.Location.Distance(currentLocation)).ToList(); + + if (items.Any()) + { + LogDebug("Collecting items..."); + + foreach (var entity in items.TakeWhile(entity => running)) + WaitForMoveToLocation(entity.Location); + + LogDebug("Finished collecting items!"); + } + else LogDebug("No items to collect!"); + state = State.SearchingForFarmlandToPlant; break; } - LogDebug(string.Format("Waiting for {0:0.00} seconds for next cycle.", Config.Delay_Between_Tasks)); + LogDebug($"Waiting for {Config.Delay_Between_Tasks:0.00} seconds for next cycle."); Thread.Sleep(Delay_Between_Tasks_Millisecond); } + movementLock?.UnLock("Farmer"); + LogDebug($"Unlocked the movement for other bots!"); LogToConsole(Translations.bot_farmer_stopped); } - private Material GetMaterialForCropType(CropType type) + private static Material GetMaterialForCropType(CropType type) { - switch (type) + return type switch { - case CropType.Beetroot: - return Material.Beetroots; - - case CropType.Carrot: - return Material.Carrots; - - case CropType.Melon: - return Material.Melon; - - case CropType.Netherwart: - return Material.NetherWart; - - case CropType.Pumpkin: - return Material.Pumpkin; - - case CropType.Potato: - return Material.Potatoes; - - case CropType.Wheat: - return Material.Wheat; - } - - throw new Exception("Material type for " + type.GetType().Name + " has not been mapped!"); + CropType.Beetroot => Material.Beetroots, + CropType.Carrot => Material.Carrots, + CropType.Melon => Material.Melon, + CropType.NetherWart => Material.NetherWart, + CropType.Pumpkin => Material.Pumpkin, + CropType.Potato => Material.Potatoes, + CropType.Wheat => Material.Wheat, + _ => throw new Exception("Material type for " + type.GetType().Name + " has not been mapped!") + }; } - private ItemType GetSeedItemTypeForCropType(CropType type) + private static ItemType GetSeedItemTypeForCropType(CropType type) { - switch (type) + return type switch { - case CropType.Beetroot: - return ItemType.BeetrootSeeds; - - case CropType.Carrot: - return ItemType.Carrot; - - case CropType.Melon: - return ItemType.MelonSeeds; - - case CropType.Netherwart: - return ItemType.NetherWart; - - case CropType.Pumpkin: - return ItemType.PumpkinSeeds; - - case CropType.Potato: - return ItemType.Potato; - - case CropType.Wheat: - return ItemType.WheatSeeds; - } + CropType.Beetroot => ItemType.BeetrootSeeds, + CropType.Carrot => ItemType.Carrot, + CropType.Melon => ItemType.MelonSeeds, + CropType.NetherWart => ItemType.NetherWart, + CropType.Pumpkin => ItemType.PumpkinSeeds, + CropType.Potato => ItemType.Potato, + CropType.Wheat => ItemType.WheatSeeds, + _ => throw new Exception("Seed type for " + type.GetType().Name + " has not been mapped!") + }; + } - throw new Exception("Seed type for " + type.GetType().Name + " has not been mapped!"); + private static ItemType GetCropItemTypeForCropType(CropType type) + { + return type switch + { + CropType.Beetroot => ItemType.Beetroot, + CropType.Carrot => ItemType.Carrot, + CropType.Melon => ItemType.Melon, + CropType.NetherWart => ItemType.NetherWart, + CropType.Pumpkin => ItemType.Pumpkin, + CropType.Potato => ItemType.Potato, + CropType.Wheat => ItemType.Wheat, + _ => throw new Exception("Item type for " + type.GetType().Name + " has not been mapped!") + }; } - private List findEmptyFarmland(int radius) + private List FindEmptyFarmland(int radius) { return GetWorld() - .FindBlock(GetCurrentLocation(), cropType == CropType.Netherwart ? Material.SoulSand : Material.Farmland, radius) - .Where(location => GetWorld().GetBlock(new Location(location.X, location.Y + 1, location.Z)).Type == Material.Air) - .ToList(); + .FindBlock(GetCurrentLocation(), + cropType == CropType.NetherWart ? Material.SoulSand : Material.Farmland, radius) + .Where(location => GetWorld().GetBlock(new Location(location.X, location.Y + 1, location.Z)).Type == + Material.Air) + .ToList(); } private List findCrops(int radius, CropType cropType, bool fullyGrown) { - Material material = GetMaterialForCropType(cropType); + var material = GetMaterialForCropType(cropType); - // A bit of a hack to enable bonemealing melon and pumpkin stems - if (!fullyGrown && (cropType == CropType.Melon || cropType == CropType.Pumpkin)) + // A bit of a hack to enable bone mealing melon and pumpkin stems + if (!fullyGrown && cropType is CropType.Melon or CropType.Pumpkin) material = cropType == CropType.Melon ? Material.MelonStem : Material.PumpkinStem; return GetWorld() .FindBlock(GetCurrentLocation(), material, radius) .Where(location => { - if (fullyGrown && (material == Material.Melon || material == Material.Pumpkin)) + if (fullyGrown && material is Material.Melon or Material.Pumpkin) return true; - bool isFullyGrown = IsCropFullyGrown(GetWorld().GetBlock(location), cropType); + var isFullyGrown = IsCropFullyGrown(GetWorld().GetBlock(location), cropType); return fullyGrown ? isFullyGrown : !isFullyGrown; }) .ToList(); @@ -566,83 +624,47 @@ private List findCrops(int radius, CropType cropType, bool fullyGrown) private bool IsCropFullyGrown(Block block, CropType cropType) { - int protocolVersion = GetProtocolVersion(); + var protocolVersion = GetProtocolVersion(); switch (cropType) { case CropType.Beetroot: - if (protocolVersion == Protocol18Handler.MC_1_19_4_Version) - { - if (block.BlockId == 12356) - return true; - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - if (block.BlockId == 11887) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version && protocolVersion <= Protocol18Handler.MC_1_19_2_Version) - { - if (block.BlockId == 10103) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version && protocolVersion <= Protocol18Handler.MC_1_18_2_Version) - { - if (block.BlockId == 9472) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion <= Protocol18Handler.MC_1_16_5_Version) - { - if (block.BlockId == 9226) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion <= Protocol18Handler.MC_1_15_2_Version) + switch (protocolVersion) { - if (block.BlockId == 8686) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_13_Version && protocolVersion < Protocol18Handler.MC_1_14_Version) - { - if (block.BlockId == 8162) + case Protocol18Handler.MC_1_20_Version when block.BlockId == 12371: + case Protocol18Handler.MC_1_19_4_Version when block.BlockId == 12356: + case Protocol18Handler.MC_1_19_3_Version when block.BlockId == 11887: + case >= Protocol18Handler.MC_1_19_Version and <= Protocol18Handler.MC_1_19_2_Version + when block.BlockId == 10103: + case >= Protocol18Handler.MC_1_17_Version and <= Protocol18Handler.MC_1_18_2_Version + when block.BlockId == 9472: + case >= Protocol18Handler.MC_1_16_Version and <= Protocol18Handler.MC_1_16_5_Version + when block.BlockId == 9226: + case >= Protocol18Handler.MC_1_14_Version and <= Protocol18Handler.MC_1_15_2_Version + when block.BlockId == 8686: + case >= Protocol18Handler.MC_1_13_Version and < Protocol18Handler.MC_1_14_Version + when block.BlockId == 8162: return true; } break; case CropType.Carrot: - if (protocolVersion == Protocol18Handler.MC_1_19_4_Version) - { - if (block.BlockId == 8598) - return true; - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - if (block.BlockId == 8370) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version && protocolVersion <= Protocol18Handler.MC_1_19_2_Version) - { - if (block.BlockId == 6930) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version && protocolVersion <= Protocol18Handler.MC_1_18_2_Version) + switch (protocolVersion) { - if (block.BlockId == 6543) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion <= Protocol18Handler.MC_1_16_5_Version) - { - if (block.BlockId == 6341) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion <= Protocol18Handler.MC_1_15_2_Version) - { - if (block.BlockId == 5801) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_13_Version && protocolVersion < Protocol18Handler.MC_1_14_Version) - { - if (block.BlockId == 5295) + case Protocol18Handler.MC_1_20_Version when block.BlockId == 8602: + case Protocol18Handler.MC_1_19_4_Version when block.BlockId == 8598: + case Protocol18Handler.MC_1_19_3_Version when block.BlockId == 8370: + case >= Protocol18Handler.MC_1_19_Version and <= Protocol18Handler.MC_1_19_2_Version + when block.BlockId == 6930: + case >= Protocol18Handler.MC_1_17_Version and <= Protocol18Handler.MC_1_18_2_Version + when block.BlockId == 6543: + case >= Protocol18Handler.MC_1_16_Version and <= Protocol18Handler.MC_1_16_5_Version + when block.BlockId == 6341: + case >= Protocol18Handler.MC_1_14_Version and <= Protocol18Handler.MC_1_15_2_Version + when block.BlockId == 5801: + case >= Protocol18Handler.MC_1_13_Version and < Protocol18Handler.MC_1_14_Version + when block.BlockId == 5295: return true; } @@ -650,193 +672,106 @@ private bool IsCropFullyGrown(Block block, CropType cropType) // Checkin for stems and attached stems instead of Melons themselves case CropType.Melon: - if (protocolVersion == Protocol18Handler.MC_1_19_4_Version) - { - if (block.BlockId == 6808 || block.BlockId == 6606) - return true; - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - if (block.BlockId == 6582 || block.BlockId == 6832) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version && protocolVersion <= Protocol18Handler.MC_1_19_2_Version) - { - if (block.BlockId == 5166 || block.BlockId == 5150) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version && protocolVersion <= Protocol18Handler.MC_1_18_2_Version) - { - if (block.BlockId == 4860 || block.BlockId == 4844) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion <= Protocol18Handler.MC_1_16_5_Version) - { - if (block.BlockId == 4791 || block.BlockId == 4775) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion <= Protocol18Handler.MC_1_15_2_Version) - { - if (block.BlockId == 4771 || block.BlockId == 4755) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_13_Version && protocolVersion < Protocol18Handler.MC_1_14_Version) + switch (protocolVersion) { - if (block.BlockId == 4268 || block.BlockId == 4252) + case Protocol18Handler.MC_1_20_Version when block.BlockId is 6836 or 6820: + case Protocol18Handler.MC_1_19_4_Version when block.BlockId is 6808 or 6606: + case Protocol18Handler.MC_1_19_3_Version when block.BlockId is 6582 or 6832: + case >= Protocol18Handler.MC_1_19_Version and <= Protocol18Handler.MC_1_19_2_Version + when block.BlockId is 5166 or 5150: + case >= Protocol18Handler.MC_1_17_Version and <= Protocol18Handler.MC_1_18_2_Version + when block.BlockId is 4860 or 4844: + case >= Protocol18Handler.MC_1_16_Version and <= Protocol18Handler.MC_1_16_5_Version + when block.BlockId is 4791 or 4775: + case >= Protocol18Handler.MC_1_14_Version and <= Protocol18Handler.MC_1_15_2_Version + when block.BlockId is 4771 or 4755: + case >= Protocol18Handler.MC_1_13_Version and < Protocol18Handler.MC_1_14_Version + when block.BlockId is 4268 or 4252: return true; } + break; - - case CropType.Netherwart: - if (protocolVersion == Protocol18Handler.MC_1_19_4_Version) - { - if (block.BlockId == 7384) - return true; - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - if (block.BlockId == 7158) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version && protocolVersion <= Protocol18Handler.MC_1_19_2_Version) - { - if (block.BlockId == 5718) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version && protocolVersion <= Protocol18Handler.MC_1_18_2_Version) - { - if (block.BlockId == 5332) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion <= Protocol18Handler.MC_1_16_5_Version) - { - if (block.BlockId == 5135) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion <= Protocol18Handler.MC_1_15_2_Version) - { - if (block.BlockId == 5115) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_13_Version && protocolVersion < Protocol18Handler.MC_1_14_Version) + + case CropType.NetherWart: + switch (protocolVersion) { - if (block.BlockId == 4612) + case Protocol18Handler.MC_1_20_Version when block.BlockId == 7388: + case Protocol18Handler.MC_1_19_4_Version when block.BlockId == 7384: + case Protocol18Handler.MC_1_19_3_Version when block.BlockId == 7158: + case >= Protocol18Handler.MC_1_19_Version and <= Protocol18Handler.MC_1_19_2_Version + when block.BlockId == 5718: + case >= Protocol18Handler.MC_1_17_Version and <= Protocol18Handler.MC_1_18_2_Version + when block.BlockId == 5332: + case >= Protocol18Handler.MC_1_16_Version and <= Protocol18Handler.MC_1_16_5_Version + when block.BlockId == 5135: + case >= Protocol18Handler.MC_1_14_Version and <= Protocol18Handler.MC_1_15_2_Version + when block.BlockId == 5115: + case >= Protocol18Handler.MC_1_13_Version and < Protocol18Handler.MC_1_14_Version + when block.BlockId == 4612: return true; } + break; // Checkin for stems and attached stems instead of Pumpkins themselves case CropType.Pumpkin: - if (protocolVersion == Protocol18Handler.MC_1_19_4_Version) - { - if (block.BlockId == 5845 || block.BlockId == 6824) - return true; - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - if (block.BlockId == 5683 || block.BlockId == 6598) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version && protocolVersion <= Protocol18Handler.MC_1_19_2_Version) - { - if (block.BlockId == 5158 || block.BlockId == 5146) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version && protocolVersion <= Protocol18Handler.MC_1_18_2_Version) - { - if (block.BlockId == 4852 || block.BlockId == 4840) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion <= Protocol18Handler.MC_1_16_5_Version) + switch (protocolVersion) { - if (block.BlockId == 4783 || block.BlockId == 4771) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion <= Protocol18Handler.MC_1_15_2_Version) - { - if (block.BlockId == 4763 || block.BlockId == 4751) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_13_Version && protocolVersion < Protocol18Handler.MC_1_14_Version) - { - if (block.BlockId == 4260 || block.BlockId == 4248) + case Protocol18Handler.MC_1_20_Version when block.BlockId is 5849 or 6816: + case Protocol18Handler.MC_1_19_4_Version when block.BlockId is 5845 or 6824: + case Protocol18Handler.MC_1_19_3_Version when block.BlockId is 5683 or 6598: + case >= Protocol18Handler.MC_1_19_Version and <= Protocol18Handler.MC_1_19_2_Version + when block.BlockId is 5158 or 5146: + case >= Protocol18Handler.MC_1_17_Version and <= Protocol18Handler.MC_1_18_2_Version + when block.BlockId is 4852 or 4840: + case >= Protocol18Handler.MC_1_16_Version and <= Protocol18Handler.MC_1_16_5_Version + when block.BlockId is 4783 or 4771: + case >= Protocol18Handler.MC_1_14_Version and <= Protocol18Handler.MC_1_15_2_Version + when block.BlockId is 4763 or 4751: + case >= Protocol18Handler.MC_1_13_Version and < Protocol18Handler.MC_1_14_Version + when block.BlockId is 4260 or 4248: return true; } + break; case CropType.Potato: - if (protocolVersion == Protocol18Handler.MC_1_19_4_Version) - { - if (block.BlockId == 8606) - return true; - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - if (block.BlockId == 8378) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version && protocolVersion <= Protocol18Handler.MC_1_19_2_Version) - { - if (block.BlockId == 6938) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version && protocolVersion <= Protocol18Handler.MC_1_18_2_Version) - { - if (block.BlockId == 6551) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion <= Protocol18Handler.MC_1_16_5_Version) - { - if (block.BlockId == 6349) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion <= Protocol18Handler.MC_1_15_2_Version) + switch (protocolVersion) { - if (block.BlockId == 5809) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_13_Version && protocolVersion < Protocol18Handler.MC_1_14_Version) - { - if (block.BlockId == 5303) + case Protocol18Handler.MC_1_20_Version when block.BlockId == 8610: + case Protocol18Handler.MC_1_19_4_Version when block.BlockId == 8606: + case Protocol18Handler.MC_1_19_3_Version when block.BlockId == 8378: + case >= Protocol18Handler.MC_1_19_Version and <= Protocol18Handler.MC_1_19_2_Version + when block.BlockId == 6938: + case >= Protocol18Handler.MC_1_17_Version and <= Protocol18Handler.MC_1_18_2_Version + when block.BlockId == 6551: + case >= Protocol18Handler.MC_1_16_Version and <= Protocol18Handler.MC_1_16_5_Version + when block.BlockId == 6349: + case >= Protocol18Handler.MC_1_14_Version and <= Protocol18Handler.MC_1_15_2_Version + when block.BlockId == 5809: + case >= Protocol18Handler.MC_1_13_Version and < Protocol18Handler.MC_1_14_Version + when block.BlockId == 5303: return true; } break; case CropType.Wheat: - if (protocolVersion == Protocol18Handler.MC_1_19_4_Version) - { - if (block.BlockId == 4281) - return true; - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - if (block.BlockId == 4233) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version && protocolVersion <= Protocol18Handler.MC_1_19_2_Version) - { - if (block.BlockId == 3619) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version && protocolVersion <= Protocol18Handler.MC_1_18_2_Version) + switch (protocolVersion) { - if (block.BlockId == 3421) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version && protocolVersion <= Protocol18Handler.MC_1_16_5_Version) - { - if (block.BlockId == 3364) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version && protocolVersion <= Protocol18Handler.MC_1_15_2_Version) - { - if (block.BlockId == 3362) - return true; - } - else if (protocolVersion >= Protocol18Handler.MC_1_13_Version && protocolVersion < Protocol18Handler.MC_1_14_Version) - { - if (block.BlockId == 3059) + case Protocol18Handler.MC_1_20_Version when block.BlockId == 4285: + case Protocol18Handler.MC_1_19_4_Version when block.BlockId == 4281: + case Protocol18Handler.MC_1_19_3_Version when block.BlockId == 4233: + case >= Protocol18Handler.MC_1_19_Version and <= Protocol18Handler.MC_1_19_2_Version + when block.BlockId == 3619: + case >= Protocol18Handler.MC_1_17_Version and <= Protocol18Handler.MC_1_18_2_Version + when block.BlockId == 3421: + case >= Protocol18Handler.MC_1_16_Version and <= Protocol18Handler.MC_1_16_5_Version + when block.BlockId == 3364: + case >= Protocol18Handler.MC_1_14_Version and <= Protocol18Handler.MC_1_15_2_Version + when block.BlockId == 3362: + case >= Protocol18Handler.MC_1_13_Version and < Protocol18Handler.MC_1_14_Version + when block.BlockId == 3059: return true; } @@ -849,28 +784,27 @@ private bool IsCropFullyGrown(Block block, CropType cropType) // Yoinked from ReinforceZwei's AutoTree and adapted to search the whole of inventory in additon to the hotbar private bool SwitchToItem(ItemType itemType) { - Container playerInventory = GetPlayerInventory(); + var playerInventory = GetPlayerInventory(); - if (playerInventory.Items.ContainsKey(GetCurrentSlot() - 36) - && playerInventory.Items[GetCurrentSlot() - 36].Type == itemType) + if (playerInventory.Items.TryGetValue(GetCurrentSlot() - 36, out Item value) && value.Type == itemType) return true; // Already selected // Search the full inventory - List fullInventorySearch = new List(playerInventory.SearchItem(itemType)); + var fullInventorySearch = new List(playerInventory.SearchItem(itemType)); - // Search for the seed in the hotbar - List hotbarSerch = fullInventorySearch.Where(slot => slot >= 36 && slot <= 44).ToList(); + // Search for the seed in the hot bar + var hotBarSearch = fullInventorySearch.Where(slot => slot is >= 36 and <= 44).ToList(); - if (hotbarSerch.Count > 0) + if (hotBarSearch.Count > 0) { - ChangeSlot((short)(hotbarSerch[0] - 36)); + ChangeSlot((short)(hotBarSearch[0] - 36)); return true; } if (fullInventorySearch.Count == 0) return false; - ItemMovingHelper movingHelper = new ItemMovingHelper(playerInventory, Handler); + var movingHelper = new ItemMovingHelper(playerInventory, Handler); movingHelper.Swap(fullInventorySearch[0], 36); ChangeSlot(0); @@ -897,19 +831,15 @@ private bool WaitForMoveToLocation(Location pos, float tolerance = 2f) // Yoinked from Daenges's Sugarcane Farmer private bool WaitForDigBlock(Location block, int digTimeout = 1000) { - if (DigBlock(block.ToFloor())) + if (!DigBlock(block.ToFloor())) return false; + short i = 0; // Maximum wait time of 10 sec. + while (GetWorld().GetBlock(block).Type != Material.Air && i <= digTimeout) { - short i = 0; // Maximum wait time of 10 sec. - while (GetWorld().GetBlock(block).Type != Material.Air && i <= digTimeout) - { - Thread.Sleep(100); - i++; - } - - return i <= digTimeout; + Thread.Sleep(100); + i++; } - return false; + return i <= digTimeout; } private bool HasItemOfTypeInInventory(ItemType itemType) @@ -924,4 +854,4 @@ private void LogDebug(object text) else LogDebugToConsole(text); } } -} +} \ No newline at end of file diff --git a/MinecraftClient/ChatBots/FollowPlayer.cs b/MinecraftClient/ChatBots/FollowPlayer.cs index 3220dfacb8..60a400297e 100644 --- a/MinecraftClient/ChatBots/FollowPlayer.cs +++ b/MinecraftClient/ChatBots/FollowPlayer.cs @@ -19,8 +19,7 @@ public class FollowPlayer : ChatBot [TomlDoNotInlineObject] public class Configs { - [NonSerialized] - private const string BotName = "FollowPlayer"; + [NonSerialized] private const string BotName = "FollowPlayer"; public bool Enabled = false; @@ -73,7 +72,8 @@ public override void Initialize() .Then(l => l.Argument("PlayerName", MccArguments.PlayerName()) .Executes(r => OnCommandStart(r.Source, Arguments.GetString(r, "PlayerName"), takeRisk: false)) .Then(l => l.Literal("-f") - .Executes(r => OnCommandStart(r.Source, Arguments.GetString(r, "PlayerName"), takeRisk: true))))) + .Executes(r => + OnCommandStart(r.Source, Arguments.GetString(r, "PlayerName"), takeRisk: true))))) .Then(l => l.Literal("stop") .Executes(r => OnCommandStop(r.Source))) .Then(l => l.Literal("_help") @@ -84,6 +84,7 @@ public override void Initialize() public override void OnUnload() { + BotMovementLock.Instance?.UnLock("Follow Player"); McClient.dispatcher.Unregister(CommandName); McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } @@ -104,7 +105,7 @@ private int OnCommandStart(CmdResult r, string name, bool takeRisk) if (!IsValidName(name)) return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_invalid_name); - Entity? player = GetEntities().Values.ToList().Find(entity => + var player = GetEntities().Values.ToList().Find(entity => entity.Type == EntityType.Player && !string.IsNullOrEmpty(entity.Name) && entity.Name.Equals(name, StringComparison.OrdinalIgnoreCase)); @@ -116,22 +117,37 @@ private int OnCommandStart(CmdResult r, string name, bool takeRisk) return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_cant_reach_player); if (_playerToFollow != null && _playerToFollow.Equals(name, StringComparison.OrdinalIgnoreCase)) - return r.SetAndReturn(CmdResult.Status.Fail, string.Format(Translations.cmd_follow_already_following, _playerToFollow)); - - string result; - if (_playerToFollow != null) - result = string.Format(Translations.cmd_follow_switched, player.Name!); - else - result = string.Format(Translations.cmd_follow_started, player.Name!); + return r.SetAndReturn(CmdResult.Status.Fail, + string.Format(Translations.cmd_follow_already_following, _playerToFollow)); + + var movementLock = BotMovementLock.Instance; + if (movementLock is { IsLocked: true }) + return r.SetAndReturn(CmdResult.Status.Fail, + string.Format(Translations.bot_common_movement_lock_held, "Follow Player", movementLock.LockedBy)); + + var result = + string.Format( + _playerToFollow != null ? Translations.cmd_follow_switched : Translations.cmd_follow_started, + player.Name!); _playerToFollow = name.ToLower(); - if (takeRisk) + switch (movementLock) { - _unsafeEnabled = true; - return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_note + '\n' + Translations.cmd_follow_unsafe_enabled); + case { IsLocked: false }: + if (!movementLock.Lock("Follow Player")) + { + LogToConsole($"§§6§1§0Follow Player bot failed to obtain the movement lock for some reason!"); + LogToConsole($"§§6§1§0Disable other bots who have movement mechanics, and try again!"); + return r.SetAndReturn(CmdResult.Status.Fail); + } + + break; } - else - return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_note); + + if (!takeRisk) return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_note); + _unsafeEnabled = true; + return r.SetAndReturn(CmdResult.Status.Done, + Translations.cmd_follow_note + '\n' + Translations.cmd_follow_unsafe_enabled); } private int OnCommandStop(CmdResult r) @@ -139,6 +155,8 @@ private int OnCommandStop(CmdResult r) if (_playerToFollow == null) return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_follow_already_stopped); + var movementLock = BotMovementLock.Instance; + movementLock?.UnLock("Follow Player"); _playerToFollow = null; return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_follow_stopping); @@ -168,8 +186,8 @@ public override void OnEntityMove(Entity entity) if (!CanMoveThere(entity.Location)) return; - // Stop at specified distance from plater (prevents pushing player around) - double distance = entity.Location.Distance(GetCurrentLocation()); + // Stop at specified distance from player (prevents pushing player around) + var distance = entity.Location.Distance(GetCurrentLocation()); if (distance < Config.Stop_At_Distance) return; @@ -182,7 +200,8 @@ public override void OnEntitySpawn(Entity entity) if (entity.Type != EntityType.Player) return; - if (_playerToFollow != null && !string.IsNullOrEmpty(entity.Name) && _playerToFollow.Equals(entity.Name, StringComparison.OrdinalIgnoreCase)) + if (_playerToFollow != null && !string.IsNullOrEmpty(entity.Name) && + _playerToFollow.Equals(entity.Name, StringComparison.OrdinalIgnoreCase)) { LogToConsole(string.Format(Translations.cmd_follow_player_came_to_the_range, _playerToFollow)); LogToConsole(Translations.cmd_follow_resuming); @@ -194,7 +213,8 @@ public override void OnEntityDespawn(Entity entity) if (entity.Type != EntityType.Player) return; - if (_playerToFollow != null && !string.IsNullOrEmpty(entity.Name) && _playerToFollow.Equals(entity.Name, StringComparison.OrdinalIgnoreCase)) + if (_playerToFollow != null && !string.IsNullOrEmpty(entity.Name) && + _playerToFollow.Equals(entity.Name, StringComparison.OrdinalIgnoreCase)) { LogToConsole(string.Format(Translations.cmd_follow_player_left_the_range, _playerToFollow)); LogToConsole(Translations.cmd_follow_pausing); @@ -203,7 +223,8 @@ public override void OnEntityDespawn(Entity entity) public override void OnPlayerLeave(Guid uuid, string? name) { - if (_playerToFollow != null && !string.IsNullOrEmpty(name) && _playerToFollow.Equals(name, StringComparison.OrdinalIgnoreCase)) + if (_playerToFollow != null && !string.IsNullOrEmpty(name) && + _playerToFollow.Equals(name, StringComparison.OrdinalIgnoreCase)) { LogToConsole(string.Format(Translations.cmd_follow_player_left, _playerToFollow)); LogToConsole(Translations.cmd_follow_stopping); @@ -213,12 +234,8 @@ public override void OnPlayerLeave(Guid uuid, string? name) private bool CanMoveThere(Location location) { - ChunkColumn? chunkColumn = GetWorld().GetChunkColumn(location); - - if (chunkColumn == null || chunkColumn.FullyLoaded == false) - return false; - - return true; + var chunkColumn = GetWorld().GetChunkColumn(location); + return chunkColumn != null && chunkColumn.FullyLoaded != false; } } } \ No newline at end of file diff --git a/MinecraftClient/ChatBots/ItemsCollector.cs b/MinecraftClient/ChatBots/ItemsCollector.cs index 60df749ab6..0c513ffb30 100644 --- a/MinecraftClient/ChatBots/ItemsCollector.cs +++ b/MinecraftClient/ChatBots/ItemsCollector.cs @@ -89,6 +89,7 @@ public override void Initialize() public override void OnUnload() { + StopTheMainProcess(); McClient.dispatcher.Unregister(CommandName); McClient.dispatcher.GetRoot().GetChild("help").RemoveChild(CommandName); } @@ -109,6 +110,18 @@ private int OnCommandStart(CmdResult r) if (running) return r.SetAndReturn(CmdResult.Status.Fail, Translations.cmd_items_collector_already_collecting); + var movementLock = BotMovementLock.Instance; + if (movementLock is { IsLocked: true }) + return r.SetAndReturn(CmdResult.Status.Fail, + string.Format(Translations.bot_common_movement_lock_held, "Items Collector", movementLock.LockedBy)); + + if (!movementLock!.Lock("Items Collector")) + { + LogToConsole($"§§6§1§0Items Collector bot failed to obtain the movement lock for some reason!"); + LogToConsole($"§§6§1§0Disable other bots who have movement mechanics, and try again!"); + return r.SetAndReturn(CmdResult.Status.Fail); + } + StartTheMainProcess(); return r.SetAndReturn(CmdResult.Status.Done, Translations.cmd_items_collector_started); } @@ -132,6 +145,7 @@ private void StartTheMainProcess() private void StopTheMainProcess() { running = false; + BotMovementLock.Instance?.UnLock("Items Collector"); } private void MainProcess() @@ -163,13 +177,8 @@ private void MainProcess() if (items.Any()) { - foreach (var entity in items) - { - if (!running) - break; - + foreach (var entity in items.TakeWhile(entity => running)) WaitForMoveToLocation(entity.Location); - } } else { diff --git a/MinecraftClient/ChatBots/WebSocketBot.cs b/MinecraftClient/ChatBots/WebSocketBot.cs index cb19e0e803..6ba4395e06 100644 --- a/MinecraftClient/ChatBots/WebSocketBot.cs +++ b/MinecraftClient/ChatBots/WebSocketBot.cs @@ -283,7 +283,7 @@ public class Configs public int Port = 8043; [TomlInlineComment("$ChatBot.WebSocketBot.Password$")] - public string? Password = "wspass12345"; + public string? Password = Guid.NewGuid().ToString().Replace("-", "").Trim().ToLower(); [TomlInlineComment("$ChatBot.WebSocketBot.DebugMode$")] public bool DebugMode = false; diff --git a/MinecraftClient/Inventory/ContainerExtensions.cs b/MinecraftClient/Inventory/ContainerExtensions.cs new file mode 100644 index 0000000000..6e6306356d --- /dev/null +++ b/MinecraftClient/Inventory/ContainerExtensions.cs @@ -0,0 +1,58 @@ +using System; + +namespace MinecraftClient.Inventory; + +using System.Linq; +using System.Linq.Expressions; + +public enum ComparisonType +{ + Equals, + NotEquals, + Less, + LessOrEqual, + Greater, + GreaterOrEqual +} + +public static class ContainerExtensions +{ + public static bool IsFull(this Container container) => + container.Items.Values.All(item => item.Count >= item.Type.StackCount()); + + public static int FirstEmptySlot(this Container container) => + container.Items.FirstOrDefault(slot => slot.Value.IsEmpty).Key; + + public static int FirstSlotWithItem(this Container container, ItemType type, int? count = null, + ComparisonType comparison = ComparisonType.Equals) => + container.Items.FirstOrDefault(slot => + slot.Value.Type == type && + (!count.HasValue || CompareCounts(slot.Value.Count, count.Value, comparison))).Key; + + public static int LastSlotWithItem(this Container container, ItemType type, int? count = null, + ComparisonType comparison = ComparisonType.Equals) => + container.Items.LastOrDefault(slot => + slot.Value.Type == type && + (!count.HasValue || CompareCounts(slot.Value.Count, count.Value, comparison))) + .Key; + + // We could have used "Expression> comparison = null" instead of "ComparisonType comparison", but it would look ugly to use + private static bool CompareCounts(int value1, int value2, ComparisonType comparison) + { + var left = Expression.Constant(value1); + var right = Expression.Constant(value2); + + Expression binaryExpression = comparison switch + { + ComparisonType.Less => Expression.LessThan(left, right), + ComparisonType.LessOrEqual => Expression.LessThanOrEqual(left, right), + ComparisonType.Greater => Expression.GreaterThan(left, right), + ComparisonType.GreaterOrEqual => Expression.GreaterThanOrEqual(left, right), + ComparisonType.Equals => Expression.Equal(left, right), + ComparisonType.NotEquals => Expression.NotEqual(left, right), + _ => Expression.Equal(left, right) + }; + + return Expression.Lambda>(binaryExpression).Compile().Invoke(); + } +} \ No newline at end of file diff --git a/MinecraftClient/Mapping/BlockExtension.cs b/MinecraftClient/Mapping/BlockExtension.cs index 9aeb193a2f..a08057adc7 100644 --- a/MinecraftClient/Mapping/BlockExtension.cs +++ b/MinecraftClient/Mapping/BlockExtension.cs @@ -6,375 +6,437 @@ public static class BlockExtension { public static bool IsTopSlab(this Block block, int protocolVersion) { - if (protocolVersion >= Protocol18Handler.MC_1_19_4_Version) + switch (protocolVersion) { - switch (block.BlockId) - { - case 11018: // OakSlab - case 11024: // SpruceSlab - case 11030: // BirchSlab - case 11036: // JungleSlab - case 11042: // AcaciaSlab - case 11054: // DarkOakSlab - case 11060: // MangroveSlab - case 18510: // CrimsonSlab - case 18516: // WarpedSlab - case 11078: // StoneSlab - case 11108: // CobblestoneSlab - case 13948: // MossyCobblestoneSlab - case 11084: // SmoothStoneSlab - case 11120: // StoneBrickSlab - case 13936: // MossyStoneBrickSlab - case 13972: // GraniteSlab - case 13924: // PolishedGraniteSlab - case 13996: // DioriteSlab - case 13942: // PolishedDioriteSlab - case 13978: // AndesiteSlab - case 13990: // PolishedAndesiteSlab - case 22132: // CobbledDeepslateSlab - case 22543: // PolishedDeepslateSlab - case 23365: // DeepslateBrickSlab - case 22954: // DeepslateTileSlab - case 11114: // BrickSlab - case 11126: // MudBrickSlab - case 11090: // SandstoneSlab - case 13960: // SmoothSandstoneSlab - case 11096: // CutSandstoneSlab - case 11144: // RedSandstoneSlab - case 13930: // SmoothRedSandstoneSlab - case 11150: // CutRedSandstoneSlab - case 10562: // PrismarineSlab - case 10568: // PrismarineBrickSlab - case 10574: // DarkPrismarineSlab - case 11132: // NetherBrickSlab - case 13984: // RedNetherBrickSlab - case 19707: // BlackstoneSlab - case 20208: // PolishedBlackstoneSlab - case 19717: // PolishedBlackstoneBrickSlab - case 13954: // EndStoneBrickSlab - case 11156: // PurpurSlab - case 11138: // QuartzSlab - case 13966: // SmoothQuartzSlab - case 21510: // CutCopperSlab - case 21504: // ExposedCutCopperSlab - case 21498: // WeatheredCutCopperSlab - case 21492: // OxidizedCutCopperSlab - case 21862: // WaxedCutCopperSlab - case 21856: // WaxedExposedCutCopperSlab - case 21850: // WaxedWeatheredCutCopperSlab - case 21844: // WaxedOxidizedCutCopperSlab - return true; - } - } - else if (protocolVersion == Protocol18Handler.MC_1_19_3_Version) - { - switch (block.BlockId) - { - case 10686: // OakSlab - case 10692: // SpruceSlab - case 10698: // BirchSlab - case 10704: // JungleSlab - case 10710: // AcaciaSlab - case 10716: // DarkOakSlab - case 10722: // MangroveSlab - case 18041: // CrimsonSlab - case 18047: // WarpedSlab - case 10740: // StoneSlab - case 10770: // CobblestoneSlab - case 13479: // MossyCobblestoneSlab - case 10746: // SmoothStoneSlab - case 10782: // StoneBrickSlab - case 13467: // MossyStoneBrickSlab - case 13503: // GraniteSlab - case 13455: // PolishedGraniteSlab - case 13527: // DioriteSlab - case 13473: // PolishedDioriteSlab - case 13509: // AndesiteSlab - case 13521: // PolishedAndesiteSlab - case 21647: // CobbledDeepslateSlab - case 22058: // PolishedDeepslateSlab - case 22880: // DeepslateBrickSlab - case 22469: // DeepslateTileSlab - case 10776: // BrickSlab - case 10788: // MudBrickSlab - case 10752: // SandstoneSlab - case 13491: // SmoothSandstoneSlab - case 10758: // CutSandstoneSlab - case 10806: // RedSandstoneSlab - case 13461: // SmoothRedSandstoneSlab - case 10812: // CutRedSandstoneSlab - case 10230: // PrismarineSlab - case 10236: // PrismarineBrickSlab - case 10242: // DarkPrismarineSlab - case 10794: // NetherBrickSlab - case 13515: // RedNetherBrickSlab - case 19238: // BlackstoneSlab - case 19739: // PolishedBlackstoneSlab - case 19248: // PolishedBlackstoneBrickSlab - case 13485: // EndStoneBrickSlab - case 10818: // PurpurSlab - case 10800: // QuartzSlab - case 13497: // SmoothQuartzSlab - case 21041: // CutCopperSlab - case 21035: // ExposedCutCopperSlab - case 21029: // WeatheredCutCopperSlab - case 21023: // OxidizedCutCopperSlab - case 21393: // WaxedCutCopperSlab - case 21387: // WaxedExposedCutCopperSlab - case 21381: // WaxedWeatheredCutCopperSlab - case 21375: // WaxedOxidizedCutCopperSlab - return true; - } - } - else if (protocolVersion >= Protocol18Handler.MC_1_19_Version) - { - switch (block.BlockId) - { - case 19257: // CutCopperSlab - case 19251: // ExposedCutCopperSlab - case 19245: // WeatheredCutCopperSlab - case 19239: // OxidizedCutCopperSlab - case 19609: // WaxedCutCopperSlab - case 19603: // WaxedExposedCutCopperSlab - case 19597: // WaxedWeatheredCutCopperSlab - case 19591: // WaxedOxidizedCutCopperSlab - case 9042: // OakSlab - case 9048: // SpruceSlab - case 9054: // BirchSlab - case 9060: // JungleSlab - case 9066: // AcaciaSlab - case 9072: // DarkOakSlab - case 9078: // MangroveSlab - case 16257: // CrimsonSlab - case 16263: // WarpedSlab - case 9084: // StoneSlab - case 9090: // SmoothStoneSlab - case 9096: // SandstoneSlab - case 9102: // CutSandstoneSlab - case 9108: // PetrifiedOakSlab - case 9114: // CobblestoneSlab - case 9120: // BrickSlab - case 9126: // StoneBrickSlab - case 9132: // MudBrickSlab - case 9138: // NetherBrickSlab - case 9144: // QuartzSlab - case 9150: // RedSandstoneSlab - case 9156: // CutRedSandstoneSlab - case 9162: // PurpurSlab - case 8586: // PrismarineSlab - case 8592: // PrismarineBrickSlab - case 8598: // DarkPrismarineSlab - case 11671: // PolishedGraniteSlab - case 11677: // SmoothRedSandstoneSlab - case 11683: // MossyStoneBrickSlab - case 11689: // PolishedDioriteSlab - case 11695: // MossyCobblestoneSlab - case 11701: // EndStoneBrickSlab - case 11707: // SmoothSandstoneSlab - case 11713: // SmoothQuartzSlab - case 11719: // GraniteSlab - case 11725: // AndesiteSlab - case 11731: // RedNetherBrickSlab - case 11737: // PolishedAndesiteSlab - case 11743: // DioriteSlab - case 19863: // CobbledDeepslateSlab - case 20274: // PolishedDeepslateSlab - case 21096: // DeepslateBrickSlab - case 20685: // DeepslateTileSlab - case 17454: // BlackstoneSlab - case 17955: // PolishedBlackstoneSlab - case 17464: // PolishedBlackstoneBrickSlab - return true; - } - } - else if (protocolVersion >= Protocol18Handler.MC_1_17_Version) - { - switch (block.BlockId) - { - case 18163: // CutCopperSlab - case 18157: // ExposedCutCopperSlab - case 18151: // WeatheredCutCopperSlab - case 18145: // OxidizedCutCopperSlab - case 18515: // WaxedCutCopperSlab - case 18509: // WaxedExposedCutCopperSlab - case 18503: // WaxedWeatheredCutCopperSlab - case 18497: // WaxedOxidizedCutCopperSlab - case 8551: // OakSlab - case 8557: // SpruceSlab - case 8563: // BirchSlab - case 8569: // JungleSlab - case 8575: // AcaciaSlab - case 8581: // DarkOakSlab - case 15302: // CrimsonSlab - case 15308: // WarpedSlab - case 8587: // StoneSlab - case 8593: // SmoothStoneSlab - case 8599: // SandstoneSlab - case 8605: // CutSandstoneSlab - case 8611: // PetrifiedOakSlab - case 8617: // CobblestoneSlab - case 8623: // BrickSlab - case 8629: // StoneBrickSlab - case 8635: // NetherBrickSlab - case 8641: // QuartzSlab - case 8647: // RedSandstoneSlab - case 8653: // CutRedSandstoneSlab - case 8659: // PurpurSlab - case 8095: // PrismarineSlab - case 8101: // PrismarineBrickSlab - case 8107: // DarkPrismarineSlab - case 11040: // PolishedGraniteSlab - case 11046: // SmoothRedSandstoneSlab - case 11052: // MossyStoneBrickSlab - case 11058: // PolishedDioriteSlab - case 11064: // MossyCobblestoneSlab - case 11070: // EndStoneBrickSlab - case 11076: // SmoothSandstoneSlab - case 11082: // SmoothQuartzSlab - case 11088: // GraniteSlab - case 11094: // AndesiteSlab - case 11100: // RedNetherBrickSlab - case 11106: // PolishedAndesiteSlab - case 11112: // DioriteSlab - case 18768: // CobbledDeepslateSlab - case 19179: // PolishedDeepslateSlab - case 20001: // DeepslateBrickSlab - case 19590: // DeepslateTileSlab - case 16499: // BlackstoneSlab - case 17000: // PolishedBlackstoneSlab - case 16509: // PolishedBlackstoneBrickSlab - return true; - } - } - else if (protocolVersion >= Protocol18Handler.MC_1_16_Version) - { - switch (block.BlockId) - { - case 8305: // OakSlab - case 8311: // SpruceSlab - case 8317: // BirchSlab - case 8323: // JungleSlab - case 8329: // AcaciaSlab - case 8335: // DarkOakSlab - case 15056: // CrimsonSlab - case 15062: // WarpedSlab - case 8341: // StoneSlab - case 8347: // SmoothStoneSlab - case 8353: // SandstoneSlab - case 8359: // CutSandstoneSlab - case 8365: // PetrifiedOakSlab - case 8371: // CobblestoneSlab - case 8377: // BrickSlab - case 8383: // StoneBrickSlab - case 8389: // NetherBrickSlab - case 8395: // QuartzSlab - case 8401: // RedSandstoneSlab - case 8407: // CutRedSandstoneSlab - case 8413: // PurpurSlab - case 7849: // PrismarineSlab - case 7855: // PrismarineBrickSlab - case 7861: // DarkPrismarineSlab - case 10794: // PolishedGraniteSlab - case 10800: // SmoothRedSandstoneSlab - case 10806: // MossyStoneBrickSlab - case 10812: // PolishedDioriteSlab - case 10818: // MossyCobblestoneSlab - case 10824: // EndStoneBrickSlab - case 10830: // SmoothSandstoneSlab - case 10836: // SmoothQuartzSlab - case 10842: // GraniteSlab - case 10848: // AndesiteSlab - case 10854: // RedNetherBrickSlab - case 10860: // PolishedAndesiteSlab - case 10866: // DioriteSlab - case 16253: // BlackstoneSlab - case 16754: // PolishedBlackstoneSlab - case 16263: // PolishedBlackstoneBrickSlab - return true; - } - } - else if (protocolVersion >= Protocol18Handler.MC_1_15_Version) - { - switch (block.BlockId) - { - case 7765: // OakSlab - case 7771: // SpruceSlab - case 7777: // BirchSlab - case 7783: // JungleSlab - case 7789: // AcaciaSlab - case 7795: // DarkOakSlab - case 7801: // StoneSlab - case 7807: // SmoothStoneSlab - case 7813: // SandstoneSlab - case 7819: // CutSandstoneSlab - case 7825: // PetrifiedOakSlab - case 7831: // CobblestoneSlab - case 7837: // BrickSlab - case 7843: // StoneBrickSlab - case 7849: // NetherBrickSlab - case 7855: // QuartzSlab - case 7861: // RedSandstoneSlab - case 7867: // CutRedSandstoneSlab - case 7873: // PurpurSlab - case 7309: // PrismarineSlab - case 7321: // DarkPrismarineSlab - case 10254: // PolishedGraniteSlab - case 10260: // SmoothRedSandstoneSlab - case 10266: // MossyStoneBrickSlab - case 10272: // PolishedDioriteSlab - case 10278: // MossyCobblestoneSlab - case 10284: // EndStoneBrickSlab - case 10290: // SmoothSandstoneSlab - case 10296: // SmoothQuartzSlab - case 10302: // GraniteSlab - case 10308: // AndesiteSlab - case 10314: // RedNetherBrickSlab - case 10320: // PolishedAndesiteSlab - case 10326: // DioriteSlab - return true; - } - } - else if (protocolVersion >= Protocol18Handler.MC_1_14_Version) - { - switch (block.BlockId) - { - case 7765: // OakSlab - case 7771: // SpruceSlab - case 7777: // BirchSlab - case 7783: // JungleSlab - case 7789: // AcaciaSlab - case 7795: // DarkOakSlab - case 7801: // StoneSlab - case 7807: // SmoothStoneSlab - case 7813: // SandstoneSlab - case 7819: // CutSandstoneSlab - case 7825: // PetrifiedOakSlab - case 7831: // CobblestoneSlab - case 7837: // BrickSlab - case 7843: // StoneBrickSlab - case 7849: // NetherBrickSlab - case 7855: // QuartzSlab - case 7861: // RedSandstoneSlab - case 7867: // CutRedSandstoneSlab - case 7873: // PurpurSlab - case 7309: // PrismarineSlab - case 7315: // PrismarineBrickSlab - case 7321: // DarkPrismarineSlab - case 10254: // PolishedGraniteSlab - case 10260: // SmoothRedSandstoneSlab - case 10266: // MossyStoneBrickSlab - case 10272: // PolishedDioriteSlab - case 10278: // MossyCobblestoneSlab - case 10284: // EndStoneBrickSlab - case 10290: // SmoothSandstoneSlab - case 10296: // SmoothQuartzSlab - case 10302: // GraniteSlab - case 10308: // AndesiteSlab - case 10314: // RedNetherBrickSlab - case 10320: // PolishedAndesiteSlab - case 10326: // DioriteSlab - return true; - } + case >= Protocol18Handler.MC_1_20_Version: + switch (block.BlockId) + { + case 11022: //OakSlab + case 11028: //SpruceSlab + case 11034: //BirchSlab + case 11040: //JungleSlab + case 11046: //AcaciaSlab + case 11058: //DarkOakSlab + case 11064: //MangroveSlab + case 18528: //CrimsonSlab + case 18534: //WarpedSlab + case 11082: //StoneSlab + case 11112: //CobblestoneSlab + case 13966: //MossyCobblestoneSlab + case 11088: //SmoothStoneSlab + case 11124: //StoneBrickSlab + case 13954: //MossyStoneBrickSlab + case 13990: //GraniteSlab + case 13942: //PolishedGraniteSlab + case 14014: //DioriteSlab + case 13960: //PolishedDioriteSlab + case 13996: //AndesiteSlab + case 14008: //PolishedAndesiteSlab + case 22534: //CobbledDeepslateSlab + case 22945: //PolishedDeepslateSlab + case 23767: //DeepslateBrickSlab + case 23356: //DeepslateTileSlab + case 11118: //BrickSlab + case 11130: //MudBrickSlab + case 11094: //SandstoneSlab + case 13978: //SmoothSandstoneSlab + case 11100: //CutSandstoneSlab + case 11148: //RedSandstoneSlab + case 13948: //SmoothRedSandstoneSlab + case 11154: //CutRedSandstoneSlab + case 10566: //PrismarineSlab + case 10572: //PrismarineBrickSlab + case 10578: //DarkPrismarineSlab + case 11136: //NetherBrickSlab + case 14002: //RedNetherBrickSlab + case 19725: //BlackstoneSlab + case 20226: //PolishedBlackstoneSlab + case 19735: //PolishedBlackstoneBrickSlab + case 13972: //EndStoneBrickSlab + case 11160: //PurpurSlab + case 11142: //QuartzSlab + case 13984: //SmoothQuartzSlab + case 21912: //CutCopperSlab + case 21906: //ExposedCutCopperSlab + case 21900: //WeatheredCutCopperSlab + case 21894: //OxidizedCutCopperSlab + case 22264: //WaxedCutCopperSlab + case 22258: //WaxedExposedCutCopperSlab + case 22252: //WaxedWeatheredCutCopperSlab + return true; + } + + break; + case Protocol18Handler.MC_1_19_4_Version: + switch (block.BlockId) + { + case 11018: // OakSlab + case 11024: // SpruceSlab + case 11030: // BirchSlab + case 11036: // JungleSlab + case 11042: // AcaciaSlab + case 11054: // DarkOakSlab + case 11060: // MangroveSlab + case 18510: // CrimsonSlab + case 18516: // WarpedSlab + case 11078: // StoneSlab + case 11108: // CobblestoneSlab + case 13948: // MossyCobblestoneSlab + case 11084: // SmoothStoneSlab + case 11120: // StoneBrickSlab + case 13936: // MossyStoneBrickSlab + case 13972: // GraniteSlab + case 13924: // PolishedGraniteSlab + case 13996: // DioriteSlab + case 13942: // PolishedDioriteSlab + case 13978: // AndesiteSlab + case 13990: // PolishedAndesiteSlab + case 22132: // CobbledDeepslateSlab + case 22543: // PolishedDeepslateSlab + case 23365: // DeepslateBrickSlab + case 22954: // DeepslateTileSlab + case 11114: // BrickSlab + case 11126: // MudBrickSlab + case 11090: // SandstoneSlab + case 13960: // SmoothSandstoneSlab + case 11096: // CutSandstoneSlab + case 11144: // RedSandstoneSlab + case 13930: // SmoothRedSandstoneSlab + case 11150: // CutRedSandstoneSlab + case 10562: // PrismarineSlab + case 10568: // PrismarineBrickSlab + case 10574: // DarkPrismarineSlab + case 11132: // NetherBrickSlab + case 13984: // RedNetherBrickSlab + case 19707: // BlackstoneSlab + case 20208: // PolishedBlackstoneSlab + case 19717: // PolishedBlackstoneBrickSlab + case 13954: // EndStoneBrickSlab + case 11156: // PurpurSlab + case 11138: // QuartzSlab + case 13966: // SmoothQuartzSlab + case 21510: // CutCopperSlab + case 21504: // ExposedCutCopperSlab + case 21498: // WeatheredCutCopperSlab + case 21492: // OxidizedCutCopperSlab + case 21862: // WaxedCutCopperSlab + case 21856: // WaxedExposedCutCopperSlab + case 21850: // WaxedWeatheredCutCopperSlab + case 21844: // WaxedOxidizedCutCopperSlab + return true; + } + + break; + case Protocol18Handler.MC_1_19_3_Version: + switch (block.BlockId) + { + case 10686: // OakSlab + case 10692: // SpruceSlab + case 10698: // BirchSlab + case 10704: // JungleSlab + case 10710: // AcaciaSlab + case 10716: // DarkOakSlab + case 10722: // MangroveSlab + case 18041: // CrimsonSlab + case 18047: // WarpedSlab + case 10740: // StoneSlab + case 10770: // CobblestoneSlab + case 13479: // MossyCobblestoneSlab + case 10746: // SmoothStoneSlab + case 10782: // StoneBrickSlab + case 13467: // MossyStoneBrickSlab + case 13503: // GraniteSlab + case 13455: // PolishedGraniteSlab + case 13527: // DioriteSlab + case 13473: // PolishedDioriteSlab + case 13509: // AndesiteSlab + case 13521: // PolishedAndesiteSlab + case 21647: // CobbledDeepslateSlab + case 22058: // PolishedDeepslateSlab + case 22880: // DeepslateBrickSlab + case 22469: // DeepslateTileSlab + case 10776: // BrickSlab + case 10788: // MudBrickSlab + case 10752: // SandstoneSlab + case 13491: // SmoothSandstoneSlab + case 10758: // CutSandstoneSlab + case 10806: // RedSandstoneSlab + case 13461: // SmoothRedSandstoneSlab + case 10812: // CutRedSandstoneSlab + case 10230: // PrismarineSlab + case 10236: // PrismarineBrickSlab + case 10242: // DarkPrismarineSlab + case 10794: // NetherBrickSlab + case 13515: // RedNetherBrickSlab + case 19238: // BlackstoneSlab + case 19739: // PolishedBlackstoneSlab + case 19248: // PolishedBlackstoneBrickSlab + case 13485: // EndStoneBrickSlab + case 10818: // PurpurSlab + case 10800: // QuartzSlab + case 13497: // SmoothQuartzSlab + case 21041: // CutCopperSlab + case 21035: // ExposedCutCopperSlab + case 21029: // WeatheredCutCopperSlab + case 21023: // OxidizedCutCopperSlab + case 21393: // WaxedCutCopperSlab + case 21387: // WaxedExposedCutCopperSlab + case 21381: // WaxedWeatheredCutCopperSlab + case 21375: // WaxedOxidizedCutCopperSlab + return true; + } + + break; + case >= Protocol18Handler.MC_1_19_Version: + switch (block.BlockId) + { + case 19257: // CutCopperSlab + case 19251: // ExposedCutCopperSlab + case 19245: // WeatheredCutCopperSlab + case 19239: // OxidizedCutCopperSlab + case 19609: // WaxedCutCopperSlab + case 19603: // WaxedExposedCutCopperSlab + case 19597: // WaxedWeatheredCutCopperSlab + case 19591: // WaxedOxidizedCutCopperSlab + case 9042: // OakSlab + case 9048: // SpruceSlab + case 9054: // BirchSlab + case 9060: // JungleSlab + case 9066: // AcaciaSlab + case 9072: // DarkOakSlab + case 9078: // MangroveSlab + case 16257: // CrimsonSlab + case 16263: // WarpedSlab + case 9084: // StoneSlab + case 9090: // SmoothStoneSlab + case 9096: // SandstoneSlab + case 9102: // CutSandstoneSlab + case 9108: // PetrifiedOakSlab + case 9114: // CobblestoneSlab + case 9120: // BrickSlab + case 9126: // StoneBrickSlab + case 9132: // MudBrickSlab + case 9138: // NetherBrickSlab + case 9144: // QuartzSlab + case 9150: // RedSandstoneSlab + case 9156: // CutRedSandstoneSlab + case 9162: // PurpurSlab + case 8586: // PrismarineSlab + case 8592: // PrismarineBrickSlab + case 8598: // DarkPrismarineSlab + case 11671: // PolishedGraniteSlab + case 11677: // SmoothRedSandstoneSlab + case 11683: // MossyStoneBrickSlab + case 11689: // PolishedDioriteSlab + case 11695: // MossyCobblestoneSlab + case 11701: // EndStoneBrickSlab + case 11707: // SmoothSandstoneSlab + case 11713: // SmoothQuartzSlab + case 11719: // GraniteSlab + case 11725: // AndesiteSlab + case 11731: // RedNetherBrickSlab + case 11737: // PolishedAndesiteSlab + case 11743: // DioriteSlab + case 19863: // CobbledDeepslateSlab + case 20274: // PolishedDeepslateSlab + case 21096: // DeepslateBrickSlab + case 20685: // DeepslateTileSlab + case 17454: // BlackstoneSlab + case 17955: // PolishedBlackstoneSlab + case 17464: // PolishedBlackstoneBrickSlab + return true; + } + + break; + case >= Protocol18Handler.MC_1_17_Version: + switch (block.BlockId) + { + case 18163: // CutCopperSlab + case 18157: // ExposedCutCopperSlab + case 18151: // WeatheredCutCopperSlab + case 18145: // OxidizedCutCopperSlab + case 18515: // WaxedCutCopperSlab + case 18509: // WaxedExposedCutCopperSlab + case 18503: // WaxedWeatheredCutCopperSlab + case 18497: // WaxedOxidizedCutCopperSlab + case 8551: // OakSlab + case 8557: // SpruceSlab + case 8563: // BirchSlab + case 8569: // JungleSlab + case 8575: // AcaciaSlab + case 8581: // DarkOakSlab + case 15302: // CrimsonSlab + case 15308: // WarpedSlab + case 8587: // StoneSlab + case 8593: // SmoothStoneSlab + case 8599: // SandstoneSlab + case 8605: // CutSandstoneSlab + case 8611: // PetrifiedOakSlab + case 8617: // CobblestoneSlab + case 8623: // BrickSlab + case 8629: // StoneBrickSlab + case 8635: // NetherBrickSlab + case 8641: // QuartzSlab + case 8647: // RedSandstoneSlab + case 8653: // CutRedSandstoneSlab + case 8659: // PurpurSlab + case 8095: // PrismarineSlab + case 8101: // PrismarineBrickSlab + case 8107: // DarkPrismarineSlab + case 11040: // PolishedGraniteSlab + case 11046: // SmoothRedSandstoneSlab + case 11052: // MossyStoneBrickSlab + case 11058: // PolishedDioriteSlab + case 11064: // MossyCobblestoneSlab + case 11070: // EndStoneBrickSlab + case 11076: // SmoothSandstoneSlab + case 11082: // SmoothQuartzSlab + case 11088: // GraniteSlab + case 11094: // AndesiteSlab + case 11100: // RedNetherBrickSlab + case 11106: // PolishedAndesiteSlab + case 11112: // DioriteSlab + case 18768: // CobbledDeepslateSlab + case 19179: // PolishedDeepslateSlab + case 20001: // DeepslateBrickSlab + case 19590: // DeepslateTileSlab + case 16499: // BlackstoneSlab + case 17000: // PolishedBlackstoneSlab + case 16509: // PolishedBlackstoneBrickSlab + return true; + } + + break; + case >= Protocol18Handler.MC_1_16_Version: + switch (block.BlockId) + { + case 8305: // OakSlab + case 8311: // SpruceSlab + case 8317: // BirchSlab + case 8323: // JungleSlab + case 8329: // AcaciaSlab + case 8335: // DarkOakSlab + case 15056: // CrimsonSlab + case 15062: // WarpedSlab + case 8341: // StoneSlab + case 8347: // SmoothStoneSlab + case 8353: // SandstoneSlab + case 8359: // CutSandstoneSlab + case 8365: // PetrifiedOakSlab + case 8371: // CobblestoneSlab + case 8377: // BrickSlab + case 8383: // StoneBrickSlab + case 8389: // NetherBrickSlab + case 8395: // QuartzSlab + case 8401: // RedSandstoneSlab + case 8407: // CutRedSandstoneSlab + case 8413: // PurpurSlab + case 7849: // PrismarineSlab + case 7855: // PrismarineBrickSlab + case 7861: // DarkPrismarineSlab + case 10794: // PolishedGraniteSlab + case 10800: // SmoothRedSandstoneSlab + case 10806: // MossyStoneBrickSlab + case 10812: // PolishedDioriteSlab + case 10818: // MossyCobblestoneSlab + case 10824: // EndStoneBrickSlab + case 10830: // SmoothSandstoneSlab + case 10836: // SmoothQuartzSlab + case 10842: // GraniteSlab + case 10848: // AndesiteSlab + case 10854: // RedNetherBrickSlab + case 10860: // PolishedAndesiteSlab + case 10866: // DioriteSlab + case 16253: // BlackstoneSlab + case 16754: // PolishedBlackstoneSlab + case 16263: // PolishedBlackstoneBrickSlab + return true; + } + + break; + case >= Protocol18Handler.MC_1_15_Version: + switch (block.BlockId) + { + case 7765: // OakSlab + case 7771: // SpruceSlab + case 7777: // BirchSlab + case 7783: // JungleSlab + case 7789: // AcaciaSlab + case 7795: // DarkOakSlab + case 7801: // StoneSlab + case 7807: // SmoothStoneSlab + case 7813: // SandstoneSlab + case 7819: // CutSandstoneSlab + case 7825: // PetrifiedOakSlab + case 7831: // CobblestoneSlab + case 7837: // BrickSlab + case 7843: // StoneBrickSlab + case 7849: // NetherBrickSlab + case 7855: // QuartzSlab + case 7861: // RedSandstoneSlab + case 7867: // CutRedSandstoneSlab + case 7873: // PurpurSlab + case 7309: // PrismarineSlab + case 7321: // DarkPrismarineSlab + case 10254: // PolishedGraniteSlab + case 10260: // SmoothRedSandstoneSlab + case 10266: // MossyStoneBrickSlab + case 10272: // PolishedDioriteSlab + case 10278: // MossyCobblestoneSlab + case 10284: // EndStoneBrickSlab + case 10290: // SmoothSandstoneSlab + case 10296: // SmoothQuartzSlab + case 10302: // GraniteSlab + case 10308: // AndesiteSlab + case 10314: // RedNetherBrickSlab + case 10320: // PolishedAndesiteSlab + case 10326: // DioriteSlab + return true; + } + + break; + case >= Protocol18Handler.MC_1_14_Version: + switch (block.BlockId) + { + case 7765: // OakSlab + case 7771: // SpruceSlab + case 7777: // BirchSlab + case 7783: // JungleSlab + case 7789: // AcaciaSlab + case 7795: // DarkOakSlab + case 7801: // StoneSlab + case 7807: // SmoothStoneSlab + case 7813: // SandstoneSlab + case 7819: // CutSandstoneSlab + case 7825: // PetrifiedOakSlab + case 7831: // CobblestoneSlab + case 7837: // BrickSlab + case 7843: // StoneBrickSlab + case 7849: // NetherBrickSlab + case 7855: // QuartzSlab + case 7861: // RedSandstoneSlab + case 7867: // CutRedSandstoneSlab + case 7873: // PurpurSlab + case 7309: // PrismarineSlab + case 7315: // PrismarineBrickSlab + case 7321: // DarkPrismarineSlab + case 10254: // PolishedGraniteSlab + case 10260: // SmoothRedSandstoneSlab + case 10266: // MossyStoneBrickSlab + case 10272: // PolishedDioriteSlab + case 10278: // MossyCobblestoneSlab + case 10284: // EndStoneBrickSlab + case 10290: // SmoothSandstoneSlab + case 10296: // SmoothQuartzSlab + case 10302: // GraniteSlab + case 10308: // AndesiteSlab + case 10314: // RedNetherBrickSlab + case 10320: // PolishedAndesiteSlab + case 10326: // DioriteSlab + return true; + } + + break; } return false; diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 8157e1bcae..e2b123288c 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -24,6 +24,7 @@ using MinecraftClient.Protocol.Session; using MinecraftClient.Proxy; using MinecraftClient.Scripting; +using Newtonsoft.Json; using static MinecraftClient.Settings; namespace MinecraftClient.Protocol.Handlers @@ -2348,6 +2349,17 @@ internal bool HandlePacket(int packetID, Queue packetData) // TODO: Use break; + // Temporarily disabled until I find a fix + /*case PacketTypesIn.BlockEntityData: + var location_ = dataTypes.ReadNextLocation(packetData); + var type_ = dataTypes.ReadNextInt(packetData); + var nbt = dataTypes.ReadNextNbt(packetData); + var nbtJson = JsonConvert.SerializeObject(nbt["messages"]); + + //log.Info($"BLOCK ENTITY DATA -> {location_.ToString()} [{type_}] -> NBT: {nbtJson}"); + + break;*/ + default: return false; //Ignored packet } diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index ea0dbe148b..4d41b142b7 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -1,4 +1,4 @@ -//------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ // // This code was generated by a tool. // @@ -3956,5 +3956,17 @@ internal static string cmd_nameitem_desc { return ResourceManager.GetString("cmd.nameitem.desc", resourceCulture); } } + + internal static string bot_antiafk_may_not_move { + get { + return ResourceManager.GetString("bot.antiafk.may.not.move", resourceCulture); + } + } + + internal static string bot_common_movement_lock_held { + get { + return ResourceManager.GetString("bot.common.movement.lock.held", resourceCulture); + } + } } } diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index fe79c72739..8cab30fcc4 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -2109,4 +2109,10 @@ Logging in... Set an item name when an Anvil inventory is active and the item is in the first slot. + + Bot movement lock is held by bot {0}, so the Anti AFK bot might not move! + + + You can not start/run/use the '{0}' bot because it requires movement, the movement is currently utilized by the '{1}' bot, stop it if you want to use this one. + \ No newline at end of file diff --git a/MinecraftClient/Scripting/BotMovementLock.cs b/MinecraftClient/Scripting/BotMovementLock.cs new file mode 100644 index 0000000000..2c29b6e8e7 --- /dev/null +++ b/MinecraftClient/Scripting/BotMovementLock.cs @@ -0,0 +1,35 @@ +namespace MinecraftClient.Scripting; + +public class BotMovementLock +{ + private static BotMovementLock? InstancePrivate; + private string _heldBy = string.Empty; + + private BotMovementLock() + { + InstancePrivate = this; + } + + public static BotMovementLock? Instance => InstancePrivate ??= new BotMovementLock(); + + public bool Lock(string owner) + { + if (owner.Trim().Length == 0 || _heldBy.Length > 0) + return false; + + _heldBy = owner.Trim(); + return true; + } + + public bool UnLock(string owner) + { + if (owner.Trim().Length == 0 || _heldBy.Length == 0 || !_heldBy.ToLower().Equals(owner.ToLower().Trim())) + return false; + + _heldBy = string.Empty; + return true; + } + + public bool IsLocked => _heldBy.Length > 0; + public string LockedBy => _heldBy; +} \ No newline at end of file