Implemented "Click Window" for 1.18 (now sending the new required fields), formated few files with Visual Studio formatting. PS: left debug for people to see, I'll remove it once everything is working

This commit is contained in:
Dušan Milutinović 2022-07-01 18:59:58 +02:00
parent b5c4cd7566
commit 3d8c112159
7 changed files with 94 additions and 29 deletions

View file

@ -25,6 +25,11 @@ namespace MinecraftClient.Inventory
/// </summary> /// </summary>
public string Title; public string Title;
/// <summary>
/// state of container
/// </summary>
public int StateID;
/// <summary> /// <summary>
/// Container Items /// Container Items
/// </summary> /// </summary>

View file

@ -1066,7 +1066,7 @@ namespace MinecraftClient
/// <param name="timeout">How long to wait until the path is evaluated (default: 5 seconds)</param> /// <param name="timeout">How long to wait until the path is evaluated (default: 5 seconds)</param>
/// <remarks>When location is unreachable, computation will reach timeout, then optionally fallback to a close location within maxOffset</remarks> /// <remarks>When location is unreachable, computation will reach timeout, then optionally fallback to a close location within maxOffset</remarks>
/// <returns>True if a path has been found</returns> /// <returns>True if a path has been found</returns>
public bool MoveTo(Location location, bool allowUnsafe = false, bool allowDirectTeleport = false, int maxOffset = 0, int minOffset = 0, TimeSpan? timeout=null) public bool MoveTo(Location location, bool allowUnsafe = false, bool allowDirectTeleport = false, int maxOffset = 0, int minOffset = 0, TimeSpan? timeout = null)
{ {
lock (locationLock) lock (locationLock)
{ {
@ -1244,7 +1244,7 @@ namespace MinecraftClient
item = inventories[windowId].Items[slotId]; item = inventories[windowId].Items[slotId];
// Inventory update must be after sending packet // Inventory update must be after sending packet
bool result = handler.SendWindowAction(windowId, slotId, action, item); bool result = handler.SendWindowAction(windowId, slotId, action, item, inventories[windowId].Items, inventories[windowId].StateID);
// Update our inventory base on action type // Update our inventory base on action type
var inventory = GetInventory(windowId); var inventory = GetInventory(windowId);
@ -1707,7 +1707,7 @@ namespace MinecraftClient
/// Teleporting to other entityies is NOT implemented yet /// Teleporting to other entityies is NOT implemented yet
public bool Spectate(Entity entity) public bool Spectate(Entity entity)
{ {
if(entity.Type == EntityType.Player) if (entity.Type == EntityType.Player)
{ {
return SpectateByUUID(entity.UUID); return SpectateByUUID(entity.UUID);
} }
@ -1723,9 +1723,9 @@ namespace MinecraftClient
/// <param name="UUID">UUID of player/entity to teleport to</param> /// <param name="UUID">UUID of player/entity to teleport to</param>
public bool SpectateByUUID(Guid UUID) public bool SpectateByUUID(Guid UUID)
{ {
if(GetGamemode() == 3) if (GetGamemode() == 3)
{ {
if(InvokeRequired) if (InvokeRequired)
return InvokeOnMainThread(() => SpectateByUUID(UUID)); return InvokeOnMainThread(() => SpectateByUUID(UUID));
return handler.SendSpectate(UUID); return handler.SendSpectate(UUID);
} }
@ -1855,7 +1855,7 @@ namespace MinecraftClient
/// Check if the client is currently processing a Movement. /// Check if the client is currently processing a Movement.
/// </summary> /// </summary>
/// <returns>true if a movement is currently handled</returns> /// <returns>true if a movement is currently handled</returns>
public bool ClientIsMoving() public bool ClientIsMoving()
{ {
return terrainAndMovementsEnabled && locationReceived && ((steps != null && steps.Count > 0) || (path != null && path.Count > 0)); return terrainAndMovementsEnabled && locationReceived && ((steps != null && steps.Count > 0) || (path != null && path.Count > 0));
} }
@ -2030,11 +2030,12 @@ namespace MinecraftClient
/// </summary> /// </summary>
/// <param name="inventoryID">Inventory ID</param> /// <param name="inventoryID">Inventory ID</param>
/// <param name="itemList">Item list, key = slot ID, value = Item information</param> /// <param name="itemList">Item list, key = slot ID, value = Item information</param>
public void OnWindowItems(byte inventoryID, Dictionary<int, Inventory.Item> itemList) public void OnWindowItems(byte inventoryID, Dictionary<int, Inventory.Item> itemList, int stateId)
{ {
if (inventories.ContainsKey(inventoryID)) if (inventories.ContainsKey(inventoryID))
{ {
inventories[inventoryID].Items = itemList; inventories[inventoryID].Items = itemList;
inventories[inventoryID].StateID = stateId;
DispatchBotEvent(bot => bot.OnInventoryUpdate(inventoryID)); DispatchBotEvent(bot => bot.OnInventoryUpdate(inventoryID));
} }
} }

View file

@ -401,7 +401,7 @@ namespace MinecraftClient.Protocol.Handlers
{ {
entityType = entityPalette.FromId(ReadNextByte(cache), living); entityType = entityPalette.FromId(ReadNextByte(cache), living);
} }
Double entityX = ReadNextDouble(cache); Double entityX = ReadNextDouble(cache);
Double entityY = ReadNextDouble(cache); Double entityY = ReadNextDouble(cache);
Double entityZ = ReadNextDouble(cache); Double entityZ = ReadNextDouble(cache);
@ -1028,6 +1028,23 @@ namespace MinecraftClient.Protocol.Handlers
return slotData.ToArray(); return slotData.ToArray();
} }
public string ByteArrayToString(byte[] ba)
{
return BitConverter.ToString(ba).Replace("-", " ");
}
public byte[] GetSlotsArray(Dictionary<int, Item> items, ItemPalette itemPalette)
{
byte[] slotsArray = new byte[items.Count];
foreach (KeyValuePair<int, Item> item in items)
{
slotsArray = ConcatBytes(slotsArray, GetShort((short)item.Key), GetItemSlot(item.Value, itemPalette));
}
return slotsArray;
}
/// <summary> /// <summary>
/// Get protocol block face from Direction /// Get protocol block face from Direction
/// </summary> /// </summary>

View file

@ -94,7 +94,8 @@ namespace MinecraftClient.Protocol.Handlers
int nbr = 0; int nbr = 0;
switch (id) switch (id)
{ {
case 0x00: byte[] keepalive = new byte[5] { 0, 0, 0, 0, 0 }; case 0x00:
byte[] keepalive = new byte[5] { 0, 0, 0, 0, 0 };
Receive(keepalive, 1, 4, SocketFlags.None); Receive(keepalive, 1, 4, SocketFlags.None);
handler.OnServerKeepAlive(); handler.OnServerKeepAlive();
Send(keepalive); break; Send(keepalive); break;
@ -183,11 +184,13 @@ namespace MinecraftClient.Protocol.Handlers
case 0xCF: if (protocolversion > 51) { readNextString(); readData(1); readNextString(); } readData(4); break; case 0xCF: if (protocolversion > 51) { readNextString(); readData(1); readNextString(); } readData(4); break;
case 0xD0: if (protocolversion > 51) { readData(1); readNextString(); } break; case 0xD0: if (protocolversion > 51) { readData(1); readNextString(); } break;
case 0xD1: if (protocolversion > 51) { readNextTeamData(); } break; case 0xD1: if (protocolversion > 51) { readNextTeamData(); } break;
case 0xFA: string channel = readNextString(); case 0xFA:
string channel = readNextString();
byte[] payload = readNextByteArray(); byte[] payload = readNextByteArray();
handler.OnPluginChannelMessage(channel, payload); handler.OnPluginChannelMessage(channel, payload);
break; break;
case 0xFF: string reason = readNextString(); case 0xFF:
string reason = readNextString();
handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, reason); break; handler.OnConnectionLost(ChatBot.DisconnectReason.InGameKick, reason); break;
default: return false; //unknown packet! default: return false; //unknown packet!
} }
@ -666,12 +669,12 @@ namespace MinecraftClient.Protocol.Handlers
} }
catch (SocketException) { return false; } catch (SocketException) { return false; }
} }
public bool SendUpdateSign(Location location, string line1, string line2, string line3, string line4) public bool SendUpdateSign(Location location, string line1, string line2, string line3, string line4)
{ {
return false; //Currently not implemented return false; //Currently not implemented
} }
public bool SendBrandInfo(string brandInfo) public bool SendBrandInfo(string brandInfo)
{ {
return false; //Only supported since MC 1.7 return false; //Only supported since MC 1.7
@ -701,23 +704,23 @@ namespace MinecraftClient.Protocol.Handlers
{ {
return false; //Currently not implemented return false; //Currently not implemented
} }
public bool SendInteractEntity(int EntityID, int type, int hand) public bool SendInteractEntity(int EntityID, int type, int hand)
{ {
return false; //Currently not implemented return false; //Currently not implemented
} }
public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags) public bool UpdateCommandBlock(Location location, string command, CommandBlockMode mode, CommandBlockFlags flags)
{ {
return false; //Currently not implemented return false; //Currently not implemented
} }
public bool SendUseItem(int hand) public bool SendUseItem(int hand)
{ {
return false; //Currently not implemented return false; //Currently not implemented
} }
public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item) public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item, Dictionary<int, Item> Items, int stateId)
{ {
return false; //Currently not implemented return false; //Currently not implemented
} }
@ -759,7 +762,8 @@ namespace MinecraftClient.Protocol.Handlers
/// <param name="data">packet Data</param> /// <param name="data">packet Data</param>
public bool SendPluginChannelPacket(string channel, byte[] data) public bool SendPluginChannelPacket(string channel, byte[] data)
{ {
try { try
{
byte[] channelLength = BitConverter.GetBytes((short)channel.Length); byte[] channelLength = BitConverter.GetBytes((short)channel.Length);
Array.Reverse(channelLength); Array.Reverse(channelLength);

View file

@ -850,7 +850,7 @@ namespace MinecraftClient.Protocol.Handlers
if (item != null) if (item != null)
inventorySlots[slotId] = item; inventorySlots[slotId] = item;
} }
handler.OnWindowItems(windowId, inventorySlots); handler.OnWindowItems(windowId, inventorySlots, stateId);
} }
break; break;
case PacketTypesIn.SetSlot: case PacketTypesIn.SetSlot:
@ -1895,7 +1895,7 @@ namespace MinecraftClient.Protocol.Handlers
catch (ObjectDisposedException) { return false; } catch (ObjectDisposedException) { return false; }
} }
public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item) public bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item, Dictionary<int, Item> items, int stateId)
{ {
try try
{ {
@ -1931,14 +1931,51 @@ namespace MinecraftClient.Protocol.Handlers
} }
List<byte> packet = new List<byte>(); List<byte> packet = new List<byte>();
log.Info("Window id: " + windowId + " - State id: " + stateId + " - Slot id: " + slotId + " - Mode: " + mode);
log.Info("Bytes > " + (byte)windowId + " - State id: " + dataTypes.ByteArrayToString(dataTypes.GetVarInt(stateId)) + " - Slot id: " + dataTypes.ByteArrayToString(dataTypes.GetVarInt(slotId)) + " - Mode: " + dataTypes.ByteArrayToString(dataTypes.GetVarInt(mode)));
packet.Add((byte)windowId); packet.Add((byte)windowId);
packet.AddRange(dataTypes.GetShort((short)slotId));
// 1.18+
if (protocolversion > MC1171Version)
{
packet.AddRange(dataTypes.GetVarInt(stateId));
packet.AddRange(dataTypes.GetShort((short)slotId));
}
// 1.17.1
else if (protocolversion == MC1171Version)
{
packet.AddRange(dataTypes.GetShort((short)slotId));
packet.AddRange(dataTypes.GetVarInt(stateId));
}
// Older
else
{
packet.AddRange(dataTypes.GetShort((short)slotId));
}
packet.Add(button); packet.Add(button);
if (protocolversion < MC117Version) packet.AddRange(dataTypes.GetShort(actionNumber)); if (protocolversion < MC117Version) packet.AddRange(dataTypes.GetShort(actionNumber));
if (protocolversion >= MC19Version) if (protocolversion >= MC1165Version)
packet.AddRange(dataTypes.GetVarInt(mode)); packet.AddRange(dataTypes.GetVarInt(mode));
else packet.Add(mode);
// 1.17+
if (protocolversion >= MC117Version)
{
byte[] arrayOfSlots = dataTypes.GetSlotsArray(items, itemPalette);
log.Info("Length: " + sizeof(byte) * arrayOfSlots.Length);
log.Info("Array: " + dataTypes.ByteArrayToString(arrayOfSlots));
packet.AddRange(dataTypes.GetVarInt(sizeof(byte) * arrayOfSlots.Length));
packet.AddRange(arrayOfSlots);
}
packet.AddRange(dataTypes.GetItemSlot(item, itemPalette)); packet.AddRange(dataTypes.GetItemSlot(item, itemPalette));
log.Info("Packet data: " + dataTypes.ByteArrayToString(packet.ToArray()));
SendPacket(PacketTypesOut.ClickWindow, packet); SendPacket(PacketTypesOut.ClickWindow, packet);
return true; return true;
} }

