using System; using Brigadier.NET; using MinecraftClient.CommandHandler; using MinecraftClient.Mapping; using MinecraftClient.Scripting; using Tomlet.Attributes; namespace MinecraftClient.ChatBots { /// /// This bot sends a command every 60 seconds in order to stay non-afk. /// public class AntiAFK : ChatBot { public static Configs Config = new(); [TomlDoNotInlineObject] public class Configs { [NonSerialized] private const string BotName = "AntiAFK"; public bool Enabled = false; [TomlInlineComment("$ChatBot.AntiAfk.Delay$")] public Range Delay = new(60); [TomlInlineComment("$ChatBot.AntiAfk.Command$")] public string Command = "/ping"; [TomlInlineComment("$ChatBot.AntiAfk.Use_Sneak$")] public bool Use_Sneak = false; [TomlInlineComment("$ChatBot.AntiAfk.Use_Terrain_Handling$")] public bool Use_Terrain_Handling = false; [TomlInlineComment("$ChatBot.AntiAfk.Walk_Range$")] public int Walk_Range = 5; [TomlInlineComment("$ChatBot.AntiAfk.Walk_Retries$")] public int Walk_Retries = 20; public void OnSettingUpdate() { if (Walk_Range <= 0) { Walk_Range = 5; LogToConsole(BotName, Translations.bot_antiafk_invalid_walk_range); } Delay.min = Math.Max(1.0, Delay.min); Delay.max = Math.Max(1.0, Delay.max); Delay.min = Math.Min(int.MaxValue / 10, Delay.min); Delay.max = Math.Min(int.MaxValue / 10, Delay.max); if (Delay.min > Delay.max) { (Delay.min, Delay.max) = (Delay.max, Delay.min); LogToConsole(BotName, Translations.bot_antiafk_swapping); } Command ??= string.Empty; } public struct Range { public double min, max; public Range(int value) { min = max = value; } public Range(int min, int max) { this.min = min; this.max = max; } } } private int count, nextrun = 50; private bool previousSneakState = false; private readonly Random random = new(); /// /// This bot sends a /ping command every X seconds in order to stay non-afk. /// public AntiAFK() { count = 0; } public override void Initialize() { if (Config.Use_Terrain_Handling) { if (!GetTerrainEnabled()) { LogToConsole(Translations.bot_antiafk_not_using_terrain_handling); } } } public override void Update() { count++; if (count >= nextrun) { DoAntiAfkStuff(); count = 0; nextrun = random.Next(Settings.DoubleToTick(Config.Delay.min), Settings.DoubleToTick(Config.Delay.max)); } } private void DoAntiAfkStuff() { if (Config.Use_Terrain_Handling && GetTerrainEnabled()) { Location currentLocation = GetCurrentLocation(); Location goal; bool moved = false; bool useAlternativeMethod = false; int triesCounter = 0; while (!moved) { if (triesCounter++ >= Config.Walk_Retries) { useAlternativeMethod = true; break; } goal = GetRandomLocationWithinRangeXZ(currentLocation, Config.Walk_Range); // 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, Config.Walk_Range); } if (!Movement.CheckChunkLoading(GetWorld(), currentLocation, goal)) { useAlternativeMethod = true; break; } else { moved = MoveToLocation(goal, allowUnsafe: false, allowDirectTeleport: false); } } if (!useAlternativeMethod && Config.Use_Sneak) { // 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(Config.Command); if (Config.Use_Sneak) { 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)); } } }