diff --git a/MinecraftClient/Mapping/MapIcon.cs b/MinecraftClient/Mapping/MapIcon.cs
new file mode 100644
index 00000000..155f1b97
--- /dev/null
+++ b/MinecraftClient/Mapping/MapIcon.cs
@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using MinecraftClient.Protocol.Handlers;
+
+namespace MinecraftClient.Mapping
+{
+ public class MapIcon
+ {
+ public MapIconType Type { set; get; }
+ public byte X { set; get; }
+ public byte Z { set; get; }
+ public byte Direction { set; get; }
+ public string? DisplayName { set; get; } = null;
+ }
+}
diff --git a/MinecraftClient/Mapping/MapIconType.cs b/MinecraftClient/Mapping/MapIconType.cs
new file mode 100644
index 00000000..68a1e307
--- /dev/null
+++ b/MinecraftClient/Mapping/MapIconType.cs
@@ -0,0 +1,39 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace MinecraftClient.Mapping
+{
+ public enum MapIconType
+ {
+ White_Arrow = 0,
+ Green_Arrow,
+ Red_Arrow,
+ Blue_Arrow,
+ White_Cross,
+ Red_Pointer,
+ White_Circle,
+ Small_White_Circle,
+ Mansion,
+ Temple,
+ White_Banner,
+ Orange_Banner,
+ Magenta_Banner,
+ Light_Blue_Banner,
+ Yellow_Banner,
+ Lime_Banner,
+ Pink_Banner,
+ Gray_Banner,
+ Light_Gray_Banner,
+ Cyan_Banner,
+ Purple_Banner,
+ Blue_Banner,
+ Brown_Banner,
+ Green_Banner,
+ Red_Banner,
+ Black_Banner,
+ Treasure_Marker
+ }
+}
diff --git a/MinecraftClient/McClient.cs b/MinecraftClient/McClient.cs
index a72bb3e9..b2bf629d 100644
--- a/MinecraftClient/McClient.cs
+++ b/MinecraftClient/McClient.cs
@@ -3064,16 +3064,22 @@ namespace MinecraftClient
}
///
- /// Called map data
+ /// Called when an update of the map is sent by the server, take a look at https://wiki.vg/Protocol#Map_Data for more info on the fields
+ /// Map format and colors: https://minecraft.fandom.com/wiki/Map_item_format
///
- ///
- ///
- ///
- ///
- ///
- public void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount)
+ /// Map ID of the map being modified
+ /// A scale of the Map, from 0 for a fully zoomed-in map (1 block per pixel) to 4 for a fully zoomed-out map (16 blocks per pixel)
+ /// Specifies whether player and item frame icons are shown
+ /// True if the map has been locked in a cartography table
+ /// A list of MapIcon objects of map icons, send only if trackingPosition is true
+ /// Numbs of columns that were updated (map width) (NOTE: If it is 0, the next fields are not used/are set to default values of 0 and null respectively)
+ /// Map height
+ /// x offset of the westernmost column
+ /// z offset of the northernmost row
+ /// a byte array of colors on the map
+ public void OnMapData(int mapid, byte scale, bool trackingPosition, bool locked, List icons, byte columnsUpdated, byte rowsUpdated, byte mapCoulmnX, byte mapCoulmnZ, byte[]? colors)
{
- DispatchBotEvent(bot => bot.OnMapData(mapid, scale, trackingposition, locked, iconcount));
+ DispatchBotEvent(bot => bot.OnMapData(mapid, scale, trackingPosition, locked, icons, columnsUpdated, rowsUpdated, mapCoulmnX, mapCoulmnZ, colors));
}
///
diff --git a/MinecraftClient/Protocol/Handlers/DataTypes.cs b/MinecraftClient/Protocol/Handlers/DataTypes.cs
index 9a0d50f1..2e2e90b7 100644
--- a/MinecraftClient/Protocol/Handlers/DataTypes.cs
+++ b/MinecraftClient/Protocol/Handlers/DataTypes.cs
@@ -584,6 +584,7 @@ namespace MinecraftClient.Protocol.Handlers
{
Dictionary data = new();
byte key = ReadNextByte(cache);
+
while (key != 0xff)
{
int type = ReadNextVarInt(cache);
@@ -599,6 +600,7 @@ namespace MinecraftClient.Protocol.Handlers
type += 1;
}
}
+
// Value's data type is depended on Type
object? value = null;
diff --git a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs
index 4dff45a9..72a44990 100644
--- a/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs
+++ b/MinecraftClient/Protocol/Handlers/PacketType18Handler.cs
@@ -62,7 +62,7 @@ namespace MinecraftClient.Protocol.Handlers
p = new PacketPalette112();
else if (protocol <= Protocol18Handler.MC_1_12_2_Version)
p = new PacketPalette1122();
- else if (protocol <= Protocol18Handler.MC_1_14_Version)
+ else if (protocol < Protocol18Handler.MC_1_14_Version)
p = new PacketPalette113();
else if (protocol <= Protocol18Handler.MC_1_15_Version)
p = new PacketPalette114();
diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs
index 595ef311..93347a38 100644
--- a/MinecraftClient/Protocol/Handlers/Protocol18.cs
+++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs
@@ -4,23 +4,22 @@ using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
+using System.Security.Cryptography;
+using System.Diagnostics;
+using System.Text.RegularExpressions;
+using System.Collections.Concurrent;
using MinecraftClient.Crypto;
using MinecraftClient.Proxy;
-using System.Security.Cryptography;
using MinecraftClient.Mapping;
using MinecraftClient.Mapping.BlockPalettes;
using MinecraftClient.Mapping.EntityPalettes;
using MinecraftClient.Protocol.Handlers.Forge;
using MinecraftClient.Inventory;
-using System.Diagnostics;
using MinecraftClient.Inventory.ItemPalettes;
using MinecraftClient.Protocol.Handlers.PacketPalettes;
using MinecraftClient.Logger;
-using System.Threading.Tasks;
using MinecraftClient.Protocol.Keys;
-using System.Text.RegularExpressions;
using MinecraftClient.Protocol.Session;
-using System.Collections.Concurrent;
using MinecraftClient.Protocol.Message;
namespace MinecraftClient.Protocol.Handlers
@@ -45,6 +44,7 @@ namespace MinecraftClient.Protocol.Handlers
internal const int MC_1_12_Version = 335;
internal const int MC_1_12_2_Version = 340;
internal const int MC_1_13_Version = 393;
+ internal const int MC_1_13_2_Version = 404;
internal const int MC_1_14_Version = 477;
internal const int MC_1_15_Version = 573;
internal const int MC_1_15_2_Version = 578;
@@ -781,20 +781,106 @@ namespace MinecraftClient.Protocol.Handlers
}
break;
case PacketTypesIn.MapData:
+ if (protocolVersion < MC_1_8_Version)
+ break;
+
int mapid = dataTypes.ReadNextVarInt(packetData);
byte scale = dataTypes.ReadNextByte(packetData);
- bool trackingposition = protocolVersion >= MC_1_17_Version ? false : dataTypes.ReadNextBool(packetData);
+
+
+ // 1.9 +
+ bool trackingPosition = true;
+
+ // 1.14+
bool locked = false;
- if (protocolVersion >= MC_1_14_Version)
- {
- locked = dataTypes.ReadNextBool(packetData);
- }
+
+ // 1.17+ (locked and trackingPosition switched places)
if (protocolVersion >= MC_1_17_Version)
{
- trackingposition = dataTypes.ReadNextBool(packetData);
+ if (protocolVersion >= MC_1_14_Version)
+ locked = dataTypes.ReadNextBool(packetData);
+
+ if (protocolVersion >= MC_1_9_Version)
+ trackingPosition = dataTypes.ReadNextBool(packetData);
}
- int iconcount = dataTypes.ReadNextVarInt(packetData);
- handler.OnMapData(mapid, scale, trackingposition, locked, iconcount);
+ else
+ {
+ if (protocolVersion >= MC_1_9_Version)
+ trackingPosition = dataTypes.ReadNextBool(packetData);
+
+ if (protocolVersion >= MC_1_14_Version)
+ locked = dataTypes.ReadNextBool(packetData);
+ }
+
+ int iconcount = 0;
+ List icons = new();
+
+ // 1,9 + = needs tracking position to be true to get the icons
+ if (protocolVersion > MC_1_9_Version ? trackingPosition : true)
+ {
+ iconcount = dataTypes.ReadNextVarInt(packetData);
+
+ for (int i = 0; i < iconcount; i++)
+ {
+ MapIcon mapIcon = new();
+
+ // 1.8 - 1.13
+ if (protocolVersion < MC_1_13_2_Version)
+ {
+ byte directionAndtype = dataTypes.ReadNextByte(packetData);
+ byte direction, type;
+
+ // 1.12.2+
+ if (protocolVersion >= MC_1_12_2_Version)
+ {
+ direction = (byte)(directionAndtype & 0xF);
+ type = (byte)((directionAndtype >> 4) & 0xF);
+ }
+ else // 1.8 - 1.12
+ {
+ direction = (byte)((directionAndtype >> 4) & 0xF);
+ type = (byte)(directionAndtype & 0xF);
+ }
+
+ mapIcon.Type = (MapIconType)type;
+ mapIcon.Direction = direction;
+ }
+
+ // 1.13.2+
+ if (protocolVersion >= MC_1_13_2_Version)
+ mapIcon.Type = (MapIconType)dataTypes.ReadNextVarInt(packetData);
+
+ mapIcon.X = dataTypes.ReadNextByte(packetData);
+ mapIcon.Z = dataTypes.ReadNextByte(packetData);
+
+ // 1.13.2+
+ if (protocolVersion >= MC_1_13_2_Version)
+ {
+ mapIcon.Direction = dataTypes.ReadNextByte(packetData);
+
+ if (dataTypes.ReadNextBool(packetData)) // Has Display Name?
+ mapIcon.DisplayName = ChatParser.ParseText(dataTypes.ReadNextString(packetData));
+ }
+
+ icons.Add(mapIcon);
+ }
+ }
+
+ byte columnsUpdated = dataTypes.ReadNextByte(packetData); // width
+ byte rowsUpdated = 0; // height
+ byte mapCoulmnX = 0;
+ byte mapRowZ = 0;
+ byte[]? colors = null;
+
+ if (columnsUpdated > 0)
+ {
+ rowsUpdated = dataTypes.ReadNextByte(packetData); // height
+ mapCoulmnX = dataTypes.ReadNextByte(packetData);
+ mapRowZ = dataTypes.ReadNextByte(packetData);
+ colors = dataTypes.ReadNextByteArray(packetData);
+ }
+
+ handler.OnMapData(mapid, scale, trackingPosition, locked, icons, columnsUpdated, rowsUpdated, mapCoulmnX, mapRowZ, colors);
break;
case PacketTypesIn.TradeList:
if ((protocolVersion >= MC_1_14_Version) && (handler.GetInventoryEnabled()))
diff --git a/MinecraftClient/Protocol/IMinecraftComHandler.cs b/MinecraftClient/Protocol/IMinecraftComHandler.cs
index e77dde34..6482b160 100644
--- a/MinecraftClient/Protocol/IMinecraftComHandler.cs
+++ b/MinecraftClient/Protocol/IMinecraftComHandler.cs
@@ -112,7 +112,7 @@ namespace MinecraftClient.Protocol
/// This method is called when the protocol handler receives a title
///
void OnTitle(int action, string titletext, string subtitletext, string actionbartext, int fadein, int stay, int fadeout, string json);
-
+
///
/// Called when receiving a connection keep-alive from the server
///
@@ -216,7 +216,7 @@ namespace MinecraftClient.Protocol
///
/// Spawned entity
void OnSpawnEntity(Entity entity);
-
+
///
/// Called when an entity has spawned
///
@@ -224,7 +224,7 @@ namespace MinecraftClient.Protocol
/// Equipment slot. 0: main hand, 1: off hand, 2–5: armor slot (2: boots, 3: leggings, 4: chestplate, 5: helmet)/param>
/// Item/param>
void OnEntityEquipment(int entityid, int slot, Item item);
-
+
///
/// Called when a player spawns or enters the client's render distance
///
@@ -312,7 +312,7 @@ namespace MinecraftClient.Protocol
/// Entity ID
/// The health of the entity
void OnEntityHealth(int entityID, float health);
-
+
///
/// Called when entity metadata or metadata changed.
///
@@ -334,14 +334,14 @@ namespace MinecraftClient.Protocol
/// Affected player's UUID
/// New game mode
void OnGamemodeUpdate(Guid uuid, int gamemode);
-
+
///
/// Called when a player's latency has changed
///
/// Affected player's UUID
/// latency
void OnLatencyUpdate(Guid uuid, int latency);
-
+
///
/// Called when Experience bar is updated
///
@@ -356,17 +356,23 @@ namespace MinecraftClient.Protocol
/// Used for setting player slot after joining game
///
void OnHeldItemChange(byte slot);
-
+
///
- /// Called map data
+ /// Called when an update of the map is sent by the server, take a look at https://wiki.vg/Protocol#Map_Data for more info on the fields
+ /// Map format and colors: https://minecraft.fandom.com/wiki/Map_item_format
///
- ///
- ///
- ///
- ///
- ///
- void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount);
-
+ /// Map ID of the map being modified
+ /// A scale of the Map, from 0 for a fully zoomed-in map (1 block per pixel) to 4 for a fully zoomed-out map (16 blocks per pixel)
+ /// Specifies whether player and item frame icons are shown
+ /// True if the map has been locked in a cartography table
+ /// A list of MapIcon objects of map icons, send only if trackingPosition is true
+ /// Numbs of columns that were updated (map width) (NOTE: If it is 0, the next fields are not used/are set to default values of 0 and null respectively)
+ /// Map height
+ /// x offset of the westernmost column
+ /// z offset of the northernmost row
+ /// a byte array of colors on the map
+ void OnMapData(int mapid, byte scale, bool trackingPosition, bool locked, List icons, byte columnsUpdated, byte rowsUpdated, byte mapCoulmnX, byte mapRowZ, byte[]? colors);
+
///
/// Called when the Player entity ID has been received from the server
///
@@ -393,7 +399,7 @@ namespace MinecraftClient.Protocol
/// Only if mode is 0 or 2. The text to be displayed for the score
/// Only if mode is 0 or 2. 0 = "integer", 1 = "hearts".
void OnScoreboardObjective(string objectivename, byte mode, string objectivevalue, int type);
-
+
///
/// Called when DisplayScoreboard
///
diff --git a/MinecraftClient/Scripting/ChatBot.cs b/MinecraftClient/Scripting/ChatBot.cs
index f5049f07..848370f1 100644
--- a/MinecraftClient/Scripting/ChatBot.cs
+++ b/MinecraftClient/Scripting/ChatBot.cs
@@ -264,14 +264,20 @@ namespace MinecraftClient
public virtual void OnLatencyUpdate(Entity entity, string playername, Guid uuid, int latency) { }
///
- /// Called when a map was updated
+ /// Called when an update of the map is sent by the server, take a look at https://wiki.vg/Protocol#Map_Data for more info on the fields
+ /// Map format and colors: https://minecraft.fandom.com/wiki/Map_item_format
///
- ///
- ///
- ///
- ///
- ///
- public virtual void OnMapData(int mapid, byte scale, bool trackingposition, bool locked, int iconcount) { }
+ /// Map ID of the map being modified
+ /// A scale of the Map, from 0 for a fully zoomed-in map (1 block per pixel) to 4 for a fully zoomed-out map (16 blocks per pixel)
+ /// Specifies whether player and item frame icons are shown
+ /// True if the map has been locked in a cartography table
+ /// A list of MapIcon objects of map icons, send only if trackingPosition is true
+ /// Numbs of columns that were updated (map width) (NOTE: If it is 0, the next fields are not used/are set to default values of 0 and null respectively)
+ /// Map height
+ /// x offset of the westernmost column
+ /// z offset of the northernmost row
+ /// a byte array of colors on the map
+ public virtual void OnMapData(int mapid, byte scale, bool trackingPosition, bool locked, List icons, byte columnsUpdated, byte rowsUpdated, byte mapCoulmnX, byte mapRowZ, byte[]? colors) { }
///
/// Called when tradeList is received from server