From bc449b404ee061de3327af61aba0ffe086054b38 Mon Sep 17 00:00:00 2001
From: ReinforceZwei <39955851+ReinforceZwei@users.noreply.github.com>
Date: Thu, 26 Mar 2020 15:01:42 +0800
Subject: [PATCH] Inventory handling
---
MinecraftClient/ChatBot.cs | 12 ++
MinecraftClient/ChatBots/AutoFishing.cs | 29 ++++-
MinecraftClient/Commands/ChangeSlot.cs | 42 +++++++
MinecraftClient/Commands/GetInventory.cs | 24 ++++
MinecraftClient/Inventory/Container.cs | 83 +++++++++++++
MinecraftClient/Inventory/ContainerType.cs | 38 ++++++
MinecraftClient/Inventory/Item.cs | 34 ++++++
MinecraftClient/Mapping/Entity.cs | 29 +++--
MinecraftClient/Mapping/EntityType.cs | 14 +++
MinecraftClient/McTcpClient.cs | 91 ++++++++++++---
MinecraftClient/MinecraftClient.csproj | 7 ++
MinecraftClient/MinecraftClient.csproj.user | 2 +-
.../Protocol/Handlers/PacketIncomingType.cs | 6 +-
.../Protocol/Handlers/PacketOutgoingType.cs | 3 +-
.../Protocol/Handlers/Protocol16.cs | 8 ++
.../Protocol/Handlers/Protocol18.cs | 110 ++++++++++++++++--
.../Handlers/Protocol18PacketTypes.cs | 13 +++
MinecraftClient/Protocol/IMinecraftCom.cs | 6 +-
.../Protocol/IMinecraftComHandler.cs | 10 +-
MinecraftClient/config/README.md | 21 ++++
20 files changed, 538 insertions(+), 44 deletions(-)
create mode 100644 MinecraftClient/Commands/ChangeSlot.cs
create mode 100644 MinecraftClient/Commands/GetInventory.cs
create mode 100644 MinecraftClient/Inventory/Container.cs
create mode 100644 MinecraftClient/Inventory/ContainerType.cs
create mode 100644 MinecraftClient/Inventory/Item.cs
create mode 100644 MinecraftClient/Mapping/EntityType.cs
diff --git a/MinecraftClient/ChatBot.cs b/MinecraftClient/ChatBot.cs
index ec9b1cbf..8d5ff48d 100644
--- a/MinecraftClient/ChatBot.cs
+++ b/MinecraftClient/ChatBot.cs
@@ -5,6 +5,7 @@ using System.Text;
using System.IO;
using System.Threading;
using System.Text.RegularExpressions;
+using MinecraftClient.Inventory;
namespace MinecraftClient
{
@@ -620,6 +621,11 @@ namespace MinecraftClient
return Handler.GetEntityHandlingEnabled();
}
+ public bool GetInventoryEnabled()
+ {
+ return Handler.GetInventoryEnabled();
+ }
+
///
/// Get the current Minecraft World
///
@@ -806,5 +812,11 @@ namespace MinecraftClient
{
return Handler.UseItemOnHand();
}
+
+ protected Container GetPlayerInventory()
+ {
+ Container container = Handler.GetPlayerInventory();
+ return new Container(container.ID,container.Type,container.Title,container.Items);
+ }
}
}
diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs
index 94567318..84304674 100644
--- a/MinecraftClient/ChatBots/AutoFishing.cs
+++ b/MinecraftClient/ChatBots/AutoFishing.cs
@@ -14,6 +14,7 @@ namespace MinecraftClient.ChatBots
private Double fishingHookThreshold = 0.2;
private Location LastPos = new Location();
private DateTime CaughtTime = DateTime.Now;
+ private bool inventoryEnabled;
public override void Initialize()
{
@@ -23,11 +24,12 @@ namespace MinecraftClient.ChatBots
ConsoleIO.WriteLine("[AutoFishing] This bot will be unloaded.");
UnloadBot();
}
+ inventoryEnabled = GetInventoryEnabled();
}
public override void OnEntitySpawn(Entity entity)
{
- if (entity.Type == 102)
+ if (entity.TypeID == 102)
{
ConsoleIO.WriteLine("Threw a fishing rod");
fishingRod.Add(entity.ID, entity);
@@ -69,15 +71,36 @@ namespace MinecraftClient.ChatBots
ConsoleIO.WriteLine("Caught a fish!");
// retract fishing rod
UseItemOnHand();
+ if (inventoryEnabled)
+ {
+ if (!hasFishingRod())
+ {
+ ConsoleIO.WriteLine("No Fishing Rod on hand. Maybe broken?");
+ return;
+ }
+ }
// non-blocking delay
Task.Factory.StartNew(delegate
{
// retract fishing rod need some time
- Thread.Sleep(500);
+ Thread.Sleep(800);
// throw again
- // TODO: to check if hand have fishing rod
UseItemOnHand();
});
}
+
+ public bool hasFishingRod()
+ {
+ if (!inventoryEnabled) return false;
+ int start = 36;
+ int end = 44;
+ Inventory.Container container = GetPlayerInventory();
+ foreach(KeyValuePair a in container.Items)
+ {
+ if (a.Key < start || a.Key > end) continue;
+ if (a.Value.ID == 622) return true;
+ }
+ return false;
+ }
}
}
diff --git a/MinecraftClient/Commands/ChangeSlot.cs b/MinecraftClient/Commands/ChangeSlot.cs
new file mode 100644
index 00000000..0f3bebe6
--- /dev/null
+++ b/MinecraftClient/Commands/ChangeSlot.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Commands
+{
+ class ChangeSlot : Command
+ {
+ public override string CMDName { get { return "changeslot"; } }
+ public override string CMDDesc { get { return "changeslot <1-9>: Change hotbar"; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ if (!handler.GetInventoryEnabled()) return "Please enable InventoryHandling in the config file first.";
+ if (hasArg(command))
+ {
+ short slot;
+ try
+ {
+ slot = Convert.ToInt16(getArg(command));
+ }
+ catch (FormatException)
+ {
+ return "Could not change slot: Not a Number";
+ }
+ if (slot >= 1 && slot <= 9)
+ {
+ if (handler.ChangeSlot(slot-=1))
+ {
+ return "Changed to slot " + (slot+=1);
+ }
+ else
+ {
+ return "Could not change slot";
+ }
+ }
+ }
+ return CMDDesc;
+ }
+ }
+}
diff --git a/MinecraftClient/Commands/GetInventory.cs b/MinecraftClient/Commands/GetInventory.cs
new file mode 100644
index 00000000..96c4d948
--- /dev/null
+++ b/MinecraftClient/Commands/GetInventory.cs
@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MinecraftClient.Inventory;
+
+namespace MinecraftClient.Commands
+{
+ class GetInventory : Command
+ {
+ public override string CMDName { get { return "getinventory"; } }
+ public override string CMDDesc { get { return "getinventory: Show your inventory."; } }
+
+ public override string Run(McTcpClient handler, string command)
+ {
+ Dictionary items = handler.GetPlayerInventory().Items;
+ foreach(KeyValuePair a in items)
+ {
+ ConsoleIO.WriteLine("Slot: "+a.Key+" ItemID: " + a.Value.ID + ", Count: " + a.Value.Count);
+ }
+ return "";
+ }
+ }
+}
diff --git a/MinecraftClient/Inventory/Container.cs b/MinecraftClient/Inventory/Container.cs
new file mode 100644
index 00000000..9e93be8a
--- /dev/null
+++ b/MinecraftClient/Inventory/Container.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Inventory
+{
+ public class Container
+ {
+ public int ID;
+ public ContainerType Type;
+ public string Title;
+ public Dictionary Items;
+
+ public Container() { }
+ public Container(int id, ContainerType type, string title)
+ {
+ ID = id;
+ Type = type;
+ Title = title;
+ }
+ public Container(int id, ContainerType type, string title,Dictionary items)
+ {
+ ID = id;
+ Type = type;
+ Title = title;
+ Items = items;
+ }
+ public Container(int id, Protocol.InventoryType type, string title)
+ {
+ ID = id;
+ Title = title;
+ }
+ public Container(int id, int typeID, string title)
+ {
+ ID = id;
+ Type = GetContainerType(typeID);
+ Title = title;
+ }
+ // for player inventory because they dont have ID and title
+ public Container(ContainerType type)
+ {
+ Type = type;
+ }
+ public Container(ContainerType type, Dictionary items)
+ {
+ Type = type;
+ Items = items;
+ }
+
+ public static ContainerType GetContainerType(int typeID)
+ {
+ // https://wiki.vg/Inventory didn't state the inventory ID, assume that list start with 0
+ switch (typeID)
+ {
+ case 0: return ContainerType.Generic_9x1;
+ case 1: return ContainerType.Generic_9x2;
+ case 2: return ContainerType.Generic_9x3;
+ case 3: return ContainerType.Generic_9x4;
+ case 4: return ContainerType.Generic_9x5;
+ case 5: return ContainerType.Generic_9x6;
+ case 6: return ContainerType.Generic_3x3;
+ case 7: return ContainerType.Anvil;
+ case 8: return ContainerType.Beacon;
+ case 9: return ContainerType.BlastFurnace;
+ case 10: return ContainerType.BrewingStand;
+ case 11: return ContainerType.Crafting;
+ case 12: return ContainerType.Enchantment;
+ case 13: return ContainerType.Furnace;
+ case 14: return ContainerType.Grindstone;
+ case 15: return ContainerType.Hopper;
+ case 16: return ContainerType.Lectern;
+ case 17: return ContainerType.Loom;
+ case 18: return ContainerType.Merchant;
+ case 19: return ContainerType.ShulkerBox;
+ case 20: return ContainerType.Smoker;
+ case 21: return ContainerType.Cartography;
+ case 22: return ContainerType.Stonecutter;
+ default: return ContainerType.Unknown;
+ }
+ }
+ }
+}
diff --git a/MinecraftClient/Inventory/ContainerType.cs b/MinecraftClient/Inventory/ContainerType.cs
new file mode 100644
index 00000000..c1276a7b
--- /dev/null
+++ b/MinecraftClient/Inventory/ContainerType.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Inventory
+{
+ // For MC 1.14 after ONLY
+ public enum ContainerType
+ {
+ Generic_9x1,
+ Generic_9x2,
+ Generic_9x3, // chest, ender chest, minecart with chest, barrel
+ Generic_9x4,
+ Generic_9x5,
+ Generic_9x6,
+ Generic_3x3,
+ Anvil,
+ Beacon,
+ BlastFurnace,
+ BrewingStand,
+ Crafting,
+ Enchantment,
+ Furnace,
+ Grindstone,
+ Hopper,
+ Lectern,
+ Loom,
+ Merchant,
+ ShulkerBox,
+ Smoker,
+ Cartography,
+ Stonecutter,
+ // not in the list
+ PlayerInventory,
+ Unknown
+ }
+}
diff --git a/MinecraftClient/Inventory/Item.cs b/MinecraftClient/Inventory/Item.cs
new file mode 100644
index 00000000..2048641d
--- /dev/null
+++ b/MinecraftClient/Inventory/Item.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Inventory
+{
+ public class Item
+ {
+ public int ID;
+ public int Count;
+ public int SlotID = -1; // which slot is this item at, -1 = not specified
+ public Dictionary NBT;
+
+ public Item(int ID,int Count,int SlotID, Dictionary NBT)
+ {
+ this.ID = ID;
+ this.Count = Count;
+ this.SlotID = SlotID;
+ this.NBT = NBT;
+ }
+ public Item(int ID, int Count, int SlotID)
+ {
+ this.ID = ID;
+ this.Count = Count;
+ this.SlotID = SlotID;
+ }
+ public Item(int ID, int Count)
+ {
+ this.ID = ID;
+ this.Count = Count;
+ }
+ }
+}
diff --git a/MinecraftClient/Mapping/Entity.cs b/MinecraftClient/Mapping/Entity.cs
index 289fdf3c..5439d271 100644
--- a/MinecraftClient/Mapping/Entity.cs
+++ b/MinecraftClient/Mapping/Entity.cs
@@ -8,7 +8,8 @@ namespace MinecraftClient.Mapping
public class Entity
{
public int ID;
- public int Type;
+ public int TypeID;
+ public EntityType Type;
public string Name;
public Location Location;
public Entity(int ID, Location location)
@@ -16,17 +17,31 @@ namespace MinecraftClient.Mapping
this.ID = ID;
this.Location = location;
}
- public Entity(int ID, int Type, Location location)
+ public Entity(int ID, int TypeID, Location location)
{
this.ID = ID;
- this.Type = Type;
- this.Name = GetMobName(Type);
+ this.TypeID = TypeID;
+ this.Name = GetMobName(TypeID);
this.Location = location;
}
- public Entity(int ID, int Type, string Name, Location location)
+ public Entity(int ID, int TypeID, EntityType type, Location location)
{
this.ID = ID;
- this.Type = Type;
+ this.TypeID = TypeID;
+ this.Type = type;
+ this.Name = GetMobName(TypeID);
+ this.Location = location;
+ }
+ public Entity(int ID, EntityType type, Location location)
+ {
+ this.ID = ID;
+ this.Type = type;
+ this.Location = location;
+ }
+ public Entity(int ID, int TypeID, string Name, Location location)
+ {
+ this.ID = ID;
+ this.TypeID = TypeID;
this.Name = Name;
this.Location = location;
}
@@ -80,7 +95,7 @@ namespace MinecraftClient.Mapping
}
public string GetMobName()
{
- return GetMobName(Type);
+ return GetMobName(TypeID);
}
}
}
diff --git a/MinecraftClient/Mapping/EntityType.cs b/MinecraftClient/Mapping/EntityType.cs
new file mode 100644
index 00000000..9333f222
--- /dev/null
+++ b/MinecraftClient/Mapping/EntityType.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MinecraftClient.Mapping
+{
+ public enum EntityType
+ {
+ MobAndAnimal,
+ Player,
+ NonLivingThings,
+ }
+}
diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs
index fb5c6984..3b28c704 100644
--- a/MinecraftClient/McTcpClient.cs
+++ b/MinecraftClient/McTcpClient.cs
@@ -10,6 +10,7 @@ using MinecraftClient.Protocol;
using MinecraftClient.Proxy;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Mapping;
+using MinecraftClient.Inventory;
namespace MinecraftClient
{
@@ -26,7 +27,7 @@ namespace MinecraftClient
private readonly List bots = new List();
private static readonly List botsOnHold = new List();
- private static List inventories = new List();
+ private static List inventories = new List();
private readonly Dictionary> registeredBotPluginChannels = new Dictionary>();
private readonly List registeredServerPluginChannels = new List();
@@ -52,14 +53,14 @@ namespace MinecraftClient
private string username;
private string uuid;
private string sessionid;
- private Inventory playerInventory;
+ private Container playerInventory = new Container(ContainerType.PlayerInventory);
private DateTime lastKeepAlive;
private object lastKeepAliveLock = new object();
private int playerEntityID;
// not really understand the Inventory Class
// so I use a Dict instead for player inventory
- private Dictionary playerItems;
+ //private Dictionary playerItems;
// Entity handling
private Dictionary entities = new Dictionary();
@@ -567,9 +568,9 @@ namespace MinecraftClient
/// Get client player's inventory items
///
/// Item Dictionary indexed by Slot ID (Check wiki.vg for slot ID)
- public Dictionary GetPlayerInventory()
+ public Container GetPlayerInventory()
{
- return playerItems;
+ return playerInventory;
}
// TODO: add command for displaying player inventory
@@ -737,13 +738,14 @@ namespace MinecraftClient
/// When an inventory is opened
///
/// Location to reach
- public void OnInventoryOpen(Inventory inventory)
+ public void OnInventoryOpen(Container inventory)
{
//TODO: Handle Inventory
if (!inventories.Contains(inventory))
{
inventories.Add(inventory);
}
+ ConsoleIO.WriteLine(inventory.Type.ToString());
}
///
@@ -754,9 +756,9 @@ namespace MinecraftClient
{
for (int i = 0; i < inventories.Count; i++)
{
- Inventory inventory = inventories[i];
+ Container inventory = inventories[i];
if (inventory == null) continue;
- if (inventory.id == inventoryID)
+ if (inventory.Type == Container.GetContainerType(inventoryID))
{
inventories.Remove(inventory);
return;
@@ -769,11 +771,27 @@ namespace MinecraftClient
///
///
///
- public void OnWindowItems(int type, Dictionary itemList)
+ public void OnWindowItems(int type, Dictionary itemList)
{
// 0 is player inventory
if (type == 0)
- playerItems = itemList;
+ playerInventory.Items = itemList;
+ }
+
+ public void OnSetSlot(byte WindowID, short SlotID, bool Present)
+ {
+ if(WindowID == 0)
+ {
+ if (playerInventory.Items.ContainsKey(SlotID))
+ playerInventory.Items.Remove(SlotID);
+ }
+ }
+ public void OnSetSlot(byte WindowID, short SlotID, bool Present, int ItemID, byte Count, Dictionary NBT)
+ {
+ if (WindowID == 0)
+ {
+ playerInventory.Items[SlotID] = new Inventory.Item(ItemID, Count, SlotID, NBT);
+ }
}
///
@@ -1081,12 +1099,12 @@ namespace MinecraftClient
/// Called when a non-living entity spawned (fishing hook, minecart, etc)
///
///
- ///
+ ///
///
///
- public void OnSpawnEntity(int EntityID, int EntityType, Guid UUID, Location location)
+ public void OnSpawnEntity(int EntityID, int TypeID, Guid UUID, Location location)
{
- Entity entity = new Entity(EntityID, EntityType, location);
+ Entity entity = new Entity(EntityID, TypeID, EntityType.NonLivingThings, location);
entities.Add(EntityID, entity);
foreach (ChatBot bot in bots.ToArray())
bot.OnEntitySpawn(entity);
@@ -1096,12 +1114,29 @@ namespace MinecraftClient
/// Called when an Entity was created/spawned.
///
///
- ///
+ ///
///
///
- public void OnSpawnLivingEntity(int EntityID, int EntityType, Guid UUID, Location location)
+ /// Cannot determine is a Mob or a Cuty Animal
+ public void OnSpawnLivingEntity(int EntityID, int TypeID, Guid UUID, Location location)
{
- Entity entity = new Entity(EntityID, EntityType, location);
+ Entity entity = new Entity(EntityID, TypeID, EntityType.MobAndAnimal, location);
+ entities.Add(EntityID, entity);
+ foreach (ChatBot bot in bots.ToArray())
+ bot.OnEntitySpawn(entity);
+ }
+
+ ///
+ /// Called when a player was spawned/in the render distance
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ public void OnSpawnPlayer(int EntityID, Guid UUID, Location location, byte Yaw, byte Pitch)
+ {
+ Entity entity = new Entity(EntityID, EntityType.Player, location);
entities.Add(EntityID, entity);
foreach (ChatBot bot in bots.ToArray())
bot.OnEntitySpawn(entity);
@@ -1118,7 +1153,7 @@ namespace MinecraftClient
if (entities.ContainsKey(a))
{
foreach (ChatBot bot in bots.ToArray())
- bot.OnEntityDespawn(new Entity(entities[a].ID, entities[a].Type, entities[a].Location));
+ bot.OnEntityDespawn(new Entity(entities[a].ID, entities[a].TypeID, entities[a].Type, entities[a].Location));
entities.Remove(a);
}
}
@@ -1143,7 +1178,7 @@ namespace MinecraftClient
entities[EntityID].Location = L;
foreach (ChatBot bot in bots.ToArray())
- bot.OnEntityMove(new Entity(entities[EntityID].ID, entities[EntityID].Type, entities[EntityID].Location));
+ bot.OnEntityMove(new Entity(entities[EntityID].ID, entities[EntityID].TypeID, entities[EntityID].Type, entities[EntityID].Location));
}
}
@@ -1163,7 +1198,7 @@ namespace MinecraftClient
entities[EntityID].Location = location;
foreach (ChatBot bot in bots.ToArray())
- bot.OnEntityMove(new Entity(entities[EntityID].ID, entities[EntityID].Type, entities[EntityID].Location));
+ bot.OnEntityMove(new Entity(entities[EntityID].ID, entities[EntityID].TypeID, entities[EntityID].Type, entities[EntityID].Location));
}
}
@@ -1236,5 +1271,23 @@ namespace MinecraftClient
{
return handler.SendInteractEntityPacket(EntityID, type);
}
+ // not work :(
+ public bool PlaceBlock(Location location)
+ {
+ ConsoleIO.WriteLine(location.ToString());
+ return handler.SendPlayerBlockPlacement(0, location, 1, 0.5f, 0.5f, 0.5f, false);
+ }
+
+ public bool ChangeSlot(short slot)
+ {
+ if (slot >= 0 && slot <= 8)
+ {
+ return handler.SendHeldItemChange(slot);
+ }
+ else
+ {
+ return false;
+ }
+ }
}
}
diff --git a/MinecraftClient/MinecraftClient.csproj b/MinecraftClient/MinecraftClient.csproj
index f5ffe2d4..9773fe0b 100644
--- a/MinecraftClient/MinecraftClient.csproj
+++ b/MinecraftClient/MinecraftClient.csproj
@@ -88,8 +88,10 @@
+
+
@@ -100,6 +102,9 @@
+
+
+
@@ -107,6 +112,7 @@
+
@@ -286,6 +292,7 @@
+