From eb517a8e78c8ca7f1fe4d561be14c9b5926af49d Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 02:10:18 +0800 Subject: [PATCH 1/7] 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 2/7] 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 949126c9cb390ec8eb8d21e03994a80e519a2078 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 16:27:37 +0800 Subject: [PATCH 3/7] 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 4/7] 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 dac60200e04b03b3f416c18df36784bb73ebcc65 Mon Sep 17 00:00:00 2001 From: BruceChen Date: Mon, 12 Sep 2022 23:15:57 +0800 Subject: [PATCH 5/7] 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 6/7] 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 7/7] 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;