From efd7c6b75b0411ad2878573590c3ff13cf35b36c Mon Sep 17 00:00:00 2001 From: BruceChen Date: Sun, 11 Sep 2022 23:45:13 +0800 Subject: [PATCH 01/10] Fix command history --- ConsoleInteractive | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ConsoleInteractive b/ConsoleInteractive index b4fd7da2..7acaa0ab 160000 --- a/ConsoleInteractive +++ b/ConsoleInteractive @@ -1 +1 @@ -Subproject commit b4fd7da2595ad54479880fc1c9c6e14975412d92 +Subproject commit 7acaa0ab31809f0f6512e6a76e53e15441de8e7c From eb517a8e78c8ca7f1fe4d561be14c9b5926af49d Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 02:10:18 +0800 Subject: [PATCH 02/10] Upgrade Auto Fishing --- ConsoleInteractive | 2 +- MinecraftClient/ChatBots/AutoFishing.cs | 185 +++++++++++++----- .../Resources/config/MinecraftClient.ini | 4 + MinecraftClient/Resources/lang/en.ini | 8 +- MinecraftClient/Scripting/ChatBot.cs | 9 + MinecraftClient/Settings.cs | 27 ++- 6 files changed, 182 insertions(+), 53 deletions(-) diff --git a/ConsoleInteractive b/ConsoleInteractive index b4fd7da2..7acaa0ab 160000 --- a/ConsoleInteractive +++ b/ConsoleInteractive @@ -1 +1 @@ -Subproject commit b4fd7da2595ad54479880fc1c9c6e14975412d92 +Subproject commit 7acaa0ab31809f0f6512e6a76e53e15441de8e7c diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 961a9527..507a736d 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -13,13 +13,30 @@ namespace MinecraftClient.ChatBots /// class AutoFishing : ChatBot { - private Entity fishingRod; - private Double fishingHookThreshold = 0.2; - private Location LastPos = new Location(); - private DateTime CaughtTime = DateTime.Now; + private int fishCount = 0; private bool inventoryEnabled; + private bool isFishing = false; - private int useItemCounter = 0; + private Entity? fishingBobber; + private Location LastPos = Location.Zero; + private DateTime CaughtTime = DateTime.Now; + + private int counter = 0; + private readonly object stateLock = new(); + private FishingState state = FishingState.WaitJoinGame; + + private int castTimeout = 12; + + private enum FishingState + { + WaitJoinGame, + WaitingToCast, + CastingRod, + WaitingFishingBobber, + WaitingFishBite, + Preparing, + Stopping, + } public override void Initialize() { @@ -32,42 +49,94 @@ namespace MinecraftClient.ChatBots inventoryEnabled = GetInventoryEnabled(); } + public override void AfterGameJoined() + { + double delay = Settings.AutoFishing_FishingDelay; + LogToConsole(Translations.Get("bot.autoFish.start", delay)); + lock (stateLock) + { + counter = (int)(delay * 10); + state = FishingState.WaitingToCast; + } + } + public override void Update() { - if (useItemCounter > 0) + lock (stateLock) { - useItemCounter--; - if (useItemCounter <= 0) + switch (state) { - UseItemInHand(); + case FishingState.WaitJoinGame: + break; + case FishingState.WaitingToCast: + if (--counter < 0) + state = FishingState.CastingRod; + break; + case FishingState.CastingRod: + UseFishRod(); + counter = 0; + state = FishingState.WaitingFishingBobber; + break; + case FishingState.WaitingFishingBobber: + if (++counter > castTimeout) + { + if (castTimeout < 6000) + castTimeout *= 2; + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.cast_timeout", castTimeout / 10.0)); + + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + state = FishingState.WaitingToCast; + } + break; + case FishingState.WaitingFishBite: + if (++counter > (int)(Settings.AutoFishing_FishingTimeout * 10)) + { + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.fishing_timeout")); + + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + state = FishingState.WaitingToCast; + } + break; + case FishingState.Preparing: + break; + case FishingState.Stopping: + break; } } } public override void OnEntitySpawn(Entity entity) { - if (entity.Type == EntityType.FishingBobber) + if (entity.Type == EntityType.FishingBobber && entity.ObjectData == GetPlayerEntityID()) { - if (GetCurrentLocation().Distance(entity.Location) < 2 && !isFishing) + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.throw")); + lock (stateLock) { - LogToConsoleTranslated("bot.autoFish.throw"); - fishingRod = entity; + fishingBobber = entity; LastPos = entity.Location; isFishing = true; + + castTimeout = 24; + counter = 0; + state = FishingState.WaitingFishBite; } } } public override void OnEntityDespawn(Entity entity) { - if (entity.Type == EntityType.FishingBobber) + if (isFishing && entity.Type == EntityType.FishingBobber && entity.ID == fishingBobber!.ID) { - if(entity.ID == fishingRod.ID) + isFishing = false; + + if (Settings.AutoFishing_Antidespawn) { - isFishing = false; - if (Settings.AutoFishing_Antidespawn) + LogToConsoleTranslated("bot.autoFish.despawn"); + + lock (stateLock) { - useItemCounter = 5; // 500ms + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + state = FishingState.WaitingToCast; } } } @@ -75,75 +144,95 @@ namespace MinecraftClient.ChatBots public override void OnEntityMove(Entity entity) { - if (isFishing) + if (isFishing && fishingBobber!.ID == entity.ID) { - if (fishingRod.ID == entity.ID) + Location Pos = entity.Location; + double Dx = LastPos.X - Pos.X; + double Dy = LastPos.Y - Pos.Y; + double Dz = LastPos.Z - Pos.Z; + LastPos = Pos; + + // check if fishing hook is stationary + if (Dx == 0 && Dz == 0) { - Location Pos = entity.Location; - Double Dx = LastPos.X - Pos.X; - Double Dy = LastPos.Y - Pos.Y; - Double Dz = LastPos.Z - Pos.Z; - LastPos = Pos; - // check if fishing hook is stationary - if (Dx == 0 && Dz == 0) + if (Math.Abs(Dy) > Settings.AutoFishing_FishingHookThreshold) { - if (Math.Abs(Dy) > fishingHookThreshold) + // caught + // prevent triggering multiple time + if ((DateTime.Now - CaughtTime).TotalSeconds > 1) { - // caught - // prevent triggering multiple time - if ((DateTime.Now - CaughtTime).TotalSeconds > 1) - { - OnCaughtFish(); - CaughtTime = DateTime.Now; - } + CaughtTime = DateTime.Now; + OnCaughtFish(); } } - fishingRod = entity; } } } public override bool OnDisconnect(DisconnectReason reason, string message) { - fishingRod = null; - LastPos = new Location(); + lock (stateLock) + { + isFishing = false; + + counter = 0; + state = FishingState.Stopping; + } + + fishingBobber = null; + LastPos = Location.Zero; CaughtTime = DateTime.Now; - isFishing = false; - useItemCounter = 0; + return base.OnDisconnect(reason, message); } + private void UseFishRod() + { + UseItemInHand(); + } + /// /// Called when detected a fish is caught /// public void OnCaughtFish() { - LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught")); - // retract fishing rod - UseItemInHand(); + lock (stateLock) + { + state = FishingState.Preparing; + } + + UseFishRod(); + + ++fishCount; + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught", fishCount)); + if (inventoryEnabled) { - if (!hasFishingRod()) + if (!HasFishingRod()) { LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.no_rod")); return; } } - // thread-safe - useItemCounter = 8; // 800ms + + lock (stateLock) + { + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + state = FishingState.WaitingToCast; + } } /// /// Check whether the player has a fishing rod in inventory /// /// TRUE if the player has a fishing rod - public bool hasFishingRod() + public bool HasFishingRod() { if (!inventoryEnabled) return false; int start = 36; int end = 44; - Inventory.Container container = GetPlayerInventory(); + Container container = GetPlayerInventory(); foreach (KeyValuePair a in container.Items) { diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini index 332c00be..bc43d351 100644 --- a/MinecraftClient/Resources/config/MinecraftClient.ini +++ b/MinecraftClient/Resources/config/MinecraftClient.ini @@ -207,6 +207,10 @@ interaction=Attack # Possible values: Interact, Attack (default) # /!\ Make sure server rules allow automated farming before using this bot enabled=false antidespawn=false +fishing_delay=3.0 # How long after entering the game to start fishing (seconds). +fishing_timeout=600.0 # Fishing timeout (seconds). Timeout will re-cast the rod +fishing_hook_threshold=0.2 # Fish hooks moving on the Y-axis above this threshold will be considered to have caught a fish. +fishing_cast_delay=0.4 # How soon to re-cast after successful fishing. [AutoEat] # Automatically eat food when your Hunger value is low diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini index 1d0cc4ad..4a30ee1c 100644 --- a/MinecraftClient/Resources/lang/en.ini +++ b/MinecraftClient/Resources/lang/en.ini @@ -447,9 +447,13 @@ bot.autoDrop.no_mode=Cannot read drop mode from config. Using include mode. bot.autoDrop.no_inventory=Cannot find inventory {0}! # AutoFish -bot.autoFish.throw=Threw a fishing rod -bot.autoFish.caught=Caught a fish! +bot.autoFish.start=Fishing will start in {0:0.0} second(s). +bot.autoFish.throw=Casting successfully. +bot.autoFish.caught=Caught a fish! (Count: {0}) bot.autoFish.no_rod=No Fishing Rod on hand. Maybe broken? +bot.autoFish.despawn=Fish floating despawn, will re-cast. +bot.autoFish.fishing_timeout=Fishing timeout, will soon re-cast. +bot.autoFish.cast_timeout=Casting timeout and will soon retry. (Timeout increased to {0:0.0} sec). # AutoRelog bot.autoRelog.launch=Launching with {0} reconnection attempts diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 4fc59e1e..2fccd721 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -1113,6 +1113,15 @@ namespace MinecraftClient return Handler.GetUserUuidStr(); } + /// + /// Return the EntityID of the current player + /// + /// EntityID of the current player + protected int GetPlayerEntityID() + { + return Handler.GetPlayerEntityID(); + } + /// /// Return the list of currently online players /// diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index db493953..7f8c71b2 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -203,6 +203,10 @@ namespace MinecraftClient //Auto Fishing public static bool AutoFishing_Enabled = false; public static bool AutoFishing_Antidespawn = false; + public static double AutoFishing_FishingDelay = 3.0; + public static double AutoFishing_FishingTimeout = 600.0; + public static double AutoFishing_FishingHookThreshold = 0.2; + public static double AutoFishing_FishingCastDelay = 0.4; //Auto Eating public static bool AutoEat_Enabled = false; @@ -711,6 +715,10 @@ namespace MinecraftClient { case "enabled": AutoFishing_Enabled = str2bool(argValue); return true; case "antidespawn": AutoFishing_Antidespawn = str2bool(argValue); return true; + case "fishing_delay": AutoFishing_FishingDelay = str2double(argValue); return true; + case "fishing_timeout": AutoFishing_FishingTimeout = str2double(argValue); return true; + case "fishing_hook_threshold": AutoFishing_FishingHookThreshold = str2double(argValue); return true; + case "fishing_cast_delay": AutoFishing_FishingCastDelay = str2double(argValue); return true; } break; @@ -863,8 +871,23 @@ namespace MinecraftClient /// Float number public static float str2float(string str) { - float f; - if (float.TryParse(str.Trim(), out f)) + if (float.TryParse(str.Trim(), out float f)) + return f; + else + { + ConsoleIO.WriteLogLine(Translations.Get("error.setting.str2int", str)); + return 0; + } + } + + /// + /// Convert the specified string to a double number, defaulting to zero if invalid argument + /// + /// String to parse as a float number + /// Double number + public static double str2double(string str) + { + if (double.TryParse(str.Trim(), out double f)) return f; else { From ccb861002095419e12e891fe00ea97c44b9cddc7 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 02:19:20 +0800 Subject: [PATCH 03/10] Support use left hand --- MinecraftClient/ChatBots/AutoFishing.cs | 5 ++++- MinecraftClient/McClient.cs | 9 +++++++++ MinecraftClient/Resources/config/MinecraftClient.ini | 1 + MinecraftClient/Scripting/ChatBot.cs | 9 +++++++++ MinecraftClient/Settings.cs | 1 + 5 files changed, 24 insertions(+), 1 deletion(-) diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 507a736d..d92d07ab 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -188,7 +188,10 @@ namespace MinecraftClient.ChatBots private void UseFishRod() { - UseItemInHand(); + if (Settings.AutoFishing_Mainhand) + UseItemInHand(); + else + UseItemInLeftHand(); } /// diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs index 3ef7fbf1..8ba106fa 100644 --- a/MinecraftClient/McClient.cs +++ b/MinecraftClient/McClient.cs @@ -1277,6 +1277,15 @@ namespace MinecraftClient return InvokeOnMainThread(() => handler.SendUseItem(0, this.sequenceId)); } + /// + /// Use the item currently in the player's left hand + /// + /// TRUE if the item was successfully used + public bool UseItemOnLeftHand() + { + return InvokeOnMainThread(() => handler.SendUseItem(1, this.sequenceId)); + } + /// /// Try to merge a slot /// diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini index bc43d351..2a9d7436 100644 --- a/MinecraftClient/Resources/config/MinecraftClient.ini +++ b/MinecraftClient/Resources/config/MinecraftClient.ini @@ -207,6 +207,7 @@ interaction=Attack # Possible values: Interact, Attack (default) # /!\ Make sure server rules allow automated farming before using this bot enabled=false antidespawn=false +main_hand=true # Use the main hand or the second hand to hold the rod fishing_delay=3.0 # How long after entering the game to start fishing (seconds). fishing_timeout=600.0 # Fishing timeout (seconds). Timeout will re-cast the rod fishing_hook_threshold=0.2 # Fish hooks moving on the Y-axis above this threshold will be considered to have caught a fish. diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 2fccd721..3e5515e9 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -1262,6 +1262,15 @@ namespace MinecraftClient return Handler.UseItemOnHand(); } + /// + /// Use item currently in the player's hand (active inventory bar slot) + /// + /// TRUE if successful + protected bool UseItemInLeftHand() + { + return Handler.UseItemOnLeftHand(); + } + /// /// Check inventory handling enable status /// diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 7f8c71b2..380f7154 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -203,6 +203,7 @@ namespace MinecraftClient //Auto Fishing public static bool AutoFishing_Enabled = false; public static bool AutoFishing_Antidespawn = false; + public static bool AutoFishing_Mainhand = true; public static double AutoFishing_FishingDelay = 3.0; public static double AutoFishing_FishingTimeout = 600.0; public static double AutoFishing_FishingHookThreshold = 0.2; From c64efe67757dd0612470c79e9e4960da009a5209 Mon Sep 17 00:00:00 2001 From: Milutinke Date: Sun, 11 Sep 2022 21:20:15 +0200 Subject: [PATCH 04/10] Added discord link --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a6768e70..fe2e0e05 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [Documentation](https://mccteam.github.io/docs/) | [Download](#download) | [Installation](https://mccteam.github.io/docs/guide/installation.html) | [Configuration](https://mccteam.github.io/docs/guide/configuration.html) | [Usage](https://mccteam.github.io/docs/guide/usage.html) -[![GitHub Actions build status](https://github.com/MCCTeam/Minecraft-Console-Client/actions/workflows/build-and-release.yml/badge.svg)](https://github.com/MCCTeam/Minecraft-Console-Client/releases/latest) +[![GitHub Actions build status](https://github.com/MCCTeam/Minecraft-Console-Client/actions/workflows/build-and-release.yml/badge.svg)](https://github.com/MCCTeam/Minecraft-Console-Client/releases/latest) Discord server @@ -31,6 +31,10 @@ Get development builds from the [Releases section](https://github.com/MCCTeam/Mi Check out the [Website](https://mccteam.github.io/), [README](https://github.com/MCCTeam/Minecraft-Console-Client/tree/master/MinecraftClient/config#minecraft-console-client-user-manual) and existing [Discussions](https://github.com/MCCTeam/Minecraft-Console-Client/discussions): Maybe your question is answered there. If not, please open a [New Discussion](https://github.com/MCCTeam/Minecraft-Console-Client/discussions/new) and ask your question. If you find a bug, please report it in the [Issues](https://github.com/MCCTeam/Minecraft-Console-Client/issues) section. +## Discord + +We now have a Discord server, click [here](https://discord.gg/sfBv4TtpC9) to join. + ## Helping Us ❤️ We are a small community so we need help to implement upgrades for new Minecraft versions, fixing bugs and expanding the project. We are always looking for motivated people to contribute. If you feel like it could be you, please have a look at the [issues](https://github.com/MCCTeam/Minecraft-Console-Client/issues?q=is%3Aissue+is%3Aopen+label%3Awaiting-for%3Acontributor) section :) From 949126c9cb390ec8eb8d21e03994a80e519a2078 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 16:27:37 +0800 Subject: [PATCH 05/10] Supports changing position and angle after catching fish --- MinecraftClient/ChatBots/AutoFishing.cs | 187 +++++++++++++++--- MinecraftClient/Commands/Move.cs | 6 +- MinecraftClient/Mapping/Movement.cs | 20 ++ .../Resources/config/MinecraftClient.ini | 9 +- MinecraftClient/Resources/lang/en.ini | 5 + MinecraftClient/Scripting/ChatBot.cs | 10 + MinecraftClient/Settings.cs | 50 ++++- 7 files changed, 249 insertions(+), 38 deletions(-) diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index d92d07ab..69617b36 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -15,6 +15,7 @@ namespace MinecraftClient.ChatBots { private int fishCount = 0; private bool inventoryEnabled; + private int castTimeout = 12; private bool isFishing = false; private Entity? fishingBobber; @@ -25,7 +26,8 @@ namespace MinecraftClient.ChatBots private readonly object stateLock = new(); private FishingState state = FishingState.WaitJoinGame; - private int castTimeout = 12; + private int curLocationIdx = 0, moveDir = 1; + float nextYaw = 0, nextPitch = 0; private enum FishingState { @@ -33,8 +35,9 @@ namespace MinecraftClient.ChatBots WaitingToCast, CastingRod, WaitingFishingBobber, - WaitingFishBite, - Preparing, + WaitingFishToBite, + DurabilityCheck, + ChangeLocation, Stopping, } @@ -47,19 +50,41 @@ namespace MinecraftClient.ChatBots UnloadBot(); } inventoryEnabled = GetInventoryEnabled(); + if (!inventoryEnabled) + LogToConsoleTranslated("bot.autoFish.no_inv_handle"); } - public override void AfterGameJoined() + private void StartFishing() { + isFishing = false; double delay = Settings.AutoFishing_FishingDelay; LogToConsole(Translations.Get("bot.autoFish.start", delay)); lock (stateLock) { counter = (int)(delay * 10); - state = FishingState.WaitingToCast; + state = FishingState.DurabilityCheck; } } + private void StopFishing() + { + isFishing = false; + lock (stateLock) + { + state = FishingState.Stopping; + } + } + + public override void AfterGameJoined() + { + StartFishing(); + } + + public override void OnRespawn() + { + StartFishing(); + } + public override void Update() { lock (stateLock) @@ -69,7 +94,9 @@ namespace MinecraftClient.ChatBots case FishingState.WaitJoinGame: break; case FishingState.WaitingToCast: - if (--counter < 0) + if (AutoEat.Eating) + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + else if (--counter < 0) state = FishingState.CastingRod; break; case FishingState.CastingRod: @@ -81,14 +108,14 @@ namespace MinecraftClient.ChatBots if (++counter > castTimeout) { if (castTimeout < 6000) - castTimeout *= 2; + castTimeout *= 2; // Exponential backoff LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.cast_timeout", castTimeout / 10.0)); counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); state = FishingState.WaitingToCast; } break; - case FishingState.WaitingFishBite: + case FishingState.WaitingFishToBite: if (++counter > (int)(Settings.AutoFishing_FishingTimeout * 10)) { LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.fishing_timeout")); @@ -97,7 +124,21 @@ namespace MinecraftClient.ChatBots state = FishingState.WaitingToCast; } break; - case FishingState.Preparing: + case FishingState.DurabilityCheck: + if (--counter < 0) + { + DurabilityCheckAndMove(); + } + break; + case FishingState.ChangeLocation: + if (!ClientIsMoving()) + { + LookAtLocation(nextYaw, nextPitch); + LogToConsole(Translations.Get("bot.autoFish.update_lookat", nextYaw, nextPitch)); + + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + state = FishingState.WaitingToCast; + } break; case FishingState.Stopping: break; @@ -118,7 +159,7 @@ namespace MinecraftClient.ChatBots castTimeout = 24; counter = 0; - state = FishingState.WaitingFishBite; + state = FishingState.WaitingFishToBite; } } } @@ -161,6 +202,7 @@ namespace MinecraftClient.ChatBots // prevent triggering multiple time if ((DateTime.Now - CaughtTime).TotalSeconds > 1) { + isFishing = false; CaughtTime = DateTime.Now; OnCaughtFish(); } @@ -169,15 +211,14 @@ namespace MinecraftClient.ChatBots } } + public override void OnDeath() + { + StopFishing(); + } + public override bool OnDisconnect(DisconnectReason reason, string message) { - lock (stateLock) - { - isFishing = false; - - counter = 0; - state = FishingState.Stopping; - } + StopFishing(); fishingBobber = null; LastPos = Location.Zero; @@ -194,34 +235,123 @@ namespace MinecraftClient.ChatBots UseItemInLeftHand(); } - /// - /// Called when detected a fish is caught - /// - public void OnCaughtFish() + private void UpdateLocation(double[,] locationList) { - lock (stateLock) + if (curLocationIdx >= locationList.GetLength(0)) { - state = FishingState.Preparing; + curLocationIdx = Math.Max(0, locationList.GetLength(0) - 2); + moveDir = -1; + } + else if (curLocationIdx < 0) + { + curLocationIdx = Math.Min(locationList.GetLength(0) - 1, 1); + moveDir = 1; } - UseFishRod(); + int locationType = locationList.GetLength(1); - ++fishCount; - LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught", fishCount)); + if (locationType == 2) + { + nextYaw = (float)locationList[curLocationIdx, 0]; + nextPitch = (float)locationList[curLocationIdx, 1]; + } + else if (locationType == 3) + { + nextYaw = GetYaw(); + nextPitch = GetPitch(); + } + else if (locationType == 5) + { + nextYaw = (float)locationList[curLocationIdx, 3]; + nextPitch = (float)locationList[curLocationIdx, 4]; + } + if (locationType == 3 || locationType == 5) + { + Location current = GetCurrentLocation(); + Location goal = new(locationList[curLocationIdx, 0], locationList[curLocationIdx, 1], locationList[curLocationIdx, 2]); + + bool isMoveSuccessed; + if (!Movement.CheckChunkLoading(GetWorld(), current, goal)) + { + LogToConsole(Translations.Get("cmd.move.chunk_not_loaded", goal.X, goal.Y, goal.Z)); + isMoveSuccessed = false; + } + else + { + isMoveSuccessed = MoveToLocation(goal, allowUnsafe: false, allowDirectTeleport: false); + } + + if (!isMoveSuccessed) + { + nextYaw = GetYaw(); + nextPitch = GetPitch(); + LogToConsole(Translations.Get("cmd.move.fail", goal)); + } + else + { + LogToConsole(Translations.Get("cmd.move.walk", goal, current)); + } + } + + curLocationIdx += moveDir; + } + + + private void DurabilityCheckAndMove() + { if (inventoryEnabled) { if (!HasFishingRod()) { LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.no_rod")); + + lock (stateLock) + { + state = FishingState.Stopping; + } + return; } } + double[,]? locationList = Settings.AutoFishing_Location; + if (locationList != null) + { + UpdateLocation(locationList); + lock (stateLock) + { + state = FishingState.ChangeLocation; + } + } + else + { + lock (stateLock) + { + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + state = FishingState.WaitingToCast; + } + } + } + + /// + /// Called when detected a fish is caught + /// + public void OnCaughtFish() + { + ++fishCount; + if (Settings.AutoFishing_Location != null) + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught_at", + fishingBobber!.Location.X, fishingBobber!.Location.Y, fishingBobber!.Location.Z, fishCount)); + else + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught", fishCount)); + lock (stateLock) { - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); - state = FishingState.WaitingToCast; + UseFishRod(); + + counter = 0; + state = FishingState.DurabilityCheck; } } @@ -233,6 +363,7 @@ namespace MinecraftClient.ChatBots { if (!inventoryEnabled) return false; + int start = 36; int end = 44; Container container = GetPlayerInventory(); diff --git a/MinecraftClient/Commands/Move.cs b/MinecraftClient/Commands/Move.cs index 1b4f85ee..da58e76b 100644 --- a/MinecraftClient/Commands/Move.cs +++ b/MinecraftClient/Commands/Move.cs @@ -74,8 +74,7 @@ namespace MinecraftClient.Commands Location goal = Movement.Move(handler.GetCurrentLocation(), direction); - ChunkColumn? chunkColumn = handler.GetWorld().GetChunkColumn(goal); - if (chunkColumn == null || chunkColumn.FullyLoaded == false) + if (!Movement.CheckChunkLoading(handler.GetWorld(), handler.GetCurrentLocation(), goal)) return Translations.Get("cmd.move.chunk_not_loaded", goal.X, goal.Y, goal.Z); if (Movement.CanMove(handler.GetWorld(), handler.GetCurrentLocation(), direction)) @@ -98,8 +97,7 @@ namespace MinecraftClient.Commands double z = args[2].StartsWith('~') ? current.Z + (args[2].Length > 1 ? double.Parse(args[2][1..]) : 0) : double.Parse(args[2]); Location goal = new(x, y, z); - ChunkColumn? chunkColumn = handler.GetWorld().GetChunkColumn(goal); - if (chunkColumn == null || chunkColumn.FullyLoaded == false) + if (!Movement.CheckChunkLoading(handler.GetWorld(), current, goal)) return Translations.Get("cmd.move.chunk_not_loaded", x, y, z); if (takeRisk || Movement.PlayerFitsHere(handler.GetWorld(), goal)) diff --git a/MinecraftClient/Mapping/Movement.cs b/MinecraftClient/Mapping/Movement.cs index 8389cdd7..21811c8d 100644 --- a/MinecraftClient/Mapping/Movement.cs +++ b/MinecraftClient/Mapping/Movement.cs @@ -643,5 +643,25 @@ namespace MinecraftClient.Mapping throw new ArgumentException("Unknown direction", "direction"); } } + + /// + /// Check that the chunks at both the start and destination locations have been loaded + /// + /// Current world + /// Start location + /// Destination location + /// Is loading complete + public static bool CheckChunkLoading(World world, Location start, Location dest) + { + ChunkColumn? chunkColumn = world.GetChunkColumn(dest); + if (chunkColumn == null || chunkColumn.FullyLoaded == false) + return false; + + chunkColumn = world.GetChunkColumn(start); + if (chunkColumn == null || chunkColumn.FullyLoaded == false) + return false; + + return true; + } } } diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini index 2a9d7436..4632cd00 100644 --- a/MinecraftClient/Resources/config/MinecraftClient.ini +++ b/MinecraftClient/Resources/config/MinecraftClient.ini @@ -207,11 +207,16 @@ interaction=Attack # Possible values: Interact, Attack (default) # /!\ Make sure server rules allow automated farming before using this bot enabled=false antidespawn=false -main_hand=true # Use the main hand or the second hand to hold the rod +main_hand=true # Use the main hand or the second hand to hold the rod. fishing_delay=3.0 # How long after entering the game to start fishing (seconds). -fishing_timeout=600.0 # Fishing timeout (seconds). Timeout will re-cast the rod +fishing_timeout=300.0 # Fishing timeout (seconds). Timeout will trigger a re-cast. fishing_hook_threshold=0.2 # Fish hooks moving on the Y-axis above this threshold will be considered to have caught a fish. fishing_cast_delay=0.4 # How soon to re-cast after successful fishing. +location= # Some plugins do not allow the player to fish in one place. This allows the player to change position/angle after each fish caught. + # Floating point numbers can be used for both coordinates and angles. Leave blank to disable this function. + # Change the angle only (recommended): location=yaw_1,pitch_1;yaw_2,pitch_2;...;yaw_n,pitch_n + # Change position only: location=x1,y1,z1;x2,y2,z2;...;xn,yn,zn + # Change both angle and position: location=x1,y1,z1,yaw_1,pitch_1;x2,y2,z2,yaw_2,pitch_2;...;xn,yn,zn,yaw_n,pitch_n [AutoEat] # Automatically eat food when your Hunger value is low diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini index 4a30ee1c..15b6d2e9 100644 --- a/MinecraftClient/Resources/lang/en.ini +++ b/MinecraftClient/Resources/lang/en.ini @@ -88,6 +88,8 @@ error.connection_timeout=§8A timeout occured while attempting to connect to thi error.forge=§8Forge Login Handshake did not complete successfully error.forge_encrypt=§8Forge StartEncryption Handshake did not complete successfully error.setting.str2int=Failed to convert '{0}' into an integer. Please check your settings. +error.setting.str2locationList.convert_fail=Failed to convert '{0}' to a floating point number. Please check your settings. +error.setting.str2locationList.format_err=Wrong format, can't parse '{0}' into position data.. Please check your settings. error.setting.argument_syntax={0}: Invalid syntax, expecting --argname=value or --section.argname=value error.setting.unknown_section={0}: Unknown setting section '{1}' error.setting.unknown_or_invalid={0}: Unknown setting or invalid value @@ -447,13 +449,16 @@ bot.autoDrop.no_mode=Cannot read drop mode from config. Using include mode. bot.autoDrop.no_inventory=Cannot find inventory {0}! # AutoFish +bot.autoFish.no_inv_handle=Inventory handling is not enabled. Cannot check rod durability and switch rods. bot.autoFish.start=Fishing will start in {0:0.0} second(s). bot.autoFish.throw=Casting successfully. bot.autoFish.caught=Caught a fish! (Count: {0}) +bot.autoFish.caught_at=Caught a fish at ({0:0.0},{1:0.0},{2:0.0})! (Count: {3}) bot.autoFish.no_rod=No Fishing Rod on hand. Maybe broken? bot.autoFish.despawn=Fish floating despawn, will re-cast. bot.autoFish.fishing_timeout=Fishing timeout, will soon re-cast. bot.autoFish.cast_timeout=Casting timeout and will soon retry. (Timeout increased to {0:0.0} sec). +bot.autoFish.update_lookat=Update yaw = {0:0.00}, pitch = {1:0.00}. # AutoRelog bot.autoRelog.launch=Launching with {0} reconnection attempts diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs index 3e5515e9..4d4ac0ac 100644 --- a/MinecraftClient/Scripting/ChatBot.cs +++ b/MinecraftClient/Scripting/ChatBot.cs @@ -1012,6 +1012,16 @@ namespace MinecraftClient Handler.UpdateLocation(Handler.GetCurrentLocation(), location); } + /// + /// Look at the specified location + /// + /// Yaw to look at + /// Pitch to look at + protected void LookAtLocation(float yaw, float pitch) + { + Handler.UpdateLocation(Handler.GetCurrentLocation(), yaw, pitch); + } + /// /// Get a Y-M-D h:m:s timestamp representing the current system date and time /// diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 380f7154..30e46cc0 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -208,6 +208,7 @@ namespace MinecraftClient public static double AutoFishing_FishingTimeout = 600.0; public static double AutoFishing_FishingHookThreshold = 0.2; public static double AutoFishing_FishingCastDelay = 0.4; + public static double[,]? AutoFishing_Location = null; //Auto Eating public static bool AutoEat_Enabled = false; @@ -720,6 +721,7 @@ namespace MinecraftClient case "fishing_timeout": AutoFishing_FishingTimeout = str2double(argValue); return true; case "fishing_hook_threshold": AutoFishing_FishingHookThreshold = str2double(argValue); return true; case "fishing_cast_delay": AutoFishing_FishingCastDelay = str2double(argValue); return true; + case "location": AutoFishing_Location = str2locationList(argValue); return true; } break; @@ -872,8 +874,8 @@ namespace MinecraftClient /// Float number public static float str2float(string str) { - if (float.TryParse(str.Trim(), out float f)) - return f; + if (float.TryParse(str.Trim(), out float num)) + return num; else { ConsoleIO.WriteLogLine(Translations.Get("error.setting.str2int", str)); @@ -888,8 +890,8 @@ namespace MinecraftClient /// Double number public static double str2double(string str) { - if (double.TryParse(str.Trim(), out double f)) - return f; + if (double.TryParse(str.Trim(), out double num)) + return num; else { ConsoleIO.WriteLogLine(Translations.Get("error.setting.str2int", str)); @@ -910,6 +912,46 @@ namespace MinecraftClient return str == "true" || str == "1"; } + /// + /// Convert the specified string to a list of location, returning null if invalid argument + /// + /// String to parse as a location list + /// Location list (null or double[*,5] or double[*,3] or double[*,2]) + public static double[,]? str2locationList(string str) + { + string[] locationStrList = str.Split(';', StringSplitOptions.RemoveEmptyEntries); + double[,]? res = null; + int codLen = 0; + for (int i = 0; i < locationStrList.Length; ++i) + { + string[] coordinates_str_list = locationStrList[i].Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); + int curCodLen = coordinates_str_list.Length; + if ((curCodLen == 2 || curCodLen == 3 || curCodLen == 5) && (i == 0 || curCodLen == codLen)) + { + if (i == 0) + { + res = new double[locationStrList.Length, curCodLen]; + codLen = curCodLen; + } + + for (int j = 0; j < curCodLen; ++j) + { + if (!double.TryParse(coordinates_str_list[j], out res![i, j])) + { + ConsoleIO.WriteLogLine(Translations.Get("error.setting.str2locationList.convert_fail", coordinates_str_list[j])); + return null; + } + } + } + else + { + ConsoleIO.WriteLogLine(Translations.Get("error.setting.str2locationList.format_err", locationStrList[i])); + return null; + } + } + return res; + } + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public static string ToLowerIfNeed(string str) { From cb2238700802e67fce880d09831311302bb66f3e Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 18:02:46 +0800 Subject: [PATCH 06/10] Support automatic rod switching --- MinecraftClient/ChatBots/AutoFishing.cs | 179 +++++++++--------- .../Resources/config/MinecraftClient.ini | 2 + MinecraftClient/Resources/lang/en.ini | 3 +- MinecraftClient/Settings.cs | 6 +- 4 files changed, 98 insertions(+), 92 deletions(-) diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 69617b36..98cf53d5 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -17,7 +17,7 @@ namespace MinecraftClient.ChatBots private bool inventoryEnabled; private int castTimeout = 12; - private bool isFishing = false; + private bool isFishing = false, isWaitingRod = false; private Entity? fishingBobber; private Location LastPos = Location.Zero; private DateTime CaughtTime = DateTime.Now; @@ -36,8 +36,9 @@ namespace MinecraftClient.ChatBots CastingRod, WaitingFishingBobber, WaitingFishToBite, + StartMove, + WaitingMovement, DurabilityCheck, - ChangeLocation, Stopping, } @@ -62,7 +63,7 @@ namespace MinecraftClient.ChatBots lock (stateLock) { counter = (int)(delay * 10); - state = FishingState.DurabilityCheck; + state = FishingState.StartMove; } } @@ -75,14 +76,12 @@ namespace MinecraftClient.ChatBots } } - public override void AfterGameJoined() + private void UseFishRod() { - StartFishing(); - } - - public override void OnRespawn() - { - StartFishing(); + if (Settings.AutoFishing_Mainhand) + UseItemInHand(); + else + UseItemInLeftHand(); } public override void Update() @@ -124,18 +123,36 @@ namespace MinecraftClient.ChatBots state = FishingState.WaitingToCast; } break; - case FishingState.DurabilityCheck: + case FishingState.StartMove: if (--counter < 0) { - DurabilityCheckAndMove(); + double[,]? locationList = Settings.AutoFishing_Location; + if (locationList != null) + { + UpdateLocation(locationList); + state = FishingState.WaitingMovement; + } + else + { + counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + state = FishingState.DurabilityCheck; + goto case FishingState.DurabilityCheck; + } } break; - case FishingState.ChangeLocation: + case FishingState.WaitingMovement: if (!ClientIsMoving()) { LookAtLocation(nextYaw, nextPitch); LogToConsole(Translations.Get("bot.autoFish.update_lookat", nextYaw, nextPitch)); + state = FishingState.DurabilityCheck; + goto case FishingState.DurabilityCheck; + } + break; + case FishingState.DurabilityCheck: + if (DurabilityCheck()) + { counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); state = FishingState.WaitingToCast; } @@ -211,6 +228,16 @@ namespace MinecraftClient.ChatBots } } + public override void AfterGameJoined() + { + StartFishing(); + } + + public override void OnRespawn() + { + StartFishing(); + } + public override void OnDeath() { StopFishing(); @@ -227,14 +254,26 @@ namespace MinecraftClient.ChatBots return base.OnDisconnect(reason, message); } - private void UseFishRod() + /// + /// Called when detected a fish is caught + /// + public void OnCaughtFish() { - if (Settings.AutoFishing_Mainhand) - UseItemInHand(); + ++fishCount; + if (Settings.AutoFishing_Location != null) + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught_at", + fishingBobber!.Location.X, fishingBobber!.Location.Y, fishingBobber!.Location.Z, fishCount)); else - UseItemInLeftHand(); - } + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught", fishCount)); + lock (stateLock) + { + UseFishRod(); + + counter = 0; + state = FishingState.StartMove; + } + } private void UpdateLocation(double[,] locationList) { if (curLocationIdx >= locationList.GetLength(0)) @@ -298,86 +337,46 @@ namespace MinecraftClient.ChatBots } - private void DurabilityCheckAndMove() - { - if (inventoryEnabled) - { - if (!HasFishingRod()) - { - LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.no_rod")); - - lock (stateLock) - { - state = FishingState.Stopping; - } - - return; - } - } - - double[,]? locationList = Settings.AutoFishing_Location; - if (locationList != null) - { - UpdateLocation(locationList); - lock (stateLock) - { - state = FishingState.ChangeLocation; - } - } - else - { - lock (stateLock) - { - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); - state = FishingState.WaitingToCast; - } - } - } - - /// - /// Called when detected a fish is caught - /// - public void OnCaughtFish() - { - ++fishCount; - if (Settings.AutoFishing_Location != null) - LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught_at", - fishingBobber!.Location.X, fishingBobber!.Location.Y, fishingBobber!.Location.Z, fishCount)); - else - LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught", fishCount)); - - lock (stateLock) - { - UseFishRod(); - - counter = 0; - state = FishingState.DurabilityCheck; - } - } - - /// - /// Check whether the player has a fishing rod in inventory - /// - /// TRUE if the player has a fishing rod - public bool HasFishingRod() + private bool DurabilityCheck() { if (!inventoryEnabled) - return false; + return true; - int start = 36; - int end = 44; + bool useMainHand = Settings.AutoFishing_Mainhand; Container container = GetPlayerInventory(); - foreach (KeyValuePair a in container.Items) + int itemSolt = useMainHand ? GetCurrentSlot() + 36 : 45; + + if (container.Items.TryGetValue(itemSolt, out Item? handItem) && + handItem.Type == ItemType.FishingRod && (64 - handItem.Damage) >= Settings.AutoFishing_DurabilityLimit) { - if (a.Key < start || a.Key > end) - continue; - - if (a.Value.Type == ItemType.FishingRod) - return true; + isWaitingRod = false; + return true; } + else + { + if (!isWaitingRod) + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.no_rod")); - return false; + if (Settings.AutoFishing_AutoRodSwitch) + { + foreach ((int slot, Item item) in container.Items) + { + if (item.Type == ItemType.FishingRod && (64 - item.Damage) >= Settings.AutoFishing_DurabilityLimit) + { + WindowAction(0, slot, WindowActionType.LeftClick); + WindowAction(0, itemSolt, WindowActionType.LeftClick); + WindowAction(0, slot, WindowActionType.LeftClick); + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.switch", slot, (64 - item.Damage))); + isWaitingRod = false; + return true; + } + } + } + + isWaitingRod = true; + return false; + } } } } diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini index 4632cd00..d5453f82 100644 --- a/MinecraftClient/Resources/config/MinecraftClient.ini +++ b/MinecraftClient/Resources/config/MinecraftClient.ini @@ -212,6 +212,8 @@ fishing_delay=3.0 # How long after entering the game to start f fishing_timeout=300.0 # Fishing timeout (seconds). Timeout will trigger a re-cast. fishing_hook_threshold=0.2 # Fish hooks moving on the Y-axis above this threshold will be considered to have caught a fish. fishing_cast_delay=0.4 # How soon to re-cast after successful fishing. +durability_limit=2 # Will not use rods with less durability than this (full durability is 64). Set to zero to disable this feature. +auto_rod_switch=true # Switch to a new rod from inventory after the current rod is unavailable. location= # Some plugins do not allow the player to fish in one place. This allows the player to change position/angle after each fish caught. # Floating point numbers can be used for both coordinates and angles. Leave blank to disable this function. # Change the angle only (recommended): location=yaw_1,pitch_1;yaw_2,pitch_2;...;yaw_n,pitch_n diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini index 15b6d2e9..637c40bd 100644 --- a/MinecraftClient/Resources/lang/en.ini +++ b/MinecraftClient/Resources/lang/en.ini @@ -454,11 +454,12 @@ bot.autoFish.start=Fishing will start in {0:0.0} second(s). bot.autoFish.throw=Casting successfully. bot.autoFish.caught=Caught a fish! (Count: {0}) bot.autoFish.caught_at=Caught a fish at ({0:0.0},{1:0.0},{2:0.0})! (Count: {3}) -bot.autoFish.no_rod=No Fishing Rod on hand. Maybe broken? +bot.autoFish.no_rod=Current fishing rod is not available. Maybe broken or low durability? bot.autoFish.despawn=Fish floating despawn, will re-cast. bot.autoFish.fishing_timeout=Fishing timeout, will soon re-cast. bot.autoFish.cast_timeout=Casting timeout and will soon retry. (Timeout increased to {0:0.0} sec). bot.autoFish.update_lookat=Update yaw = {0:0.00}, pitch = {1:0.00}. +bot.autoFish.switch=Switch to the rod in slot {0}, durability {1}/64. # AutoRelog bot.autoRelog.launch=Launching with {0} reconnection attempts diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 30e46cc0..0a14b1a6 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -208,6 +208,8 @@ namespace MinecraftClient public static double AutoFishing_FishingTimeout = 600.0; public static double AutoFishing_FishingHookThreshold = 0.2; public static double AutoFishing_FishingCastDelay = 0.4; + public static double AutoFishing_DurabilityLimit = 2; + public static bool AutoFishing_AutoRodSwitch = true; public static double[,]? AutoFishing_Location = null; //Auto Eating @@ -721,8 +723,10 @@ namespace MinecraftClient case "fishing_timeout": AutoFishing_FishingTimeout = str2double(argValue); return true; case "fishing_hook_threshold": AutoFishing_FishingHookThreshold = str2double(argValue); return true; case "fishing_cast_delay": AutoFishing_FishingCastDelay = str2double(argValue); return true; + case "durability_limit": AutoFishing_DurabilityLimit = str2int(argValue); return true; + case "auto_rod_switch": AutoFishing_AutoRodSwitch = str2bool(argValue); return true; case "location": AutoFishing_Location = str2locationList(argValue); return true; - } + } break; case Section.AutoEat: From 34277e3fbd1e0d555d2f6c040151d373c140c4ed Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 19:02:08 +0800 Subject: [PATCH 07/10] Fix a bug in message signature --- MinecraftClient/Protocol/Handlers/Protocol18.cs | 2 +- MinecraftClient/Protocol/PlayerInfo.cs | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 3f7b233c..aa22af19 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -595,7 +595,7 @@ namespace MinecraftClient.Protocol.Handlers bool lastVerifyResult = player.IsMessageChainLegal(); verifyResult = player.VerifyMessageHead(ref precedingSignature, ref headerSignature, ref bodyDigest); if (lastVerifyResult && !verifyResult) - log.Warn("Player " + player.Name + "'s message chain is broken!"); + log.Warn(Translations.Get("chat.message_chain_broken", player.Name)); } } } diff --git a/MinecraftClient/Protocol/PlayerInfo.cs b/MinecraftClient/Protocol/PlayerInfo.cs index b16376ce..3d6f0a40 100644 --- a/MinecraftClient/Protocol/PlayerInfo.cs +++ b/MinecraftClient/Protocol/PlayerInfo.cs @@ -46,6 +46,7 @@ namespace MinecraftClient.Protocol Gamemode = gamemode; Ping = ping; DisplayName = displayName; + lastMessageVerified = false; if (timeStamp != null && publicKey != null && signature != null) { DateTimeOffset dateTimeOffset = DateTimeOffset.FromUnixTimeMilliseconds((long)timeStamp); @@ -53,13 +54,13 @@ namespace MinecraftClient.Protocol try { PublicKey = new PublicKey(publicKey, signature); + lastMessageVerified = true; } catch (System.Security.Cryptography.CryptographicException) { PublicKey = null; } } - lastMessageVerified = true; precedingSignature = null; } @@ -121,9 +122,15 @@ namespace MinecraftClient.Protocol if (this.lastMessageVerified == false) return false; if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null)) + { + this.lastMessageVerified = false; return false; + } if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!)) + { + this.lastMessageVerified = false; return false; + } DateTimeOffset timeOffset = DateTimeOffset.FromUnixTimeMilliseconds(timestamp); @@ -150,9 +157,15 @@ namespace MinecraftClient.Protocol if (this.lastMessageVerified == false) return false; if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null)) + { + this.lastMessageVerified = false; return false; + } if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!)) + { + this.lastMessageVerified = false; return false; + } bool res = PublicKey.VerifyHeader(Uuid, ref bodyDigest, ref headerSignature, ref precedingSignature); From dac60200e04b03b3f416c18df36784bb73ebcc65 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 23:15:57 +0800 Subject: [PATCH 08/10] Configurable to start fishing automatically or not --- MinecraftClient/ChatBots/AutoFishing.cs | 34 ++++++++++++++----- .../Resources/config/MinecraftClient.ini | 1 + MinecraftClient/Settings.cs | 3 ++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 98cf53d5..775f74a9 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -58,12 +58,22 @@ namespace MinecraftClient.ChatBots private void StartFishing() { isFishing = false; - double delay = Settings.AutoFishing_FishingDelay; - LogToConsole(Translations.Get("bot.autoFish.start", delay)); - lock (stateLock) + if (Settings.AutoFishing_AutoStart) { - counter = (int)(delay * 10); - state = FishingState.StartMove; + double delay = Settings.AutoFishing_FishingDelay; + LogToConsole(Translations.Get("bot.autoFish.start", delay)); + lock (stateLock) + { + counter = (int)(delay * 10); + state = FishingState.StartMove; + } + } + else + { + lock (stateLock) + { + state = FishingState.WaitJoinGame; + } } } @@ -129,8 +139,16 @@ namespace MinecraftClient.ChatBots double[,]? locationList = Settings.AutoFishing_Location; if (locationList != null) { - UpdateLocation(locationList); - state = FishingState.WaitingMovement; + if (GetTerrainEnabled()) + { + UpdateLocation(locationList); + state = FishingState.WaitingMovement; + } + else + { + LogToConsole(Translations.Get("extra.terrainandmovement_required")); + state = FishingState.WaitJoinGame; + } } else { @@ -274,6 +292,7 @@ namespace MinecraftClient.ChatBots state = FishingState.StartMove; } } + private void UpdateLocation(double[,] locationList) { if (curLocationIdx >= locationList.GetLength(0)) @@ -336,7 +355,6 @@ namespace MinecraftClient.ChatBots curLocationIdx += moveDir; } - private bool DurabilityCheck() { if (!inventoryEnabled) diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini index d5453f82..caa957b8 100644 --- a/MinecraftClient/Resources/config/MinecraftClient.ini +++ b/MinecraftClient/Resources/config/MinecraftClient.ini @@ -208,6 +208,7 @@ interaction=Attack # Possible values: Interact, Attack (default) enabled=false antidespawn=false main_hand=true # Use the main hand or the second hand to hold the rod. +auto_start=true # Whether to start fishing automatically after entering a world. fishing_delay=3.0 # How long after entering the game to start fishing (seconds). fishing_timeout=300.0 # Fishing timeout (seconds). Timeout will trigger a re-cast. fishing_hook_threshold=0.2 # Fish hooks moving on the Y-axis above this threshold will be considered to have caught a fish. diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 0a14b1a6..da17ce82 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -204,6 +204,7 @@ namespace MinecraftClient public static bool AutoFishing_Enabled = false; public static bool AutoFishing_Antidespawn = false; public static bool AutoFishing_Mainhand = true; + public static bool AutoFishing_AutoStart = true; public static double AutoFishing_FishingDelay = 3.0; public static double AutoFishing_FishingTimeout = 600.0; public static double AutoFishing_FishingHookThreshold = 0.2; @@ -719,6 +720,8 @@ namespace MinecraftClient { case "enabled": AutoFishing_Enabled = str2bool(argValue); return true; case "antidespawn": AutoFishing_Antidespawn = str2bool(argValue); return true; + case "main_hand": AutoFishing_Mainhand = str2bool(argValue); return true; + case "auto_start": AutoFishing_AutoStart = str2bool(argValue); return true; case "fishing_delay": AutoFishing_FishingDelay = str2double(argValue); return true; case "fishing_timeout": AutoFishing_FishingTimeout = str2double(argValue); return true; case "fishing_hook_threshold": AutoFishing_FishingHookThreshold = str2double(argValue); return true; From fc444fcbd67e147c5146a37997d86612b517c4c8 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Tue, 13 Sep 2022 19:25:00 +0800 Subject: [PATCH 09/10] Supports setting thresholds --- MinecraftClient/ChatBots/AutoFishing.cs | 55 +++++++++++-------- .../Resources/config/MinecraftClient.ini | 12 ++-- MinecraftClient/Settings.cs | 20 ++++--- 3 files changed, 51 insertions(+), 36 deletions(-) diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 775f74a9..55637ec6 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -104,7 +104,7 @@ namespace MinecraftClient.ChatBots break; case FishingState.WaitingToCast: if (AutoEat.Eating) - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + counter = (int)(Settings.AutoFishing_CastDelay * 10); else if (--counter < 0) state = FishingState.CastingRod; break; @@ -120,7 +120,7 @@ namespace MinecraftClient.ChatBots castTimeout *= 2; // Exponential backoff LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.cast_timeout", castTimeout / 10.0)); - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + counter = (int)(Settings.AutoFishing_CastDelay * 10); state = FishingState.WaitingToCast; } break; @@ -129,7 +129,7 @@ namespace MinecraftClient.ChatBots { LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.fishing_timeout")); - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + counter = (int)(Settings.AutoFishing_CastDelay * 10); state = FishingState.WaitingToCast; } break; @@ -152,7 +152,7 @@ namespace MinecraftClient.ChatBots } else { - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + counter = (int)(Settings.AutoFishing_CastDelay * 10); state = FishingState.DurabilityCheck; goto case FishingState.DurabilityCheck; } @@ -171,7 +171,7 @@ namespace MinecraftClient.ChatBots case FishingState.DurabilityCheck: if (DurabilityCheck()) { - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); + counter = (int)(Settings.AutoFishing_CastDelay * 10); state = FishingState.WaitingToCast; } break; @@ -185,6 +185,9 @@ namespace MinecraftClient.ChatBots { if (entity.Type == EntityType.FishingBobber && entity.ObjectData == GetPlayerEntityID()) { + if (Settings.AutoFishing_LogFishingBobber) + LogToConsole(string.Format("FishingBobber spawn at {0}, distance = {1:0.00}", entity.Location, GetCurrentLocation().Distance(entity.Location))); + LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.throw")); lock (stateLock) { @@ -201,18 +204,24 @@ namespace MinecraftClient.ChatBots public override void OnEntityDespawn(Entity entity) { - if (isFishing && entity.Type == EntityType.FishingBobber && entity.ID == fishingBobber!.ID) + if (entity.Type == EntityType.FishingBobber && entity.ID == fishingBobber!.ID) { - isFishing = false; + if (Settings.AutoFishing_LogFishingBobber) + LogToConsole(string.Format("FishingBobber despawn at {0}", entity.Location)); - if (Settings.AutoFishing_Antidespawn) + if (isFishing) { - LogToConsoleTranslated("bot.autoFish.despawn"); + isFishing = false; - lock (stateLock) + if (Settings.AutoFishing_Antidespawn) { - counter = (int)(Settings.AutoFishing_FishingCastDelay * 10); - state = FishingState.WaitingToCast; + LogToConsoleTranslated("bot.autoFish.despawn"); + + lock (stateLock) + { + counter = (int)(Settings.AutoFishing_CastDelay * 10); + state = FishingState.WaitingToCast; + } } } } @@ -228,19 +237,19 @@ namespace MinecraftClient.ChatBots double Dz = LastPos.Z - Pos.Z; LastPos = Pos; - // check if fishing hook is stationary - if (Dx == 0 && Dz == 0) + if (Settings.AutoFishing_LogFishingBobber) + LogToConsole(string.Format("FishingBobber {0} Dx={1:0.000000} Dy={2:0.000000} Dz={3:0.000000}", Pos, Dx, Math.Abs(Dy), Dz)); + + if (Math.Abs(Dx) < Math.Abs(Settings.AutoFishing_StationaryThreshold) && + Math.Abs(Dz) < Math.Abs(Settings.AutoFishing_StationaryThreshold) && + Math.Abs(Dy) > Math.Abs(Settings.AutoFishing_HookThreshold)) { - if (Math.Abs(Dy) > Settings.AutoFishing_FishingHookThreshold) + // prevent triggering multiple time + if ((DateTime.Now - CaughtTime).TotalSeconds > 1) { - // caught - // prevent triggering multiple time - if ((DateTime.Now - CaughtTime).TotalSeconds > 1) - { - isFishing = false; - CaughtTime = DateTime.Now; - OnCaughtFish(); - } + isFishing = false; + CaughtTime = DateTime.Now; + OnCaughtFish(); } } } diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini index caa957b8..634004f8 100644 --- a/MinecraftClient/Resources/config/MinecraftClient.ini +++ b/MinecraftClient/Resources/config/MinecraftClient.ini @@ -209,17 +209,19 @@ enabled=false antidespawn=false main_hand=true # Use the main hand or the second hand to hold the rod. auto_start=true # Whether to start fishing automatically after entering a world. +cast_delay=0.4 # How soon to re-cast after successful fishing. fishing_delay=3.0 # How long after entering the game to start fishing (seconds). fishing_timeout=300.0 # Fishing timeout (seconds). Timeout will trigger a re-cast. -fishing_hook_threshold=0.2 # Fish hooks moving on the Y-axis above this threshold will be considered to have caught a fish. -fishing_cast_delay=0.4 # How soon to re-cast after successful fishing. durability_limit=2 # Will not use rods with less durability than this (full durability is 64). Set to zero to disable this feature. auto_rod_switch=true # Switch to a new rod from inventory after the current rod is unavailable. +stationary_threshold=0.001 # Hooks moving in the X and Z axes below this threshold will be considered stationary. +hook_threshold=0.2 # A stationary hook moving on the Y-axis above this threshold will be considered to have caught a fish. +log_fishing_bobber=false # For debugging purposes, you can use this log to adjust the two thresholds mentioned above. location= # Some plugins do not allow the player to fish in one place. This allows the player to change position/angle after each fish caught. # Floating point numbers can be used for both coordinates and angles. Leave blank to disable this function. - # Change the angle only (recommended): location=yaw_1,pitch_1;yaw_2,pitch_2;...;yaw_n,pitch_n - # Change position only: location=x1,y1,z1;x2,y2,z2;...;xn,yn,zn - # Change both angle and position: location=x1,y1,z1,yaw_1,pitch_1;x2,y2,z2,yaw_2,pitch_2;...;xn,yn,zn,yaw_n,pitch_n + # Change the angle only (recommended): location=yaw_1, pitch_1; yaw_2, pitch_2; ...; yaw_n, pitch_n + # Change position only: location=x1, y1, z1; x2, y2, z2; ...; xn, yn, zn + # Change both angle and position: location=x1, y1, z1, yaw_1, pitch_1; x2, y2, z2, yaw_2, pitch_2; ... ;xn, yn, zn, yaw_n, pitch_n [AutoEat] # Automatically eat food when your Hunger value is low diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index da17ce82..254f7c31 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -205,12 +205,14 @@ namespace MinecraftClient public static bool AutoFishing_Antidespawn = false; public static bool AutoFishing_Mainhand = true; public static bool AutoFishing_AutoStart = true; - public static double AutoFishing_FishingDelay = 3.0; - public static double AutoFishing_FishingTimeout = 600.0; - public static double AutoFishing_FishingHookThreshold = 0.2; - public static double AutoFishing_FishingCastDelay = 0.4; + public static double AutoFishing_CastDelay = 0.4; + public static double AutoFishing_FishingDelay = 3.0; + public static double AutoFishing_FishingTimeout = 300.0; public static double AutoFishing_DurabilityLimit = 2; public static bool AutoFishing_AutoRodSwitch = true; + public static double AutoFishing_StationaryThreshold = 0.001; + public static double AutoFishing_HookThreshold = 0.2; + public static bool AutoFishing_LogFishingBobber = false; public static double[,]? AutoFishing_Location = null; //Auto Eating @@ -722,14 +724,16 @@ namespace MinecraftClient case "antidespawn": AutoFishing_Antidespawn = str2bool(argValue); return true; case "main_hand": AutoFishing_Mainhand = str2bool(argValue); return true; case "auto_start": AutoFishing_AutoStart = str2bool(argValue); return true; + case "cast_delay": AutoFishing_CastDelay = str2double(argValue); return true; case "fishing_delay": AutoFishing_FishingDelay = str2double(argValue); return true; case "fishing_timeout": AutoFishing_FishingTimeout = str2double(argValue); return true; - case "fishing_hook_threshold": AutoFishing_FishingHookThreshold = str2double(argValue); return true; - case "fishing_cast_delay": AutoFishing_FishingCastDelay = str2double(argValue); return true; case "durability_limit": AutoFishing_DurabilityLimit = str2int(argValue); return true; - case "auto_rod_switch": AutoFishing_AutoRodSwitch = str2bool(argValue); return true; + case "auto_rod_switch": AutoFishing_AutoRodSwitch = str2bool(argValue); return true; + case "stationary_threshold": AutoFishing_StationaryThreshold = str2double(argValue); return true; + case "hook_threshold": AutoFishing_HookThreshold = str2double(argValue); return true; + case "log_fishing_bobber": AutoFishing_LogFishingBobber = str2bool(argValue); return true; case "location": AutoFishing_Location = str2locationList(argValue); return true; - } + } break; case Section.AutoEat: From 97248aad164ed8ba3088ca1f99b0d32b3de480e6 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Tue, 13 Sep 2022 19:29:17 +0800 Subject: [PATCH 10/10] Add OnSettingsReload --- MinecraftClient/ChatBots/AutoFishing.cs | 26 +++++++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 55637ec6..b767cdc2 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -47,14 +47,36 @@ namespace MinecraftClient.ChatBots if (!GetEntityHandlingEnabled()) { LogToConsoleTranslated("extra.entity_required"); - LogToConsoleTranslated("general.bot_unload"); - UnloadBot(); + state = FishingState.WaitJoinGame; } inventoryEnabled = GetInventoryEnabled(); if (!inventoryEnabled) LogToConsoleTranslated("bot.autoFish.no_inv_handle"); } + /// + /// Update settings when reloaded + /// + public /* override */ void OnSettingsReload() + { + if (Settings.AutoFishing_Enabled) + { + if (!GetEntityHandlingEnabled()) + { + LogToConsoleTranslated("extra.entity_required"); + state = FishingState.WaitJoinGame; + } + inventoryEnabled = GetInventoryEnabled(); + if (!inventoryEnabled) + LogToConsoleTranslated("bot.autoFish.no_inv_handle"); + } + else + { + UnloadBot(); + return; + } + } + private void StartFishing() { isFishing = false;