From 51d03b9ced5faf67336963613a824d86d03d9180 Mon Sep 17 00:00:00 2001 From: ReinforceZwei <39955851+ReinforceZwei@users.noreply.github.com> Date: Sun, 22 Mar 2020 20:12:06 +0800 Subject: [PATCH] Added basic auto fishing --- MinecraftClient/Commands/Fishing.cs | 48 ++++++++ MinecraftClient/Commands/UseItem.cs | 19 ++++ MinecraftClient/McTcpClient.cs | 106 ++++++++++++++++-- MinecraftClient/MinecraftClient.csproj | 2 + .../Protocol/Handlers/PacketIncomingType.cs | 3 +- .../Protocol/Handlers/PacketOutgoingType.cs | 3 +- .../Protocol/Handlers/Protocol16.cs | 4 + .../Protocol/Handlers/Protocol18.cs | 47 +++++++- .../Handlers/Protocol18PacketTypes.cs | 2 + MinecraftClient/Protocol/IMinecraftCom.cs | 2 + .../Protocol/IMinecraftComHandler.cs | 4 + 11 files changed, 222 insertions(+), 18 deletions(-) create mode 100644 MinecraftClient/Commands/Fishing.cs create mode 100644 MinecraftClient/Commands/UseItem.cs diff --git a/MinecraftClient/Commands/Fishing.cs b/MinecraftClient/Commands/Fishing.cs new file mode 100644 index 00000000..7648fd6a --- /dev/null +++ b/MinecraftClient/Commands/Fishing.cs @@ -0,0 +1,48 @@ +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 new file mode 100644 index 00000000..2002ed0f --- /dev/null +++ b/MinecraftClient/Commands/UseItem.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace MinecraftClient.Commands +{ + class UseItem : Command + { + public override string CMDName { get { return "useitem"; } } + public override string CMDDesc { get { return "useitem: Use (left click) an item on the hand"; } } + + public override string Run(McTcpClient handler, string command) + { + handler.useItemOnHand(); + return "Use an item"; + } + } +} diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index 7ac1464b..9346b3e6 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -4,6 +4,7 @@ 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; @@ -1081,7 +1082,32 @@ namespace MinecraftClient } } - + private Dictionary fishingRod = new Dictionary(); + private Double fishingHookThreshold = -0.3; // must be negetive + public bool AutoFishing { get; set; } = false; + 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); + } + } + } /// /// Called when an Entity was created/spawned. @@ -1092,15 +1118,17 @@ namespace MinecraftClient /// public void OnSpawnLivingEntity(int EntityID, int EntityType, Guid UUID, Location location) { - if (!Settings.AutoAttackMobs) return; string name = getEntityName(EntityType); if (name != "") { Entity entity = new Entity(EntityID, EntityType, name, location); entitiesToTrack.Add(EntityID, entity); - if (calculateDistance(location, GetCurrentLocation()) < attackRange) + if (Settings.AutoAttackMobs) { - entitiesToAttack.Add(EntityID, entity); + if (calculateDistance(location, GetCurrentLocation()) < attackRange) + { + entitiesToAttack.Add(EntityID, entity); + } } } } @@ -1111,7 +1139,6 @@ namespace MinecraftClient /// public void OnDestroyEntities(int[] Entities) { - if (!Settings.AutoAttackMobs) return; foreach (int a in Entities) { if (entitiesToTrack.ContainsKey(a)) @@ -1119,6 +1146,11 @@ namespace MinecraftClient entitiesToAttack.Remove(a); entitiesToTrack.Remove(a); } + + if (fishingRod.ContainsKey(a)) + { + fishingRod.Remove(a); + } } } @@ -1161,6 +1193,23 @@ namespace MinecraftClient entitiesToAttack.Remove(EntityID); } } + if (fishingRod.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(); + } + } + } } /// @@ -1184,7 +1233,6 @@ namespace MinecraftClient } } } - /// /// Called when server sent a Time Update packet. @@ -1224,11 +1272,46 @@ namespace MinecraftClient /// public void OnEntityTeleport(int EntityID, Double X, Double Y, Double Z, bool onGround) { - if (!Settings.AutoAttackMobs) return; - if (entitiesToTrack.ContainsKey(EntityID)) + if (Settings.AutoAttackMobs) { - entitiesToTrack[EntityID].Location = new Location(X, Y, Z); + 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(); + }); } /// @@ -1287,6 +1370,9 @@ namespace MinecraftClient playerEntityID = EntityID; } - + public void useItemOnHand() + { + handler.SendUseItemPacket(0); + } } } diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj index 54e9e3ad..a271317d 100644 --- a/MinecraftClient/MinecraftClient.csproj +++ b/MinecraftClient/MinecraftClient.csproj @@ -89,6 +89,7 @@ + @@ -98,6 +99,7 @@ + diff --git a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs index 87f9fe1b..6a552d8e 100644 --- a/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketIncomingType.cs @@ -40,6 +40,7 @@ namespace MinecraftClient.Protocol.Handlers EntityPositionAndRotation, EntityProperties, TimeUpdate, - EntityTeleport + EntityTeleport, + EntityStatus } } diff --git a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs index de1f8a92..08ebd947 100644 --- a/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs +++ b/MinecraftClient/Protocol/Handlers/PacketOutgoingType.cs @@ -22,6 +22,7 @@ namespace MinecraftClient.Protocol.Handlers TeleportConfirm, //modified by reinforce HeldItemChange, - InteractEntity + InteractEntity, + UseItem } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index 458d50a0..c76ce309 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -747,5 +747,9 @@ namespace MinecraftClient.Protocol.Handlers { return true; } + public bool SendUseItemPacket(int hand) + { + return true; + } } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index ed04f92f..f8dba950 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -540,9 +540,7 @@ namespace MinecraftClient.Protocol.Handlers SendPacket(PacketOutgoingType.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, dataTypes.GetVarInt(3))); //Accepted pack SendPacket(PacketOutgoingType.ResourcePackStatus, dataTypes.ConcatBytes(responseHeader, dataTypes.GetVarInt(0))); //Successfully loaded break; - // modified by reinforce - case PacketIncomingType.SpawnLivingEntity: - if (login_phase) break; + case PacketIncomingType.SpawnEntity: int EntityID = dataTypes.ReadNextVarInt(packetData); Guid EntityUUID = dataTypes.ReadNextUUID(packetData); int EntityType = dataTypes.ReadNextVarInt(packetData); @@ -551,13 +549,31 @@ namespace MinecraftClient.Protocol.Handlers Double Z = dataTypes.ReadNextDouble(packetData); byte EntityYaw = dataTypes.ReadNextByte(packetData); byte EntityPitch = dataTypes.ReadNextByte(packetData); - byte EntityHeadPitch = 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); - + + 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); + + EntityLocation = new Location(X, Y, Z); handler.OnSpawnLivingEntity(EntityID,EntityType,EntityUUID,EntityLocation); break; @@ -597,7 +613,7 @@ namespace MinecraftClient.Protocol.Handlers DeltaX = DeltaX / (128 * 32); DeltaY = DeltaY / (128 * 32); DeltaZ = DeltaZ / (128 * 32); - //handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); + handler.OnEntityPosition(EntityID, DeltaX, DeltaY, DeltaZ, OnGround); break; case PacketIncomingType.EntityProperties: EntityID = dataTypes.ReadNextVarInt(packetData); @@ -643,6 +659,11 @@ namespace MinecraftClient.Protocol.Handlers 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); + break; default: return false; //Ignored packet } @@ -1162,5 +1183,19 @@ namespace MinecraftClient.Protocol.Handlers { return true; } + + public bool SendUseItemPacket(int hand) + { + try + { + List packet = new List(); + packet.AddRange(dataTypes.GetVarInt(hand)); + SendPacket(PacketOutgoingType.UseItem, packet); + return true; + } + catch (SocketException) { return false; } + catch (System.IO.IOException) { return false; } + catch (ObjectDisposedException) { return false; } + } } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs b/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs index 62bc1c74..9150ab61 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18PacketTypes.cs @@ -269,6 +269,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x2A: return PacketIncomingType.EntityPositionAndRotation; case 0x59: return PacketIncomingType.EntityProperties; case 0x57: return PacketIncomingType.EntityTeleport; + case 0x1C: return PacketIncomingType.EntityStatus; default: return PacketIncomingType.UnknownPacket; } } @@ -383,6 +384,7 @@ namespace MinecraftClient.Protocol.Handlers case PacketOutgoingType.TeleportConfirm: return 0x00; case PacketOutgoingType.HeldItemChange: return 0x23; case PacketOutgoingType.InteractEntity: return 0x0E; + case PacketOutgoingType.UseItem: return 0x2D; } } diff --git a/MinecraftClient/Protocol/IMinecraftCom.cs b/MinecraftClient/Protocol/IMinecraftCom.cs index 83cec5ca..a4860042 100644 --- a/MinecraftClient/Protocol/IMinecraftCom.cs +++ b/MinecraftClient/Protocol/IMinecraftCom.cs @@ -89,5 +89,7 @@ namespace MinecraftClient.Protocol 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); + + bool SendUseItemPacket(int hand); } } diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs index 7c3c321c..866e6658 100644 --- a/MinecraftClient/Protocol/IMinecraftComHandler.cs +++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs @@ -126,6 +126,8 @@ namespace MinecraftClient.Protocol /// The data from the channel void OnPluginChannelMessage(string channel, byte[] data); + void OnSpawnEntity(int EntityID, int EntityType, Guid UUID, Location location); + void OnSpawnLivingEntity(int EntityID, int EntityType, Guid UUID, Location location); void OnDestroyEntities(int[] EntityID); @@ -140,6 +142,8 @@ namespace MinecraftClient.Protocol void OnEntityTeleport(int EntityID, Double X, Double Y, Double Z, bool onGround); + void OnEntityStatus(int EntityID, byte EntityStatus); + void SetPlayerEntityID(int EntityID); } }