diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs index 0dc8b3a6..5b338086 100644 --- a/MinecraftClient/ChatBot.cs +++ b/MinecraftClient/ChatBot.cs @@ -137,6 +137,17 @@ namespace MinecraftClient /// The payload for the message public virtual void OnPluginMessage(string channel, byte[] data) { } + public virtual void OnPlayerProperty(Dictionary prop) { } + + public virtual void OnServerTpsUpdate(Double tps) { } + + public virtual void OnEntityMove(Mapping.Entity entity) { } + + public virtual void OnEntitySpawn(Mapping.Entity entity) { } + + public virtual void OnEntityDespawn(int EntityID) { } + + /* =================================================================== */ /* ToolBox - Methods below might be useful while creating your bot. */ /* You should not need to interact with other classes of the program. */ @@ -599,6 +610,16 @@ namespace MinecraftClient return Handler.SetTerrainEnabled(enabled); } + /// + /// Get entity handling status + /// + /// + /// Entity Handling cannot be enabled in runtime (or after joining server) + public bool GetEntityHandlingEnabled() + { + return Handler.GetEntityHandlingEnabled(); + } + /// /// Get the current Minecraft World /// @@ -764,5 +785,26 @@ namespace MinecraftClient } return Handler.SendPluginChannelMessage(channel, data, sendEvenIfNotRegistered); } + + protected Double GetServerTPS() + { + return Handler.GetServerTPS(); + } + + /// + /// Interact with an entity + /// + /// + /// 0: interact, 1: attack, 2: interact at + /// + protected bool InteractEntity(int EntityID, int type) + { + return Handler.InteractEntity(EntityID, type); + } + + protected bool UseItemOnHand() + { + return Handler.UseItemOnHand(); + } } } diff --git a/MinecraftClient/ChatBots/AutoAttack.cs b/MinecraftClient/ChatBots/AutoAttack.cs new file mode 100644 index 00000000..d65f8ab7 --- /dev/null +++ b/MinecraftClient/ChatBots/AutoAttack.cs @@ -0,0 +1,99 @@ +using MinecraftClient.Mapping; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MinecraftClient.ChatBots +{ + class AutoAttack : ChatBot + { + private Dictionary entitiesToAttack = new Dictionary(); // mobs within attack range + private Dictionary entitiesToTrack = new Dictionary(); // all mobs in view distance + private int attackCooldown = 6; + private int attackCooldownCounter = 6; + private Double attackSpeed = 4; + private Double attackCooldownSecond; + private int attackRange = 4; + private Double serverTPS; + + public override void Initialize() + { + if (!GetEntityHandlingEnabled()) + { + ConsoleIO.WriteLine("[AutoAttack] Entity Handling is not enabled in the config file!"); + ConsoleIO.WriteLine("Please enable it to use this bot."); + UnloadBot(); + } + } + + public override void Update() + { + if (attackCooldownCounter == 0) + { + attackCooldownCounter = attackCooldown; + if (entitiesToAttack.Count > 0) + { + foreach (KeyValuePair a in entitiesToAttack) + { + InteractEntity(a.Key, 1); + } + } + } + else + { + attackCooldownCounter--; + } + } + + public override void OnEntitySpawn(Entity entity) + { + if (entity.GetMobName() != "") + { + entitiesToTrack.Add(entity.ID, entity); + } + } + public override void OnEntityDespawn(int EntityID) + { + if (entitiesToTrack.ContainsKey(EntityID)) + { + entitiesToTrack.Remove(EntityID); + } + } + public override void OnEntityMove(Entity entity) + { + if (entitiesToTrack.ContainsKey(entity.ID)) + { + Double distance = Entity.CalculateDistance(GetCurrentLocation(), entity.Location); + if(distance < attackRange) + { + if(!entitiesToAttack.ContainsKey(entity.ID)) + entitiesToAttack.Add(entity.ID, entity); + } + } + } + + public override void OnPlayerProperty(Dictionary prop) + { + // adjust auto attack cooldown for maximum attack damage + if (prop.ContainsKey("generic.attackSpeed")) + { + if (attackSpeed != prop["generic.attackSpeed"]) + { + GetServerTPS(); + attackSpeed = prop["generic.attackSpeed"]; + attackCooldownSecond = 1 / attackSpeed * (serverTPS / 20.0); // server tps will affect the cooldown + attackCooldown = Convert.ToInt32(Math.Truncate(attackCooldownSecond / 0.1) + 1); + } + } + } + + public override void OnServerTpsUpdate(double tps) + { + serverTPS = tps; + // re-calculate attack speed + attackCooldownSecond = 1 / attackSpeed * (serverTPS / 20.0); // server tps will affect the cooldown + attackCooldown = Convert.ToInt32(Math.Truncate(attackCooldownSecond / 0.1) + 1); + } + } +} diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs new file mode 100644 index 00000000..6262a209 --- /dev/null +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Threading; +using MinecraftClient.Mapping; + +namespace MinecraftClient.ChatBots +{ + class AutoFishing : ChatBot + { + private Dictionary fishingRod = new Dictionary(); + private Double fishingHookThreshold = 0.2; + private Location LastPos = new Location(); + private DateTime CaughtTime = DateTime.Now; + + public override void Initialize() + { + if (!GetEntityHandlingEnabled()) + { + ConsoleIO.WriteLine("[AutoFishing] Entity Handling is not enabled in the config file!"); + ConsoleIO.WriteLine("Please enable it to use this bot."); + UnloadBot(); + } + } + + public override void OnEntitySpawn(Entity entity) + { + if (entity.Type == 102) + { + ConsoleIO.WriteLine("Threw a fishing rod"); + fishingRod.Add(entity.ID, entity); + LastPos = entity.Location; + } + } + public override void OnEntityMove(Entity entity) + { + if (fishingRod.ContainsKey(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) + { + if (Math.Abs(Dy) > fishingHookThreshold) + { + // caught + // prevent triggering multiple time + if ((DateTime.Now - CaughtTime).TotalSeconds > 1) + { + OnCaughtFish(); + CaughtTime = DateTime.Now; + } + } + } + fishingRod[entity.ID] = entity; + } + } + + // TODO: Move into ChatBot + /// + /// Called when detected a fish is caught + /// + public void OnCaughtFish() + { + ConsoleIO.WriteLine("Caught a fish!"); + // retract fishing rod + UseItemOnHand(); + // non-blocking delay + Task.Factory.StartNew(delegate + { + // retract fishing rod need some time + Thread.Sleep(500); + // throw again + // TODO: to check if hand have fishing rod + UseItemOnHand(); + }); + } + } +} diff --git a/MinecraftClient/Commands/AutoAttack.cs b/MinecraftClient/Commands/AutoAttack.cs index e9663497..33f839a0 100644 --- a/MinecraftClient/Commands/AutoAttack.cs +++ b/MinecraftClient/Commands/AutoAttack.cs @@ -8,39 +8,35 @@ namespace MinecraftClient.Commands class AutoAttack : Command { public override string CMDName { get { return "autoattack"; } } - public override string CMDDesc { get { return "autoattack : Enable/disable auto attack mobs."; } } + public override string CMDDesc { get { return "autoattack : Auto attack mobs around you."; } } public override string Run(McTcpClient handler, string command) { if (hasArg(command)) { - string state = getArg(command); - if (state.ToLower() == "on") + string arg = getArg(command); + if (arg == "on") { - if (!handler.AutoAttack) + if (handler.GetEntityHandlingEnabled()) { - handler.AutoAttack = true; - return "Auto attack turned on."; + // TODO: check if the bot already loaded + // I don't know how :C + handler.BotLoad(new ChatBots.AutoAttack()); + return "Auto Attack now enabled."; } else { - return "Auto attack is on."; - } - }else if (state.ToLower() == "off") - { - if (handler.AutoAttack) - { - handler.AutoAttack = false; - return "Auto attack turned off."; - } - else - { - return "Auto attack is off."; + return "Please enable EntityHandling in the config before using this."; } } - return ""; + else if(arg == "off") + { + // TODO: unload auto attack bot + // I don't know how to unload a single bot :C + return "Currently not implemented :/"; + } } - else return CMDDesc; + return CMDDesc; } } } diff --git a/MinecraftClient/Commands/Fishing.cs b/MinecraftClient/Commands/Fishing.cs deleted file mode 100644 index 7648fd6a..00000000 --- a/MinecraftClient/Commands/Fishing.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace MinecraftClient.Commands -{ - class Fishing : Command - { - public override string CMDName { get { return "fishing"; } } - public override string CMDDesc { get { return "fishing : Auto fishing"; } } - - public override string Run(McTcpClient handler, string command) - { - if (hasArg(command)) - { - string state = getArg(command); - if (state.ToLower() == "on") - { - if (!handler.AutoFishing) - { - handler.AutoFishing = true; - handler.useItemOnHand(); - return "Auto fishing turned on."; - } - else - { - return "Auto fishing is on."; - } - } - else if (state.ToLower() == "off") - { - if (handler.AutoFishing) - { - handler.AutoFishing = false; - handler.useItemOnHand(); - return "Auto fishing turned off."; - } - else - { - return "Auto fishing is off."; - } - } - } - return CMDDesc; - } - } -} diff --git a/MinecraftClient/Commands/UseItem.cs b/MinecraftClient/Commands/UseItem.cs index 2002ed0f..858409ca 100644 --- a/MinecraftClient/Commands/UseItem.cs +++ b/MinecraftClient/Commands/UseItem.cs @@ -12,7 +12,7 @@ namespace MinecraftClient.Commands public override string Run(McTcpClient handler, string command) { - handler.useItemOnHand(); + handler.UseItemOnHand(); return "Use an item"; } } diff --git a/MinecraftClient/Mapping/Entity.cs b/MinecraftClient/Mapping/Entity.cs new file mode 100644 index 00000000..289fdf3c --- /dev/null +++ b/MinecraftClient/Mapping/Entity.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MinecraftClient.Mapping +{ + public class Entity + { + public int ID; + public int Type; + public string Name; + public Location Location; + public Entity(int ID, Location location) + { + this.ID = ID; + this.Location = location; + } + public Entity(int ID, int Type, Location location) + { + this.ID = ID; + this.Type = Type; + this.Name = GetMobName(Type); + this.Location = location; + } + public Entity(int ID, int Type, string Name, Location location) + { + this.ID = ID; + this.Type = Type; + this.Name = Name; + this.Location = location; + } + + + /// + /// Calculate the distance between two coordinate + /// + /// + /// + /// + public static double CalculateDistance(Location l1, Location l2) + { + return Math.Sqrt(Math.Pow(l2.X - l1.X, 2) + Math.Pow(l2.Y - l1.Y, 2) + Math.Pow(l2.Z - l1.Z, 2)); + } + /// + /// Get the mob name by entity type ID. + /// + /// + /// + public static string GetMobName(int EntityType) + { + // only mobs in this list will be auto attacked + switch (EntityType) + { + case 5: return "Blaze"; + case 12: return "Creeper"; + case 16: return "Drowned"; + case 23: return "Evoker"; + case 29: return "Ghast"; + case 31: return "Guardian"; + case 33: return "Husk"; + case 41: return "Magma Cube"; + case 57: return "Zombie Pigman"; + case 63: return "Shulker"; + case 65: return "Silverfish"; + case 66: return "Skeleton"; + case 68: return "Slime"; + case 75: return "Stray"; + case 84: return "Vex"; + case 87: return "Vindicator"; + case 88: return "Pillager"; + case 90: return "Witch"; + case 92: return "Wither Skeleton"; + case 95: return "Zombie"; + case 97: return "Zombie Villager"; + case 98: return "Phantom"; + case 99: return "Ravager"; + default: return ""; + } + } + public string GetMobName() + { + return GetMobName(Type); + } + } +} diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index e0419185..b2c69133 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -4,7 +4,6 @@ using System.Linq; using System.Text; using System.Net.Sockets; using System.Threading; -using System.Threading.Tasks; using System.IO; using System.Net; using MinecraftClient.Protocol; @@ -36,6 +35,7 @@ namespace MinecraftClient private bool terrainAndMovementsRequested = false; private bool inventoryHandlingEnabled; private bool inventoryHandlingRequested = false; + private bool entityHandlingEnabled; private object locationLock = new object(); private bool locationReceived = false; @@ -59,47 +59,16 @@ namespace MinecraftClient private int playerEntityID; // not really understand the Inventory Class // so I use a Dict instead for player inventory - private Dictionary playerItems; + private Dictionary playerItems; - // auto attack - private class Entity - { - public int ID; - public int Type; - public string Name; - public Location Location; - public Entity(int ID, Location location) - { - this.ID = ID; - this.Location = location; - } - public Entity(int ID, int Type, string Name, Location location) - { - this.ID = ID; - this.Type = Type; - this.Name = Name; - this.Location = location; - } - } - private Dictionary entitiesToAttack = new Dictionary(); // mobs within attack range - private Dictionary entitiesToTrack = new Dictionary(); // all mobs in view distance - private int attackCooldown = 6; - private int attackCooldownCounter = 6; - private Double attackSpeed; - private Double attackCooldownSecond; - private int attackRange = 4; + // Entity handling + private Dictionary entities = new Dictionary(); // server TPS private long lastAge = 0; private DateTime lastTime; private Double serverTPS = 0; - public bool AutoAttack - { - get => Settings.AutoAttackMobs; - set => Settings.AutoAttackMobs = value; - } - public int GetServerPort() { return port; } public string GetServerHost() { return host; } public string GetUsername() { return username; } @@ -107,6 +76,13 @@ namespace MinecraftClient public string GetSessionID() { return sessionid; } public Location GetCurrentLocation() { return location; } public World GetWorld() { return world; } + public Double GetServerTPS() { return serverTPS; } + + // get bots list for unloading them by commands + public List GetLoadedChatBots() + { + return bots; + } TcpClient client; IMinecraftCom handler; @@ -157,6 +133,7 @@ namespace MinecraftClient { terrainAndMovementsEnabled = Settings.TerrainAndMovements; inventoryHandlingEnabled = Settings.InventoryHandling; + entityHandlingEnabled = Settings.EntityHandling; bool retry = false; this.sessionid = sessionID; @@ -178,9 +155,10 @@ namespace MinecraftClient if (Settings.ScriptScheduler_Enabled) { BotLoad(new ChatBots.ScriptScheduler(Settings.ExpandVars(Settings.ScriptScheduler_TasksFile))); } if (Settings.RemoteCtrl_Enabled) { BotLoad(new ChatBots.RemoteControl()); } if (Settings.AutoRespond_Enabled) { BotLoad(new ChatBots.AutoRespond(Settings.AutoRespond_Matches)); } + if (Settings.AutoAttack_Enabled) { BotLoad(new ChatBots.AutoAttack()); } + if (Settings.AutoFishing_Enabled) { BotLoad(new ChatBots.AutoFishing()); } //Add your ChatBot here by uncommenting and adapting //BotLoad(new ChatBots.YourBot()); - //BotLoad(new ChatBots.kill()); } } @@ -575,6 +553,26 @@ namespace MinecraftClient return true; } + /// + /// Get entity handling status + /// + /// + /// Entity Handling cannot be enabled in runtime (or after joining server) + public bool GetEntityHandlingEnabled() + { + return entityHandlingEnabled; + } + + /// + /// Get client player's inventory items + /// + /// Item Dictionary indexed by Slot ID (Check wiki.vg for slot ID) + public Dictionary GetPlayerInventory() + { + return playerItems; + } + // TODO: add command for displaying player inventory + /// /// Called when the server sends a new player location, /// or if a ChatBot whishes to update the player's location. @@ -773,14 +771,9 @@ namespace MinecraftClient /// public void OnWindowItems(int type, Dictionary itemList) { - // player inventory - //if (type == 0) - // playerItems = itemList; - foreach(KeyValuePair pair in itemList) - { - ConsoleIO.WriteLine("Slot: "+pair.Key+" itemID:"+pair.Value.id); - } - ConsoleIO.WriteLine("Type: "+type); + // 0 is player inventory + if (type == 0) + playerItems = itemList; } /// @@ -880,25 +873,7 @@ namespace MinecraftClient } } - // auto attack entity within range - if (Settings.AutoAttackMobs) - { - if (attackCooldownCounter == 0) - { - attackCooldownCounter = attackCooldown; - if (entitiesToAttack.Count > 0) - { - foreach (KeyValuePair a in entitiesToAttack) - { - handler.SendInteractEntityPacket(a.Key, 1); - } - } - } - else - { - attackCooldownCounter--; - } - } + } /// @@ -1101,32 +1076,20 @@ namespace MinecraftClient } } } - - private Dictionary fishingRod = new Dictionary(); - private Double fishingHookThreshold = -0.3; // must be negetive - public bool AutoFishing { get; set; } = false; + + /// + /// Called when a non-living entity spawned (fishing hook, minecart, etc) + /// + /// + /// + /// + /// public void OnSpawnEntity(int EntityID, int EntityType, Guid UUID, Location location) { - if (EntityType == 102 && AutoFishing) - { - ConsoleIO.WriteLine("Threw a fishing rod"); - fishingRod.Add(EntityID,new Entity(EntityID, EntityType, "fishing bobber", location)); - } - } - - public void OnEntityStatus(int EntityID, byte EntityStatus) - { - if (fishingRod.ContainsKey(EntityID)) - { - if (EntityStatus == 31) - { - ConsoleIO.WriteLine("Status is bobber"); - } - else - { - ConsoleIO.WriteLine("Status is " + EntityStatus); - } - } + Entity entity = new Entity(EntityID, EntityType, location); + entities.Add(EntityID, entity); + foreach (ChatBot bot in bots.ToArray()) + bot.OnEntitySpawn(entity); } /// @@ -1138,19 +1101,10 @@ namespace MinecraftClient /// public void OnSpawnLivingEntity(int EntityID, int EntityType, Guid UUID, Location location) { - string name = getEntityName(EntityType); - if (name != "") - { - Entity entity = new Entity(EntityID, EntityType, name, location); - entitiesToTrack.Add(EntityID, entity); - if (Settings.AutoAttackMobs) - { - if (calculateDistance(location, GetCurrentLocation()) < attackRange) - { - entitiesToAttack.Add(EntityID, entity); - } - } - } + Entity entity = new Entity(EntityID, EntityType, location); + entities.Add(EntityID, entity); + foreach (ChatBot bot in bots.ToArray()) + bot.OnEntitySpawn(entity); } /// @@ -1161,24 +1115,15 @@ namespace MinecraftClient { foreach (int a in Entities) { - if (entitiesToTrack.ContainsKey(a)) + if (entities.ContainsKey(a)) { - entitiesToAttack.Remove(a); - entitiesToTrack.Remove(a); - } - - if (fishingRod.ContainsKey(a)) - { - fishingRod.Remove(a); + entities.Remove(a); } + foreach (ChatBot bot in bots.ToArray()) + bot.OnEntityDespawn(a); } } - public void OnSetCooldown(int itemID, int tick) - { - ConsoleIO.WriteLine("Set Cooldown on item " + itemID + " by " + tick + " ticks"); - } - /// /// Called when an entity's position changed within 8 block of its previous position. /// @@ -1189,46 +1134,36 @@ namespace MinecraftClient /// public void OnEntityPosition(int EntityID, Double Dx, Double Dy, Double Dz,bool onGround) { - if (entitiesToTrack.ContainsKey(EntityID)) + if (entities.ContainsKey(EntityID)) { - Entity entity = entitiesToTrack[EntityID]; - Location L = entity.Location; + Location L = entities[EntityID].Location; L.X += Dx; L.Y += Dy; L.Z += Dz; - entitiesToTrack[EntityID].Location = L; - if(entitiesToAttack.ContainsKey(EntityID)) - entitiesToAttack[EntityID].Location = L; - Double distance = calculateDistance(L, GetCurrentLocation()); - - if (distance < attackRange) - { - if (!entitiesToAttack.ContainsKey(EntityID)) - { - entitiesToAttack.Add(EntityID, entity); - } - } - else - { - entitiesToAttack.Remove(EntityID); - } + entities[EntityID].Location = L; + + foreach (ChatBot bot in bots.ToArray()) + bot.OnEntityMove(new Entity(entities[EntityID].ID, entities[EntityID].Type, entities[EntityID].Location)); } - if (fishingRod.ContainsKey(EntityID)) + + } + /// + /// Called when an entity moved over 8 block. + /// + /// + /// + /// + /// + /// + public void OnEntityTeleport(int EntityID, Double X, Double Y, Double Z, bool onGround) + { + if (entities.ContainsKey(EntityID)) { - Location L = fishingRod[EntityID].Location; - L.X += Dx; - L.Y += Dy; - L.Z += Dz; - fishingRod[EntityID].Location = L; - // check if fishing hook is stationary - if (Dx == 0 && Dz == 0) - { - if (Dy < fishingHookThreshold) - { - // caught - OnCaughtFish(); - } - } + Location location = new Location(X, Y, Z); + entities[EntityID].Location = location; + + foreach (ChatBot bot in bots.ToArray()) + bot.OnEntityMove(new Entity(entities[EntityID].ID, entities[EntityID].Type, entities[EntityID].Location)); } } @@ -1241,16 +1176,8 @@ namespace MinecraftClient { if(EntityID == playerEntityID) { - // adjust auto attack cooldown for maximum attack damage - if (prop.ContainsKey("generic.attackSpeed")) - { - if (attackSpeed != prop["generic.attackSpeed"]) - { - attackSpeed = prop["generic.attackSpeed"]; - attackCooldownSecond = 1 / attackSpeed * (serverTPS / 20.0); // server tps will affect the cooldown - attackCooldown = Convert.ToInt16(Math.Truncate(attackCooldownSecond / 0.1) + 1); - } - } + foreach (ChatBot bot in bots.ToArray()) + bot.OnPlayerProperty(prop); } } @@ -1261,17 +1188,20 @@ namespace MinecraftClient /// public void OnTimeUpdate(long WorldAge, long TimeOfDay) { - if (!Settings.AutoAttackMobs) return; - // calculate server tps for adjusting attack cooldown + // calculate server tps if (lastAge != 0) { DateTime currentTime = DateTime.Now; - Double tps = (WorldAge - lastAge) / (currentTime - lastTime).TotalSeconds; + long tickDiff = WorldAge - lastAge; + Double tps = tickDiff / (currentTime - lastTime).TotalSeconds; lastAge = WorldAge; lastTime = currentTime; - if (tps <= 20 || tps >= 0) + if (tps <= 20.0 && tps >= 0.0 && serverTPS != tps) { serverTPS = tps; + // invoke ChatBot + foreach (ChatBot bot in bots.ToArray()) + bot.OnServerTpsUpdate(tps); } } else @@ -1281,105 +1211,6 @@ namespace MinecraftClient } } - - /// - /// Called when an entity moved over 8 block. - /// - /// - /// - /// - /// - /// - public void OnEntityTeleport(int EntityID, Double X, Double Y, Double Z, bool onGround) - { - if (Settings.AutoAttackMobs) - { - if (entitiesToTrack.ContainsKey(EntityID)) - { - entitiesToTrack[EntityID].Location = new Location(X, Y, Z); - } - } - if (fishingRod.ContainsKey(EntityID)) - { - Location L = fishingRod[EntityID].Location; - Double Dy = L.Y - Y; - L.X = X; - L.Y = Y; - L.Z = Z; - fishingRod[EntityID].Location = L; - if (Dy < fishingHookThreshold) - { - // caught - OnCaughtFish(); - } - } - } - - /// - /// Called when detected a fish is caught - /// - public void OnCaughtFish() - { - ConsoleIO.WriteLine("Caught a fish!"); - // retract fishing rod - useItemOnHand(); - // retract fishing rod need some time - Task.Factory.StartNew(delegate - { - Thread.Sleep(500); - // throw again - // TODO: to check if hand have fishing rod - if(AutoFishing) - useItemOnHand(); - }); - } - - /// - /// Calculate the distance between two coordinate - /// - /// - /// - /// - public double calculateDistance(Location l1,Location l2) - { - return Math.Sqrt(Math.Pow(l2.X - l1.X, 2) + Math.Pow(l2.Y - l1.Y, 2) + Math.Pow(l2.Z - l1.Z, 2)); - } - /// - /// Get the entity name by entity type ID. - /// - /// - /// - public string getEntityName(int EntityType) - { - // only mobs in this list will be auto attacked - switch (EntityType) - { - case 5: return "Blaze"; - case 12: return "Creeper"; - case 16: return "Drowned"; - case 23: return "Evoker"; - case 29: return "Ghast"; - case 31: return "Guardian"; - case 33: return "Husk"; - case 41: return "Magma Cube"; - case 57: return "Zombie Pigman"; - case 63: return "Shulker"; - case 65: return "Silverfish"; - case 66: return "Skeleton"; - case 68: return "Slime"; - case 75: return "Stray"; - case 84: return "Vex"; - case 87: return "Vindicator"; - case 88: return "Pillager"; - case 90: return "Witch"; - case 92: return "Wither Skeleton"; - case 95: return "Zombie"; - case 97: return "Zombie Villager"; - case 98: return "Phantom"; - case 99: return "Ravager"; - default: return ""; - } - } /// /// Set client player's ID for later receiving player's own properties @@ -1390,9 +1221,20 @@ namespace MinecraftClient playerEntityID = EntityID; } - public void useItemOnHand() + public bool UseItemOnHand() { - handler.SendUseItemPacket(0); + return handler.SendUseItemPacket(0); + } + + /// + /// Interact with an entity + /// + /// + /// 0: interact, 1: attack, 2: interact at + /// + public bool InteractEntity(int EntityID, int type) + { + return handler.SendInteractEntityPacket(EntityID, type); } } } diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj index a271317d..f5dcca51 100644 --- a/MinecraftClient/MinecraftClient.csproj +++ b/MinecraftClient/MinecraftClient.csproj @@ -75,6 +75,8 @@ + + @@ -89,7 +91,6 @@ - @@ -106,6 +107,7 @@ + diff --git a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs index 6a552d8e..6fac944b 100644 --- a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs @@ -33,7 +33,6 @@ namespace MinecraftClient.Protocol.Handlers OpenWindow, WindowItems, SetSlot, - UnknownPacket, DestroyEntities, SetCooldown, EntityPosition, @@ -41,6 +40,7 @@ namespace MinecraftClient.Protocol.Handlers EntityProperties, TimeUpdate, EntityTeleport, - EntityStatus + EntityStatus, + UnknownPacket } } diff --git a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs index 08ebd947..92c99bc9 100644 --- a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs @@ -20,7 +20,6 @@ namespace MinecraftClient.Protocol.Handlers PlayerPosition, PlayerPositionAndLook, TeleportConfirm, - //modified by reinforce HeldItemChange, InteractEntity, UseItem diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index c76ce309..ada62472 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -641,6 +641,24 @@ namespace MinecraftClient.Protocol.Handlers return false; //Currently not implemented } + //Currently not implemented + public bool SendInteractEntityPacket(int EntityID, int type) + { + return false; + } + public bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z, int hand) + { + return false; + } + public bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z) + { + return false; + } + public bool SendUseItemPacket(int hand) + { + return false; + } + /// /// Send a plugin channel packet to the server. /// @@ -733,23 +751,5 @@ namespace MinecraftClient.Protocol.Handlers } catch { return false; } } - - // reinforce - public bool SendInteractEntityPacket(int EntityID, int type) - { - return true; - } - public bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z, int hand) - { - return true; - } - public bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z) - { - return true; - } - public bool SendUseItemPacket(int hand) - { - return true; - } } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index bdca756e..0784986f 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -245,9 +245,8 @@ namespace MinecraftClient.Protocol.Handlers float pitch = dataTypes.ReadNextFloat(packetData); byte locMask = dataTypes.ReadNextByte(packetData); - // player pos is needed for calculate entity distance - // modified by reinforce - if (handler.GetTerrainEnabled() || true) + // entity handling require player pos for distance calculating + if (handler.GetTerrainEnabled() || handler.GetEntityHandlingEnabled()) { if (protocolversion >= MC18Version) { @@ -510,10 +509,10 @@ namespace MinecraftClient.Protocol.Handlers } break; case PacketIncomingType.WindowItems: - if (handler.GetInventoryEnabled()||true) + if (handler.GetInventoryEnabled()||true) // set true in .ini but GetInventoryEnabled seems like return false { /* - * Following commented code not working + * Following commented code will crash * byte id = dataTypes.ReadNextByte(packetData); short elements = dataTypes.ReadNextShort(packetData); @@ -562,107 +561,119 @@ namespace MinecraftClient.Protocol.Handlers SendPacket(PacketOutgoingType.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, dataTypes.GetVarInt(0))); //Successfully loaded break; case PacketIncomingType.SpawnEntity: - int EntityID = dataTypes.ReadNextVarInt(packetData); - Guid EntityUUID = dataTypes.ReadNextUUID(packetData); - int EntityType = dataTypes.ReadNextVarInt(packetData); - Double X = dataTypes.ReadNextDouble(packetData); - Double Y = dataTypes.ReadNextDouble(packetData); - Double Z = dataTypes.ReadNextDouble(packetData); - byte EntityYaw = dataTypes.ReadNextByte(packetData); - byte EntityPitch = dataTypes.ReadNextByte(packetData); - int Data = dataTypes.ReadNextInt(packetData); - short VelocityX = dataTypes.ReadNextShort(packetData); - short VelocityY = dataTypes.ReadNextShort(packetData); - short VelocityZ = dataTypes.ReadNextShort(packetData); + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Guid EntityUUID = dataTypes.ReadNextUUID(packetData); + int EntityType = dataTypes.ReadNextVarInt(packetData); + Double X = dataTypes.ReadNextDouble(packetData); + Double Y = dataTypes.ReadNextDouble(packetData); + Double Z = dataTypes.ReadNextDouble(packetData); + byte EntityYaw = dataTypes.ReadNextByte(packetData); + byte EntityPitch = dataTypes.ReadNextByte(packetData); + int Data = dataTypes.ReadNextInt(packetData); + short VelocityX = dataTypes.ReadNextShort(packetData); + short VelocityY = dataTypes.ReadNextShort(packetData); + short VelocityZ = dataTypes.ReadNextShort(packetData); - Location EntityLocation = new Location(X, Y, Z); + Location EntityLocation = new Location(X, Y, Z); - handler.OnSpawnEntity(EntityID, EntityType, EntityUUID, EntityLocation); + handler.OnSpawnEntity(EntityID, EntityType, EntityUUID, EntityLocation); + } break; case PacketIncomingType.SpawnLivingEntity: - if (login_phase) break; - EntityID = dataTypes.ReadNextVarInt(packetData); - EntityUUID = dataTypes.ReadNextUUID(packetData); - EntityType = dataTypes.ReadNextVarInt(packetData); - X = dataTypes.ReadNextDouble(packetData); - Y = dataTypes.ReadNextDouble(packetData); - Z = dataTypes.ReadNextDouble(packetData); - EntityYaw = dataTypes.ReadNextByte(packetData); - EntityPitch = dataTypes.ReadNextByte(packetData); - byte EntityHeadPitch = dataTypes.ReadNextByte(packetData); - VelocityX = dataTypes.ReadNextShort(packetData); - VelocityY = dataTypes.ReadNextShort(packetData); - VelocityZ = dataTypes.ReadNextShort(packetData); + if (login_phase) break; // same packet ID with login packet + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Guid EntityUUID = dataTypes.ReadNextUUID(packetData); + int EntityType = dataTypes.ReadNextVarInt(packetData); + Double X = dataTypes.ReadNextDouble(packetData); + Double Y = dataTypes.ReadNextDouble(packetData); + Double Z = dataTypes.ReadNextDouble(packetData); + byte EntityYaw = dataTypes.ReadNextByte(packetData); + byte EntityPitch = dataTypes.ReadNextByte(packetData); + byte EntityHeadPitch = dataTypes.ReadNextByte(packetData); + short VelocityX = dataTypes.ReadNextShort(packetData); + short VelocityY = dataTypes.ReadNextShort(packetData); + short VelocityZ = dataTypes.ReadNextShort(packetData); - EntityLocation = new Location(X, Y, Z); - - handler.OnSpawnLivingEntity(EntityID,EntityType,EntityUUID,EntityLocation); + Location EntityLocation = new Location(X, Y, Z); + + handler.OnSpawnLivingEntity(EntityID, EntityType, EntityUUID, EntityLocation); + } break; case PacketIncomingType.DestroyEntities: - int EntityCount = dataTypes.ReadNextVarInt(packetData); - int[] EntitiesList = new int[EntityCount]; - for(int i = 0; i < EntityCount; i++) + if (handler.GetEntityHandlingEnabled()) { - EntitiesList[i] = dataTypes.ReadNextVarInt(packetData); + int EntityCount = dataTypes.ReadNextVarInt(packetData); + int[] EntitiesList = new int[EntityCount]; + for (int i = 0; i < EntityCount; i++) + { + EntitiesList[i] = dataTypes.ReadNextVarInt(packetData); + } + handler.OnDestroyEntities(EntitiesList); } - handler.OnDestroyEntities(EntitiesList); - break; - case PacketIncomingType.SetCooldown: - int _itemID = dataTypes.ReadNextVarInt(packetData); - int tick = dataTypes.ReadNextVarInt(packetData); - handler.OnSetCooldown(_itemID, tick); break; case PacketIncomingType.EntityPosition: - EntityID = dataTypes.ReadNextVarInt(packetData); - Double DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - bool OnGround = dataTypes.ReadNextBool(packetData); - DeltaX = DeltaX / (128 * 32); - DeltaY = DeltaY / (128 * 32); - DeltaZ = DeltaZ / (128 * 32); - handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ,OnGround); + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Double DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + bool OnGround = dataTypes.ReadNextBool(packetData); + DeltaX = DeltaX / (128 * 32); + DeltaY = DeltaY / (128 * 32); + DeltaZ = DeltaZ / (128 * 32); + handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); + } break; case PacketIncomingType.EntityPositionAndRotation: - EntityID = dataTypes.ReadNextVarInt(packetData); - DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); - yaw = dataTypes.ReadNextByte(packetData); - pitch = dataTypes.ReadNextByte(packetData); - OnGround = dataTypes.ReadNextBool(packetData); - DeltaX = DeltaX / (128 * 32); - DeltaY = DeltaY / (128 * 32); - DeltaZ = DeltaZ / (128 * 32); - handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Double DeltaX = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaY = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + Double DeltaZ = Convert.ToDouble(dataTypes.ReadNextShort(packetData)); + byte _yaw = dataTypes.ReadNextByte(packetData); + byte _pitch = dataTypes.ReadNextByte(packetData); + bool OnGround = dataTypes.ReadNextBool(packetData); + DeltaX = DeltaX / (128 * 32); + DeltaY = DeltaY / (128 * 32); + DeltaZ = DeltaZ / (128 * 32); + handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); + } break; case PacketIncomingType.EntityProperties: - EntityID = dataTypes.ReadNextVarInt(packetData); - int NumberOfProperties = dataTypes.ReadNextInt(packetData); - Dictionary keys = new Dictionary(); - for(int i = 0; i < NumberOfProperties; i++) + if (handler.GetEntityHandlingEnabled()) { - string _key = dataTypes.ReadNextString(packetData); - Double _value = dataTypes.ReadNextDouble(packetData); - - - int NumberOfModifiers = dataTypes.ReadNextVarInt(packetData); - //if (NumberOfModifiers == 0) continue; - for(int j = 0; j < NumberOfModifiers; j++) + int EntityID = dataTypes.ReadNextVarInt(packetData); + int NumberOfProperties = dataTypes.ReadNextInt(packetData); + Dictionary keys = new Dictionary(); + for (int i = 0; i < NumberOfProperties; i++) { - dataTypes.ReadNextUUID(packetData); - Double amount = dataTypes.ReadNextDouble(packetData); - byte operation = dataTypes.ReadNextByte(packetData); - switch (operation) + string _key = dataTypes.ReadNextString(packetData); + Double _value = dataTypes.ReadNextDouble(packetData); + + + int NumberOfModifiers = dataTypes.ReadNextVarInt(packetData); + for (int j = 0; j < NumberOfModifiers; j++) { - case 0: _value += amount; break; - case 1: _value += (amount / 100); break; - case 2: _value *= amount; break; + dataTypes.ReadNextUUID(packetData); + Double amount = dataTypes.ReadNextDouble(packetData); + byte operation = dataTypes.ReadNextByte(packetData); + switch (operation) + { + case 0: _value += amount; break; + case 1: _value += (amount / 100); break; + case 2: _value *= amount; break; + } } + keys.Add(_key, _value); } - keys.Add(_key, _value); + handler.OnEntityProperties(EntityID, keys); } - handler.OnEntityProperties(EntityID, keys); break; case PacketIncomingType.TimeUpdate: if (login_phase) break; @@ -671,19 +682,17 @@ namespace MinecraftClient.Protocol.Handlers handler.OnTimeUpdate(WorldAge, TimeOfday); break; case PacketIncomingType.EntityTeleport: - EntityID = dataTypes.ReadNextVarInt(packetData); - X = dataTypes.ReadNextDouble(packetData); - Y = dataTypes.ReadNextDouble(packetData); - Z = dataTypes.ReadNextDouble(packetData); - EntityYaw = dataTypes.ReadNextByte(packetData); - EntityPitch = dataTypes.ReadNextByte(packetData); - OnGround = dataTypes.ReadNextBool(packetData); - handler.OnEntityTeleport(EntityID, X, Y, Z, OnGround); - break; - case PacketIncomingType.EntityStatus: - EntityID = dataTypes.ReadNextInt(packetData); - byte EntityStatus = dataTypes.ReadNextByte(packetData); - handler.OnEntityStatus(EntityID, EntityStatus); + if (handler.GetEntityHandlingEnabled()) + { + int EntityID = dataTypes.ReadNextVarInt(packetData); + Double X = dataTypes.ReadNextDouble(packetData); + Double Y = dataTypes.ReadNextDouble(packetData); + Double Z = dataTypes.ReadNextDouble(packetData); + byte EntityYaw = dataTypes.ReadNextByte(packetData); + byte EntityPitch = dataTypes.ReadNextByte(packetData); + bool OnGround = dataTypes.ReadNextBool(packetData); + handler.OnEntityTeleport(EntityID, X, Y, Z, OnGround); + } break; default: return false; //Ignored packet @@ -1195,14 +1204,14 @@ namespace MinecraftClient.Protocol.Handlers catch (System.IO.IOException) { return false; } catch (ObjectDisposedException) { return false; } } - // TODO: Interact at block location + // TODO: Interact at block location (e.g. chest) public bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z, int hand) { - return true; + return false; } public bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z) { - return true; + return false; } public bool SendUseItemPacket(int hand) diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index a4860042..3a02e83e 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -84,8 +84,7 @@ namespace MinecraftClient.Protocol /// packet Data /// True if message was successfully sent bool SendPluginChannelPacket(string channel, byte[] data); - - // by reinforce + bool SendInteractEntityPacket(int EntityID, int type); bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z, int hand); bool SendInteractEntityPacket(int EntityID, int type, float X, float Y, float Z); diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index 70f22d93..98eb2123 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -30,6 +30,7 @@ namespace MinecraftClient.Protocol bool SetTerrainEnabled(bool enabled); bool GetInventoryEnabled(); bool SetInventoryEnabled(bool enabled); + bool GetEntityHandlingEnabled(); /// /// Called when a server was successfully joined @@ -132,8 +133,6 @@ namespace MinecraftClient.Protocol void OnDestroyEntities(int[] EntityID); - void OnSetCooldown(int itemID, int tick); - void OnEntityPosition(int EntityID, Double Dx, Double Dy, Double Dz,bool onGround); void OnEntityProperties(int EntityID, Dictionary prop); @@ -142,8 +141,6 @@ namespace MinecraftClient.Protocol void OnEntityTeleport(int EntityID, Double X, Double Y, Double Z, bool onGround); - void OnEntityStatus(int EntityID, byte EntityStatus); - void OnWindowItems(int type, Dictionary itemList); void SetPlayerEntityID(int EntityID); diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 7952dae0..624fe59f 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -95,7 +95,7 @@ namespace MinecraftClient public static bool DebugMessages = false; public static bool ResolveSrvRecords = true; public static bool ResolveSrvRecordsShortTimeout = true; - public static bool AutoAttackMobs = false; + public static bool EntityHandling = false; //AntiAFK Settings public static bool AntiAFK_Enabled = false; @@ -150,12 +150,18 @@ namespace MinecraftClient public static bool AutoRespond_Enabled = false; public static string AutoRespond_Matches = "matches.ini"; + //Auto Attack + public static bool AutoAttack_Enabled = false; + + //Auto Fishing + public static bool AutoFishing_Enabled = false; + //Custom app variables and Minecraft accounts private static readonly Dictionary AppVars = new Dictionary(); private static readonly Dictionary> Accounts = new Dictionary>(); private static readonly Dictionary> Servers = new Dictionary>(); - private enum ParseMode { Default, Main, AppVars, Proxy, MCSettings, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, ChatFormat, AutoRespond }; + private enum ParseMode { Default, Main, AppVars, Proxy, MCSettings, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, ChatFormat, AutoRespond, AutoAttack, AutoFishing }; /// /// Load settings from the give INI file @@ -196,6 +202,8 @@ namespace MinecraftClient case "appvars": pMode = ParseMode.AppVars; break; case "autorespond": pMode = ParseMode.AutoRespond; break; case "chatformat": pMode = ParseMode.ChatFormat; break; + case "autoattack": pMode = ParseMode.AutoAttack; break; + case "autofishing": pMode = ParseMode.AutoFishing; break; default: pMode = ParseMode.Default; break; } } @@ -231,7 +239,7 @@ namespace MinecraftClient case "privatemsgscmdname": PrivateMsgsCmdName = argValue.ToLower().Trim(); break; case "botmessagedelay": botMessageDelay = TimeSpan.FromSeconds(str2int(argValue)); break; case "debugmessages": DebugMessages = str2bool(argValue); break; - case "autoattackmobs": AutoAttackMobs = str2bool(argValue); break; + case "enableentityhandling": EntityHandling = str2bool(argValue); break; case "botowners": Bots_Owners.Clear(); @@ -449,6 +457,20 @@ namespace MinecraftClient } break; + case ParseMode.AutoAttack: + switch (argName.ToLower()) + { + case "enabled": AutoAttack_Enabled = str2bool(argValue); break; + } + break; + + case ParseMode.AutoFishing: + switch (argName.ToLower()) + { + case "enabled": AutoFishing_Enabled = str2bool(argValue); break; + } + break; + case ParseMode.MCSettings: switch (argName.ToLower()) { @@ -560,7 +582,7 @@ namespace MinecraftClient + "debugmessages=false # Please enable this before submitting bug reports. Thanks!\r\n" + "scriptcache=true # Cache compiled scripts for faster load on low-end devices\r\n" + "timestamps=false # Prepend timestamps to chat messages\r\n" - + "autoattackmobs=false # Auto attack mobs around client player\r\n" + + "enableentityhandling=false # Toggle entities handling\r\n" + "\r\n" + "[AppVars]\r\n" + "# yourvar=yourvalue\r\n" @@ -639,7 +661,15 @@ namespace MinecraftClient + "\r\n" + "[AutoRespond]\r\n" + "enabled=false\r\n" - + "matchesfile=matches.ini\r\n", Encoding.UTF8); + + "matchesfile=matches.ini\r\n" + + "\r\n" + + "[AutoAttack]\r\n" + + "# Entity Handling NEED to be enabled first\r\n" + + "enabled=false\r\n" + + "\r\n" + + "[AutoFishing]\r\n" + + "# Entity Handling NEED to be enabled first\r\n" + + "enabled=false", Encoding.UTF8); } ///