Upgrade Auto Fishing

This commit is contained in:
BruceChen 2022-09-12 02:10:18 +08:00
parent 223c13561c
commit eb517a8e78
6 changed files with 182 additions and 53 deletions

@ -1 +1 @@
Subproject commit b4fd7da2595ad54479880fc1c9c6e14975412d92 Subproject commit 7acaa0ab31809f0f6512e6a76e53e15441de8e7c

View file

@ -13,13 +13,30 @@ namespace MinecraftClient.ChatBots
/// </summary> /// </summary>
class AutoFishing : ChatBot class AutoFishing : ChatBot
{ {
private Entity fishingRod; private int fishCount = 0;
private Double fishingHookThreshold = 0.2;
private Location LastPos = new Location();
private DateTime CaughtTime = DateTime.Now;
private bool inventoryEnabled; private bool inventoryEnabled;
private bool isFishing = false; 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() public override void Initialize()
{ {
@ -32,42 +49,94 @@ namespace MinecraftClient.ChatBots
inventoryEnabled = GetInventoryEnabled(); 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() public override void Update()
{ {
if (useItemCounter > 0) lock (stateLock)
{ {
useItemCounter--; switch (state)
if (useItemCounter <= 0)
{ {
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) 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"); fishingBobber = entity;
fishingRod = entity;
LastPos = entity.Location; LastPos = entity.Location;
isFishing = true; isFishing = true;
castTimeout = 24;
counter = 0;
state = FishingState.WaitingFishBite;
} }
} }
} }
public override void OnEntityDespawn(Entity entity) 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; LogToConsoleTranslated("bot.autoFish.despawn");
if (Settings.AutoFishing_Antidespawn)
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) 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; if (Math.Abs(Dy) > Settings.AutoFishing_FishingHookThreshold)
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) > fishingHookThreshold) // caught
// prevent triggering multiple time
if ((DateTime.Now - CaughtTime).TotalSeconds > 1)
{ {
// caught CaughtTime = DateTime.Now;
// prevent triggering multiple time OnCaughtFish();
if ((DateTime.Now - CaughtTime).TotalSeconds > 1)
{
OnCaughtFish();
CaughtTime = DateTime.Now;
}
} }
} }
fishingRod = entity;
} }
} }
} }
public override bool OnDisconnect(DisconnectReason reason, string message) public override bool OnDisconnect(DisconnectReason reason, string message)
{ {
fishingRod = null; lock (stateLock)
LastPos = new Location(); {
isFishing = false;
counter = 0;
state = FishingState.Stopping;
}
fishingBobber = null;
LastPos = Location.Zero;
CaughtTime = DateTime.Now; CaughtTime = DateTime.Now;
isFishing = false;
useItemCounter = 0;
return base.OnDisconnect(reason, message); return base.OnDisconnect(reason, message);
} }
private void UseFishRod()
{
UseItemInHand();
}
/// <summary> /// <summary>
/// Called when detected a fish is caught /// Called when detected a fish is caught
/// </summary> /// </summary>
public void OnCaughtFish() public void OnCaughtFish()
{ {
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught")); lock (stateLock)
// retract fishing rod {
UseItemInHand(); state = FishingState.Preparing;
}
UseFishRod();
++fishCount;
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.caught", fishCount));
if (inventoryEnabled) if (inventoryEnabled)
{ {
if (!hasFishingRod()) if (!HasFishingRod())
{ {
LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.no_rod")); LogToConsole(GetTimestamp() + ": " + Translations.Get("bot.autoFish.no_rod"));
return; return;
} }
} }
// thread-safe
useItemCounter = 8; // 800ms lock (stateLock)
{
counter = (int)(Settings.AutoFishing_FishingCastDelay * 10);
state = FishingState.WaitingToCast;
}
} }
/// <summary> /// <summary>
/// Check whether the player has a fishing rod in inventory /// Check whether the player has a fishing rod in inventory
/// </summary> /// </summary>
/// <returns>TRUE if the player has a fishing rod</returns> /// <returns>TRUE if the player has a fishing rod</returns>
public bool hasFishingRod() public bool HasFishingRod()
{ {
if (!inventoryEnabled) if (!inventoryEnabled)
return false; return false;
int start = 36; int start = 36;
int end = 44; int end = 44;
Inventory.Container container = GetPlayerInventory(); Container container = GetPlayerInventory();
foreach (KeyValuePair<int, Item> a in container.Items) foreach (KeyValuePair<int, Item> a in container.Items)
{ {

View file

@ -207,6 +207,10 @@ interaction=Attack # Possible values: Interact, Attack (default)
# /!\ Make sure server rules allow automated farming before using this bot # /!\ Make sure server rules allow automated farming before using this bot
enabled=false enabled=false
antidespawn=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] [AutoEat]
# Automatically eat food when your Hunger value is low # Automatically eat food when your Hunger value is low

View file

@ -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}! bot.autoDrop.no_inventory=Cannot find inventory {0}!
# AutoFish # AutoFish
bot.autoFish.throw=Threw a fishing rod bot.autoFish.start=Fishing will start in {0:0.0} second(s).
bot.autoFish.caught=Caught a fish! 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.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 # AutoRelog
bot.autoRelog.launch=Launching with {0} reconnection attempts bot.autoRelog.launch=Launching with {0} reconnection attempts

View file

@ -1113,6 +1113,15 @@ namespace MinecraftClient
return Handler.GetUserUuidStr(); return Handler.GetUserUuidStr();
} }
/// <summary>
/// Return the EntityID of the current player
/// </summary>
/// <returns>EntityID of the current player</returns>
protected int GetPlayerEntityID()
{
return Handler.GetPlayerEntityID();
}
/// <summary> /// <summary>
/// Return the list of currently online players /// Return the list of currently online players
/// </summary> /// </summary>

View file

@ -203,6 +203,10 @@ namespace MinecraftClient
//Auto Fishing //Auto Fishing
public static bool AutoFishing_Enabled = false; public static bool AutoFishing_Enabled = false;
public static bool AutoFishing_Antidespawn = 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 //Auto Eating
public static bool AutoEat_Enabled = false; public static bool AutoEat_Enabled = false;
@ -711,6 +715,10 @@ namespace MinecraftClient
{ {
case "enabled": AutoFishing_Enabled = str2bool(argValue); return true; case "enabled": AutoFishing_Enabled = str2bool(argValue); return true;
case "antidespawn": AutoFishing_Antidespawn = 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; break;
@ -863,8 +871,23 @@ namespace MinecraftClient
/// <returns>Float number</returns> /// <returns>Float number</returns>
public static float str2float(string str) public static float str2float(string str)
{ {
float f; if (float.TryParse(str.Trim(), out float f))
if (float.TryParse(str.Trim(), out f)) return f;
else
{
ConsoleIO.WriteLogLine(Translations.Get("error.setting.str2int", str));
return 0;
}
}
/// <summary>
/// Convert the specified string to a double number, defaulting to zero if invalid argument
/// </summary>
/// <param name="str">String to parse as a float number</param>
/// <returns>Double number</returns>
public static double str2double(string str)
{
if (double.TryParse(str.Trim(), out double f))
return f; return f;
else else
{ {