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
{