diff --git a/MinecraftClient/ChatBots/AutoAttack.cs b/MinecraftClient/ChatBots/AutoAttack.cs index 7085099a..55bc156d 100644 --- a/MinecraftClient/ChatBots/AutoAttack.cs +++ b/MinecraftClient/ChatBots/AutoAttack.cs @@ -1,8 +1,7 @@ using MinecraftClient.Mapping; using System; using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.IO; namespace MinecraftClient.ChatBots { @@ -23,8 +22,13 @@ namespace MinecraftClient.ChatBots private bool singleMode = true; private bool priorityDistance = true; private InteractType interactMode; + private bool attackHostile = true; + private bool attackPassive = false; + private string listMode = "blacklist"; + private List listedEntites = new(); - public AutoAttack(string mode, string priority, bool overrideAttackSpeed = false, double cooldownSeconds = 1, InteractType interaction = InteractType.Attack) + public AutoAttack( + string mode, string priority, bool overrideAttackSpeed = false, double cooldownSeconds = 1, InteractType interaction = InteractType.Attack) { if (mode == "single") singleMode = true; @@ -53,6 +57,35 @@ namespace MinecraftClient.ChatBots attackCooldown = Convert.ToInt32(Math.Truncate(attackCooldownSeconds / 0.1) + 1); } } + + this.attackHostile = Settings.AutoAttack_Attack_Hostile; + this.attackPassive = Settings.AutoAttack_Attack_Passive; + + if (Settings.AutoAttack_ListMode.Length > 0) + { + listMode = Settings.AutoAttack_ListMode.ToLower(); + + if (!(listMode.Equals("whitelist", StringComparison.OrdinalIgnoreCase) || listMode.Equals("blacklist", StringComparison.OrdinalIgnoreCase))) + { + LogToConsole(Translations.TryGet("bot.autoAttack.invalidlist")); + listMode = "blacklist"; + } + } + else LogToConsole(Translations.TryGet("bot.autoAttack.invalidlist")); + + if (File.Exists(Settings.AutoAttack_ListFile)) + { + string[] entityList = LoadDistinctEntriesFromFile(Settings.AutoAttack_ListFile); + + if (entityList.Length > 0) + { + foreach (var item in entityList) + { + if (Enum.TryParse(item, true, out EntityType resultingType)) + listedEntites.Add(resultingType); + } + } + } } public override void Initialize() @@ -149,7 +182,7 @@ namespace MinecraftClient.ChatBots public override void OnEntityHealth(Entity entity, float health) { - if (!entity.Type.IsHostile()) + if (!IsAllowedToAttack(entity)) return; if (entitiesToAttack.ContainsKey(entity.ID)) @@ -163,6 +196,25 @@ namespace MinecraftClient.ChatBots } } + private bool IsAllowedToAttack(Entity entity) + { + bool result = false; + + if (attackHostile && entity.Type.IsHostile()) + result = true; + + if (attackPassive && entity.Type.IsPassive()) + result = true; + + if (listedEntites.Count > 0) + { + bool inList = listedEntites.Contains(entity.Type); + result = listMode.Equals("blacklist") ? (inList ? false : result) : (inList ? true : false); + } + + return result; + } + public override void OnEntityMove(Entity entity) { shouldAttackEntity(entity); @@ -197,6 +249,7 @@ namespace MinecraftClient.ChatBots { if (overrideAttackSpeed) return; + serverTPS = tps; // re-calculate attack speed attackCooldownSeconds = 1 / attackSpeed * (serverTPS / 20.0); // server tps will affect the cooldown @@ -211,7 +264,7 @@ namespace MinecraftClient.ChatBots /// If the entity should be attacked public bool shouldAttackEntity(Entity entity) { - if (!entity.Type.IsHostile() || entity.Health <= 0) + if (!IsAllowedToAttack(entity) || entity.Health <= 0) return false; bool isBeingAttacked = entitiesToAttack.ContainsKey(entity.ID); diff --git a/MinecraftClient/Mapping/EntityTypeExtensions.cs b/MinecraftClient/Mapping/EntityTypeExtensions.cs index a467b3ad..b022394b 100644 --- a/MinecraftClient/Mapping/EntityTypeExtensions.cs +++ b/MinecraftClient/Mapping/EntityTypeExtensions.cs @@ -54,6 +54,52 @@ namespace MinecraftClient.Mapping } } + /// + /// Return TRUE if the Entity is a passive mob + /// + /// New mobs added in newer Minecraft versions might be absent from the list + /// TRUE if a passive mob + public static bool IsPassive(this EntityType e) + { + switch (e) + { + case EntityType.Bat: + case EntityType.Cat: + case EntityType.Chicken: + case EntityType.Cod: + case EntityType.Cow: + case EntityType.Dolphin: + case EntityType.Donkey: + case EntityType.Fox: + case EntityType.Frog: + case EntityType.GlowSquid: + case EntityType.Goat: + case EntityType.Horse: + case EntityType.IronGolem: + case EntityType.Llama: + case EntityType.Mooshroom: + case EntityType.Mule: + case EntityType.Ocelot: + case EntityType.Panda: + case EntityType.Parrot: + case EntityType.Pig: + case EntityType.Salmon: + case EntityType.Sheep: + case EntityType.Silverfish: + case EntityType.SnowGolem: + case EntityType.Squid: + case EntityType.Turtle: + case EntityType.Villager: + case EntityType.WanderingTrader: + case EntityType.Wolf: + case EntityType.ZombieHorse: + case EntityType.SkeletonHorse: + return true; + default: + return false; + } + } + /// /// Indicates whether the entity type contains an inner item /// diff --git a/MinecraftClient/Resources/config/MinecraftClient.ini b/MinecraftClient/Resources/config/MinecraftClient.ini index 8507fba4..1fdb59bb 100644 --- a/MinecraftClient/Resources/config/MinecraftClient.ini +++ b/MinecraftClient/Resources/config/MinecraftClient.ini @@ -202,6 +202,13 @@ mode=single # single or multi. single target one mob per priority=distance # health or distance. Only needed when using single mode cooldownseconds=auto # How long to wait between each attack. Use auto to let MCC calculate it interaction=Attack # Possible values: Interact, Attack (default), InteractAt (Interact and Attack) +attackhostile=true # Allow attacking hostile mobs +attackpassive=false # Allow attacking passive mobs +listmode=blacklist # Wether to treat the list from the file bellow as a whitelist or as a blacklist +# A path to the file which contains blacklisted or whitelisted entities, entity types are written on a new line +# All entity types can be found here: https://bit.ly/3Rg68lp +# The file is not created by default. +listfile=autoattack-list.txt [AutoFishing] # Automatically catch fish using a fishing rod diff --git a/MinecraftClient/Resources/lang/en.ini b/MinecraftClient/Resources/lang/en.ini index 119bf5a2..0ee5163d 100644 --- a/MinecraftClient/Resources/lang/en.ini +++ b/MinecraftClient/Resources/lang/en.ini @@ -431,6 +431,7 @@ cmd.useitem.use=Used an item bot.autoAttack.mode=Unknown attack mode: {0}. Using single mode as default. bot.autoAttack.priority=Unknown priority: {0}. Using distance priority as default. bot.autoAttack.invalidcooldown=Attack cooldown value cannot be smaller than 0. Using auto as default +bot.autoAttack.invalidlist=Invalid list type provided, using the default list mode of: 'blacklist' # AutoCraft bot.autoCraft.cmd=Auto-crafting ChatBot command diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index ce270300..4704661a 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -204,6 +204,10 @@ namespace MinecraftClient public static bool AutoAttack_OverrideAttackSpeed = false; public static double AutoAttack_CooldownSeconds = 1; public static InteractType AutoAttack_Interaction = InteractType.Attack; + public static bool AutoAttack_Attack_Hostile = true; + public static bool AutoAttack_Attack_Passive = false; + public static string AutoAttack_ListMode = "blacklist"; + public static string AutoAttack_ListFile = "autoattack-list.txt"; //Auto Fishing public static bool AutoFishing_Enabled = false; @@ -727,6 +731,14 @@ namespace MinecraftClient return true; case "interaction": return Enum.TryParse(argValue, true, out AutoAttack_Interaction); + case "attackhostile": + AutoAttack_Attack_Hostile = str2bool(argValue); return true; + case "attackpassive": + AutoAttack_Attack_Passive = str2bool(argValue); return true; + case "listmode": + AutoAttack_ListMode = argValue; return true; + case "listfile": + AutoAttack_ListFile = argValue; return true; } break;