diff --git a/MinecraftClient/ChatBots/AntiAFK.cs b/MinecraftClient/ChatBots/AntiAFK.cs
index a54e8bcc..d078aae5 100644
--- a/MinecraftClient/ChatBots/AntiAFK.cs
+++ b/MinecraftClient/ChatBots/AntiAFK.cs
@@ -1,7 +1,5 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using MinecraftClient.Mapping;
namespace MinecraftClient.ChatBots
{
@@ -12,28 +10,158 @@ namespace MinecraftClient.ChatBots
public class AntiAFK : ChatBot
{
private int count;
- private int timeping;
+ private string pingparam;
+ private int timeping = 600;
+ private int timepingMax = -1;
+ private bool useTerrainHandling = false;
+ private bool previousSneakState = false;
+ private int walkRange = 5;
+ private int walkRetries = 10;
+ private Random random = new Random();
///
/// This bot sends a /ping command every X seconds in order to stay non-afk.
///
- /// Time amount between each ping (10 = 1s, 600 = 1 minute, etc.)
+ /// Time amount between each ping (10 = 1s, 600 = 1 minute, etc.) Can be a range of numbers eg. 10-600
- public AntiAFK(int pingparam)
+ public AntiAFK(string pingparam, bool useTerrainHandling, int walkRange, int walkRetries)
{
count = 0;
- timeping = pingparam;
+ this.pingparam = pingparam;
+ this.useTerrainHandling = useTerrainHandling;
+ this.walkRange = walkRange;
+ this.walkRetries = walkRetries;
+ }
+
+ public override void Initialize()
+ {
+ if (useTerrainHandling)
+ {
+ if (!GetTerrainEnabled())
+ {
+ useTerrainHandling = false;
+ LogToConsole(Translations.TryGet("bot.antiafk.not_using_terrain_handling"));
+ }
+ else
+ {
+ if (walkRange <= 0)
+ {
+ walkRange = 5;
+ LogToConsole(Translations.TryGet("bot.antiafk.invalid_walk_range"));
+ }
+ }
+ }
+
+ if (string.IsNullOrEmpty(pingparam))
+ LogToConsole(Translations.TryGet("bot.antiafk.invalid_time"));
+ else
+ {
+ // Handle the random range
+ if (pingparam.Contains("-"))
+ {
+ string[] parts = pingparam.Split("-");
+
+ if (parts.Length == 2)
+ {
+ if (int.TryParse(parts[0].Trim(), out int firstTime))
+ {
+ timeping = firstTime;
+
+ if (int.TryParse(parts[1].Trim(), out int secondTime))
+ timepingMax = secondTime;
+ else LogToConsole(Translations.TryGet("bot.antiafk.invalid_range_partial", timeping));
+ }
+ else LogToConsole(Translations.TryGet("bot.antiafk.invalid_range"));
+ }
+ else LogToConsole(Translations.TryGet("bot.antiafk.invalid_range"));
+ }
+ else
+ {
+ if (int.TryParse(pingparam.Trim(), out int value))
+ timeping = value;
+ else LogToConsole(Translations.TryGet("bot.antiafk.invalid_value"));
+ }
+ }
+
+ if (timepingMax != -1 && timeping > timepingMax)
+ {
+ int temporary = timepingMax;
+ timepingMax = timeping;
+ timeping = temporary;
+
+ LogToConsole(Translations.TryGet("bot.antiafk.swapping"));
+ }
+
if (timeping < 10) { timeping = 10; } //To avoid flooding
}
public override void Update()
{
count++;
- if (count == timeping)
+
+ if ((timepingMax != -1 && count == random.Next(timeping, timepingMax)) || count == timeping)
{
- SendText(Settings.AntiAFK_Command);
+ DoAntiAfkStuff();
count = 0;
}
+
+ }
+
+ private void DoAntiAfkStuff()
+ {
+ if (useTerrainHandling)
+ {
+ Location currentLocation = GetCurrentLocation();
+ Location goal;
+
+ bool moved = false;
+ bool useAlternativeMethod = false;
+ int triesCounter = 0;
+
+ while (!moved)
+ {
+ if (triesCounter++ >= walkRetries)
+ {
+ useAlternativeMethod = true;
+ break;
+ }
+
+ goal = GetRandomLocationWithinRangeXZ(currentLocation, walkRange);
+
+ // Prevent getting the same location
+ while ((currentLocation.X == goal.X) && (currentLocation.Y == goal.Y) && (currentLocation.Z == goal.Z))
+ {
+ LogToConsole("Same location!, generating new one");
+ goal = GetRandomLocationWithinRangeXZ(currentLocation, walkRange);
+ }
+
+ if (!Movement.CheckChunkLoading(GetWorld(), currentLocation, goal))
+ {
+ useAlternativeMethod = true;
+ break;
+ }
+ else moved = MoveToLocation(goal, allowUnsafe: false, allowDirectTeleport: false);
+ }
+
+ if (!useAlternativeMethod)
+ {
+ // Solve the case when the bot was closed in 1x2, was sneaking, but then he was freed, this will make him not sneak anymore
+ previousSneakState = false;
+ Sneak(false);
+
+ return;
+ }
+ }
+
+ SendText(Settings.AntiAFK_Command);
+ Sneak(previousSneakState);
+ previousSneakState = !previousSneakState;
+ count = 0;
+ }
+
+ private Location GetRandomLocationWithinRangeXZ(Location currentLocation, int range)
+ {
+ return new Location(currentLocation.X + random.Next(range * -1, range), currentLocation.Y, currentLocation.Z + random.Next(range * -1, range));
}
}
}
diff --git a/MinecraftClient/ChatBots/Map.cs b/MinecraftClient/ChatBots/Map.cs
index 0969daba..a6793e1f 100644
--- a/MinecraftClient/ChatBots/Map.cs
+++ b/MinecraftClient/ChatBots/Map.cs
@@ -33,7 +33,7 @@ namespace MinecraftClient.ChatBots
deleteAllOnExit = Settings.Map_Delete_All_On_Unload;
notifyOnFirstUpdate = Settings.Map_Notify_On_First_Update;
- RegisterChatBotCommand("maps", "bot.map.cmd.desc", "maps > | maps >", OnMapCommand);
+ RegisterChatBotCommand("maps", "bot.map.cmd.desc", "maps list|render or maps l|r ", OnMapCommand);
}
public override void OnUnload()
diff --git a/MinecraftClient/Commands/Bed.cs b/MinecraftClient/Commands/Bed.cs
new file mode 100644
index 00000000..89f6c7a7
--- /dev/null
+++ b/MinecraftClient/Commands/Bed.cs
@@ -0,0 +1,150 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using MinecraftClient.Mapping;
+
+namespace MinecraftClient.Commands
+{
+ public class BedCommand : Command
+ {
+ public override string CmdName { get { return "bed"; } }
+ public override string CmdUsage { get { return "bed leave|sleep |sleep "; } }
+ public override string CmdDesc { get { return "cmd.bed.desc"; } }
+
+ public override string Run(McClient handler, string command, Dictionary localVars)
+ {
+ string[] args = getArgs(command);
+
+ if (args.Length >= 1)
+ {
+ string subcommand = args[0].ToLower().Trim();
+
+ if (subcommand.Equals("leave") || subcommand.Equals("l"))
+ {
+ handler.SendEntityAction(Protocol.EntityActionType.LeaveBed);
+ return Translations.TryGet("cmd.bed.leaving");
+ }
+
+ if (subcommand.Equals("sleep") || subcommand.Equals("s"))
+ {
+ if (args.Length == 2)
+ {
+ if (!int.TryParse(args[1], out int radius))
+ return CmdUsage;
+
+ handler.GetLogger().Info(Translations.TryGet("cmd.bed.searching", radius));
+
+ Location current = handler.GetCurrentLocation();
+ Location bedLocation = current;
+
+ Material[] bedMaterialList = new Material[]{
+ Material.BlackBed,
+ Material.BlueBed,
+ Material.BrownBed,
+ Material.CyanBed,
+ Material.GrayBed,
+ Material.GreenBed,
+ Material.LightBlueBed,
+ Material.LightGrayBed,
+ Material.LimeBed,
+ Material.MagentaBed,
+ Material.OrangeBed,
+ Material.PinkBed,
+ Material.PurpleBed,
+ Material.RedBed,
+ Material.WhiteBed,
+ Material.YellowBed
+ };
+
+ bool found = false;
+ foreach (Material material in bedMaterialList)
+ {
+ List beds = handler.GetWorld().FindBlock(current, material, radius);
+
+ if (beds.Count > 0)
+ {
+ found = true;
+ bedLocation = beds.First();
+ break;
+ }
+ }
+
+ if (!found)
+ return Translations.TryGet("cmd.bed.bed_not_found");
+
+ handler.Log.Info(Translations.TryGet("cmd.bed.found_a_bed_at", bedLocation.X, bedLocation.Y, bedLocation.Z));
+
+ if (!Movement.CheckChunkLoading(handler.GetWorld(), current, bedLocation))
+ return Translations.Get("cmd.move.chunk_not_loaded", bedLocation.X, bedLocation.Y, bedLocation.Z);
+
+ if (handler.MoveTo(bedLocation))
+ {
+ Task.Factory.StartNew(() =>
+ {
+ bool atTheLocation = false;
+ DateTime timeout = DateTime.Now.AddSeconds(60);
+
+ while (DateTime.Now < timeout)
+ {
+ if (handler.GetCurrentLocation() == bedLocation || handler.GetCurrentLocation().Distance(bedLocation) <= 2.0)
+ {
+ atTheLocation = true;
+ break;
+ }
+ }
+
+ if (!atTheLocation)
+ {
+ handler.Log.Info(Translations.TryGet("cmd.bed.failed_to_reach_in_time", bedLocation.X, bedLocation.Y, bedLocation.Z));
+ return;
+ }
+
+ handler.Log.Info(Translations.TryGet("cmd.bed.moving", bedLocation.X, bedLocation.Y, bedLocation.Z));
+
+ bool res = handler.PlaceBlock(bedLocation, Direction.Down);
+
+ handler.Log.Info(Translations.TryGet(
+ "cmd.bed.trying_to_use",
+ bedLocation.X,
+ bedLocation.Y,
+ bedLocation.Z,
+ Translations.TryGet(res ? "cmd.bed.in" : "cmd.bed.not_in")
+ ));
+ });
+
+ return "";
+ }
+
+ return Translations.Get("cmd.bed.cant_reach_safely");
+ }
+
+ if (args.Length >= 3)
+ {
+ Location current = handler.GetCurrentLocation();
+ double x = args[1].StartsWith('~') ? current.X + (args[1].Length > 1 ? double.Parse(args[1][1..]) : 0) : double.Parse(args[1]);
+ double y = args[2].StartsWith('~') ? current.Y + (args[2].Length > 1 ? double.Parse(args[2][1..]) : 0) : double.Parse(args[2]);
+ double z = args[3].StartsWith('~') ? current.Z + (args[3].Length > 1 ? double.Parse(args[3][1..]) : 0) : double.Parse(args[3]);
+
+ Location block = new Location(x, y, z).ToFloor(), blockCenter = block.ToCenter();
+
+ if (!handler.GetWorld().GetBlock(block).Type.IsBed())
+ return Translations.TryGet("cmd.bed.not_a_bed", blockCenter.X, blockCenter.Y, blockCenter.Z);
+
+ bool res = handler.PlaceBlock(block, Direction.Down);
+
+ return Translations.TryGet(
+ "cmd.bed.trying_to_use",
+ blockCenter.X,
+ blockCenter.Y,
+ blockCenter.Z,
+ Translations.TryGet(res ? "cmd.bed.in" : "cmd.bed.not_in")
+ );
+ }
+ }
+ }
+
+ return CmdUsage;
+ }
+ }
+}
\ No newline at end of file
diff --git a/MinecraftClient/Mapping/MaterialExtensions.cs b/MinecraftClient/Mapping/MaterialExtensions.cs
index fafa4894..f1b9129a 100644
--- a/MinecraftClient/Mapping/MaterialExtensions.cs
+++ b/MinecraftClient/Mapping/MaterialExtensions.cs
@@ -752,6 +752,7 @@ namespace MinecraftClient.Mapping
return false;
}
}
+
///
/// Check if the provided material is a liquid a player can swim into
///
@@ -768,5 +769,36 @@ namespace MinecraftClient.Mapping
return false;
}
}
+
+ ///
+ /// Check if the provided material is a bed
+ ///
+ /// Material to test
+ /// True if the material is a bed
+ public static bool IsBed(this Material m)
+ {
+ switch (m)
+ {
+ case Material.BlackBed:
+ case Material.BlueBed:
+ case Material.BrownBed:
+ case Material.CyanBed:
+ case Material.GrayBed:
+ case Material.GreenBed:
+ case Material.LightBlueBed:
+ case Material.LightGrayBed:
+ case Material.LimeBed:
+ case Material.MagentaBed:
+ case Material.OrangeBed:
+ case Material.PinkBed:
+ case Material.PurpleBed:
+ case Material.RedBed:
+ case Material.WhiteBed:
+ case Material.YellowBed:
+ return true;
+ default:
+ return false;
+ }
+ }
}
}
diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs
index f5305d2e..89809d3f 100644
--- a/MinecraftClient/McClient.cs
+++ b/MinecraftClient/McClient.cs
@@ -271,7 +271,7 @@ namespace MinecraftClient
///
private void RegisterBots(bool reload = false)
{
- if (Settings.AntiAFK_Enabled) { BotLoad(new AntiAFK(Settings.AntiAFK_Delay)); }
+ if (Settings.AntiAFK_Enabled) { BotLoad(new AntiAFK(Settings.AntiAFK_Delay, Settings.AntiAFK_UseTerrain_Handling, Settings.AntiAFK_Walk_Range, Settings.AntiAFK_Walk_Retries)); }
if (Settings.Hangman_Enabled) { BotLoad(new HangmanGame(Settings.Hangman_English)); }
if (Settings.Alerts_Enabled) { BotLoad(new Alerts()); }
if (Settings.ChatLog_Enabled) { BotLoad(new ChatLog(Settings.ExpandVars(Settings.ChatLog_File), Settings.ChatLog_Filter, Settings.ChatLog_DateTime)); }
diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini
index 55562ea7..5ec3aeb8 100644
--- a/MinecraftClient/Resources/config/MinecraftClient.ini
+++ b/MinecraftClient/Resources/config/MinecraftClient.ini
@@ -138,11 +138,15 @@ logtofile=false # Log alerts info a file
logfile=alerts-log.txt # The name of a file where alers logs will be written
[AntiAFK]
-# Send a command on a regular basis to avoid automatic AFK disconnection
+# Send a command on a regular or random basis or make the bot walk around randomly to avoid automatic AFK disconnection
# /!\ Make sure your server rules do not forbid anti-AFK mechanisms!
+# /!\ Make sure you keep the bot in an enclosure to prevent it wandering off if you're using terrain handling! (Recommended size 5x5x5)
enabled=false
-delay=600 #10 = 1s
-command=/ping
+delay=600 # 10 = 1s (Can also be a random number between 2 numbers, example: 50-600) (Default: 600)
+command=/ping # Command to send to the server
+use_terrain_handling=false # Use terrain handling to enable the bot to move around
+walk_range=5 # The range the bot can move around randomly (Note: the bigger the range, the slower the bot will be)
+walk_retries=20 # How many timec can the bot fail trying to move before using the command method
[AutoRelog]
# Automatically relog when disconnected by server, for example because the server is restating
@@ -282,6 +286,7 @@ backupinterval=300 # How long should replay file be auto-saved, i
# This is due to a slow pathfinding algorithm, we're working on getting a better one
# You can tweak the update limit and find what works best for you. (NOTE: Do not but a very low one, because you might achieve the opposite,
# this might clog the thread for terain handling) and thus slow the bot even more.
+# /!\ Make sure server rules allow an option like this in the rules of the server before using this bot
enabled=false
update_limit=10 # The rate at which the bot does calculations (10 = 1s) (Default: 5) (You can tweak this if you feel the bot is too slow)
stop_at_distance=3 # Do not follow the player if he is in the range of 3 blocks (prevents the bot from pushing a player in an infinite loop)
@@ -295,15 +300,17 @@ log_delay=600 # 10 = 1s
[Map]
# Allows you to render maps into .jpg images
# This is useful for solving captchas which use maps
-# NOTE: This is a new feature, we could not find the proper color mappings, but we are continuing with the search
-# The colors are not like in minecraft and might look ugly
-# This feature is currently only useful for solving captchas, which is it's primary purpose for the time being.
+# The maps are rendered into Rendered_Maps folder.
+# NOTE:
+# This feature is currently only useful for solving captchas which use maps.
# If some servers have a very short time for solving captchas, enabe auto_render_on_update and prepare to open the file quickly.
# On linux you can use FTP to access generated files.
+# In the future it might will be possible to display maps directly in the console with a separate command.
+# /!\ Make sure server rules allow bots to be used on the server, or you risk being punished.
enabled=false
resize_map=false # Should the map be resized? (Default one is small 128x128)
resize_to=256 # The size to resize the map to (Note: the bigger it is, the lower the quallity is)
auto_render_on_update=false # Automatically render the map once it's received or updated from/by the server
-delete_rendered_on_unload=true # Delete all rendered maps on unload or exit
+delete_rendered_on_unload=true # Delete all rendered maps on unload/reload (Does not delete the images if you exit the client)
notify_on_first_update=false # Get a notification when you have gotten a map from the server for the first time
- # Note: Will be printed for each map in vicinity, could cause spam if there are a lot of maps
\ No newline at end of file
+ # Note: Will be printed for each map in vicinity, could cause spam if there are a lot of maps
\ No newline at end of file
diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini
index 9cbda134..1a05a119 100644
--- a/MinecraftClient/Resources/lang/en.ini
+++ b/MinecraftClient/Resources/lang/en.ini
@@ -344,6 +344,20 @@ cmd.inventory.help.unknown=Unknown action.
cmd.inventory.found_items=Found items
cmd.inventory.no_found_items=Could not find the specified item in any of avaliable Inventories!
+# Leave bed
+cmd.bed.desc=Used to sleep in or leave a bed.
+cmd.bed.leaving=Sending a command to leave a bed to the server.
+cmd.bed.trying_to_use=Trying to sleep in a bed on location (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}). Result: {3}
+cmd.bed.in=Succesfully laid in bed!
+cmd.bed.not_in=Could not lay in bed. Are you trying to sleep in a bed? (PS: You must use the head block coordinates of the bed)
+cmd.bed.not_a_bed=The block on (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) is not a bed!
+cmd.bed.searching=Searching for a bed in radius of {0}...
+cmd.bed.bed_not_found=Could not find a bed!
+cmd.bed.found_a_bed_at=Found a bet at (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}).
+cmd.bed.cant_reach_safely=Can not reach the bed safely!
+cmd.bed.moving=Moving to (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) where the bed is located.
+cmd.bed.failed_to_reach_in_time=Failed to reach the bed position (X: {0:0.0}, Y: {1:0.0}, Z: {2:0.0}) in time (30 seconds). Giving up!
+
# List
cmd.list.desc=get the player list.
cmd.list.players=PlayerList: {0}
@@ -428,6 +442,14 @@ cmd.useitem.use=Used an item
[bot]
# ChatBots. Naming style: bot..
+# Anti AFK
+bot.antiafk.not_using_terrain_handling=The terrain handling is not enabled in the settings of the client, enable it if you want to use it with this bot. Using alternative (command) method.
+bot.antiafk.invalid_range_partial=Invalid time range provided, using the first part of the range {0} as the time!
+bot.antiafk.invalid_range=Invalid time range provided, using default time of 600!
+bot.antiafk.invalid_value=Invalid time provided, using default time of 600!
+bot.antiafk.swapping=The time range begins with a bigger value, swapped them around.
+bot.antiafk.invalid_walk_range=Invalid walk range provided, must be a positive integer greater than 0, using default value of 5!
+
# AutoAttack
bot.autoAttack.mode=Unknown attack mode: {0}. Using single mode as default.
bot.autoAttack.priority=Unknown priority: {0}. Using distance priority as default.
diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs
index 74e2bf28..70ff4a5b 100644
--- a/MinecraftClient/Settings.cs
+++ b/MinecraftClient/Settings.cs
@@ -141,8 +141,11 @@ namespace MinecraftClient
//AntiAFK Settings
public static bool AntiAFK_Enabled = false;
- public static int AntiAFK_Delay = 600;
+ public static string AntiAFK_Delay = "600";
public static string AntiAFK_Command = "/ping";
+ public static bool AntiAFK_UseTerrain_Handling = false;
+ public static int AntiAFK_Walk_Range = 5;
+ public static int AntiAFK_Walk_Retries = 20;
//Hangman Settings
public static bool Hangman_Enabled = false;
@@ -598,8 +601,11 @@ namespace MinecraftClient
switch (ToLowerIfNeed(argName))
{
case "enabled": AntiAFK_Enabled = str2bool(argValue); return true;
- case "delay": AntiAFK_Delay = str2int(argValue); return true;
+ case "delay": AntiAFK_Delay = argValue; return true;
case "command": AntiAFK_Command = argValue == "" ? "/ping" : argValue; return true;
+ case "use_terrain_handling": AntiAFK_UseTerrain_Handling = str2bool(argValue); return true;
+ case "walk_range": AntiAFK_Walk_Range = str2int(argValue); return true;
+ case "walk_retries": AntiAFK_Walk_Retries = str2int(argValue); return true;
}
break;