View file

@ -94,7 +94,7 @@ namespace MinecraftClient.Protocol
/// <param name="data">packet Data</param> /// <param name="data">packet Data</param>
/// <returns>True if message was successfully sent</returns> /// <returns>True if message was successfully sent</returns>
bool SendPluginChannelPacket(string channel, byte[] data); bool SendPluginChannelPacket(string channel, byte[] data);
/// <summary> /// <summary>
/// Send Entity Action packet to the server. /// Send Entity Action packet to the server.
/// </summary> /// </summary>
@ -102,7 +102,7 @@ namespace MinecraftClient.Protocol
/// <param name="type">Type of packet to send</param> /// <param name="type">Type of packet to send</param>
/// <returns>True if packet was successfully sent</returns> /// <returns>True if packet was successfully sent</returns>
bool SendEntityAction(int EntityID, int type); bool SendEntityAction(int EntityID, int type);
/// <summary> /// <summary>
/// Send a held item change packet to the server. /// Send a held item change packet to the server.
/// </summary> /// </summary>
@ -140,7 +140,7 @@ namespace MinecraftClient.Protocol
/// <param name="Z">Z coordinate for "interact at"</param> /// <param name="Z">Z coordinate for "interact at"</param>
/// <returns>True if packet was successfully sent</returns> /// <returns>True if packet was successfully sent</returns>
bool SendInteractEntity(int EntityID, int type, float X, float Y, float Z); bool SendInteractEntity(int EntityID, int type, float X, float Y, float Z);
/// <summary> /// <summary>
/// Send an entity interaction packet to the server. /// Send an entity interaction packet to the server.
/// </summary> /// </summary>
@ -165,7 +165,7 @@ namespace MinecraftClient.Protocol
/// <param name="buttom">Action to perform</param> /// <param name="buttom">Action to perform</param>
/// <param name="item">Item in the clicked slot</param> /// <param name="item">Item in the clicked slot</param>
/// <returns>True if packet was successfully sent</returns> /// <returns>True if packet was successfully sent</returns>
bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item); bool SendWindowAction(int windowId, int slotId, WindowActionType action, Item item, Dictionary<int, Item> Items, int stateId);
/// <summary> /// <summary>
/// Request Creative Mode item creation into regular/survival Player Inventory /// Request Creative Mode item creation into regular/survival Player Inventory
@ -220,7 +220,7 @@ namespace MinecraftClient.Protocol
/// <param name="line4">New line 4</param> /// <param name="line4">New line 4</param>
/// <returns>True if packet was succcessfully sent</returns> /// <returns>True if packet was succcessfully sent</returns>
bool SendUpdateSign(Location location, string line1, string line2, string line3, string line4); bool SendUpdateSign(Location location, string line1, string line2, string line3, string line4);
/// <summary> /// <summary>
/// Update command block /// Update command block
/// </summary> /// </summary>

View file

@ -263,7 +263,8 @@ namespace MinecraftClient.Protocol
/// </summary> /// </summary>
/// <param name="inventoryID">Inventory ID</param> /// <param name="inventoryID">Inventory ID</param>
/// <param name="itemList">Item list</param> /// <param name="itemList">Item list</param>
void OnWindowItems(byte inventoryID, Dictionary<int, Item> itemList); /// <param name="stateId">State ID</param>
void OnWindowItems(byte inventoryID, Dictionary<int, Item> itemList, int stateId);
/// <summary> /// <summary>
/// Called when a single slot has been updated inside an inventory /// Called when a single slot has been updated inside an inventory