mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Added 1.19.1/2 + Terrain Handling
Added 1.19.1/2 + Terrain Handling
This commit is contained in:
commit
a383ead27f
26 changed files with 1433 additions and 576 deletions
|
|
@ -22,6 +22,13 @@ namespace MinecraftClient.Mapping
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly bool piglinSafe = false;
|
public readonly bool piglinSafe = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Possibly the light level(s) at which monsters can spawn.
|
||||||
|
/// </summary>
|
||||||
|
public readonly int monsterSpawnMinLightLevel = 0;
|
||||||
|
public readonly int monsterSpawnMaxLightLevel = 7;
|
||||||
|
public readonly int monsterSpawnBlockLightLimit = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// When false, compasses spin randomly. When true, nether portals can spawn zombified piglins.
|
/// When false, compasses spin randomly. When true, nether portals can spawn zombified piglins.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -132,6 +139,25 @@ namespace MinecraftClient.Mapping
|
||||||
|
|
||||||
if (nbt.ContainsKey("piglin_safe"))
|
if (nbt.ContainsKey("piglin_safe"))
|
||||||
this.piglinSafe = 1 == (byte)nbt["piglin_safe"];
|
this.piglinSafe = 1 == (byte)nbt["piglin_safe"];
|
||||||
|
if (nbt.ContainsKey("monster_spawn_light_level"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var monsterSpawnLightLevelObj = nbt["monster_spawn_light_level"];
|
||||||
|
if (monsterSpawnLightLevelObj.GetType() == typeof(int))
|
||||||
|
this.monsterSpawnMinLightLevel = this.monsterSpawnMaxLightLevel = (int)monsterSpawnLightLevelObj;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var inclusive = (Dictionary<string, object>)(((Dictionary<string, object>)monsterSpawnLightLevelObj)["value"]);
|
||||||
|
this.monsterSpawnMinLightLevel = (int)inclusive["min_inclusive"];
|
||||||
|
this.monsterSpawnMaxLightLevel = (int)inclusive["max_inclusive"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
catch (KeyNotFoundException) { }
|
||||||
|
}
|
||||||
|
if (nbt.ContainsKey("monster_spawn_block_light_limit"))
|
||||||
|
this.monsterSpawnBlockLightLimit = (int)nbt["monster_spawn_block_light_limit"];
|
||||||
if (nbt.ContainsKey("natural"))
|
if (nbt.ContainsKey("natural"))
|
||||||
this.natural = 1 == (byte)nbt["natural"];
|
this.natural = 1 == (byte)nbt["natural"];
|
||||||
if (nbt.ContainsKey("ambient_light"))
|
if (nbt.ContainsKey("ambient_light"))
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,9 @@ namespace MinecraftClient.Mapping
|
||||||
case Material.BlackShulkerBox:
|
case Material.BlackShulkerBox:
|
||||||
case Material.BlackStainedGlass:
|
case Material.BlackStainedGlass:
|
||||||
case Material.BlackStainedGlassPane:
|
case Material.BlackStainedGlassPane:
|
||||||
|
case Material.Blackstone:
|
||||||
|
case Material.BlackstoneSlab:
|
||||||
|
case Material.BlackstoneStairs:
|
||||||
case Material.BlackTerracotta:
|
case Material.BlackTerracotta:
|
||||||
case Material.BlackWool:
|
case Material.BlackWool:
|
||||||
case Material.BlastFurnace:
|
case Material.BlastFurnace:
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ namespace MinecraftClient.Mapping
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The dimension info of the world
|
/// The dimension info of the world
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static Dimension dimension = new Dimension();
|
private static Dimension curDimension = new Dimension();
|
||||||
|
|
||||||
|
private static Dictionary<string, Dimension>? dimensionList = null;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Lock for thread safety
|
/// Lock for thread safety
|
||||||
|
|
@ -89,24 +91,42 @@ namespace MinecraftClient.Mapping
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Set dimension type
|
/// Storage of all dimensional data - 1.19.1 and above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="registryCodec">Registry Codec nbt data</param>
|
||||||
|
public static void StoreDimensionList(Dictionary<string, object> registryCodec)
|
||||||
|
{
|
||||||
|
dimensionList = new();
|
||||||
|
var dimensionListNbt = (object[])(((Dictionary<string, object>)registryCodec["minecraft:dimension_type"])["value"]);
|
||||||
|
foreach (Dictionary<string, object> dimensionNbt in dimensionListNbt)
|
||||||
|
{
|
||||||
|
string dimensionName = (string)dimensionNbt["name"];
|
||||||
|
Dictionary<string, object> element = (Dictionary<string, object>)dimensionNbt["element"];
|
||||||
|
dimensionList.Add(dimensionName, new Dimension(dimensionName, element));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set current dimension - 1.16 and above
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="name"> The name of the dimension type</param>
|
/// <param name="name"> The name of the dimension type</param>
|
||||||
/// <param name="nbt">The dimension type (NBT Tag Compound)</param>
|
/// <param name="nbt">The dimension type (NBT Tag Compound)</param>
|
||||||
public static void SetDimension(string name, Dictionary<string, object> nbt)
|
public static void SetDimension(string name)
|
||||||
{
|
{
|
||||||
// will change in 1.19 and above
|
curDimension = dimensionList![name]; // Should not fail
|
||||||
dimension = new Dimension(name, nbt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get current dimension
|
/// Get current dimension
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Current dimension</returns>
|
/// <returns>Current dimension</returns>
|
||||||
public static Dimension GetDimension()
|
public static Dimension GetDimension()
|
||||||
{
|
{
|
||||||
return dimension;
|
return curDimension;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ using MinecraftClient.Mapping;
|
||||||
using MinecraftClient.Inventory;
|
using MinecraftClient.Inventory;
|
||||||
using MinecraftClient.Logger;
|
using MinecraftClient.Logger;
|
||||||
using MinecraftClient.Protocol.Keys;
|
using MinecraftClient.Protocol.Keys;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient
|
namespace MinecraftClient
|
||||||
{
|
{
|
||||||
|
|
@ -68,9 +69,10 @@ namespace MinecraftClient
|
||||||
private int port;
|
private int port;
|
||||||
private int protocolversion;
|
private int protocolversion;
|
||||||
private string username;
|
private string username;
|
||||||
private string uuid;
|
private Guid uuid;
|
||||||
|
private string uuidStr;
|
||||||
private string sessionid;
|
private string sessionid;
|
||||||
private PlayerKeyPair playerKeyPair;
|
private PlayerKeyPair? playerKeyPair;
|
||||||
private DateTime lastKeepAlive;
|
private DateTime lastKeepAlive;
|
||||||
private object lastKeepAliveLock = new();
|
private object lastKeepAliveLock = new();
|
||||||
private int respawnTicks = 0;
|
private int respawnTicks = 0;
|
||||||
|
|
@ -104,7 +106,8 @@ namespace MinecraftClient
|
||||||
public int GetServerPort() { return port; }
|
public int GetServerPort() { return port; }
|
||||||
public string GetServerHost() { return host; }
|
public string GetServerHost() { return host; }
|
||||||
public string GetUsername() { return username; }
|
public string GetUsername() { return username; }
|
||||||
public string GetUserUUID() { return uuid; }
|
public Guid GetUserUuid() { return uuid; }
|
||||||
|
public string GetUserUuidStr() { return uuidStr; }
|
||||||
public string GetSessionID() { return sessionid; }
|
public string GetSessionID() { return sessionid; }
|
||||||
public Location GetCurrentLocation() { return location; }
|
public Location GetCurrentLocation() { return location; }
|
||||||
public float GetYaw() { return playerYaw; }
|
public float GetYaw() { return playerYaw; }
|
||||||
|
|
@ -141,7 +144,7 @@ namespace MinecraftClient
|
||||||
/// <param name="server_ip">The server IP</param>
|
/// <param name="server_ip">The server IP</param>
|
||||||
/// <param name="port">The server port to use</param>
|
/// <param name="port">The server port to use</param>
|
||||||
/// <param name="protocolversion">Minecraft protocol version to use</param>
|
/// <param name="protocolversion">Minecraft protocol version to use</param>
|
||||||
public McClient(string username, string uuid, string sessionID, PlayerKeyPair playerKeyPair, int protocolversion, ForgeInfo forgeInfo, string server_ip, ushort port)
|
public McClient(string username, string uuid, string sessionID, PlayerKeyPair? playerKeyPair, int protocolversion, ForgeInfo forgeInfo, string server_ip, ushort port)
|
||||||
{
|
{
|
||||||
StartClient(username, uuid, sessionID, playerKeyPair, server_ip, port, protocolversion, forgeInfo, false, "");
|
StartClient(username, uuid, sessionID, playerKeyPair, server_ip, port, protocolversion, forgeInfo, false, "");
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +159,7 @@ namespace MinecraftClient
|
||||||
/// <param name="port">The server port to use</param>
|
/// <param name="port">The server port to use</param>
|
||||||
/// <param name="protocolversion">Minecraft protocol version to use</param>
|
/// <param name="protocolversion">Minecraft protocol version to use</param>
|
||||||
/// <param name="command">The text or command to send.</param>
|
/// <param name="command">The text or command to send.</param>
|
||||||
public McClient(string username, string uuid, string sessionID, PlayerKeyPair playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo forgeInfo, string command)
|
public McClient(string username, string uuid, string sessionID, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo forgeInfo, string command)
|
||||||
{
|
{
|
||||||
StartClient(username, uuid, sessionID, playerKeyPair, server_ip, port, protocolversion, forgeInfo, true, command);
|
StartClient(username, uuid, sessionID, playerKeyPair, server_ip, port, protocolversion, forgeInfo, true, command);
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +175,7 @@ namespace MinecraftClient
|
||||||
/// <param name="uuid">The player's UUID for online-mode authentication</param>
|
/// <param name="uuid">The player's UUID for online-mode authentication</param>
|
||||||
/// <param name="singlecommand">If set to true, the client will send a single command and then disconnect from the server</param>
|
/// <param name="singlecommand">If set to true, the client will send a single command and then disconnect from the server</param>
|
||||||
/// <param name="command">The text or command to send. Will only be sent if singlecommand is set to true.</param>
|
/// <param name="command">The text or command to send. Will only be sent if singlecommand is set to true.</param>
|
||||||
private void StartClient(string user, string uuid, string sessionID, PlayerKeyPair playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo forgeInfo, bool singlecommand, string command)
|
private void StartClient(string user, string uuid, string sessionID, PlayerKeyPair? playerKeyPair, string server_ip, ushort port, int protocolversion, ForgeInfo forgeInfo, bool singlecommand, string command)
|
||||||
{
|
{
|
||||||
terrainAndMovementsEnabled = Settings.TerrainAndMovements;
|
terrainAndMovementsEnabled = Settings.TerrainAndMovements;
|
||||||
inventoryHandlingEnabled = Settings.InventoryHandling;
|
inventoryHandlingEnabled = Settings.InventoryHandling;
|
||||||
|
|
@ -180,7 +183,9 @@ namespace MinecraftClient
|
||||||
|
|
||||||
bool retry = false;
|
bool retry = false;
|
||||||
this.sessionid = sessionID;
|
this.sessionid = sessionID;
|
||||||
this.uuid = uuid;
|
if (!Guid.TryParse(uuid, out this.uuid))
|
||||||
|
this.uuid = Guid.Empty;
|
||||||
|
this.uuidStr = uuid;
|
||||||
this.username = user;
|
this.username = user;
|
||||||
this.host = server_ip;
|
this.host = server_ip;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
|
|
@ -2093,20 +2098,18 @@ namespace MinecraftClient
|
||||||
List<string> links = new();
|
List<string> links = new();
|
||||||
string messageText;
|
string messageText;
|
||||||
|
|
||||||
if (message.isJson)
|
if (message.isSignedChat)
|
||||||
{
|
{
|
||||||
if (message.isSignedChat)
|
if (!Settings.ShowIllegalSignedChat && !message.isSystemChat && !(bool)message.isSignatureLegal!)
|
||||||
{
|
return;
|
||||||
if (!Settings.ShowIllegalSignedChat && !message.isSystemChat && !(bool)message.isSignatureLegal!)
|
messageText = ChatParser.ParseSignedChat(message, links);
|
||||||
return;
|
|
||||||
messageText = ChatParser.ParseSignedChat(message, links);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
messageText = ChatParser.ParseText(message.content, links);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
messageText = message.content;
|
if (message.isJson)
|
||||||
|
messageText = ChatParser.ParseText(message.content, links);
|
||||||
|
else
|
||||||
|
messageText = message.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Chat(messageText);
|
Log.Chat(messageText);
|
||||||
|
|
@ -2243,15 +2246,16 @@ namespace MinecraftClient
|
||||||
if (player.Name == username)
|
if (player.Name == username)
|
||||||
{
|
{
|
||||||
// 1.19+ offline server is possible to return different uuid
|
// 1.19+ offline server is possible to return different uuid
|
||||||
this.uuid = player.UUID.ToString().Replace("-", string.Empty);
|
this.uuid = player.Uuid;
|
||||||
|
this.uuidStr = player.Uuid.ToString().Replace("-", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
lock (onlinePlayers)
|
lock (onlinePlayers)
|
||||||
{
|
{
|
||||||
onlinePlayers[player.UUID] = player;
|
onlinePlayers[player.Uuid] = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
DispatchBotEvent(bot => bot.OnPlayerJoin(player.UUID, player.Name));
|
DispatchBotEvent(bot => bot.OnPlayerJoin(player.Uuid, player.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ namespace MinecraftClient
|
||||||
|
|
||||||
public const string Version = MCHighestVersion;
|
public const string Version = MCHighestVersion;
|
||||||
public const string MCLowestVersion = "1.4.6";
|
public const string MCLowestVersion = "1.4.6";
|
||||||
public const string MCHighestVersion = "1.19";
|
public const string MCHighestVersion = "1.19.2";
|
||||||
public static readonly string BuildInfo = null;
|
public static readonly string BuildInfo = null;
|
||||||
|
|
||||||
private static Tuple<Thread, CancellationTokenSource>? offlinePrompt = null;
|
private static Tuple<Thread, CancellationTokenSource>? offlinePrompt = null;
|
||||||
|
|
|
||||||
|
|
@ -1105,9 +1105,58 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="bytes">Byte array</param>
|
/// <param name="bytes">Byte array</param>
|
||||||
/// <returns>String representation</returns>
|
/// <returns>String representation</returns>
|
||||||
public string ByteArrayToString(byte[] bytes)
|
public string ByteArrayToString(byte[]? bytes)
|
||||||
{
|
{
|
||||||
return BitConverter.ToString(bytes).Replace("-", " ");
|
if (bytes == null)
|
||||||
|
return "null";
|
||||||
|
else
|
||||||
|
return BitConverter.ToString(bytes).Replace("-", " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write LastSeenMessageList
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="msgList">Message.LastSeenMessageList</param>
|
||||||
|
/// <param name="isOnlineMode">Whether the server is in online mode</param>
|
||||||
|
/// <returns>Message.LastSeenMessageList Packet Data</returns>
|
||||||
|
public byte[] GetLastSeenMessageList(Message.LastSeenMessageList msgList, bool isOnlineMode)
|
||||||
|
{
|
||||||
|
if (!isOnlineMode)
|
||||||
|
return GetVarInt(0); // Message list size
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<byte> fields = new();
|
||||||
|
fields.AddRange(GetVarInt(msgList.entries.Length)); // Message list size
|
||||||
|
foreach (Message.LastSeenMessageList.Entry entry in msgList.entries)
|
||||||
|
{
|
||||||
|
fields.AddRange(entry.profileId.ToBigEndianBytes()); // UUID
|
||||||
|
fields.AddRange(GetVarInt(entry.lastSignature.Length)); // Signature length
|
||||||
|
fields.AddRange(entry.lastSignature); // Signature data
|
||||||
|
}
|
||||||
|
return fields.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write LastSeenMessageList.Acknowledgment
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="ack">Acknowledgment</param>
|
||||||
|
/// <param name="isOnlineMode">Whether the server is in online mode</param>
|
||||||
|
/// <returns>Acknowledgment Packet Data</returns>
|
||||||
|
public byte[] GetAcknowledgment(Message.LastSeenMessageList.Acknowledgment ack, bool isOnlineMode)
|
||||||
|
{
|
||||||
|
List<byte> fields = new();
|
||||||
|
fields.AddRange(GetLastSeenMessageList(ack.lastSeen, isOnlineMode));
|
||||||
|
if (!isOnlineMode || ack.lastReceived == null)
|
||||||
|
fields.AddRange(GetBool(false)); // Has last received message
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fields.AddRange(GetBool(true));
|
||||||
|
fields.AddRange(ack.lastReceived.profileId.ToBigEndianBytes()); // Has last received message
|
||||||
|
fields.AddRange(GetVarInt(ack.lastReceived.lastSignature.Length)); // Last received message signature length
|
||||||
|
fields.AddRange(ack.lastReceived.lastSignature); // Last received message signature data
|
||||||
|
}
|
||||||
|
return fields.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,165 +6,165 @@ namespace MinecraftClient.Protocol.Handlers.PacketPalettes
|
||||||
{
|
{
|
||||||
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
|
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
|
||||||
{
|
{
|
||||||
{ 0x00, PacketTypesIn.SpawnEntity }, // Changed in 1.19 (Wiki name: Spawn Entity) - DONE
|
{ 0x00, PacketTypesIn.SpawnEntity }, // Changed in 1.19 (Wiki name: Spawn Entity) - DONE
|
||||||
{ 0x01, PacketTypesIn.SpawnExperienceOrb }, //(Wiki name: Spawn Exeprience Orb)
|
{ 0x01, PacketTypesIn.SpawnExperienceOrb }, // (Wiki name: Spawn Exeprience Orb)
|
||||||
{ 0x02, PacketTypesIn.SpawnPlayer },
|
{ 0x02, PacketTypesIn.SpawnPlayer }, //
|
||||||
{ 0x03, PacketTypesIn.EntityAnimation }, //(Wiki name: Entity Animation (clientbound))
|
{ 0x03, PacketTypesIn.EntityAnimation }, // (Wiki name: Entity Animation (clientbound))
|
||||||
{ 0x04, PacketTypesIn.Statistics }, //(Wiki name: Award Statistics)
|
{ 0x04, PacketTypesIn.Statistics }, // (Wiki name: Award Statistics)
|
||||||
{ 0x05, PacketTypesIn.BlockChangedAck }, //Added 1.19 (Wiki name: Acknowledge Block Change) - DONE
|
{ 0x05, PacketTypesIn.BlockChangedAck }, // Added 1.19 (Wiki name: Acknowledge Block Change) - DONE
|
||||||
{ 0x06, PacketTypesIn.BlockBreakAnimation }, //(Wiki name: Set Block Destroy Stage)
|
{ 0x06, PacketTypesIn.BlockBreakAnimation }, // (Wiki name: Set Block Destroy Stage)
|
||||||
{ 0x07, PacketTypesIn.BlockEntityData },
|
{ 0x07, PacketTypesIn.BlockEntityData }, //
|
||||||
{ 0x08, PacketTypesIn.BlockAction },
|
{ 0x08, PacketTypesIn.BlockAction }, //
|
||||||
{ 0x09, PacketTypesIn.BlockChange }, //(Wiki name: Block Update)
|
{ 0x09, PacketTypesIn.BlockChange }, // (Wiki name: Block Update)
|
||||||
{ 0x0A, PacketTypesIn.BossBar },
|
{ 0x0A, PacketTypesIn.BossBar }, //
|
||||||
{ 0x0B, PacketTypesIn.ServerDifficulty }, // (Wiki name: Change Difficulty)
|
{ 0x0B, PacketTypesIn.ServerDifficulty }, // (Wiki name: Change Difficulty)
|
||||||
{ 0x0C, PacketTypesIn.ChatPreview }, // Added 1.19
|
{ 0x0C, PacketTypesIn.ChatPreview }, // Added 1.19
|
||||||
{ 0x0D, PacketTypesIn.ClearTiles },
|
{ 0x0D, PacketTypesIn.ClearTiles }, //
|
||||||
{ 0x0E, PacketTypesIn.TabComplete }, // (Wiki name: Command Suggestions Response)
|
{ 0x0E, PacketTypesIn.TabComplete }, // (Wiki name: Command Suggestions Response)
|
||||||
{ 0x0F, PacketTypesIn.DeclareCommands }, // (Wiki name: Commands)
|
{ 0x0F, PacketTypesIn.DeclareCommands }, // (Wiki name: Commands)
|
||||||
{ 0x10, PacketTypesIn.CloseWindow }, // (Wiki name: Close Container (clientbound))
|
{ 0x10, PacketTypesIn.CloseWindow }, // (Wiki name: Close Container (clientbound))
|
||||||
{ 0x11, PacketTypesIn.WindowItems }, // (Wiki name: Set Container Content)
|
{ 0x11, PacketTypesIn.WindowItems }, // (Wiki name: Set Container Content)
|
||||||
{ 0x12, PacketTypesIn.WindowProperty }, // (Wiki name: Set Container Property)
|
{ 0x12, PacketTypesIn.WindowProperty }, // (Wiki name: Set Container Property)
|
||||||
{ 0x13, PacketTypesIn.SetSlot }, // (Wiki name: Set Container Slot)
|
{ 0x13, PacketTypesIn.SetSlot }, // (Wiki name: Set Container Slot)
|
||||||
{ 0x14, PacketTypesIn.SetCooldown },
|
{ 0x14, PacketTypesIn.SetCooldown }, //
|
||||||
{ 0x15, PacketTypesIn.PluginMessage }, // (Wiki name: Plugin Message (clientbound))
|
{ 0x15, PacketTypesIn.PluginMessage }, // (Wiki name: Plugin Message (clientbound))
|
||||||
{ 0x16, PacketTypesIn.NamedSoundEffect }, // Changed in 1.19 (Added "Speed" field) (Wiki name: Custom Sound Effect) - DONE (No need to be implemented)
|
{ 0x16, PacketTypesIn.NamedSoundEffect }, // Changed in 1.19 (Added "Speed" field) (Wiki name: Custom Sound Effect) - DONE (No need to be implemented)
|
||||||
{ 0x17, PacketTypesIn.Disconnect },
|
{ 0x17, PacketTypesIn.Disconnect }, //
|
||||||
{ 0x18, PacketTypesIn.EntityStatus }, // (Wiki name: Entity Event)
|
{ 0x18, PacketTypesIn.EntityStatus }, // (Wiki name: Entity Event)
|
||||||
{ 0x19, PacketTypesIn.Explosion }, // Changed in 1.19 (Location fields are now Double instead of Float) (Wiki name: Explosion) - DONE
|
{ 0x19, PacketTypesIn.Explosion }, // Changed in 1.19 (Location fields are now Double instead of Float) (Wiki name: Explosion) - DONE
|
||||||
{ 0x1A, PacketTypesIn.UnloadChunk }, // (Wiki name: Forget Chunk)
|
{ 0x1A, PacketTypesIn.UnloadChunk }, // (Wiki name: Forget Chunk)
|
||||||
{ 0x1B, PacketTypesIn.ChangeGameState }, // (Wiki name: Game Event)
|
{ 0x1B, PacketTypesIn.ChangeGameState }, // (Wiki name: Game Event)
|
||||||
{ 0x1C, PacketTypesIn.OpenHorseWindow }, // (Wiki name: Horse Screen Open)
|
{ 0x1C, PacketTypesIn.OpenHorseWindow }, // (Wiki name: Horse Screen Open)
|
||||||
{ 0x1D, PacketTypesIn.InitializeWorldBorder },
|
{ 0x1D, PacketTypesIn.InitializeWorldBorder }, //
|
||||||
{ 0x1E, PacketTypesIn.KeepAlive },
|
{ 0x1E, PacketTypesIn.KeepAlive }, //
|
||||||
{ 0x1F, PacketTypesIn.ChunkData },
|
{ 0x1F, PacketTypesIn.ChunkData }, //
|
||||||
{ 0x20, PacketTypesIn.Effect }, // (Wiki name: Level Event)
|
{ 0x20, PacketTypesIn.Effect }, // (Wiki name: Level Event)
|
||||||
{ 0x21, PacketTypesIn.Particle }, // Changed in 1.19 ("Particle Data" field is now "Max Speed", it's the same Float data type) (Wiki name: Level Particle) - DONE (No need to be implemented)
|
{ 0x21, PacketTypesIn.Particle }, // Changed in 1.19 ("Particle Data" field is now "Max Speed", it's the same Float data type) (Wiki name: Level Particle) - DONE (No need to be implemented)
|
||||||
{ 0x22, PacketTypesIn.UpdateLight }, // (Wiki name: Light Update)
|
{ 0x22, PacketTypesIn.UpdateLight }, // (Wiki name: Light Update)
|
||||||
{ 0x23, PacketTypesIn.JoinGame }, // Changed in 1.19 (lot's of changes) (Wiki name: Login (play)) - DONE
|
{ 0x23, PacketTypesIn.JoinGame }, // Changed in 1.19 (lot's of changes) (Wiki name: Login (play)) - DONE
|
||||||
{ 0x24, PacketTypesIn.MapData }, // (Wiki name: Map Item Data)
|
{ 0x24, PacketTypesIn.MapData }, // (Wiki name: Map Item Data)
|
||||||
{ 0x25, PacketTypesIn.TradeList }, // (Wiki name: Merchant Offers)
|
{ 0x25, PacketTypesIn.TradeList }, // (Wiki name: Merchant Offers)
|
||||||
{ 0x26, PacketTypesIn.EntityPosition }, // (Wiki name: Move Entity Position)
|
{ 0x26, PacketTypesIn.EntityPosition }, // (Wiki name: Move Entity Position)
|
||||||
{ 0x27, PacketTypesIn.EntityPositionAndRotation }, // (Wiki name: Move Entity Position and Rotation)
|
{ 0x27, PacketTypesIn.EntityPositionAndRotation }, // (Wiki name: Move Entity Position and Rotation)
|
||||||
{ 0x28, PacketTypesIn.EntityRotation }, // (Wiki name: Move Entity Rotation)
|
{ 0x28, PacketTypesIn.EntityRotation }, // (Wiki name: Move Entity Rotation)
|
||||||
{ 0x29, PacketTypesIn.VehicleMove }, // (Wiki name: Move Vehicle)
|
{ 0x29, PacketTypesIn.VehicleMove }, // (Wiki name: Move Vehicle)
|
||||||
{ 0x2A, PacketTypesIn.OpenBook },
|
{ 0x2A, PacketTypesIn.OpenBook }, //
|
||||||
{ 0x2B, PacketTypesIn.OpenWindow }, // (Wiki name: Open Screen)
|
{ 0x2B, PacketTypesIn.OpenWindow }, // (Wiki name: Open Screen)
|
||||||
{ 0x2C, PacketTypesIn.OpenSignEditor },
|
{ 0x2C, PacketTypesIn.OpenSignEditor }, //
|
||||||
{ 0x2D, PacketTypesIn.Ping }, // (Wiki name: Ping (play))
|
{ 0x2D, PacketTypesIn.Ping }, // (Wiki name: Ping (play))
|
||||||
{ 0x2E, PacketTypesIn.CraftRecipeResponse }, // (Wiki name: Place Ghost Recipe)
|
{ 0x2E, PacketTypesIn.CraftRecipeResponse }, // (Wiki name: Place Ghost Recipe)
|
||||||
{ 0x2F, PacketTypesIn.PlayerAbilities },
|
{ 0x2F, PacketTypesIn.PlayerAbilities }, //
|
||||||
{ 0x30, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message)
|
{ 0x30, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message)
|
||||||
{ 0x31, PacketTypesIn.EndCombatEvent }, // (Wiki name: Player Combat End)
|
{ 0x31, PacketTypesIn.EndCombatEvent }, // (Wiki name: Player Combat End)
|
||||||
{ 0x32, PacketTypesIn.EnterCombatEvent }, // (Wiki name: Player Combat Enter)
|
{ 0x32, PacketTypesIn.EnterCombatEvent }, // (Wiki name: Player Combat Enter)
|
||||||
{ 0x33, PacketTypesIn.DeathCombatEvent }, // (Wiki name: Player Combat Kill)
|
{ 0x33, PacketTypesIn.DeathCombatEvent }, // (Wiki name: Player Combat Kill)
|
||||||
{ 0x34, PacketTypesIn.PlayerInfo }, // Changed in 1.19 (Heavy changes) - DONE
|
{ 0x34, PacketTypesIn.PlayerInfo }, // Changed in 1.19 (Heavy changes) - DONE
|
||||||
{ 0x35, PacketTypesIn.FacePlayer }, // (Wiki name: Player Look At)
|
{ 0x35, PacketTypesIn.FacePlayer }, // (Wiki name: Player Look At)
|
||||||
{ 0x36, PacketTypesIn.PlayerPositionAndLook }, // (Wiki name: Player Position)
|
{ 0x36, PacketTypesIn.PlayerPositionAndLook }, // (Wiki name: Player Position)
|
||||||
{ 0x37, PacketTypesIn.UnlockRecipes }, // (Wiki name: Recipe)
|
{ 0x37, PacketTypesIn.UnlockRecipes }, // (Wiki name: Recipe)
|
||||||
{ 0x38, PacketTypesIn.DestroyEntities }, // (Wiki name: Remove Entites)
|
{ 0x38, PacketTypesIn.DestroyEntities }, // (Wiki name: Remove Entites)
|
||||||
{ 0x39, PacketTypesIn.RemoveEntityEffect },
|
{ 0x39, PacketTypesIn.RemoveEntityEffect }, //
|
||||||
{ 0x3A, PacketTypesIn.ResourcePackSend }, // (Wiki name: Resource Pack)
|
{ 0x3A, PacketTypesIn.ResourcePackSend }, // (Wiki name: Resource Pack)
|
||||||
{ 0x3B, PacketTypesIn.Respawn }, // Changed in 1.19 (Heavy changes) - DONE
|
{ 0x3B, PacketTypesIn.Respawn }, // Changed in 1.19 (Heavy changes) - DONE
|
||||||
{ 0x3C, PacketTypesIn.EntityHeadLook }, // (Wiki name: Rotate Head)
|
{ 0x3C, PacketTypesIn.EntityHeadLook }, // (Wiki name: Rotate Head)
|
||||||
{ 0x3D, PacketTypesIn.MultiBlockChange }, // (Wiki name: Sections Block Update)
|
{ 0x3D, PacketTypesIn.MultiBlockChange }, // (Wiki name: Sections Block Update)
|
||||||
{ 0x3E, PacketTypesIn.SelectAdvancementTab },
|
{ 0x3E, PacketTypesIn.SelectAdvancementTab }, //
|
||||||
{ 0x3F, PacketTypesIn.ServerData }, // Added in 1.19
|
{ 0x3F, PacketTypesIn.ServerData }, // Added in 1.19
|
||||||
{ 0x40, PacketTypesIn.ActionBar }, // (Wiki name: Set Action Bar Text)
|
{ 0x40, PacketTypesIn.ActionBar }, // (Wiki name: Set Action Bar Text)
|
||||||
{ 0x41, PacketTypesIn.WorldBorderCenter }, // (Wiki name: Set Border Center)
|
{ 0x41, PacketTypesIn.WorldBorderCenter }, // (Wiki name: Set Border Center)
|
||||||
{ 0x42, PacketTypesIn.WorldBorderLerpSize },
|
{ 0x42, PacketTypesIn.WorldBorderLerpSize }, //
|
||||||
{ 0x43, PacketTypesIn.WorldBorderSize }, // (Wiki name: Set World Border Size)
|
{ 0x43, PacketTypesIn.WorldBorderSize }, // (Wiki name: Set World Border Size)
|
||||||
{ 0x44, PacketTypesIn.WorldBorderWarningDelay }, // (Wiki name: Set World Border Warning Delay)
|
{ 0x44, PacketTypesIn.WorldBorderWarningDelay }, // (Wiki name: Set World Border Warning Delay)
|
||||||
{ 0x45, PacketTypesIn.WorldBorderWarningReach }, // (Wiki name: Set Border Warning Distance)
|
{ 0x45, PacketTypesIn.WorldBorderWarningReach }, // (Wiki name: Set Border Warning Distance)
|
||||||
{ 0x46, PacketTypesIn.Camera }, // (Wiki name: Set Camera)
|
{ 0x46, PacketTypesIn.Camera }, // (Wiki name: Set Camera)
|
||||||
{ 0x47, PacketTypesIn.HeldItemChange }, // (Wiki name: Set Carried Item (clientbound))
|
{ 0x47, PacketTypesIn.HeldItemChange }, // (Wiki name: Set Carried Item (clientbound))
|
||||||
{ 0x48, PacketTypesIn.UpdateViewPosition }, // (Wiki name: Set Chunk Cache Center)
|
{ 0x48, PacketTypesIn.UpdateViewPosition }, // (Wiki name: Set Chunk Cache Center)
|
||||||
{ 0x49, PacketTypesIn.UpdateViewDistance }, // (Wiki name: Set Chunk Cache Radius)
|
{ 0x49, PacketTypesIn.UpdateViewDistance }, // (Wiki name: Set Chunk Cache Radius)
|
||||||
{ 0x4A, PacketTypesIn.SpawnPosition }, // (Wiki name: Set Default Spawn Position)
|
{ 0x4A, PacketTypesIn.SpawnPosition }, // (Wiki name: Set Default Spawn Position)
|
||||||
{ 0x4B, PacketTypesIn.SetDisplayChatPreview }, // Added in 1.19 (Wiki name: Set Display Chat Preview)
|
{ 0x4B, PacketTypesIn.SetDisplayChatPreview }, // Added in 1.19 (Wiki name: Set Display Chat Preview)
|
||||||
{ 0x4C, PacketTypesIn.DisplayScoreboard }, // (Wiki name: Set Display Objective)
|
{ 0x4C, PacketTypesIn.DisplayScoreboard }, // (Wiki name: Set Display Objective)
|
||||||
{ 0x4D, PacketTypesIn.EntityMetadata }, // (Wiki name: Set Entity Metadata)
|
{ 0x4D, PacketTypesIn.EntityMetadata }, // (Wiki name: Set Entity Metadata)
|
||||||
{ 0x4E, PacketTypesIn.AttachEntity }, // (Wiki name: Set Entity Link)
|
{ 0x4E, PacketTypesIn.AttachEntity }, // (Wiki name: Set Entity Link)
|
||||||
{ 0x4F, PacketTypesIn.EntityVelocity }, // (Wiki name: Set Entity Motion)
|
{ 0x4F, PacketTypesIn.EntityVelocity }, // (Wiki name: Set Entity Motion)
|
||||||
{ 0x50, PacketTypesIn.EntityEquipment }, // (Wiki name: Set Equipment)
|
{ 0x50, PacketTypesIn.EntityEquipment }, // (Wiki name: Set Equipment)
|
||||||
{ 0x51, PacketTypesIn.SetExperience },
|
{ 0x51, PacketTypesIn.SetExperience }, //
|
||||||
{ 0x52, PacketTypesIn.UpdateHealth }, // (Wiki name: Set Health)
|
{ 0x52, PacketTypesIn.UpdateHealth }, // (Wiki name: Set Health)
|
||||||
{ 0x53, PacketTypesIn.ScoreboardObjective }, // (Wiki name: Set Objective)
|
{ 0x53, PacketTypesIn.ScoreboardObjective }, // (Wiki name: Set Objective)
|
||||||
{ 0x54, PacketTypesIn.SetPassengers },
|
{ 0x54, PacketTypesIn.SetPassengers }, //
|
||||||
{ 0x55, PacketTypesIn.Teams }, // (Wiki name: Set Player Team)
|
{ 0x55, PacketTypesIn.Teams }, // (Wiki name: Set Player Team)
|
||||||
{ 0x56, PacketTypesIn.UpdateScore }, // (Wiki name: Set Score)
|
{ 0x56, PacketTypesIn.UpdateScore }, // (Wiki name: Set Score)
|
||||||
{ 0x57, PacketTypesIn.UpdateSimulationDistance }, // (Wiki name: Set Simulation Distance)
|
{ 0x57, PacketTypesIn.UpdateSimulationDistance }, // (Wiki name: Set Simulation Distance)
|
||||||
{ 0x58, PacketTypesIn.SetTitleSubTitle }, // (Wiki name: Set Subtitle Test)
|
{ 0x58, PacketTypesIn.SetTitleSubTitle }, // (Wiki name: Set Subtitle Test)
|
||||||
{ 0x59, PacketTypesIn.TimeUpdate }, // (Wiki name: Set Time)
|
{ 0x59, PacketTypesIn.TimeUpdate }, // (Wiki name: Set Time)
|
||||||
{ 0x5A, PacketTypesIn.SetTitleText }, // (Wiki name: Set Title)
|
{ 0x5A, PacketTypesIn.SetTitleText }, // (Wiki name: Set Title)
|
||||||
{ 0x5B, PacketTypesIn.SetTitleTime }, // (Wiki name: Set Titles Animation)
|
{ 0x5B, PacketTypesIn.SetTitleTime }, // (Wiki name: Set Titles Animation)
|
||||||
{ 0x5C, PacketTypesIn.EntitySoundEffect }, // (Wiki name: Sound Entity)
|
{ 0x5C, PacketTypesIn.EntitySoundEffect }, // (Wiki name: Sound Entity)
|
||||||
{ 0x5D, PacketTypesIn.SoundEffect }, // Changed in 1.19 (Added "Seed" field) (Wiki name: Sound Effect) - DONE (No need to be implemented)
|
{ 0x5D, PacketTypesIn.SoundEffect }, // Changed in 1.19 (Added "Seed" field) (Wiki name: Sound Effect) - DONE (No need to be implemented)
|
||||||
{ 0x5E, PacketTypesIn.StopSound },
|
{ 0x5E, PacketTypesIn.StopSound }, //
|
||||||
{ 0x5F, PacketTypesIn.SystemChat }, // Added in 1.19 (Wiki name: System Chat Message)
|
{ 0x5F, PacketTypesIn.SystemChat }, // Added in 1.19 (Wiki name: System Chat Message)
|
||||||
{ 0x60, PacketTypesIn.PlayerListHeaderAndFooter }, // (Wiki name: Tab List)
|
{ 0x60, PacketTypesIn.PlayerListHeaderAndFooter }, // (Wiki name: Tab List)
|
||||||
{ 0x61, PacketTypesIn.NBTQueryResponse }, // (Wiki name: Tab Query)
|
{ 0x61, PacketTypesIn.NBTQueryResponse }, // (Wiki name: Tab Query)
|
||||||
{ 0x62, PacketTypesIn.CollectItem }, // (Wiki name: Take Item Entity)
|
{ 0x62, PacketTypesIn.CollectItem }, // (Wiki name: Take Item Entity)
|
||||||
{ 0x63, PacketTypesIn.EntityTeleport }, // (Wiki name: Teleport Entity)
|
{ 0x63, PacketTypesIn.EntityTeleport }, // (Wiki name: Teleport Entity)
|
||||||
{ 0x64, PacketTypesIn.Advancements }, // (Wiki name: Update Advancements)
|
{ 0x64, PacketTypesIn.Advancements }, // (Wiki name: Update Advancements)
|
||||||
{ 0x65, PacketTypesIn.EntityProperties }, // (Wiki name: Update Attributes)
|
{ 0x65, PacketTypesIn.EntityProperties }, // (Wiki name: Update Attributes)
|
||||||
{ 0x66, PacketTypesIn.EntityEffect }, // Changed in 1.19 (Added "Has Factor Data" and "Factor Codec" fields) (Wiki name: Entity Effect) - DONE
|
{ 0x66, PacketTypesIn.EntityEffect }, // Changed in 1.19 (Added "Has Factor Data" and "Factor Codec" fields) (Wiki name: Entity Effect) - DONE
|
||||||
{ 0x67, PacketTypesIn.DeclareRecipes }, // (Wiki name: Update Recipes)
|
{ 0x67, PacketTypesIn.DeclareRecipes }, // (Wiki name: Update Recipes)
|
||||||
{ 0x68, PacketTypesIn.Tags }, // (Wiki name: Update Tags)
|
{ 0x68, PacketTypesIn.Tags }, // (Wiki name: Update Tags)
|
||||||
};
|
};
|
||||||
|
|
||||||
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
|
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
|
||||||
{
|
{
|
||||||
{ 0x00, PacketTypesOut.TeleportConfirm }, // (Wiki name: Confirm Teleportation)
|
{ 0x00, PacketTypesOut.TeleportConfirm }, // (Wiki name: Confirm Teleportation)
|
||||||
{ 0x01, PacketTypesOut.QueryBlockNBT }, // (Wiki name: Query Block Entity Tag)
|
{ 0x01, PacketTypesOut.QueryBlockNBT }, // (Wiki name: Query Block Entity Tag)
|
||||||
{ 0x02, PacketTypesOut.SetDifficulty }, // (Wiki name: Change Difficutly)
|
{ 0x02, PacketTypesOut.SetDifficulty }, // (Wiki name: Change Difficutly)
|
||||||
{ 0x03, PacketTypesOut.ChatCommand }, // Added in 1.19
|
{ 0x03, PacketTypesOut.ChatCommand }, // Added in 1.19
|
||||||
{ 0x04, PacketTypesOut.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Chat)
|
{ 0x04, PacketTypesOut.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Chat)
|
||||||
{ 0x05, PacketTypesOut.ChatPreview }, // Added in 1.19 (Wiki name: Chat Preview (serverbound))
|
{ 0x05, PacketTypesOut.ChatPreview }, // Added in 1.19 (Wiki name: Chat Preview (serverbound))
|
||||||
{ 0x06, PacketTypesOut.ClientStatus }, // (Wiki name: Client Command)
|
{ 0x06, PacketTypesOut.ClientStatus }, // (Wiki name: Client Command)
|
||||||
{ 0x07, PacketTypesOut.ClientSettings }, // (Wiki name: Client Information)
|
{ 0x07, PacketTypesOut.ClientSettings }, // (Wiki name: Client Information)
|
||||||
{ 0x08, PacketTypesOut.TabComplete }, // (Wiki name: Command Suggestions Request)
|
{ 0x08, PacketTypesOut.TabComplete }, // (Wiki name: Command Suggestions Request)
|
||||||
{ 0x09, PacketTypesOut.ClickWindowButton }, // (Wiki name: Click Container Button)
|
{ 0x09, PacketTypesOut.ClickWindowButton }, // (Wiki name: Click Container Button)
|
||||||
{ 0x0A, PacketTypesOut.ClickWindow }, // (Wiki name: Click Container)
|
{ 0x0A, PacketTypesOut.ClickWindow }, // (Wiki name: Click Container)
|
||||||
{ 0x0B, PacketTypesOut.CloseWindow }, // (Wiki name: Close Container (serverbound))
|
{ 0x0B, PacketTypesOut.CloseWindow }, // (Wiki name: Close Container (serverbound))
|
||||||
{ 0x0C, PacketTypesOut.PluginMessage }, // (Wiki name: Plugin Message (serverbound))
|
{ 0x0C, PacketTypesOut.PluginMessage }, // (Wiki name: Plugin Message (serverbound))
|
||||||
{ 0x0D, PacketTypesOut.EditBook },
|
{ 0x0D, PacketTypesOut.EditBook }, //
|
||||||
{ 0x0E, PacketTypesOut.EntityNBTRequest }, // (Wiki name: Query Entity Tag)
|
{ 0x0E, PacketTypesOut.EntityNBTRequest }, // (Wiki name: Query Entity Tag)
|
||||||
{ 0x0F, PacketTypesOut.InteractEntity }, // (Wiki name: Interact)
|
{ 0x0F, PacketTypesOut.InteractEntity }, // (Wiki name: Interact)
|
||||||
{ 0x10, PacketTypesOut.GenerateStructure }, // (Wiki name: Jigsaw Generate)
|
{ 0x10, PacketTypesOut.GenerateStructure }, // (Wiki name: Jigsaw Generate)
|
||||||
{ 0x11, PacketTypesOut.KeepAlive },
|
{ 0x11, PacketTypesOut.KeepAlive }, //
|
||||||
{ 0x12, PacketTypesOut.LockDifficulty },
|
{ 0x12, PacketTypesOut.LockDifficulty }, //
|
||||||
{ 0x13, PacketTypesOut.PlayerPosition }, // (Wiki name: Move Player Position)
|
{ 0x13, PacketTypesOut.PlayerPosition }, // (Wiki name: Move Player Position)
|
||||||
{ 0x14, PacketTypesOut.PlayerPositionAndRotation }, // (Wiki name: Set Player Position and Rotation)
|
{ 0x14, PacketTypesOut.PlayerPositionAndRotation }, // (Wiki name: Set Player Position and Rotation)
|
||||||
{ 0x15, PacketTypesOut.PlayerRotation }, // (Wiki name: Set Player Rotation)
|
{ 0x15, PacketTypesOut.PlayerRotation }, // (Wiki name: Set Player Rotation)
|
||||||
{ 0x16, PacketTypesOut.PlayerMovement }, // (Wiki name: Set Player On Ground)
|
{ 0x16, PacketTypesOut.PlayerMovement }, // (Wiki name: Set Player On Ground)
|
||||||
{ 0x17, PacketTypesOut.VehicleMove }, // (Wiki name: Move Vehicle (serverbound))
|
{ 0x17, PacketTypesOut.VehicleMove }, // (Wiki name: Move Vehicle (serverbound))
|
||||||
{ 0x18, PacketTypesOut.SteerBoat }, // (Wiki name: Paddle Boat)
|
{ 0x18, PacketTypesOut.SteerBoat }, // (Wiki name: Paddle Boat)
|
||||||
{ 0x19, PacketTypesOut.PickItem },
|
{ 0x19, PacketTypesOut.PickItem }, //
|
||||||
{ 0x1A, PacketTypesOut.CraftRecipeRequest }, // (Wiki name: Place recipe)
|
{ 0x1A, PacketTypesOut.CraftRecipeRequest }, // (Wiki name: Place recipe)
|
||||||
{ 0x1B, PacketTypesOut.PlayerAbilities },
|
{ 0x1B, PacketTypesOut.PlayerAbilities }, //
|
||||||
{ 0x1C, PacketTypesOut.PlayerDigging }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Player Action) - DONE
|
{ 0x1C, PacketTypesOut.PlayerDigging }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Player Action) - DONE
|
||||||
{ 0x1D, PacketTypesOut.EntityAction }, // (Wiki name: Player Command)
|
{ 0x1D, PacketTypesOut.EntityAction }, // (Wiki name: Player Command)
|
||||||
{ 0x1E, PacketTypesOut.SteerVehicle }, // (Wiki name: Player Input)
|
{ 0x1E, PacketTypesOut.SteerVehicle }, // (Wiki name: Player Input)
|
||||||
{ 0x1F, PacketTypesOut.Pong }, // (Wiki name: Pong (play))
|
{ 0x1F, PacketTypesOut.Pong }, // (Wiki name: Pong (play))
|
||||||
{ 0x20, PacketTypesOut.SetDisplayedRecipe }, // (Wiki name: Recipe Book Change Settings)
|
{ 0x20, PacketTypesOut.SetDisplayedRecipe }, // (Wiki name: Recipe Book Change Settings)
|
||||||
{ 0x21, PacketTypesOut.SetRecipeBookState }, // (Wiki name: Recipe Book Seen Recipe)
|
{ 0x21, PacketTypesOut.SetRecipeBookState }, // (Wiki name: Recipe Book Seen Recipe)
|
||||||
{ 0x22, PacketTypesOut.NameItem }, // (Wiki name: Rename Item)
|
{ 0x22, PacketTypesOut.NameItem }, // (Wiki name: Rename Item)
|
||||||
{ 0x23, PacketTypesOut.ResourcePackStatus }, // (Wiki name: Resource Pack (serverbound))
|
{ 0x23, PacketTypesOut.ResourcePackStatus }, // (Wiki name: Resource Pack (serverbound))
|
||||||
{ 0x24, PacketTypesOut.AdvancementTab }, // (Wiki name: Seen Advancements)
|
{ 0x24, PacketTypesOut.AdvancementTab }, // (Wiki name: Seen Advancements)
|
||||||
{ 0x25, PacketTypesOut.SelectTrade },
|
{ 0x25, PacketTypesOut.SelectTrade }, //
|
||||||
{ 0x26, PacketTypesOut.SetBeaconEffect }, // Changed in 1.19 (Added a "Secondary Effect Present" and "Secondary Effect" fields) (Wiki name: Set Beacon) - DONE - (No need to be implemented)
|
{ 0x26, PacketTypesOut.SetBeaconEffect }, // Changed in 1.19 (Added a "Secondary Effect Present" and "Secondary Effect" fields) (Wiki name: Set Beacon) - DONE - (No need to be implemented)
|
||||||
{ 0x27, PacketTypesOut.HeldItemChange }, // (Wiki name: Set Carried Item (serverbound))
|
{ 0x27, PacketTypesOut.HeldItemChange }, // (Wiki name: Set Carried Item (serverbound))
|
||||||
{ 0x28, PacketTypesOut.UpdateCommandBlock }, // (Wiki name: Set Command Block)
|
{ 0x28, PacketTypesOut.UpdateCommandBlock }, // (Wiki name: Set Command Block)
|
||||||
{ 0x29, PacketTypesOut.UpdateCommandBlockMinecart },
|
{ 0x29, PacketTypesOut.UpdateCommandBlockMinecart }, //
|
||||||
{ 0x2A, PacketTypesOut.CreativeInventoryAction }, // (Wiki name: Set Creative Mode Slot)
|
{ 0x2A, PacketTypesOut.CreativeInventoryAction }, // (Wiki name: Set Creative Mode Slot)
|
||||||
{ 0x2B, PacketTypesOut.UpdateJigsawBlock }, // (Wiki name: Set Jigsaw Block)
|
{ 0x2B, PacketTypesOut.UpdateJigsawBlock }, // (Wiki name: Set Jigsaw Block)
|
||||||
{ 0x2C, PacketTypesOut.UpdateStructureBlock }, // (Wiki name: Set Structure Block)
|
{ 0x2C, PacketTypesOut.UpdateStructureBlock }, // (Wiki name: Set Structure Block)
|
||||||
{ 0x2D, PacketTypesOut.UpdateSign }, // (Wiki name: Sign Update)
|
{ 0x2D, PacketTypesOut.UpdateSign }, // (Wiki name: Sign Update)
|
||||||
{ 0x2E, PacketTypesOut.Animation }, // (Wiki name: Swing)
|
{ 0x2E, PacketTypesOut.Animation }, // (Wiki name: Swing)
|
||||||
{ 0x2F, PacketTypesOut.Spectate }, // (Wiki name: Teleport To Entity)
|
{ 0x2F, PacketTypesOut.Spectate }, // (Wiki name: Teleport To Entity)
|
||||||
{ 0x30, PacketTypesOut.PlayerBlockPlacement }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item On) - DONE
|
{ 0x30, PacketTypesOut.PlayerBlockPlacement }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item On) - DONE
|
||||||
{ 0x31, PacketTypesOut.UseItem }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item) - DONE
|
{ 0x31, PacketTypesOut.UseItem }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item) - DONE
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override Dictionary<int, PacketTypesIn> GetListIn()
|
protected override Dictionary<int, PacketTypesIn> GetListIn()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MinecraftClient.Protocol.Handlers.PacketPalettes
|
||||||
|
{
|
||||||
|
public class PacketPalette1192 : PacketTypePalette
|
||||||
|
{
|
||||||
|
private Dictionary<int, PacketTypesIn> typeIn = new Dictionary<int, PacketTypesIn>()
|
||||||
|
{
|
||||||
|
{ 0x00, PacketTypesIn.SpawnEntity }, // Changed in 1.19 (Wiki name: Spawn Entity) - DONE
|
||||||
|
{ 0x01, PacketTypesIn.SpawnExperienceOrb }, // (Wiki name: Spawn Exeprience Orb)
|
||||||
|
{ 0x02, PacketTypesIn.SpawnPlayer }, //
|
||||||
|
{ 0x03, PacketTypesIn.EntityAnimation }, // (Wiki name: Entity Animation (clientbound))
|
||||||
|
{ 0x04, PacketTypesIn.Statistics }, // (Wiki name: Award Statistics)
|
||||||
|
{ 0x05, PacketTypesIn.BlockChangedAck }, // Added 1.19 (Wiki name: Acknowledge Block Change) - DONE
|
||||||
|
{ 0x06, PacketTypesIn.BlockBreakAnimation }, // (Wiki name: Set Block Destroy Stage)
|
||||||
|
{ 0x07, PacketTypesIn.BlockEntityData }, //
|
||||||
|
{ 0x08, PacketTypesIn.BlockAction }, //
|
||||||
|
{ 0x09, PacketTypesIn.BlockChange }, // (Wiki name: Block Update)
|
||||||
|
{ 0x0A, PacketTypesIn.BossBar }, //
|
||||||
|
{ 0x0B, PacketTypesIn.ServerDifficulty }, // (Wiki name: Change Difficulty)
|
||||||
|
{ 0x0C, PacketTypesIn.ChatPreview }, // Added 1.19
|
||||||
|
{ 0x0D, PacketTypesIn.ClearTiles }, //
|
||||||
|
{ 0x0E, PacketTypesIn.TabComplete }, // (Wiki name: Command Suggestions Response)
|
||||||
|
{ 0x0F, PacketTypesIn.DeclareCommands }, // (Wiki name: Commands)
|
||||||
|
{ 0x10, PacketTypesIn.CloseWindow }, // (Wiki name: Close Container (clientbound))
|
||||||
|
{ 0x11, PacketTypesIn.WindowItems }, // (Wiki name: Set Container Content)
|
||||||
|
{ 0x12, PacketTypesIn.WindowProperty }, // (Wiki name: Set Container Property)
|
||||||
|
{ 0x13, PacketTypesIn.SetSlot }, // (Wiki name: Set Container Slot)
|
||||||
|
{ 0x14, PacketTypesIn.SetCooldown }, //
|
||||||
|
{ 0x15, PacketTypesIn.ChatSuggestions }, // Added 1.19.1
|
||||||
|
{ 0x16, PacketTypesIn.PluginMessage }, // (Wiki name: Plugin Message (clientbound))
|
||||||
|
{ 0x17, PacketTypesIn.NamedSoundEffect }, // Changed in 1.19 (Added "Speed" field) (Wiki name: Custom Sound Effect) - DONE (No need to be implemented)
|
||||||
|
{ 0x18, PacketTypesIn.HideMessage }, // Added 1.19.1
|
||||||
|
{ 0x19, PacketTypesIn.Disconnect }, //
|
||||||
|
{ 0x1A, PacketTypesIn.EntityStatus }, // (Wiki name: Entity Event)
|
||||||
|
{ 0x1B, PacketTypesIn.Explosion }, // Changed in 1.19 (Location fields are now Double instead of Float) (Wiki name: Explosion) - DONE
|
||||||
|
{ 0x1C, PacketTypesIn.UnloadChunk }, // (Wiki name: Forget Chunk)
|
||||||
|
{ 0x1D, PacketTypesIn.ChangeGameState }, // (Wiki name: Game Event)
|
||||||
|
{ 0x1E, PacketTypesIn.OpenHorseWindow }, // (Wiki name: Horse Screen Open)
|
||||||
|
{ 0x1F, PacketTypesIn.InitializeWorldBorder }, //
|
||||||
|
{ 0x20, PacketTypesIn.KeepAlive }, //
|
||||||
|
{ 0x21, PacketTypesIn.ChunkData }, //
|
||||||
|
{ 0x22, PacketTypesIn.Effect }, // (Wiki name: Level Event)
|
||||||
|
{ 0x23, PacketTypesIn.Particle }, // Changed in 1.19 ("Particle Data" field is now "Max Speed", it's the same Float data type) (Wiki name: Level Particle) - DONE (No need to be implemented)
|
||||||
|
{ 0x24, PacketTypesIn.UpdateLight }, // (Wiki name: Light Update)
|
||||||
|
{ 0x25, PacketTypesIn.JoinGame }, // Changed in 1.19 (lot's of changes) (Wiki name: Login (play)) - DONE
|
||||||
|
{ 0x26, PacketTypesIn.MapData }, // (Wiki name: Map Item Data)
|
||||||
|
{ 0x27, PacketTypesIn.TradeList }, // (Wiki name: Merchant Offers)
|
||||||
|
{ 0x28, PacketTypesIn.EntityPosition }, // (Wiki name: Move Entity Position)
|
||||||
|
{ 0x29, PacketTypesIn.EntityPositionAndRotation }, // (Wiki name: Move Entity Position and Rotation)
|
||||||
|
{ 0x2A, PacketTypesIn.EntityRotation }, // (Wiki name: Move Entity Rotation)
|
||||||
|
{ 0x2B, PacketTypesIn.VehicleMove }, // (Wiki name: Move Vehicle)
|
||||||
|
{ 0x2C, PacketTypesIn.OpenBook }, //
|
||||||
|
{ 0x2D, PacketTypesIn.OpenWindow }, // (Wiki name: Open Screen)
|
||||||
|
{ 0x2E, PacketTypesIn.OpenSignEditor }, //
|
||||||
|
{ 0x2F, PacketTypesIn.Ping }, // (Wiki name: Ping (play))
|
||||||
|
{ 0x30, PacketTypesIn.CraftRecipeResponse }, // (Wiki name: Place Ghost Recipe)
|
||||||
|
{ 0x31, PacketTypesIn.PlayerAbilities }, //
|
||||||
|
{ 0x32, PacketTypesIn.MessageHeader }, // Added 1.19.1
|
||||||
|
{ 0x33, PacketTypesIn.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Player Chat Message)
|
||||||
|
{ 0x34, PacketTypesIn.EndCombatEvent }, // (Wiki name: Player Combat End)
|
||||||
|
{ 0x35, PacketTypesIn.EnterCombatEvent }, // (Wiki name: Player Combat Enter)
|
||||||
|
{ 0x36, PacketTypesIn.DeathCombatEvent }, // (Wiki name: Player Combat Kill)
|
||||||
|
{ 0x37, PacketTypesIn.PlayerInfo }, // Changed in 1.19 (Heavy changes) - DONE
|
||||||
|
{ 0x38, PacketTypesIn.FacePlayer }, // (Wiki name: Player Look At)
|
||||||
|
{ 0x39, PacketTypesIn.PlayerPositionAndLook }, // (Wiki name: Player Position)
|
||||||
|
{ 0x3A, PacketTypesIn.UnlockRecipes }, // (Wiki name: Recipe)
|
||||||
|
{ 0x3B, PacketTypesIn.DestroyEntities }, // (Wiki name: Remove Entites)
|
||||||
|
{ 0x3C, PacketTypesIn.RemoveEntityEffect }, //
|
||||||
|
{ 0x3D, PacketTypesIn.ResourcePackSend }, // (Wiki name: Resource Pack)
|
||||||
|
{ 0x3E, PacketTypesIn.Respawn }, // Changed in 1.19 (Heavy changes) - DONE
|
||||||
|
{ 0x3F, PacketTypesIn.EntityHeadLook }, // (Wiki name: Rotate Head)
|
||||||
|
{ 0x40, PacketTypesIn.MultiBlockChange }, // (Wiki name: Sections Block Update)
|
||||||
|
{ 0x41, PacketTypesIn.SelectAdvancementTab }, //
|
||||||
|
{ 0x42, PacketTypesIn.ServerData }, // Added in 1.19
|
||||||
|
{ 0x43, PacketTypesIn.ActionBar }, // (Wiki name: Set Action Bar Text)
|
||||||
|
{ 0x44, PacketTypesIn.WorldBorderCenter }, // (Wiki name: Set Border Center)
|
||||||
|
{ 0x45, PacketTypesIn.WorldBorderLerpSize }, //
|
||||||
|
{ 0x46, PacketTypesIn.WorldBorderSize }, // (Wiki name: Set World Border Size)
|
||||||
|
{ 0x47, PacketTypesIn.WorldBorderWarningDelay }, // (Wiki name: Set World Border Warning Delay)
|
||||||
|
{ 0x48, PacketTypesIn.WorldBorderWarningReach }, // (Wiki name: Set Border Warning Distance)
|
||||||
|
{ 0x49, PacketTypesIn.Camera }, // (Wiki name: Set Camera)
|
||||||
|
{ 0x4A, PacketTypesIn.HeldItemChange }, // (Wiki name: Set Carried Item (clientbound))
|
||||||
|
{ 0x4B, PacketTypesIn.UpdateViewPosition }, // (Wiki name: Set Chunk Cache Center)
|
||||||
|
{ 0x4C, PacketTypesIn.UpdateViewDistance }, // (Wiki name: Set Chunk Cache Radius)
|
||||||
|
{ 0x4D, PacketTypesIn.SpawnPosition }, // (Wiki name: Set Default Spawn Position)
|
||||||
|
{ 0x4E, PacketTypesIn.SetDisplayChatPreview }, // Added in 1.19 (Wiki name: Set Display Chat Preview)
|
||||||
|
{ 0x4F, PacketTypesIn.DisplayScoreboard }, // (Wiki name: Set Display Objective)
|
||||||
|
{ 0x50, PacketTypesIn.EntityMetadata }, // (Wiki name: Set Entity Metadata)
|
||||||
|
{ 0x51, PacketTypesIn.AttachEntity }, // (Wiki name: Set Entity Link)
|
||||||
|
{ 0x52, PacketTypesIn.EntityVelocity }, // (Wiki name: Set Entity Motion)
|
||||||
|
{ 0x53, PacketTypesIn.EntityEquipment }, // (Wiki name: Set Equipment)
|
||||||
|
{ 0x54, PacketTypesIn.SetExperience }, //
|
||||||
|
{ 0x55, PacketTypesIn.UpdateHealth }, // (Wiki name: Set Health)
|
||||||
|
{ 0x56, PacketTypesIn.ScoreboardObjective }, // (Wiki name: Set Objective)
|
||||||
|
{ 0x57, PacketTypesIn.SetPassengers }, //
|
||||||
|
{ 0x58, PacketTypesIn.Teams }, // (Wiki name: Set Player Team)
|
||||||
|
{ 0x59, PacketTypesIn.UpdateScore }, // (Wiki name: Set Score)
|
||||||
|
{ 0x5A, PacketTypesIn.UpdateSimulationDistance }, // (Wiki name: Set Simulation Distance)
|
||||||
|
{ 0x5B, PacketTypesIn.SetTitleSubTitle }, // (Wiki name: Set Subtitle Test)
|
||||||
|
{ 0x5C, PacketTypesIn.TimeUpdate }, // (Wiki name: Set Time)
|
||||||
|
{ 0x5D, PacketTypesIn.SetTitleText }, // (Wiki name: Set Title)
|
||||||
|
{ 0x5E, PacketTypesIn.SetTitleTime }, // (Wiki name: Set Titles Animation)
|
||||||
|
{ 0x5F, PacketTypesIn.EntitySoundEffect }, // (Wiki name: Sound Entity)
|
||||||
|
{ 0x60, PacketTypesIn.SoundEffect }, // Changed in 1.19 (Added "Seed" field) (Wiki name: Sound Effect) - DONE (No need to be implemented)
|
||||||
|
{ 0x61, PacketTypesIn.StopSound }, //
|
||||||
|
{ 0x62, PacketTypesIn.SystemChat }, // Added in 1.19 (Wiki name: System Chat Message)
|
||||||
|
{ 0x63, PacketTypesIn.PlayerListHeaderAndFooter }, // (Wiki name: Tab List)
|
||||||
|
{ 0x64, PacketTypesIn.NBTQueryResponse }, // (Wiki name: Tab Query)
|
||||||
|
{ 0x65, PacketTypesIn.CollectItem }, // (Wiki name: Take Item Entity)
|
||||||
|
{ 0x66, PacketTypesIn.EntityTeleport }, // (Wiki name: Teleport Entity)
|
||||||
|
{ 0x67, PacketTypesIn.Advancements }, // (Wiki name: Update Advancements)
|
||||||
|
{ 0x68, PacketTypesIn.EntityProperties }, // (Wiki name: Update Attributes)
|
||||||
|
{ 0x69, PacketTypesIn.EntityEffect }, // Changed in 1.19 (Added "Has Factor Data" and "Factor Codec" fields) (Wiki name: Entity Effect) - DONE
|
||||||
|
{ 0x6A, PacketTypesIn.DeclareRecipes }, // (Wiki name: Update Recipes)
|
||||||
|
{ 0x6B, PacketTypesIn.Tags }, // (Wiki name: Update Tags)
|
||||||
|
};
|
||||||
|
|
||||||
|
private Dictionary<int, PacketTypesOut> typeOut = new Dictionary<int, PacketTypesOut>()
|
||||||
|
{
|
||||||
|
{ 0x00, PacketTypesOut.TeleportConfirm }, // (Wiki name: Confirm Teleportation)
|
||||||
|
{ 0x01, PacketTypesOut.QueryBlockNBT }, // (Wiki name: Query Block Entity Tag)
|
||||||
|
{ 0x02, PacketTypesOut.SetDifficulty }, // (Wiki name: Change Difficutly)
|
||||||
|
{ 0x03, PacketTypesOut.MessageAcknowledgment }, // Added in 1.19.1
|
||||||
|
{ 0x04, PacketTypesOut.ChatCommand }, // Added in 1.19
|
||||||
|
{ 0x05, PacketTypesOut.ChatMessage }, // Changed in 1.19 (Completely changed) (Wiki name: Chat)
|
||||||
|
{ 0x06, PacketTypesOut.ChatPreview }, // Added in 1.19 (Wiki name: Chat Preview (serverbound))
|
||||||
|
{ 0x07, PacketTypesOut.ClientStatus }, // (Wiki name: Client Command)
|
||||||
|
{ 0x08, PacketTypesOut.ClientSettings }, // (Wiki name: Client Information)
|
||||||
|
{ 0x09, PacketTypesOut.TabComplete }, // (Wiki name: Command Suggestions Request)
|
||||||
|
{ 0x0A, PacketTypesOut.ClickWindowButton }, // (Wiki name: Click Container Button)
|
||||||
|
{ 0x0B, PacketTypesOut.ClickWindow }, // (Wiki name: Click Container)
|
||||||
|
{ 0x0C, PacketTypesOut.CloseWindow }, // (Wiki name: Close Container (serverbound))
|
||||||
|
{ 0x0D, PacketTypesOut.PluginMessage }, // (Wiki name: Plugin Message (serverbound))
|
||||||
|
{ 0x0E, PacketTypesOut.EditBook }, //
|
||||||
|
{ 0x0F, PacketTypesOut.EntityNBTRequest }, // (Wiki name: Query Entity Tag)
|
||||||
|
{ 0x10, PacketTypesOut.InteractEntity }, // (Wiki name: Interact)
|
||||||
|
{ 0x11, PacketTypesOut.GenerateStructure }, // (Wiki name: Jigsaw Generate)
|
||||||
|
{ 0x12, PacketTypesOut.KeepAlive }, //
|
||||||
|
{ 0x13, PacketTypesOut.LockDifficulty }, //
|
||||||
|
{ 0x14, PacketTypesOut.PlayerPosition }, // (Wiki name: Move Player Position)
|
||||||
|
{ 0x15, PacketTypesOut.PlayerPositionAndRotation }, // (Wiki name: Set Player Position and Rotation)
|
||||||
|
{ 0x16, PacketTypesOut.PlayerRotation }, // (Wiki name: Set Player Rotation)
|
||||||
|
{ 0x17, PacketTypesOut.PlayerMovement }, // (Wiki name: Set Player On Ground)
|
||||||
|
{ 0x18, PacketTypesOut.VehicleMove }, // (Wiki name: Move Vehicle (serverbound))
|
||||||
|
{ 0x19, PacketTypesOut.SteerBoat }, // (Wiki name: Paddle Boat)
|
||||||
|
{ 0x1A, PacketTypesOut.PickItem }, //
|
||||||
|
{ 0x1B, PacketTypesOut.CraftRecipeRequest }, // (Wiki name: Place recipe)
|
||||||
|
{ 0x1C, PacketTypesOut.PlayerAbilities }, //
|
||||||
|
{ 0x1D, PacketTypesOut.PlayerDigging }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Player Action) - DONE
|
||||||
|
{ 0x1E, PacketTypesOut.EntityAction }, // (Wiki name: Player Command)
|
||||||
|
{ 0x1F, PacketTypesOut.SteerVehicle }, // (Wiki name: Player Input)
|
||||||
|
{ 0x20, PacketTypesOut.Pong }, // (Wiki name: Pong (play))
|
||||||
|
{ 0x21, PacketTypesOut.SetDisplayedRecipe }, // (Wiki name: Recipe Book Change Settings)
|
||||||
|
{ 0x22, PacketTypesOut.SetRecipeBookState }, // (Wiki name: Recipe Book Seen Recipe)
|
||||||
|
{ 0x23, PacketTypesOut.NameItem }, // (Wiki name: Rename Item)
|
||||||
|
{ 0x24, PacketTypesOut.ResourcePackStatus }, // (Wiki name: Resource Pack (serverbound))
|
||||||
|
{ 0x25, PacketTypesOut.AdvancementTab }, // (Wiki name: Seen Advancements)
|
||||||
|
{ 0x26, PacketTypesOut.SelectTrade }, //
|
||||||
|
{ 0x27, PacketTypesOut.SetBeaconEffect }, // Changed in 1.19 (Added a "Secondary Effect Present" and "Secondary Effect" fields) (Wiki name: Set Beacon) - DONE - (No need to be implemented)
|
||||||
|
{ 0x28, PacketTypesOut.HeldItemChange }, // (Wiki name: Set Carried Item (serverbound))
|
||||||
|
{ 0x29, PacketTypesOut.UpdateCommandBlock }, // (Wiki name: Set Command Block)
|
||||||
|
{ 0x2A, PacketTypesOut.UpdateCommandBlockMinecart }, //
|
||||||
|
{ 0x2B, PacketTypesOut.CreativeInventoryAction }, // (Wiki name: Set Creative Mode Slot)
|
||||||
|
{ 0x2C, PacketTypesOut.UpdateJigsawBlock }, // (Wiki name: Set Jigsaw Block)
|
||||||
|
{ 0x2D, PacketTypesOut.UpdateStructureBlock }, // (Wiki name: Set Structure Block)
|
||||||
|
{ 0x2E, PacketTypesOut.UpdateSign }, // (Wiki name: Sign Update)
|
||||||
|
{ 0x2F, PacketTypesOut.Animation }, // (Wiki name: Swing)
|
||||||
|
{ 0x30, PacketTypesOut.Spectate }, // (Wiki name: Teleport To Entity)
|
||||||
|
{ 0x31, PacketTypesOut.PlayerBlockPlacement }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item On) - DONE
|
||||||
|
{ 0x32, PacketTypesOut.UseItem }, // Changed in 1.19 (Added a "Sequence" field) (Wiki name: Use Item) - DONE
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override Dictionary<int, PacketTypesIn> GetListIn()
|
||||||
|
{
|
||||||
|
return typeIn;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Dictionary<int, PacketTypesOut> GetListOut()
|
||||||
|
{
|
||||||
|
return typeOut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -51,8 +51,9 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
public PacketTypePalette GetTypeHandler(int protocol)
|
public PacketTypePalette GetTypeHandler(int protocol)
|
||||||
{
|
{
|
||||||
PacketTypePalette p;
|
PacketTypePalette p;
|
||||||
if (protocol > Protocol18Handler.MC_1_19_Version)
|
if (protocol > Protocol18Handler.MC_1_19_2_Version)
|
||||||
throw new NotImplementedException(Translations.Get("exception.palette.packet"));
|
throw new NotImplementedException(Translations.Get("exception.palette.packet"));
|
||||||
|
|
||||||
if (protocol <= Protocol18Handler.MC_1_8_Version)
|
if (protocol <= Protocol18Handler.MC_1_8_Version)
|
||||||
p = new PacketPalette17();
|
p = new PacketPalette17();
|
||||||
else if (protocol <= Protocol18Handler.MC_1_11_2_Version)
|
else if (protocol <= Protocol18Handler.MC_1_11_2_Version)
|
||||||
|
|
@ -75,8 +76,10 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
p = new PacketPalette117();
|
p = new PacketPalette117();
|
||||||
else if (protocol <= Protocol18Handler.MC_1_18_2_Version)
|
else if (protocol <= Protocol18Handler.MC_1_18_2_Version)
|
||||||
p = new PacketPalette118();
|
p = new PacketPalette118();
|
||||||
else
|
else if (protocol <= Protocol18Handler.MC_1_19_Version)
|
||||||
p = new PacketPalette119();
|
p = new PacketPalette119();
|
||||||
|
else
|
||||||
|
p = new PacketPalette1192();
|
||||||
|
|
||||||
p.SetForgeEnabled(this.forgeEnabled);
|
p.SetForgeEnabled(this.forgeEnabled);
|
||||||
return p;
|
return p;
|
||||||
|
|
|
||||||
|
|
@ -10,128 +10,129 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum PacketTypesIn
|
public enum PacketTypesIn
|
||||||
{
|
{
|
||||||
SpawnEntity,
|
AcknowledgePlayerDigging, //
|
||||||
SpawnExperienceOrb,
|
ActionBar, //
|
||||||
SpawnWeatherEntity,
|
Advancements, //
|
||||||
SpawnLivingEntity,
|
AttachEntity, //
|
||||||
SpawnPainting,
|
BlockAction, //
|
||||||
SpawnPlayer,
|
BlockBreakAnimation, //
|
||||||
EntityAnimation,
|
BlockChange, //
|
||||||
Statistics,
|
BlockChangedAck, // Added in 1.19
|
||||||
AcknowledgePlayerDigging,
|
BlockEntityData, //
|
||||||
BlockBreakAnimation,
|
BossBar, //
|
||||||
BlockEntityData,
|
Camera, //
|
||||||
BlockAction,
|
ChangeGameState, //
|
||||||
BlockChange,
|
ChatMessage, //
|
||||||
BossBar,
|
ChatPreview, // Added in 1.19
|
||||||
ServerDifficulty,
|
ChatSuggestions, // Added in 1.19.1 (1.19.2)
|
||||||
ChatMessage,
|
ChunkData, //
|
||||||
MultiBlockChange,
|
ClearTiles, //
|
||||||
TabComplete,
|
CloseWindow, //
|
||||||
DeclareCommands,
|
CollectItem, //
|
||||||
WindowConfirmation,
|
CombatEvent, //
|
||||||
CloseWindow,
|
CraftRecipeResponse, //
|
||||||
WindowItems,
|
DeathCombatEvent, //
|
||||||
WindowProperty,
|
DeclareCommands, //
|
||||||
SetSlot,
|
DeclareRecipes, //
|
||||||
SetCooldown,
|
DestroyEntities, //
|
||||||
PluginMessage,
|
Disconnect, //
|
||||||
NamedSoundEffect,
|
DisplayScoreboard, //
|
||||||
Disconnect,
|
Effect, //
|
||||||
EntityStatus,
|
EndCombatEvent, //
|
||||||
Explosion,
|
EnterCombatEvent, //
|
||||||
UnloadChunk,
|
EntityAnimation, //
|
||||||
ChangeGameState,
|
EntityEffect, //
|
||||||
OpenHorseWindow,
|
EntityEquipment, //
|
||||||
KeepAlive,
|
EntityHeadLook, //
|
||||||
ChunkData,
|
EntityMetadata, //
|
||||||
Effect,
|
EntityMovement, //
|
||||||
Particle,
|
EntityPosition, //
|
||||||
UpdateLight,
|
EntityPositionAndRotation, //
|
||||||
JoinGame,
|
EntityProperties, //
|
||||||
MapData,
|
EntityRotation, //
|
||||||
TradeList,
|
EntitySoundEffect, //
|
||||||
EntityPosition,
|
EntityStatus, //
|
||||||
EntityPositionAndRotation,
|
EntityTeleport, //
|
||||||
EntityRotation,
|
EntityVelocity, //
|
||||||
EntityMovement,
|
Explosion, //
|
||||||
VehicleMove,
|
FacePlayer, //
|
||||||
OpenBook,
|
HeldItemChange, //
|
||||||
OpenWindow,
|
HideMessage, // Added in 1.19.1 (1.19.2)
|
||||||
OpenSignEditor,
|
InitializeWorldBorder, //
|
||||||
CraftRecipeResponse,
|
JoinGame, //
|
||||||
PlayerAbilities,
|
KeepAlive, //
|
||||||
CombatEvent,
|
MapChunkBulk, // For 1.8 or below
|
||||||
PlayerInfo,
|
MapData, //
|
||||||
FacePlayer,
|
MessageHeader, // Added in 1.19.1 (1.19.2)
|
||||||
PlayerPositionAndLook,
|
MultiBlockChange, //
|
||||||
UnlockRecipes,
|
NamedSoundEffect, //
|
||||||
DestroyEntities,
|
NBTQueryResponse, //
|
||||||
RemoveEntityEffect,
|
OpenBook, //
|
||||||
ResourcePackSend,
|
OpenHorseWindow, //
|
||||||
Respawn,
|
OpenSignEditor, //
|
||||||
EntityHeadLook,
|
OpenWindow, //
|
||||||
SelectAdvancementTab,
|
Particle, //
|
||||||
WorldBorder,
|
Ping, //
|
||||||
Camera,
|
PlayerAbilities, //
|
||||||
HeldItemChange,
|
PlayerInfo, //
|
||||||
UpdateViewPosition,
|
PlayerListHeaderAndFooter, //
|
||||||
UpdateViewDistance,
|
PlayerPositionAndLook, //
|
||||||
DisplayScoreboard,
|
PluginMessage, //
|
||||||
EntityMetadata,
|
RemoveEntityEffect, //
|
||||||
AttachEntity,
|
ResourcePackSend, //
|
||||||
EntityVelocity,
|
Respawn, //
|
||||||
EntityEquipment,
|
ScoreboardObjective, //
|
||||||
SetExperience,
|
SelectAdvancementTab, //
|
||||||
UpdateHealth,
|
ServerData, // Added in 1.19
|
||||||
ScoreboardObjective,
|
ServerDifficulty, //
|
||||||
SetPassengers,
|
SetCompression, // For 1.8 or below
|
||||||
Teams,
|
SetCooldown, //
|
||||||
UpdateScore,
|
SetDisplayChatPreview, // Added in 1.19
|
||||||
SpawnPosition,
|
SetExperience, //
|
||||||
TimeUpdate,
|
SetPassengers, //
|
||||||
Title,
|
SetSlot, //
|
||||||
EntitySoundEffect,
|
SetTitleSubTitle, //
|
||||||
SoundEffect,
|
SetTitleText, //
|
||||||
StopSound,
|
SetTitleTime, //
|
||||||
PlayerListHeaderAndFooter,
|
SkulkVibrationSignal, //
|
||||||
NBTQueryResponse,
|
SoundEffect, //
|
||||||
CollectItem,
|
SpawnEntity, //
|
||||||
EntityTeleport,
|
SpawnExperienceOrb, //
|
||||||
Advancements,
|
SpawnLivingEntity, //
|
||||||
EntityProperties,
|
SpawnPainting, //
|
||||||
EntityEffect,
|
SpawnPlayer, //
|
||||||
DeclareRecipes,
|
SpawnPosition, //
|
||||||
SetTitleTime,
|
SpawnWeatherEntity, //
|
||||||
SetTitleText,
|
Statistics, //
|
||||||
SetTitleSubTitle,
|
StopSound, //
|
||||||
WorldBorderWarningReach,
|
SystemChat, // Added in 1.19
|
||||||
WorldBorderWarningDelay,
|
TabComplete, //
|
||||||
WorldBorderSize,
|
Tags, //
|
||||||
WorldBorderLerpSize,
|
Teams, //
|
||||||
WorldBorderCenter,
|
TimeUpdate, //
|
||||||
ActionBar,
|
Title, //
|
||||||
Tags,
|
TradeList, //
|
||||||
DeathCombatEvent,
|
Unknown, // For old version packet that have been removed and not used by mcc
|
||||||
EnterCombatEvent,
|
UnloadChunk, //
|
||||||
EndCombatEvent,
|
UnlockRecipes, //
|
||||||
Ping,
|
UpdateEntityNBT, // For 1.8 or below
|
||||||
InitializeWorldBorder,
|
UpdateHealth, //
|
||||||
SkulkVibrationSignal,
|
UpdateLight, //
|
||||||
ClearTiles,
|
UpdateScore, //
|
||||||
UseBed, // For 1.13.2 or below
|
UpdateSign, // For 1.8 or below
|
||||||
MapChunkBulk, // For 1.8 or below
|
UpdateSimulationDistance, //
|
||||||
SetCompression, // For 1.8 or below
|
UpdateViewDistance, //
|
||||||
UpdateSign, // For 1.8 or below
|
UpdateViewPosition, //
|
||||||
UpdateEntityNBT, // For 1.8 or below
|
UseBed, // For 1.13.2 or below
|
||||||
Unknown, // For old version packet that have been removed and not used by mcc
|
VehicleMove, //
|
||||||
UpdateSimulationDistance,
|
WindowConfirmation, //
|
||||||
|
WindowItems, //
|
||||||
// 1.19 Additions
|
WindowProperty, //
|
||||||
BlockChangedAck,
|
WorldBorder, //
|
||||||
ChatPreview,
|
WorldBorderCenter, //
|
||||||
ServerData,
|
WorldBorderLerpSize, //
|
||||||
SetDisplayChatPreview,
|
WorldBorderSize, //
|
||||||
SystemChat
|
WorldBorderWarningDelay, //
|
||||||
|
WorldBorderWarningReach, //
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,62 +10,61 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum PacketTypesOut
|
public enum PacketTypesOut
|
||||||
{
|
{
|
||||||
TeleportConfirm,
|
AdvancementTab, //
|
||||||
QueryBlockNBT,
|
Animation, //
|
||||||
SetDifficulty,
|
ChatCommand, // Added in 1.19
|
||||||
ChatMessage,
|
ChatMessage, //
|
||||||
ClientStatus,
|
ChatPreview, // Added in 1.19
|
||||||
ClientSettings,
|
ClickWindow, //
|
||||||
TabComplete,
|
ClickWindowButton, //
|
||||||
WindowConfirmation,
|
ClientSettings, //
|
||||||
ClickWindowButton,
|
ClientStatus, //
|
||||||
ClickWindow,
|
CloseWindow, //
|
||||||
CloseWindow,
|
CraftRecipeRequest, //
|
||||||
PluginMessage,
|
CreativeInventoryAction, //
|
||||||
EditBook,
|
EditBook, //
|
||||||
EntityNBTRequest,
|
EnchantItem, // For 1.13.2 or below
|
||||||
InteractEntity,
|
EntityAction, //
|
||||||
KeepAlive,
|
EntityNBTRequest, //
|
||||||
LockDifficulty,
|
GenerateStructure, // Added in 1.16
|
||||||
PlayerPosition,
|
HeldItemChange, //
|
||||||
PlayerPositionAndRotation,
|
InteractEntity, //
|
||||||
PlayerRotation,
|
KeepAlive, //
|
||||||
PlayerMovement,
|
LockDifficulty, //
|
||||||
VehicleMove,
|
MessageAcknowledgment, // Added in 1.19.1 (1.19.2)
|
||||||
SteerBoat,
|
NameItem, //
|
||||||
PickItem,
|
PickItem, //
|
||||||
CraftRecipeRequest,
|
PlayerAbilities, //
|
||||||
PlayerAbilities,
|
PlayerBlockPlacement, //
|
||||||
PlayerDigging,
|
PlayerDigging, //
|
||||||
EntityAction,
|
PlayerMovement, //
|
||||||
SteerVehicle,
|
PlayerPosition, //
|
||||||
RecipeBookData,
|
PlayerPositionAndRotation, //
|
||||||
NameItem,
|
PlayerRotation, //
|
||||||
ResourcePackStatus,
|
PluginMessage, //
|
||||||
AdvancementTab,
|
Pong, //
|
||||||
SelectTrade,
|
PrepareCraftingGrid, // For 1.12 - 1.12.1 only
|
||||||
SetBeaconEffect,
|
QueryBlockNBT, //
|
||||||
HeldItemChange,
|
RecipeBookData, //
|
||||||
UpdateCommandBlock,
|
ResourcePackStatus, //
|
||||||
UpdateCommandBlockMinecart,
|
SelectTrade, //
|
||||||
CreativeInventoryAction,
|
SetBeaconEffect, //
|
||||||
UpdateJigsawBlock,
|
SetDifficulty, //
|
||||||
UpdateStructureBlock,
|
SetDisplayedRecipe, // Added in 1.16.2
|
||||||
UpdateSign,
|
SetRecipeBookState, // Added in 1.16.2
|
||||||
Animation,
|
Spectate, //
|
||||||
Spectate,
|
SteerBoat, //
|
||||||
PlayerBlockPlacement,
|
SteerVehicle, //
|
||||||
UseItem,
|
TabComplete, //
|
||||||
Pong,
|
TeleportConfirm, //
|
||||||
PrepareCraftingGrid, // For 1.12 - 1.12.1 only
|
Unknown, // For old version packet that have been removed and not used by mcc
|
||||||
EnchantItem, // For 1.13.2 or below
|
UpdateCommandBlock, //
|
||||||
GenerateStructure, // Added in 1.16
|
UpdateCommandBlockMinecart, //
|
||||||
SetDisplayedRecipe, // Added in 1.16.2
|
UpdateJigsawBlock, //
|
||||||
SetRecipeBookState, // Added in 1.16.2
|
UpdateSign, //
|
||||||
Unknown, // For old version packet that have been removed and not used by mcc
|
UpdateStructureBlock, //
|
||||||
|
UseItem, //
|
||||||
// Added in 1.19
|
VehicleMove, //
|
||||||
ChatCommand,
|
WindowConfirmation, //
|
||||||
ChatPreview,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using System.Security.Cryptography;
|
||||||
using MinecraftClient.Mapping;
|
using MinecraftClient.Mapping;
|
||||||
using MinecraftClient.Inventory;
|
using MinecraftClient.Inventory;
|
||||||
using MinecraftClient.Protocol.Keys;
|
using MinecraftClient.Protocol.Keys;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Handlers
|
namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
|
|
@ -559,7 +560,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
public bool Login(PlayerKeyPair playerKeyPair)
|
public bool Login(PlayerKeyPair playerKeyPair)
|
||||||
{
|
{
|
||||||
if (Handshake(handler.GetUserUUID(), handler.GetUsername(), handler.GetSessionID(), handler.GetServerHost(), handler.GetServerPort()))
|
if (Handshake(handler.GetUserUuidStr(), handler.GetUsername(), handler.GetSessionID(), handler.GetServerHost(), handler.GetServerPort()))
|
||||||
{
|
{
|
||||||
Send(new byte[] { 0xCD, 0 });
|
Send(new byte[] { 0xCD, 0 });
|
||||||
try
|
try
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ using MinecraftClient.Logger;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MinecraftClient.Protocol.Keys;
|
using MinecraftClient.Protocol.Keys;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Handlers
|
namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
|
|
@ -55,6 +56,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
internal const int MC_1_18_1_Version = 757;
|
internal const int MC_1_18_1_Version = 757;
|
||||||
internal const int MC_1_18_2_Version = 758;
|
internal const int MC_1_18_2_Version = 758;
|
||||||
internal const int MC_1_19_Version = 759;
|
internal const int MC_1_19_Version = 759;
|
||||||
|
internal const int MC_1_19_2_Version = 760;
|
||||||
|
|
||||||
private int compression_treshold = 0;
|
private int compression_treshold = 0;
|
||||||
private bool autocomplete_received = false;
|
private bool autocomplete_received = false;
|
||||||
|
|
@ -64,6 +66,11 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
private bool login_phase = true;
|
private bool login_phase = true;
|
||||||
private int protocolVersion;
|
private int protocolVersion;
|
||||||
private int currentDimension;
|
private int currentDimension;
|
||||||
|
private bool isOnlineMode = false;
|
||||||
|
|
||||||
|
private int pendingAcknowledgments = 0;
|
||||||
|
private LastSeenMessagesCollector lastSeenMessagesCollector = new(5);
|
||||||
|
private LastSeenMessageList.Entry? lastReceivedMessage = null;
|
||||||
|
|
||||||
Protocol18Forge pForge;
|
Protocol18Forge pForge;
|
||||||
Protocol18Terrain pTerrain;
|
Protocol18Terrain pTerrain;
|
||||||
|
|
@ -91,85 +98,105 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
this.log = handler.GetLogger();
|
this.log = handler.GetLogger();
|
||||||
this.randomGen = RandomNumberGenerator.Create();
|
this.randomGen = RandomNumberGenerator.Create();
|
||||||
|
|
||||||
if (handler.GetTerrainEnabled() && protocolVersion > MC_1_18_2_Version)
|
if (handler.GetTerrainEnabled() && protocolVersion > MC_1_19_2_Version)
|
||||||
{
|
{
|
||||||
log.Error(Translations.Get("extra.terrainandmovement_disabled"));
|
log.Error(Translations.Get("extra.terrainandmovement_disabled"));
|
||||||
handler.SetTerrainEnabled(false);
|
handler.SetTerrainEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handler.GetInventoryEnabled() && (protocolVersion < MC_1_10_Version || protocolVersion > MC_1_19_Version))
|
if (handler.GetInventoryEnabled() && (protocolVersion < MC_1_10_Version || protocolVersion > MC_1_19_2_Version))
|
||||||
{
|
{
|
||||||
log.Error(Translations.Get("extra.inventory_disabled"));
|
log.Error(Translations.Get("extra.inventory_disabled"));
|
||||||
handler.SetInventoryEnabled(false);
|
handler.SetInventoryEnabled(false);
|
||||||
}
|
}
|
||||||
|
if (handler.GetEntityHandlingEnabled() && (protocolVersion < MC_1_10_Version || protocolVersion > MC_1_19_2_Version))
|
||||||
if (handler.GetEntityHandlingEnabled() && (protocolVersion < MC_1_10_Version || protocolVersion > MC_1_19_Version))
|
|
||||||
{
|
{
|
||||||
log.Error(Translations.Get("extra.entity_disabled"));
|
log.Error(Translations.Get("extra.entity_disabled"));
|
||||||
handler.SetEntityHandlingEnabled(false);
|
handler.SetEntityHandlingEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Block palette
|
// Block palette
|
||||||
if (protocolVersion >= MC_1_13_Version)
|
if (protocolVersion > MC_1_19_2_Version && handler.GetTerrainEnabled())
|
||||||
{
|
throw new NotImplementedException(Translations.Get("exception.palette.block"));
|
||||||
if (protocolVersion > MC_1_19_Version && handler.GetTerrainEnabled())
|
|
||||||
throw new NotImplementedException(Translations.Get("exception.palette.block"));
|
|
||||||
|
|
||||||
if (protocolVersion == MC_1_19_Version)
|
if (protocolVersion >= MC_1_19_Version)
|
||||||
Block.Palette = new Palette119();
|
Block.Palette = new Palette119();
|
||||||
else if (protocolVersion >= MC_1_17_Version)
|
else if (protocolVersion >= MC_1_17_Version)
|
||||||
Block.Palette = new Palette117();
|
Block.Palette = new Palette117();
|
||||||
else if (protocolVersion >= MC_1_16_Version)
|
else if (protocolVersion >= MC_1_16_Version)
|
||||||
Block.Palette = new Palette116();
|
Block.Palette = new Palette116();
|
||||||
else if (protocolVersion >= MC_1_15_Version)
|
else if (protocolVersion >= MC_1_15_Version)
|
||||||
Block.Palette = new Palette115();
|
Block.Palette = new Palette115();
|
||||||
else if (protocolVersion >= MC_1_14_Version)
|
else if (protocolVersion >= MC_1_14_Version)
|
||||||
Block.Palette = new Palette114();
|
Block.Palette = new Palette114();
|
||||||
else Block.Palette = new Palette113();
|
else if (protocolVersion >= MC_1_13_Version)
|
||||||
|
Block.Palette = new Palette113();
|
||||||
}
|
else
|
||||||
else Block.Palette = new Palette112();
|
Block.Palette = new Palette112();
|
||||||
|
|
||||||
// Entity palette
|
// Entity palette
|
||||||
if (protocolVersion >= MC_1_13_Version)
|
if (protocolVersion > MC_1_19_2_Version && handler.GetEntityHandlingEnabled())
|
||||||
{
|
throw new NotImplementedException(Translations.Get("exception.palette.entity"));
|
||||||
if (protocolVersion > MC_1_19_Version && handler.GetEntityHandlingEnabled())
|
|
||||||
throw new NotImplementedException(Translations.Get("exception.palette.entity"));
|
|
||||||
|
|
||||||
if (protocolVersion == MC_1_19_Version)
|
if (protocolVersion >= MC_1_19_Version)
|
||||||
entityPalette = new EntityPalette119();
|
entityPalette = new EntityPalette119();
|
||||||
else if (protocolVersion >= MC_1_17_Version)
|
else if (protocolVersion >= MC_1_17_Version)
|
||||||
entityPalette = new EntityPalette117();
|
entityPalette = new EntityPalette117();
|
||||||
else if (protocolVersion >= MC_1_16_2_Version)
|
else if (protocolVersion >= MC_1_16_2_Version)
|
||||||
entityPalette = new EntityPalette1162();
|
entityPalette = new EntityPalette1162();
|
||||||
else if (protocolVersion >= MC_1_16_Version)
|
else if (protocolVersion >= MC_1_16_Version)
|
||||||
entityPalette = new EntityPalette1161();
|
entityPalette = new EntityPalette1161();
|
||||||
else if (protocolVersion >= MC_1_15_Version)
|
else if (protocolVersion >= MC_1_15_Version)
|
||||||
entityPalette = new EntityPalette115();
|
entityPalette = new EntityPalette115();
|
||||||
else if (protocolVersion >= MC_1_14_Version)
|
else if (protocolVersion >= MC_1_14_Version)
|
||||||
entityPalette = new EntityPalette114();
|
entityPalette = new EntityPalette114();
|
||||||
else entityPalette = new EntityPalette113();
|
else if (protocolVersion >= MC_1_13_Version)
|
||||||
}
|
entityPalette = new EntityPalette113();
|
||||||
else entityPalette = new EntityPalette112();
|
else
|
||||||
|
entityPalette = new EntityPalette112();
|
||||||
|
|
||||||
// Item palette
|
// Item palette
|
||||||
if (protocolVersion >= MC_1_16_2_Version)
|
if (protocolVersion > MC_1_19_2_Version && handler.GetInventoryEnabled())
|
||||||
{
|
throw new NotImplementedException(Translations.Get("exception.palette.item"));
|
||||||
if (protocolVersion > MC_1_19_Version && handler.GetInventoryEnabled())
|
|
||||||
throw new NotImplementedException(Translations.Get("exception.palette.item"));
|
|
||||||
|
|
||||||
if (protocolVersion == MC_1_19_Version)
|
if (protocolVersion >= MC_1_19_Version)
|
||||||
itemPalette = new ItemPalette119();
|
itemPalette = new ItemPalette119();
|
||||||
else if (protocolVersion >= MC_1_18_1_Version)
|
else if (protocolVersion >= MC_1_18_1_Version)
|
||||||
itemPalette = new ItemPalette118();
|
itemPalette = new ItemPalette118();
|
||||||
else if (protocolVersion >= MC_1_17_Version)
|
else if (protocolVersion >= MC_1_17_Version)
|
||||||
itemPalette = new ItemPalette117();
|
itemPalette = new ItemPalette117();
|
||||||
else if (protocolVersion >= MC_1_16_2_Version)
|
else if (protocolVersion >= MC_1_16_2_Version)
|
||||||
if (protocolVersion >= MC_1_16_2_Version)
|
itemPalette = new ItemPalette1162();
|
||||||
itemPalette = new ItemPalette1162();
|
else if (protocolVersion >= MC_1_16_1_Version)
|
||||||
else itemPalette = new ItemPalette1161();
|
itemPalette = new ItemPalette1161();
|
||||||
}
|
else
|
||||||
else itemPalette = new ItemPalette115();
|
itemPalette = new ItemPalette115();
|
||||||
|
|
||||||
|
// MessageType
|
||||||
|
// You can find it in https://wiki.vg/Protocol#Player_Chat_Message or /net/minecraft/network/message/MessageType.java
|
||||||
|
if (this.protocolVersion >= MC_1_19_2_Version)
|
||||||
|
ChatParser.ChatId2Type = new()
|
||||||
|
{
|
||||||
|
{ 0, ChatParser.MessageType.CHAT },
|
||||||
|
{ 1, ChatParser.MessageType.SAY_COMMAND },
|
||||||
|
{ 2, ChatParser.MessageType.MSG_COMMAND_INCOMING },
|
||||||
|
{ 3, ChatParser.MessageType.MSG_COMMAND_OUTGOING },
|
||||||
|
{ 4, ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING },
|
||||||
|
{ 5, ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING },
|
||||||
|
{ 6, ChatParser.MessageType.EMOTE_COMMAND },
|
||||||
|
};
|
||||||
|
else if (this.protocolVersion == MC_1_19_Version)
|
||||||
|
ChatParser.ChatId2Type = new()
|
||||||
|
{
|
||||||
|
{ 0, ChatParser.MessageType.CHAT },
|
||||||
|
{ 1, ChatParser.MessageType.RAW_MSG },
|
||||||
|
{ 2, ChatParser.MessageType.RAW_MSG },
|
||||||
|
{ 3, ChatParser.MessageType.SAY_COMMAND },
|
||||||
|
{ 4, ChatParser.MessageType.MSG_COMMAND_INCOMING },
|
||||||
|
{ 5, ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING },
|
||||||
|
{ 6, ChatParser.MessageType.EMOTE_COMMAND },
|
||||||
|
{ 7, ChatParser.MessageType.RAW_MSG },
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -328,26 +355,22 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
int worldCount = dataTypes.ReadNextVarInt(packetData); // Dimension Count (World Count) - 1.16 and above
|
int worldCount = dataTypes.ReadNextVarInt(packetData); // Dimension Count (World Count) - 1.16 and above
|
||||||
for (int i = 0; i < worldCount; i++)
|
for (int i = 0; i < worldCount; i++)
|
||||||
dataTypes.ReadNextString(packetData); // Dimension Names (World Names) - 1.16 and above
|
dataTypes.ReadNextString(packetData); // Dimension Names (World Names) - 1.16 and above
|
||||||
dataTypes.ReadNextNbt(packetData); // Registry Codec (Dimension Codec) - 1.16 and above
|
var registryCodec = dataTypes.ReadNextNbt(packetData); // Registry Codec (Dimension Codec) - 1.16 and above
|
||||||
|
World.StoreDimensionList(registryCodec);
|
||||||
}
|
}
|
||||||
|
|
||||||
string? currentDimensionName = null;
|
|
||||||
Dictionary<string, object>? currentDimensionType = null;
|
|
||||||
|
|
||||||
// Current dimension
|
// Current dimension
|
||||||
// NBT Tag Compound: 1.16.2 and above
|
// String: 1.19 and above
|
||||||
|
// NBT Tag Compound: [1.16.2 to 1.18.2]
|
||||||
// String identifier: 1.16 and 1.16.1
|
// String identifier: 1.16 and 1.16.1
|
||||||
// varInt: [1.9.1 to 1.15.2]
|
// varInt: [1.9.1 to 1.15.2]
|
||||||
// byte: below 1.9.1
|
// byte: below 1.9.1
|
||||||
if (protocolVersion >= MC_1_16_Version)
|
if (protocolVersion >= MC_1_16_Version)
|
||||||
{
|
{
|
||||||
if (protocolVersion >= MC_1_19_Version)
|
if (protocolVersion >= MC_1_19_Version)
|
||||||
{
|
dataTypes.ReadNextString(packetData); // Dimension Type: Identifier
|
||||||
dataTypes.ReadNextString(packetData); // Dimension Type: Identifier
|
|
||||||
currentDimensionType = new Dictionary<string, object>();
|
|
||||||
}
|
|
||||||
else if (protocolVersion >= MC_1_16_2_Version)
|
else if (protocolVersion >= MC_1_16_2_Version)
|
||||||
currentDimensionType = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
|
dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
|
||||||
else
|
else
|
||||||
dataTypes.ReadNextString(packetData);
|
dataTypes.ReadNextString(packetData);
|
||||||
this.currentDimension = 0;
|
this.currentDimension = 0;
|
||||||
|
|
@ -361,10 +384,10 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
||||||
|
|
||||||
if (protocolVersion >= MC_1_16_Version)
|
if (protocolVersion >= MC_1_16_Version)
|
||||||
currentDimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above
|
{
|
||||||
|
string dimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above
|
||||||
if (protocolVersion >= MC_1_16_2_Version)
|
World.SetDimension(dimensionName);
|
||||||
World.SetDimension(currentDimensionName, currentDimensionType);
|
}
|
||||||
|
|
||||||
if (protocolVersion >= MC_1_15_Version)
|
if (protocolVersion >= MC_1_15_Version)
|
||||||
dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above
|
dataTypes.ReadNextLong(packetData); // Hashed world seed - 1.15 and above
|
||||||
|
|
@ -392,8 +415,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location
|
bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location
|
||||||
if (hasDeathLocation)
|
if (hasDeathLocation)
|
||||||
{
|
{
|
||||||
dataTypes.ReadNextString(packetData); // Death dimension name: Identifier
|
dataTypes.ReadNextString(packetData); // Death dimension name: Identifier
|
||||||
dataTypes.ReadNextLocation(packetData); // Death location
|
dataTypes.ReadNextLocation(packetData); // Death location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -422,7 +445,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
handler.OnTextReceived(new(message, true, messageType, senderUUID));
|
handler.OnTextReceived(new(message, true, messageType, senderUUID));
|
||||||
}
|
}
|
||||||
else // 1.19+
|
else if (protocolVersion == MC_1_19_Version) // 1.19
|
||||||
{
|
{
|
||||||
string signedChat = dataTypes.ReadNextString(packetData);
|
string signedChat = dataTypes.ReadNextString(packetData);
|
||||||
|
|
||||||
|
|
@ -446,38 +469,134 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
byte[] messageSignature = dataTypes.ReadNextByteArray(packetData);
|
byte[] messageSignature = dataTypes.ReadNextByteArray(packetData);
|
||||||
|
|
||||||
PlayerInfo? player = handler.GetPlayerInfo(senderUUID);
|
bool verifyResult;
|
||||||
bool verifyResult = player == null ? false : player.VerifyMessage(signedChat, senderUUID, timestamp, salt, ref messageSignature);
|
if (!isOnlineMode)
|
||||||
|
verifyResult = false;
|
||||||
|
else if (senderUUID == handler.GetUserUuid())
|
||||||
|
verifyResult = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlayerInfo? player = handler.GetPlayerInfo(senderUUID);
|
||||||
|
verifyResult = player == null ? false : player.VerifyMessage(signedChat, timestamp, salt, ref messageSignature);
|
||||||
|
}
|
||||||
|
|
||||||
handler.OnTextReceived(new(signedChat, true, messageType, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, verifyResult));
|
ChatMessage chat = new(signedChat, true, messageType, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, messageSignature, verifyResult);
|
||||||
|
handler.OnTextReceived(chat);
|
||||||
|
}
|
||||||
|
else // 1.19.1 +
|
||||||
|
{
|
||||||
|
byte[]? precedingSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData) : null;
|
||||||
|
Guid senderUUID = dataTypes.ReadNextUUID(packetData);
|
||||||
|
byte[] headerSignature = dataTypes.ReadNextByteArray(packetData);
|
||||||
|
|
||||||
|
string signedChat = dataTypes.ReadNextString(packetData);
|
||||||
|
string? decorated = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null;
|
||||||
|
|
||||||
|
long timestamp = dataTypes.ReadNextLong(packetData);
|
||||||
|
long salt = dataTypes.ReadNextLong(packetData);
|
||||||
|
|
||||||
|
int lastSeenMessageListLen = dataTypes.ReadNextVarInt(packetData);
|
||||||
|
LastSeenMessageList.Entry[] lastSeenMessageList = new LastSeenMessageList.Entry[lastSeenMessageListLen];
|
||||||
|
for (int i = 0; i < lastSeenMessageListLen; ++i)
|
||||||
|
{
|
||||||
|
Guid user = dataTypes.ReadNextUUID(packetData);
|
||||||
|
byte[] lastSignature = dataTypes.ReadNextByteArray(packetData);
|
||||||
|
lastSeenMessageList[i] = new(user, lastSignature);
|
||||||
|
}
|
||||||
|
LastSeenMessageList lastSeenMessages = new(lastSeenMessageList);
|
||||||
|
|
||||||
|
string? unsignedChatContent = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null;
|
||||||
|
|
||||||
|
int filterEnum = dataTypes.ReadNextVarInt(packetData);
|
||||||
|
if (filterEnum == 2) // PARTIALLY_FILTERED
|
||||||
|
dataTypes.ReadNextULongArray(packetData);
|
||||||
|
|
||||||
|
int chatTypeId = dataTypes.ReadNextVarInt(packetData);
|
||||||
|
string chatName = dataTypes.ReadNextString(packetData);
|
||||||
|
string? targetName = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextString(packetData) : null;
|
||||||
|
|
||||||
|
Dictionary<string, Json.JSONData> chatInfo = Json.ParseJson(chatName).Properties;
|
||||||
|
string senderDisplayName = (chatInfo.ContainsKey("insertion") ? chatInfo["insertion"] : chatInfo["text"]).StringValue;
|
||||||
|
string? senderTeamName = null;
|
||||||
|
ChatParser.MessageType messageTypeEnum = ChatParser.ChatId2Type!.GetValueOrDefault(chatTypeId, ChatParser.MessageType.CHAT);
|
||||||
|
if (targetName != null &&
|
||||||
|
(messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_INCOMING || messageTypeEnum == ChatParser.MessageType.TEAM_MSG_COMMAND_OUTGOING))
|
||||||
|
senderTeamName = Json.ParseJson(targetName).Properties["with"].DataArray[0].Properties["text"].StringValue;
|
||||||
|
|
||||||
|
bool verifyResult;
|
||||||
|
if (!isOnlineMode)
|
||||||
|
verifyResult = false;
|
||||||
|
else if (senderUUID == handler.GetUserUuid())
|
||||||
|
verifyResult = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlayerInfo? player = handler.GetPlayerInfo(senderUUID);
|
||||||
|
if (player == null || !player.IsMessageChainLegal())
|
||||||
|
verifyResult = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool lastVerifyResult = player.IsMessageChainLegal();
|
||||||
|
verifyResult = player.VerifyMessage(signedChat, timestamp, salt, ref headerSignature, ref precedingSignature, lastSeenMessages);
|
||||||
|
if (lastVerifyResult && !verifyResult)
|
||||||
|
log.Warn(Translations.Get("chat.message_chain_broken", senderDisplayName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChatMessage chat = new(signedChat, false, chatTypeId, senderUUID, unsignedChatContent, senderDisplayName, senderTeamName, timestamp, headerSignature, verifyResult);
|
||||||
|
if (isOnlineMode && !chat.lacksSender())
|
||||||
|
this.acknowledge(chat);
|
||||||
|
handler.OnTextReceived(chat);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PacketTypesIn.MessageHeader:
|
||||||
|
if (protocolVersion >= MC_1_19_2_Version)
|
||||||
|
{
|
||||||
|
byte[]? precedingSignature = dataTypes.ReadNextBool(packetData) ? dataTypes.ReadNextByteArray(packetData) : null;
|
||||||
|
Guid senderUUID = dataTypes.ReadNextUUID(packetData);
|
||||||
|
byte[] headerSignature = dataTypes.ReadNextByteArray(packetData);
|
||||||
|
byte[] bodyDigest = dataTypes.ReadNextByteArray(packetData);
|
||||||
|
|
||||||
|
bool verifyResult;
|
||||||
|
if (!isOnlineMode)
|
||||||
|
verifyResult = false;
|
||||||
|
else if (senderUUID == handler.GetUserUuid())
|
||||||
|
verifyResult = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PlayerInfo? player = handler.GetPlayerInfo(senderUUID);
|
||||||
|
if (player == null || !player.IsMessageChainLegal())
|
||||||
|
verifyResult = false;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool lastVerifyResult = player.IsMessageChainLegal();
|
||||||
|
verifyResult = player.VerifyMessageHead(ref precedingSignature, ref headerSignature, ref bodyDigest);
|
||||||
|
if (lastVerifyResult && !verifyResult)
|
||||||
|
log.Warn("Player " + player.DisplayName + "'s message chain is broken!");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketTypesIn.Respawn:
|
case PacketTypesIn.Respawn:
|
||||||
string? dimensionNameInRespawn = null;
|
|
||||||
Dictionary<string, object> dimensionTypeInRespawn = null;
|
|
||||||
if (protocolVersion >= MC_1_16_Version)
|
if (protocolVersion >= MC_1_16_Version)
|
||||||
{
|
{
|
||||||
if (protocolVersion >= MC_1_19_Version)
|
if (protocolVersion >= MC_1_19_Version)
|
||||||
{
|
dataTypes.ReadNextString(packetData); // Dimension Type: Identifier
|
||||||
dataTypes.ReadNextString(packetData); // Dimension Type: Identifier
|
|
||||||
dimensionTypeInRespawn = new Dictionary<string, object>();
|
|
||||||
}
|
|
||||||
else if (protocolVersion >= MC_1_16_2_Version)
|
else if (protocolVersion >= MC_1_16_2_Version)
|
||||||
dimensionTypeInRespawn = dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
|
dataTypes.ReadNextNbt(packetData); // Dimension Type: NBT Tag Compound
|
||||||
else
|
else
|
||||||
dataTypes.ReadNextString(packetData);
|
dataTypes.ReadNextString(packetData);
|
||||||
this.currentDimension = 0;
|
this.currentDimension = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{ // 1.15 and below
|
||||||
// 1.15 and below
|
|
||||||
this.currentDimension = dataTypes.ReadNextInt(packetData);
|
this.currentDimension = dataTypes.ReadNextInt(packetData);
|
||||||
}
|
}
|
||||||
if (protocolVersion >= MC_1_16_Version)
|
|
||||||
dimensionNameInRespawn = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above
|
|
||||||
|
|
||||||
if (protocolVersion >= MC_1_16_2_Version)
|
if (protocolVersion >= MC_1_16_Version)
|
||||||
World.SetDimension(dimensionNameInRespawn, dimensionTypeInRespawn);
|
{
|
||||||
|
string dimensionName = dataTypes.ReadNextString(packetData); // Dimension Name (World Name) - 1.16 and above
|
||||||
|
World.SetDimension(dimensionName);
|
||||||
|
}
|
||||||
|
|
||||||
if (protocolVersion < MC_1_14_Version)
|
if (protocolVersion < MC_1_14_Version)
|
||||||
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
dataTypes.ReadNextByte(packetData); // Difficulty - 1.13 and below
|
||||||
|
|
@ -499,8 +618,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location
|
bool hasDeathLocation = dataTypes.ReadNextBool(packetData); // Has death location
|
||||||
if (hasDeathLocation)
|
if (hasDeathLocation)
|
||||||
{
|
{
|
||||||
dataTypes.ReadNextString(packetData); // Death dimension name: Identifier
|
dataTypes.ReadNextString(packetData); // Death dimension name: Identifier
|
||||||
dataTypes.ReadNextLocation(packetData); // Death location
|
dataTypes.ReadNextLocation(packetData); // Death location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handler.OnRespawn();
|
handler.OnRespawn();
|
||||||
|
|
@ -829,6 +948,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
//handler.OnTextReceived(message, true);
|
//handler.OnTextReceived(message, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case PacketTypesIn.ChatSuggestions:
|
||||||
break;
|
break;
|
||||||
case PacketTypesIn.MapChunkBulk:
|
case PacketTypesIn.MapChunkBulk:
|
||||||
if (protocolVersion < MC_1_9_Version && handler.GetTerrainEnabled())
|
if (protocolVersion < MC_1_9_Version && handler.GetTerrainEnabled())
|
||||||
|
|
@ -904,14 +1025,20 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
string name = dataTypes.ReadNextString(packetData); // Player name
|
string name = dataTypes.ReadNextString(packetData); // Player name
|
||||||
int propNum = dataTypes.ReadNextVarInt(packetData); // Number of properties in the following array
|
int propNum = dataTypes.ReadNextVarInt(packetData); // Number of properties in the following array
|
||||||
|
|
||||||
Tuple<string, string, string>[]? property = null; // Property: Tuple<Name, Value, Signature(empty if there is no signature)
|
// Property: Tuple<Name, Value, Signature(empty if there is no signature)
|
||||||
|
// The Property field looks as in the response of https://wiki.vg/Mojang_API#UUID_to_Profile_and_Skin.2FCape
|
||||||
|
const bool useProperty = false;
|
||||||
|
Tuple<string, string, string?>[]? properties = useProperty ?
|
||||||
|
new Tuple<string, string, string?>[propNum] : null;
|
||||||
for (int p = 0; p < propNum; p++)
|
for (int p = 0; p < propNum; p++)
|
||||||
{
|
{
|
||||||
string key = dataTypes.ReadNextString(packetData); // Name
|
string propertyName = dataTypes.ReadNextString(packetData); // Name: String (32767)
|
||||||
string val = dataTypes.ReadNextString(packetData); // Value
|
string val = dataTypes.ReadNextString(packetData); // Value: String (32767)
|
||||||
|
string? propertySignature = null;
|
||||||
if (dataTypes.ReadNextBool(packetData)) // Is Signed
|
if (dataTypes.ReadNextBool(packetData)) // Is Signed
|
||||||
dataTypes.ReadNextString(packetData); // Signature
|
propertySignature = dataTypes.ReadNextString(packetData); // Signature: String (32767)
|
||||||
|
if (useProperty)
|
||||||
|
properties![p] = new(propertyName, val, propertySignature);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gameMode = dataTypes.ReadNextVarInt(packetData); // Gamemode
|
int gameMode = dataTypes.ReadNextVarInt(packetData); // Gamemode
|
||||||
|
|
@ -942,7 +1069,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.OnPlayerJoin(new PlayerInfo(uuid, name, property, gameMode, ping, displayName, keyExpiration, publicKey, signature));
|
handler.OnPlayerJoin(new PlayerInfo(uuid, name, properties, gameMode, ping, displayName, keyExpiration, publicKey, signature));
|
||||||
break;
|
break;
|
||||||
case 0x01: //Update gamemode
|
case 0x01: //Update gamemode
|
||||||
handler.OnGamemodeUpdate(uuid, dataTypes.ReadNextVarInt(packetData));
|
handler.OnGamemodeUpdate(uuid, dataTypes.ReadNextVarInt(packetData));
|
||||||
|
|
@ -1291,13 +1418,16 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
int EntityID = dataTypes.ReadNextVarInt(packetData);
|
int EntityID = dataTypes.ReadNextVarInt(packetData);
|
||||||
Dictionary<int, object> metadata = dataTypes.ReadNextMetadata(packetData, itemPalette);
|
Dictionary<int, object> metadata = dataTypes.ReadNextMetadata(packetData, itemPalette);
|
||||||
|
|
||||||
// See https://wiki.vg/Entity_metadata#Living_Entity
|
int healthField; // See https://wiki.vg/Entity_metadata#Living_Entity
|
||||||
int healthField = 7; // From 1.10 to 1.13.2
|
if (protocolVersion > MC_1_19_2_Version)
|
||||||
if (protocolVersion >= MC_1_14_Version)
|
throw new NotImplementedException(Translations.Get("exception.palette.healthfield"));
|
||||||
healthField = 8; // 1.14 and above
|
else if (protocolVersion >= MC_1_17_Version) // 1.17 and above
|
||||||
if (protocolVersion >= MC_1_17_Version)
|
healthField = 9;
|
||||||
healthField = 9; // 1.17 and above
|
else if (protocolVersion >= MC_1_14_Version) // 1.14 and above
|
||||||
if (protocolVersion > MC_1_19_Version)
|
healthField = 8;
|
||||||
|
else if (protocolVersion >= MC_1_10_Version) // 1.10 and above
|
||||||
|
healthField = 7;
|
||||||
|
else
|
||||||
throw new NotImplementedException(Translations.Get("exception.palette.healthfield"));
|
throw new NotImplementedException(Translations.Get("exception.palette.healthfield"));
|
||||||
|
|
||||||
if (metadata.ContainsKey(healthField) && metadata[healthField] != null && metadata[healthField].GetType() == typeof(float))
|
if (metadata.ContainsKey(healthField) && metadata[healthField] != null && metadata[healthField].GetType() == typeof(float))
|
||||||
|
|
@ -1541,13 +1671,27 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
fullLoginPacket.AddRange(dataTypes.GetBool(true)); // Has Sig Data
|
fullLoginPacket.AddRange(dataTypes.GetBool(true)); // Has Sig Data
|
||||||
fullLoginPacket.AddRange(dataTypes.GetLong(playerKeyPair.GetExpirationMilliseconds())); // Expiration time
|
fullLoginPacket.AddRange(dataTypes.GetLong(playerKeyPair.GetExpirationMilliseconds())); // Expiration time
|
||||||
fullLoginPacket.AddRange(dataTypes.GetArray(playerKeyPair.PublicKey.Key)); // Public key received from Microsoft API
|
fullLoginPacket.AddRange(dataTypes.GetArray(playerKeyPair.PublicKey.Key)); // Public key received from Microsoft API
|
||||||
fullLoginPacket.AddRange(dataTypes.GetArray(playerKeyPair.PublicKey.Signature)); // Public key signature received from Microsoft API
|
if (protocolVersion >= MC_1_19_2_Version)
|
||||||
|
fullLoginPacket.AddRange(dataTypes.GetArray(playerKeyPair.PublicKey.SignatureV2!)); // Public key signature received from Microsoft API
|
||||||
|
else
|
||||||
|
fullLoginPacket.AddRange(dataTypes.GetArray(playerKeyPair.PublicKey.Signature!)); // Public key signature received from Microsoft API
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (protocolVersion >= MC_1_19_2_Version)
|
||||||
|
{
|
||||||
|
Guid uuid = handler.GetUserUuid();
|
||||||
|
if (uuid == Guid.Empty)
|
||||||
|
fullLoginPacket.AddRange(dataTypes.GetBool(false)); // Has UUID
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fullLoginPacket.AddRange(dataTypes.GetBool(true)); // Has UUID
|
||||||
|
fullLoginPacket.AddRange(dataTypes.GetUUID(uuid)); // UUID
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SendPacket(0x00, fullLoginPacket);
|
SendPacket(0x00, fullLoginPacket);
|
||||||
|
|
||||||
int packetID = -1;
|
int packetID = -1;
|
||||||
Queue<byte> packetData = new Queue<byte>();
|
Queue<byte> packetData = new();
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
ReadNextPacket(ref packetID, packetData);
|
ReadNextPacket(ref packetID, packetData);
|
||||||
|
|
@ -1558,10 +1702,11 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
else if (packetID == 0x01) //Encryption request
|
else if (packetID == 0x01) //Encryption request
|
||||||
{
|
{
|
||||||
|
this.isOnlineMode = true;
|
||||||
string serverID = dataTypes.ReadNextString(packetData);
|
string serverID = dataTypes.ReadNextString(packetData);
|
||||||
byte[] serverPublicKey = dataTypes.ReadNextByteArray(packetData);
|
byte[] serverPublicKey = dataTypes.ReadNextByteArray(packetData);
|
||||||
byte[] token = dataTypes.ReadNextByteArray(packetData);
|
byte[] token = dataTypes.ReadNextByteArray(packetData);
|
||||||
return StartEncryption(handler.GetUserUUID(), handler.GetSessionID(), token, serverID, serverPublicKey, playerKeyPair);
|
return StartEncryption(handler.GetUserUuidStr(), handler.GetSessionID(), token, serverID, serverPublicKey, playerKeyPair);
|
||||||
}
|
}
|
||||||
else if (packetID == 0x02) //Login successful
|
else if (packetID == 0x02) //Login successful
|
||||||
{
|
{
|
||||||
|
|
@ -1753,7 +1898,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// Ping a Minecraft server to get information about the server
|
/// Ping a Minecraft server to get information about the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if ping was successful</returns>
|
/// <returns>True if ping was successful</returns>
|
||||||
public static bool doPing(string host, int port, ref int protocolVersion, ref ForgeInfo? forgeInfo)
|
public static bool doPing(string host, int port, ref int protocolversion, ref ForgeInfo? forgeInfo)
|
||||||
{
|
{
|
||||||
string version = "";
|
string version = "";
|
||||||
TcpClient tcp = ProxyHandler.newTcpClient(host, port);
|
TcpClient tcp = ProxyHandler.newTcpClient(host, port);
|
||||||
|
|
@ -1805,12 +1950,12 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
//Retrieve protocol version number for handling this server
|
//Retrieve protocol version number for handling this server
|
||||||
if (versionData.Properties.ContainsKey("protocol"))
|
if (versionData.Properties.ContainsKey("protocol"))
|
||||||
protocolVersion = int.Parse(versionData.Properties["protocol"].StringValue);
|
protocolversion = int.Parse(versionData.Properties["protocol"].StringValue);
|
||||||
|
|
||||||
// Check for forge on the server.
|
// Check for forge on the server.
|
||||||
Protocol18Forge.ServerInfoCheckForge(jsonData, ref forgeInfo);
|
Protocol18Forge.ServerInfoCheckForge(jsonData, ref forgeInfo);
|
||||||
|
|
||||||
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.server_protocol", version, protocolVersion + (forgeInfo != null ? Translations.Get("mcc.with_forge") : "")));
|
ConsoleIO.WriteLineFormatted(Translations.Get("mcc.server_protocol", version, protocolversion + (forgeInfo != null ? Translations.Get("mcc.with_forge") : "")));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1843,41 +1988,87 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
return protocolVersion;
|
return protocolVersion;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send MessageAcknowledgment packet
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="acknowledgment">Message acknowledgment</param>
|
||||||
|
/// <returns>True if properly sent</returns>
|
||||||
|
public bool SendMessageAcknowledgment(LastSeenMessageList.Acknowledgment acknowledgment)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] fields = dataTypes.GetAcknowledgment(acknowledgment, isOnlineMode);
|
||||||
|
|
||||||
|
SendPacket(PacketTypesOut.MessageAcknowledgment, fields);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (SocketException) { return false; }
|
||||||
|
catch (System.IO.IOException) { return false; }
|
||||||
|
catch (ObjectDisposedException) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public LastSeenMessageList.Acknowledgment consumeAcknowledgment()
|
||||||
|
{
|
||||||
|
this.pendingAcknowledgments = 0;
|
||||||
|
return new LastSeenMessageList.Acknowledgment(this.lastSeenMessagesCollector.GetLastSeenMessages(), this.lastReceivedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void acknowledge(ChatMessage message)
|
||||||
|
{
|
||||||
|
LastSeenMessageList.Entry? entry = message.toLastSeenMessageEntry();
|
||||||
|
|
||||||
|
if (entry != null)
|
||||||
|
{
|
||||||
|
lastSeenMessagesCollector.Add(entry);
|
||||||
|
lastReceivedMessage = null;
|
||||||
|
|
||||||
|
if (pendingAcknowledgments++ > 64)
|
||||||
|
SendMessageAcknowledgment(this.consumeAcknowledgment());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The signable argument names and their values from command
|
/// The signable argument names and their values from command
|
||||||
/// Signature will used in Vanilla's say, me, msg, teammsg, ban, banip, and kick commands.
|
/// Signature will used in Vanilla's say, me, msg, teammsg, ban, banip, and kick commands.
|
||||||
/// https://gist.github.com/kennytv/ed783dd244ca0321bbd882c347892874#signed-command-arguments
|
/// https://gist.github.com/kennytv/ed783dd244ca0321bbd882c347892874#signed-command-arguments
|
||||||
|
/// You can find all the commands that need to be signed by searching for "MessageArgumentType.getSignedMessage" in the source code.
|
||||||
|
/// Don't forget to handle the redirected commands, e.g. /tm, /w
|
||||||
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="command">Command</param>
|
/// <param name="command">Command</param>
|
||||||
/// <returns> List< Argument Name, Argument Value > </returns>
|
/// <returns> List< Argument Name, Argument Value > </returns>
|
||||||
private List<Tuple<string, string>> collectCommandArguments(string command)
|
private List<Tuple<string, string>>? CollectCommandArguments(string command)
|
||||||
{
|
{
|
||||||
List<Tuple<string, string>> needSigned = new();
|
if (!isOnlineMode || !Settings.SignMessageInCommand)
|
||||||
|
return null;
|
||||||
|
|
||||||
if (!Settings.SignMessageInCommand)
|
List<Tuple<string, string>> needSigned = new();
|
||||||
return needSigned;
|
|
||||||
|
|
||||||
string[] argStage1 = command.Split(' ', 2, StringSplitOptions.None);
|
string[] argStage1 = command.Split(' ', 2, StringSplitOptions.None);
|
||||||
if (argStage1.Length == 2)
|
if (argStage1.Length == 2)
|
||||||
{
|
{
|
||||||
/* /me <action>
|
/* /me <action>
|
||||||
/say <message>
|
/say <message>
|
||||||
/teammsg <message> */
|
/teammsg <message>
|
||||||
|
/tm <message> */
|
||||||
if (argStage1[0] == "me")
|
if (argStage1[0] == "me")
|
||||||
needSigned.Add(new("action", argStage1[1]));
|
needSigned.Add(new("action", argStage1[1]));
|
||||||
else if (argStage1[0] == "say" || argStage1[0] == "teammsg")
|
else if (argStage1[0] == "say" || argStage1[0] == "teammsg" || argStage1[0] == "tm")
|
||||||
needSigned.Add(new("message", argStage1[1]));
|
needSigned.Add(new("message", argStage1[1]));
|
||||||
else if (argStage1[0] == "msg" || argStage1[0] == "ban" || argStage1[0] == "ban-ip" || argStage1[0] == "kick")
|
else if (argStage1[0] == "msg" || argStage1[0] == "tell" || argStage1[0] == "w" ||
|
||||||
|
argStage1[0] == "ban" || argStage1[0] == "ban-ip" || argStage1[0] == "kick")
|
||||||
{
|
{
|
||||||
/* /msg <targets> <message>
|
/* /msg <targets> <message>
|
||||||
|
/tell <targets> <message>
|
||||||
|
/w <targets> <message>
|
||||||
/ban <target> [<reason>]
|
/ban <target> [<reason>]
|
||||||
/ban-ip <target> [<reason>]
|
/ban-ip <target> [<reason>]
|
||||||
/kick <target> [<reason>] */
|
/kick <target> [<reason>] */
|
||||||
string[] argStage2 = argStage1[1].Split(' ', 2, StringSplitOptions.None);
|
string[] argStage2 = argStage1[1].Split(' ', 2, StringSplitOptions.None);
|
||||||
if (argStage2.Length == 2)
|
if (argStage2.Length == 2)
|
||||||
{
|
{
|
||||||
if (argStage1[0] == "msg")
|
if (argStage1[0] == "msg" || argStage1[0] == "tell" || argStage1[0] == "w")
|
||||||
needSigned.Add(new("message", argStage2[1]));
|
needSigned.Add(new("message", argStage2[1]));
|
||||||
else if (argStage1[0] == "ban" || argStage1[0] == "ban-ip" || argStage1[0] == "kick")
|
else if (argStage1[0] == "ban" || argStage1[0] == "ban-ip" || argStage1[0] == "kick")
|
||||||
needSigned.Add(new("reason", argStage2[1]));
|
needSigned.Add(new("reason", argStage2[1]));
|
||||||
|
|
@ -1889,7 +2080,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Send a chat command to the server
|
/// Send a chat command to the server - 1.19 and above
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="command">Command</param>
|
/// <param name="command">Command</param>
|
||||||
/// <param name="playerKeyPair">PlayerKeyPair</param>
|
/// <param name="playerKeyPair">PlayerKeyPair</param>
|
||||||
|
|
@ -1906,6 +2097,9 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
LastSeenMessageList.Acknowledgment? acknowledgment =
|
||||||
|
(protocolVersion >= MC_1_19_2_Version) ? this.consumeAcknowledgment() : null;
|
||||||
|
|
||||||
List<byte> fields = new();
|
List<byte> fields = new();
|
||||||
|
|
||||||
// Command: String
|
// Command: String
|
||||||
|
|
@ -1915,24 +2109,25 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
DateTimeOffset timeNow = DateTimeOffset.UtcNow;
|
DateTimeOffset timeNow = DateTimeOffset.UtcNow;
|
||||||
fields.AddRange(dataTypes.GetLong(timeNow.ToUnixTimeMilliseconds()));
|
fields.AddRange(dataTypes.GetLong(timeNow.ToUnixTimeMilliseconds()));
|
||||||
|
|
||||||
List<Tuple<string, string>> needSigned = collectCommandArguments(command); // List< Argument Name, Argument Value >
|
List<Tuple<string, string>>? needSigned =
|
||||||
// foreach (var msg in needSigned)
|
playerKeyPair != null ? CollectCommandArguments(command) : null; // List< Argument Name, Argument Value >
|
||||||
// log.Info("<" + msg.Item1 + ">: " + msg.Item2);
|
if (needSigned == null || needSigned!.Count == 0)
|
||||||
if (needSigned.Count == 0 || playerKeyPair == null || !Settings.SignMessageInCommand)
|
|
||||||
{
|
{
|
||||||
fields.AddRange(dataTypes.GetLong(0)); // Salt: Long
|
fields.AddRange(dataTypes.GetLong(0)); // Salt: Long
|
||||||
fields.AddRange(dataTypes.GetVarInt(0)); // Signature Length: VarInt
|
fields.AddRange(dataTypes.GetVarInt(0)); // Signature Length: VarInt
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string uuid = handler.GetUserUUID()!;
|
Guid uuid = handler.GetUserUuid();
|
||||||
byte[] salt = GenerateSalt();
|
byte[] salt = GenerateSalt();
|
||||||
fields.AddRange(salt); // Salt: Long
|
fields.AddRange(salt); // Salt: Long
|
||||||
fields.AddRange(dataTypes.GetVarInt(needSigned.Count)); // Signature Length: VarInt
|
fields.AddRange(dataTypes.GetVarInt(needSigned.Count)); // Signature Length: VarInt
|
||||||
foreach (var argument in needSigned)
|
foreach (var argument in needSigned)
|
||||||
{
|
{
|
||||||
fields.AddRange(dataTypes.GetString(argument.Item1)); // Argument name: String
|
fields.AddRange(dataTypes.GetString(argument.Item1)); // Argument name: String
|
||||||
byte[] sign = playerKeyPair.PrivateKey.SignMessage(argument.Item2, uuid, timeNow, ref salt);
|
byte[] sign = (protocolVersion >= MC_1_19_2_Version) ?
|
||||||
|
playerKeyPair!.PrivateKey.SignMessage(argument.Item2, uuid, timeNow, ref salt, acknowledgment!.lastSeen) :
|
||||||
|
playerKeyPair!.PrivateKey.SignMessage(argument.Item2, uuid, timeNow, ref salt);
|
||||||
fields.AddRange(dataTypes.GetVarInt(sign.Length)); // Signature length: VarInt
|
fields.AddRange(dataTypes.GetVarInt(sign.Length)); // Signature length: VarInt
|
||||||
fields.AddRange(sign); // Signature: Byte Array
|
fields.AddRange(sign); // Signature: Byte Array
|
||||||
}
|
}
|
||||||
|
|
@ -1941,6 +2136,12 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
// Signed Preview: Boolean
|
// Signed Preview: Boolean
|
||||||
fields.AddRange(dataTypes.GetBool(false));
|
fields.AddRange(dataTypes.GetBool(false));
|
||||||
|
|
||||||
|
if (protocolVersion >= MC_1_19_2_Version)
|
||||||
|
{
|
||||||
|
// Message Acknowledgment
|
||||||
|
fields.AddRange(dataTypes.GetAcknowledgment(acknowledgment!, isOnlineMode));
|
||||||
|
}
|
||||||
|
|
||||||
SendPacket(PacketTypesOut.ChatCommand, fields);
|
SendPacket(PacketTypesOut.ChatCommand, fields);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -1973,11 +2174,14 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
if (protocolVersion >= MC_1_19_Version)
|
if (protocolVersion >= MC_1_19_Version)
|
||||||
{
|
{
|
||||||
|
LastSeenMessageList.Acknowledgment? acknowledgment =
|
||||||
|
(protocolVersion >= MC_1_19_2_Version) ? this.consumeAcknowledgment() : null;
|
||||||
|
|
||||||
// Timestamp: Instant(Long)
|
// Timestamp: Instant(Long)
|
||||||
DateTimeOffset timeNow = DateTimeOffset.UtcNow;
|
DateTimeOffset timeNow = DateTimeOffset.UtcNow;
|
||||||
fields.AddRange(dataTypes.GetLong(timeNow.ToUnixTimeMilliseconds()));
|
fields.AddRange(dataTypes.GetLong(timeNow.ToUnixTimeMilliseconds()));
|
||||||
|
|
||||||
if (playerKeyPair == null || !Settings.SignChat)
|
if (!isOnlineMode || playerKeyPair == null || !Settings.SignChat)
|
||||||
{
|
{
|
||||||
fields.AddRange(dataTypes.GetLong(0)); // Salt: Long
|
fields.AddRange(dataTypes.GetLong(0)); // Salt: Long
|
||||||
fields.AddRange(dataTypes.GetVarInt(0)); // Signature Length: VarInt
|
fields.AddRange(dataTypes.GetVarInt(0)); // Signature Length: VarInt
|
||||||
|
|
@ -1989,14 +2193,22 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
fields.AddRange(salt);
|
fields.AddRange(salt);
|
||||||
|
|
||||||
// Signature Length & Signature: (VarInt) and Byte Array
|
// Signature Length & Signature: (VarInt) and Byte Array
|
||||||
string uuid = handler.GetUserUUID()!;
|
Guid uuid = handler.GetUserUuid();
|
||||||
byte[] sign = playerKeyPair.PrivateKey.SignMessage(message, uuid, timeNow, ref salt);
|
byte[] sign = (protocolVersion >= MC_1_19_2_Version) ?
|
||||||
|
playerKeyPair.PrivateKey.SignMessage(message, uuid, timeNow, ref salt, acknowledgment!.lastSeen) :
|
||||||
|
playerKeyPair.PrivateKey.SignMessage(message, uuid, timeNow, ref salt);
|
||||||
fields.AddRange(dataTypes.GetVarInt(sign.Length));
|
fields.AddRange(dataTypes.GetVarInt(sign.Length));
|
||||||
fields.AddRange(sign);
|
fields.AddRange(sign);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signed Preview: Boolean
|
// Signed Preview: Boolean
|
||||||
fields.AddRange(dataTypes.GetBool(false));
|
fields.AddRange(dataTypes.GetBool(false));
|
||||||
|
|
||||||
|
if (protocolVersion >= MC_1_19_2_Version)
|
||||||
|
{
|
||||||
|
// Message Acknowledgment
|
||||||
|
fields.AddRange(dataTypes.GetAcknowledgment(acknowledgment!, isOnlineMode));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
SendPacket(PacketTypesOut.ChatMessage, fields);
|
SendPacket(PacketTypesOut.ChatMessage, fields);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -2077,9 +2289,12 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
List<byte> fields = new List<byte>();
|
List<byte> fields = new List<byte>();
|
||||||
fields.AddRange(dataTypes.GetString(language));
|
fields.AddRange(dataTypes.GetString(language));
|
||||||
fields.Add(viewDistance);
|
fields.Add(viewDistance);
|
||||||
fields.AddRange(protocolVersion >= MC_1_9_Version
|
|
||||||
? dataTypes.GetVarInt(chatMode)
|
if (protocolVersion >= MC_1_9_Version)
|
||||||
: new byte[] { chatMode });
|
fields.AddRange(dataTypes.GetVarInt(chatMode));
|
||||||
|
else
|
||||||
|
fields.AddRange(new byte[] { chatMode });
|
||||||
|
|
||||||
fields.Add(chatColors ? (byte)1 : (byte)0);
|
fields.Add(chatColors ? (byte)1 : (byte)0);
|
||||||
if (protocolVersion < MC_1_8_Version)
|
if (protocolVersion < MC_1_8_Version)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ namespace MinecraftClient.Protocol
|
||||||
/// Start the login procedure once connected to the server
|
/// Start the login procedure once connected to the server
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if login was successful</returns>
|
/// <returns>True if login was successful</returns>
|
||||||
bool Login(PlayerKeyPair playerKeyPair);
|
bool Login(PlayerKeyPair? playerKeyPair);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Disconnect from the server
|
/// Disconnect from the server
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Text;
|
||||||
using MinecraftClient.Mapping;
|
using MinecraftClient.Mapping;
|
||||||
using MinecraftClient.Inventory;
|
using MinecraftClient.Inventory;
|
||||||
using MinecraftClient.Logger;
|
using MinecraftClient.Logger;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol
|
namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
|
|
@ -22,7 +23,8 @@ namespace MinecraftClient.Protocol
|
||||||
int GetServerPort();
|
int GetServerPort();
|
||||||
string GetServerHost();
|
string GetServerHost();
|
||||||
string GetUsername();
|
string GetUsername();
|
||||||
string GetUserUUID();
|
Guid GetUserUuid();
|
||||||
|
string GetUserUuidStr();
|
||||||
string GetSessionID();
|
string GetSessionID();
|
||||||
string[] GetOnlinePlayers();
|
string[] GetOnlinePlayers();
|
||||||
Dictionary<string, string> GetOnlinePlayersWithUUID();
|
Dictionary<string, string> GetOnlinePlayersWithUUID();
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol
|
namespace MinecraftClient.Protocol.Message
|
||||||
{
|
{
|
||||||
public class ChatMessage
|
public class ChatMessage
|
||||||
{
|
{
|
||||||
|
|
@ -17,7 +17,7 @@ namespace MinecraftClient.Protocol
|
||||||
|
|
||||||
// 0: chat (chat box), 1: system message (chat box), 2: game info (above hotbar), 3: say command,
|
// 0: chat (chat box), 1: system message (chat box), 2: game info (above hotbar), 3: say command,
|
||||||
// 4: msg command, 5: team msg command, 6: emote command, 7: tellraw command
|
// 4: msg command, 5: team msg command, 6: emote command, 7: tellraw command
|
||||||
public readonly int chatType;
|
public readonly int chatTypeId;
|
||||||
|
|
||||||
public readonly Guid senderUUID;
|
public readonly Guid senderUUID;
|
||||||
|
|
||||||
|
|
@ -31,31 +31,44 @@ namespace MinecraftClient.Protocol
|
||||||
|
|
||||||
public readonly DateTime? timestamp;
|
public readonly DateTime? timestamp;
|
||||||
|
|
||||||
|
public readonly byte[]? signature;
|
||||||
|
|
||||||
public readonly bool? isSignatureLegal;
|
public readonly bool? isSignatureLegal;
|
||||||
|
|
||||||
public ChatMessage(string content, bool isJson, int chatType, Guid senderUUID, string? unsignedContent, string displayName, string? teamName, long timestamp, bool isSignatureLegal)
|
public ChatMessage(string content, bool isJson, int chatType, Guid senderUUID, string? unsignedContent, string displayName, string? teamName, long timestamp, byte[] signature, bool isSignatureLegal)
|
||||||
{
|
{
|
||||||
this.isSignedChat = true;
|
isSignedChat = true;
|
||||||
this.isSystemChat = false;
|
isSystemChat = false;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.isJson = isJson;
|
this.isJson = isJson;
|
||||||
this.chatType = chatType;
|
this.chatTypeId = chatType;
|
||||||
this.senderUUID = senderUUID;
|
this.senderUUID = senderUUID;
|
||||||
this.unsignedContent = unsignedContent;
|
this.unsignedContent = unsignedContent;
|
||||||
this.displayName = displayName;
|
this.displayName = displayName;
|
||||||
this.teamName = teamName;
|
this.teamName = teamName;
|
||||||
this.timestamp = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime;
|
this.timestamp = DateTimeOffset.FromUnixTimeMilliseconds(timestamp).DateTime;
|
||||||
|
this.signature = signature;
|
||||||
this.isSignatureLegal = isSignatureLegal;
|
this.isSignatureLegal = isSignatureLegal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ChatMessage(string content, bool isJson, int chatType, Guid senderUUID, bool isSystemChat = false)
|
public ChatMessage(string content, bool isJson, int chatType, Guid senderUUID, bool isSystemChat = false)
|
||||||
{
|
{
|
||||||
this.isSignedChat = isSystemChat;
|
isSignedChat = isSystemChat;
|
||||||
this.isSystemChat = isSystemChat;
|
this.isSystemChat = isSystemChat;
|
||||||
this.content = content;
|
this.content = content;
|
||||||
this.isJson = isJson;
|
this.isJson = isJson;
|
||||||
this.chatType = chatType;
|
this.chatTypeId = chatType;
|
||||||
this.senderUUID = senderUUID;
|
this.senderUUID = senderUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LastSeenMessageList.Entry? toLastSeenMessageEntry()
|
||||||
|
{
|
||||||
|
return signature != null ? new LastSeenMessageList.Entry(senderUUID, signature) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool lacksSender()
|
||||||
|
{
|
||||||
|
return this.senderUUID == Guid.Empty;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol
|
namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
|
|
@ -12,6 +13,20 @@ namespace MinecraftClient.Protocol
|
||||||
|
|
||||||
static class ChatParser
|
static class ChatParser
|
||||||
{
|
{
|
||||||
|
public enum MessageType
|
||||||
|
{
|
||||||
|
CHAT,
|
||||||
|
SAY_COMMAND,
|
||||||
|
MSG_COMMAND_INCOMING,
|
||||||
|
MSG_COMMAND_OUTGOING,
|
||||||
|
TEAM_MSG_COMMAND_INCOMING,
|
||||||
|
TEAM_MSG_COMMAND_OUTGOING,
|
||||||
|
EMOTE_COMMAND,
|
||||||
|
RAW_MSG
|
||||||
|
};
|
||||||
|
|
||||||
|
public static Dictionary<int, MessageType>? ChatId2Type;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The main function to convert text from MC 1.6+ JSON to MC 1.5.2 formatted text
|
/// The main function to convert text from MC 1.6+ JSON to MC 1.5.2 formatted text
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -31,60 +46,68 @@ namespace MinecraftClient.Protocol
|
||||||
/// <returns>Returns the translated text</returns>
|
/// <returns>Returns the translated text</returns>
|
||||||
public static string ParseSignedChat(ChatMessage message, List<string>? links = null)
|
public static string ParseSignedChat(ChatMessage message, List<string>? links = null)
|
||||||
{
|
{
|
||||||
string content;
|
string chatContent = Settings.ShowModifiedChat && message.unsignedContent != null ? message.unsignedContent : message.content;
|
||||||
if (Settings.ShowModifiedChat && message.unsignedContent != null)
|
string content = message.isJson ? ParseText(chatContent, links) : chatContent;
|
||||||
content = ChatParser.ParseText(message.unsignedContent, links);
|
|
||||||
else
|
|
||||||
content = ChatParser.ParseText(message.content, links);
|
|
||||||
string sender = message.displayName!;
|
string sender = message.displayName!;
|
||||||
|
|
||||||
string text;
|
string text;
|
||||||
List<string> usingData = new();
|
List<string> usingData = new();
|
||||||
switch (message.chatType)
|
|
||||||
|
MessageType chatType;
|
||||||
|
if (message.isSystemChat)
|
||||||
|
chatType = MessageType.RAW_MSG;
|
||||||
|
else if (!ChatId2Type!.TryGetValue(message.chatTypeId, out chatType))
|
||||||
|
chatType = MessageType.CHAT;
|
||||||
|
switch (chatType)
|
||||||
{
|
{
|
||||||
case 0: // chat (chat box)
|
case MessageType.CHAT:
|
||||||
usingData.Add(sender);
|
usingData.Add(sender);
|
||||||
usingData.Add(content);
|
usingData.Add(content);
|
||||||
text = TranslateString("chat.type.text", usingData);
|
text = TranslateString("chat.type.text", usingData);
|
||||||
break;
|
break;
|
||||||
case 1: // system message (chat box)
|
case MessageType.SAY_COMMAND:
|
||||||
text = content;
|
|
||||||
break;
|
|
||||||
case 2: // game info (above hotbar)
|
|
||||||
text = content;
|
|
||||||
break;
|
|
||||||
case 3: // say command
|
|
||||||
usingData.Add(sender);
|
usingData.Add(sender);
|
||||||
usingData.Add(content);
|
usingData.Add(content);
|
||||||
text = TranslateString("chat.type.announcement", usingData);
|
text = TranslateString("chat.type.announcement", usingData);
|
||||||
break;
|
break;
|
||||||
case 4: // msg command
|
case MessageType.MSG_COMMAND_INCOMING:
|
||||||
usingData.Add(sender);
|
usingData.Add(sender);
|
||||||
usingData.Add(content);
|
usingData.Add(content);
|
||||||
text = TranslateString("commands.message.display.incoming", usingData);
|
text = TranslateString("commands.message.display.incoming", usingData);
|
||||||
break;
|
break;
|
||||||
case 5: // team msg command (/teammsg)
|
case MessageType.MSG_COMMAND_OUTGOING:
|
||||||
|
usingData.Add(sender);
|
||||||
|
usingData.Add(content);
|
||||||
|
text = TranslateString("commands.message.display.outgoing", usingData);
|
||||||
|
break;
|
||||||
|
case MessageType.TEAM_MSG_COMMAND_INCOMING:
|
||||||
usingData.Add(message.teamName!);
|
usingData.Add(message.teamName!);
|
||||||
usingData.Add(sender);
|
usingData.Add(sender);
|
||||||
usingData.Add(content);
|
usingData.Add(content);
|
||||||
text = TranslateString("chat.type.team.text", usingData);
|
text = TranslateString("chat.type.team.text", usingData);
|
||||||
break;
|
break;
|
||||||
case 6: // emote command (/me)
|
case MessageType.TEAM_MSG_COMMAND_OUTGOING:
|
||||||
|
usingData.Add(message.teamName!);
|
||||||
|
usingData.Add(sender);
|
||||||
|
usingData.Add(content);
|
||||||
|
text = TranslateString("chat.type.team.sent", usingData);
|
||||||
|
break;
|
||||||
|
case MessageType.EMOTE_COMMAND:
|
||||||
usingData.Add(sender);
|
usingData.Add(sender);
|
||||||
usingData.Add(content);
|
usingData.Add(content);
|
||||||
text = TranslateString("chat.type.emote", usingData);
|
text = TranslateString("chat.type.emote", usingData);
|
||||||
break;
|
break;
|
||||||
case 7: // tellraw command
|
case MessageType.RAW_MSG:
|
||||||
text = content;
|
text = content;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
text = $"{sender}: {content}";
|
goto case MessageType.CHAT;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
string color = String.Empty;
|
string color = string.Empty;
|
||||||
if (message.isSystemChat)
|
if (message.isSystemChat)
|
||||||
{
|
{
|
||||||
if (Settings.MarkSystemMessage)
|
if (Settings.MarkSystemMessage)
|
||||||
color = "§z §r "; // Custom: Background Gray
|
color = "§z §r "; // Custom color code §z : Background Gray
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -93,18 +116,18 @@ namespace MinecraftClient.Protocol
|
||||||
if (Settings.ShowModifiedChat && message.unsignedContent != null)
|
if (Settings.ShowModifiedChat && message.unsignedContent != null)
|
||||||
{
|
{
|
||||||
if (Settings.MarkModifiedMsg)
|
if (Settings.MarkModifiedMsg)
|
||||||
color = "§x §r "; // Custom: Background Yellow
|
color = "§x §r "; // Custom color code §x : Background Yellow
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Settings.MarkLegallySignedMsg)
|
if (Settings.MarkLegallySignedMsg)
|
||||||
color = "§y §r "; // Custom: Background Green
|
color = "§y §r "; // Custom color code §y : Background Green
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (Settings.MarkIllegallySignedMsg)
|
if (Settings.MarkIllegallySignedMsg)
|
||||||
color = "§w §r "; // Custom: Background Red
|
color = "§w §r "; // Custom color code §w : Background Red
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return color + text;
|
return color + text;
|
||||||
|
|
@ -172,13 +195,13 @@ namespace MinecraftClient.Protocol
|
||||||
TranslationRules["commands.message.display.outgoing"] = "§7You whisper to %s: %s";
|
TranslationRules["commands.message.display.outgoing"] = "§7You whisper to %s: %s";
|
||||||
|
|
||||||
//Language file in a subfolder, depending on the language setting
|
//Language file in a subfolder, depending on the language setting
|
||||||
if (!System.IO.Directory.Exists("lang"))
|
if (!Directory.Exists("lang"))
|
||||||
System.IO.Directory.CreateDirectory("lang");
|
Directory.CreateDirectory("lang");
|
||||||
|
|
||||||
string Language_File = "lang" + Path.DirectorySeparatorChar + Settings.Language + ".lang";
|
string Language_File = "lang" + Path.DirectorySeparatorChar + Settings.Language + ".lang";
|
||||||
|
|
||||||
//File not found? Try downloading language file from Mojang's servers?
|
//File not found? Try downloading language file from Mojang's servers?
|
||||||
if (!System.IO.File.Exists(Language_File))
|
if (!File.Exists(Language_File))
|
||||||
{
|
{
|
||||||
ConsoleIO.WriteLineFormatted(Translations.Get("chat.download", Settings.Language));
|
ConsoleIO.WriteLineFormatted(Translations.Get("chat.download", Settings.Language));
|
||||||
try
|
try
|
||||||
|
|
@ -197,7 +220,7 @@ namespace MinecraftClient.Protocol
|
||||||
stringBuilder.Append(entry.Key + "=" + entry.Value.StringValue + Environment.NewLine);
|
stringBuilder.Append(entry.Key + "=" + entry.Value.StringValue + Environment.NewLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
System.IO.File.WriteAllText(Language_File, stringBuilder.ToString());
|
File.WriteAllText(Language_File, stringBuilder.ToString());
|
||||||
ConsoleIO.WriteLineFormatted(Translations.Get("chat.done", Language_File));
|
ConsoleIO.WriteLineFormatted(Translations.Get("chat.done", Language_File));
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
|
|
@ -207,17 +230,17 @@ namespace MinecraftClient.Protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
//Download Failed? Defaulting to en_GB.lang if the game is installed
|
//Download Failed? Defaulting to en_GB.lang if the game is installed
|
||||||
if (!System.IO.File.Exists(Language_File) //Try en_GB.lang
|
if (!File.Exists(Language_File) //Try en_GB.lang
|
||||||
&& System.IO.File.Exists(Settings.TranslationsFile_FromMCDir))
|
&& File.Exists(Settings.TranslationsFile_FromMCDir))
|
||||||
{
|
{
|
||||||
Language_File = Settings.TranslationsFile_FromMCDir;
|
Language_File = Settings.TranslationsFile_FromMCDir;
|
||||||
Translations.WriteLineFormatted("chat.from_dir");
|
Translations.WriteLineFormatted("chat.from_dir");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Load the external dictionnary of translation rules or display an error message
|
//Load the external dictionnary of translation rules or display an error message
|
||||||
if (System.IO.File.Exists(Language_File))
|
if (File.Exists(Language_File))
|
||||||
{
|
{
|
||||||
string[] translations = System.IO.File.ReadAllLines(Language_File);
|
string[] translations = File.ReadAllLines(Language_File);
|
||||||
foreach (string line in translations)
|
foreach (string line in translations)
|
||||||
{
|
{
|
||||||
if (line.Length > 0)
|
if (line.Length > 0)
|
||||||
|
|
@ -289,7 +312,7 @@ namespace MinecraftClient.Protocol
|
||||||
}
|
}
|
||||||
return result.ToString();
|
return result.ToString();
|
||||||
}
|
}
|
||||||
else return "[" + rulename + "] " + String.Join(" ", using_data);
|
else return "[" + rulename + "] " + string.Join(" ", using_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -315,11 +338,11 @@ namespace MinecraftClient.Protocol
|
||||||
if (clickEvent.Properties.ContainsKey("action")
|
if (clickEvent.Properties.ContainsKey("action")
|
||||||
&& clickEvent.Properties.ContainsKey("value")
|
&& clickEvent.Properties.ContainsKey("value")
|
||||||
&& clickEvent.Properties["action"].StringValue == "open_url"
|
&& clickEvent.Properties["action"].StringValue == "open_url"
|
||||||
&& !String.IsNullOrEmpty(clickEvent.Properties["value"].StringValue))
|
&& !string.IsNullOrEmpty(clickEvent.Properties["value"].StringValue))
|
||||||
{
|
{
|
||||||
links.Add(clickEvent.Properties["value"].StringValue);
|
links.Add(clickEvent.Properties["value"].StringValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (data.Properties.ContainsKey("extra"))
|
if (data.Properties.ContainsKey("extra"))
|
||||||
{
|
{
|
||||||
Json.JSONData[] extras = data.Properties["extra"].DataArray.ToArray();
|
Json.JSONData[] extras = data.Properties["extra"].DataArray.ToArray();
|
||||||
|
|
@ -372,7 +395,7 @@ namespace MinecraftClient.Protocol
|
||||||
System.Net.HttpWebRequest myRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
|
System.Net.HttpWebRequest myRequest = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
|
||||||
myRequest.Method = "GET";
|
myRequest.Method = "GET";
|
||||||
System.Net.WebResponse myResponse = myRequest.GetResponse();
|
System.Net.WebResponse myResponse = myRequest.GetResponse();
|
||||||
System.IO.StreamReader sr = new System.IO.StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
|
StreamReader sr = new StreamReader(myResponse.GetResponseStream(), Encoding.UTF8);
|
||||||
string result = sr.ReadToEnd();
|
string result = sr.ReadToEnd();
|
||||||
sr.Close();
|
sr.Close();
|
||||||
myResponse.Close();
|
myResponse.Close();
|
||||||
117
MinecraftClient/Protocol/Message/LastSeenMessageList.cs
Normal file
117
MinecraftClient/Protocol/Message/LastSeenMessageList.cs
Normal file
|
|
@ -0,0 +1,117 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace MinecraftClient.Protocol.Message
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A list of messages a client has seen.
|
||||||
|
/// </summary>
|
||||||
|
public class LastSeenMessageList
|
||||||
|
{
|
||||||
|
public static readonly LastSeenMessageList EMPTY = new(new Entry[0]);
|
||||||
|
public static readonly int MAX_ENTRIES = 5;
|
||||||
|
|
||||||
|
public Entry[] entries;
|
||||||
|
|
||||||
|
public LastSeenMessageList(Entry[] list)
|
||||||
|
{
|
||||||
|
entries = list;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteForSign(List<byte> data)
|
||||||
|
{
|
||||||
|
foreach (Entry entry in entries)
|
||||||
|
{
|
||||||
|
data.Add(70);
|
||||||
|
data.AddRange(entry.profileId.ToBigEndianBytes());
|
||||||
|
data.AddRange(entry.lastSignature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A pair of a player's UUID and the signature of the last message they saw, used as an entry of LastSeenMessageList.
|
||||||
|
/// </summary>
|
||||||
|
public class Entry
|
||||||
|
{
|
||||||
|
public Guid profileId;
|
||||||
|
public byte[] lastSignature;
|
||||||
|
|
||||||
|
public Entry(Guid profileId, byte[] lastSignature)
|
||||||
|
{
|
||||||
|
this.profileId = profileId;
|
||||||
|
this.lastSignature = lastSignature;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A record of messages acknowledged by a client.
|
||||||
|
/// This holds the messages the client has recently seen, as well as the last message they received, if any.
|
||||||
|
/// </summary>
|
||||||
|
public class Acknowledgment
|
||||||
|
{
|
||||||
|
public LastSeenMessageList lastSeen;
|
||||||
|
public Entry? lastReceived;
|
||||||
|
|
||||||
|
public Acknowledgment(LastSeenMessageList lastSeenMessageList, Entry? lastReceivedMessage)
|
||||||
|
{
|
||||||
|
lastSeen = lastSeenMessageList;
|
||||||
|
lastReceived = lastReceivedMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Collects the message that are last seen by a client.
|
||||||
|
/// The message, along with the "last received" message, forms an "acknowledgment" of received messages.
|
||||||
|
/// They are sent to the server when the client has enough messages received or when they send a message.
|
||||||
|
/// The maximum amount of message entries are specified in the constructor.The vanilla clients collect 5 entries.
|
||||||
|
/// Calling add adds the message to the beginning of the entries list, and evicts the oldest message.
|
||||||
|
/// If there are entries with the same sender profile ID, the older entry will be replaced with null instead of filling the hole.
|
||||||
|
/// </summary>
|
||||||
|
public class LastSeenMessagesCollector
|
||||||
|
{
|
||||||
|
private readonly LastSeenMessageList.Entry[] entries;
|
||||||
|
private int size = 0;
|
||||||
|
private LastSeenMessageList lastSeenMessages;
|
||||||
|
|
||||||
|
public LastSeenMessagesCollector(int size)
|
||||||
|
{
|
||||||
|
lastSeenMessages = LastSeenMessageList.EMPTY;
|
||||||
|
entries = new LastSeenMessageList.Entry[size];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(LastSeenMessageList.Entry entry)
|
||||||
|
{
|
||||||
|
LastSeenMessageList.Entry? lastEntry = entry;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
LastSeenMessageList.Entry curEntry = entries[i];
|
||||||
|
entries[i] = lastEntry;
|
||||||
|
lastEntry = curEntry;
|
||||||
|
if (curEntry.profileId == entry.profileId)
|
||||||
|
{
|
||||||
|
lastEntry = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastEntry != null && size < entries.Length)
|
||||||
|
entries[size++] = lastEntry;
|
||||||
|
|
||||||
|
LastSeenMessageList.Entry[] msgList = new LastSeenMessageList.Entry[size];
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
msgList[i] = entries[i];
|
||||||
|
lastSeenMessages = new LastSeenMessageList(msgList);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LastSeenMessageList GetLastSeenMessages()
|
||||||
|
{
|
||||||
|
return lastSeenMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,17 +4,18 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MinecraftClient.Protocol.Keys;
|
using MinecraftClient.Protocol.Keys;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol
|
namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
public class PlayerInfo
|
public class PlayerInfo
|
||||||
{
|
{
|
||||||
public readonly Guid UUID;
|
public readonly Guid Uuid;
|
||||||
|
|
||||||
public readonly string Name;
|
public readonly string Name;
|
||||||
|
|
||||||
// Tuple<Name, Value, Signature(empty if there is no signature)
|
// Tuple<Name, Value, Signature(empty if there is no signature)
|
||||||
public readonly Tuple<string, string, string>[]? Property;
|
public readonly Tuple<string, string, string?>[]? Property;
|
||||||
|
|
||||||
public int Gamemode;
|
public int Gamemode;
|
||||||
|
|
||||||
|
|
@ -26,9 +27,13 @@ namespace MinecraftClient.Protocol
|
||||||
|
|
||||||
private readonly DateTime? KeyExpiresAt;
|
private readonly DateTime? KeyExpiresAt;
|
||||||
|
|
||||||
public PlayerInfo(Guid uuid, string name, Tuple<string, string, string>[]? property, int gamemode, int ping, string? displayName, long? timeStamp, byte[]? publicKey, byte[]? signature)
|
private bool lastMessageVerified;
|
||||||
|
|
||||||
|
private byte[]? precedingSignature;
|
||||||
|
|
||||||
|
public PlayerInfo(Guid uuid, string name, Tuple<string, string, string?>[]? property, int gamemode, int ping, string? displayName, long? timeStamp, byte[]? publicKey, byte[]? signature)
|
||||||
{
|
{
|
||||||
UUID = uuid;
|
Uuid = uuid;
|
||||||
Name = name;
|
Name = name;
|
||||||
if (property != null)
|
if (property != null)
|
||||||
Property = property;
|
Property = property;
|
||||||
|
|
@ -48,36 +53,107 @@ namespace MinecraftClient.Protocol
|
||||||
PublicKey = null;
|
PublicKey = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lastMessageVerified = true;
|
||||||
|
precedingSignature = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayerInfo(string name, Guid uuid)
|
public PlayerInfo(string name, Guid uuid)
|
||||||
{
|
{
|
||||||
Name = name;
|
Name = name;
|
||||||
UUID = uuid;
|
Uuid = uuid;
|
||||||
Gamemode = -1;
|
Gamemode = -1;
|
||||||
Ping = 0;
|
Ping = 0;
|
||||||
|
lastMessageVerified = true;
|
||||||
|
precedingSignature = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsKeyVaild()
|
public bool IsMessageChainLegal()
|
||||||
{
|
{
|
||||||
return PublicKey != null && DateTime.Now.ToUniversalTime() > this.KeyExpiresAt;
|
return this.lastMessageVerified;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool VerifyMessage(string message, Guid uuid, long timestamp, long salt, ref byte[] signature)
|
public bool IsKeyExpired()
|
||||||
{
|
{
|
||||||
if (PublicKey == null)
|
return DateTime.Now.ToUniversalTime() > this.KeyExpiresAt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify message - 1.19
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message content</param>
|
||||||
|
/// <param name="timestamp">Timestamp</param>
|
||||||
|
/// <param name="salt">Salt</param>
|
||||||
|
/// <param name="signature">Message signature</param>
|
||||||
|
/// <returns>Is this message vaild</returns>
|
||||||
|
public bool VerifyMessage(string message, long timestamp, long salt, ref byte[] signature)
|
||||||
|
{
|
||||||
|
if (PublicKey == null || IsKeyExpired())
|
||||||
return false;
|
return false;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string uuidString = uuid.ToString().Replace("-", string.Empty);
|
|
||||||
|
|
||||||
DateTimeOffset timeOffset = DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
|
DateTimeOffset timeOffset = DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
|
||||||
|
|
||||||
byte[] saltByte = BitConverter.GetBytes(salt);
|
byte[] saltByte = BitConverter.GetBytes(salt);
|
||||||
Array.Reverse(saltByte);
|
Array.Reverse(saltByte);
|
||||||
|
|
||||||
return PublicKey.VerifyMessage(message, uuidString, timeOffset, ref saltByte, ref signature);
|
return PublicKey.VerifyMessage(message, Uuid, timeOffset, ref saltByte, ref signature);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify message - 1.19.1 and above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message content</param>
|
||||||
|
/// <param name="timestamp">Timestamp</param>
|
||||||
|
/// <param name="salt">Salt</param>
|
||||||
|
/// <param name="signature">Message signature</param>
|
||||||
|
/// <param name="precedingSignature">Preceding message signature</param>
|
||||||
|
/// <param name="lastSeenMessages">LastSeenMessages</param>
|
||||||
|
/// <returns>Is this message chain vaild</returns>
|
||||||
|
public bool VerifyMessage(string message, long timestamp, long salt, ref byte[] signature, ref byte[]? precedingSignature, LastSeenMessageList lastSeenMessages)
|
||||||
|
{
|
||||||
|
if (this.lastMessageVerified == false)
|
||||||
|
return false;
|
||||||
|
if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null))
|
||||||
|
return false;
|
||||||
|
if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DateTimeOffset timeOffset = DateTimeOffset.FromUnixTimeMilliseconds(timestamp);
|
||||||
|
|
||||||
|
byte[] saltByte = BitConverter.GetBytes(salt);
|
||||||
|
Array.Reverse(saltByte);
|
||||||
|
|
||||||
|
bool res = PublicKey.VerifyMessage(message, Uuid, timeOffset, ref saltByte, ref signature, ref precedingSignature, lastSeenMessages);
|
||||||
|
|
||||||
|
this.lastMessageVerified = res;
|
||||||
|
this.precedingSignature = signature;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify message head - 1.19.1 and above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="precedingSignature">Preceding message signature</param>
|
||||||
|
/// <param name="headerSignature">Message signature</param>
|
||||||
|
/// <param name="bodyDigest">Message body hash</param>
|
||||||
|
/// <returns>Is this message chain vaild</returns>
|
||||||
|
public bool VerifyMessageHead(ref byte[]? precedingSignature, ref byte[] headerSignature, ref byte[] bodyDigest)
|
||||||
|
{
|
||||||
|
if (this.lastMessageVerified == false)
|
||||||
|
return false;
|
||||||
|
if (PublicKey == null || IsKeyExpired() || (this.precedingSignature != null && precedingSignature == null))
|
||||||
|
return false;
|
||||||
|
if (this.precedingSignature != null && !this.precedingSignature.SequenceEqual(precedingSignature!))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool res = PublicKey.VerifyHeader(ref bodyDigest, ref headerSignature);
|
||||||
|
|
||||||
|
this.lastMessageVerified = res;
|
||||||
|
this.precedingSignature = headerSignature;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MinecraftClient.Protocol.Handlers;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Keys
|
namespace MinecraftClient.Protocol.Keys
|
||||||
{
|
{
|
||||||
static class KeyUtils
|
static class KeyUtils
|
||||||
{
|
{
|
||||||
private static string certificates = "https://api.minecraftservices.com/player/certificates";
|
private static readonly SHA256 sha256Hash = SHA256.Create();
|
||||||
|
|
||||||
|
private static readonly string certificates = "https://api.minecraftservices.com/player/certificates";
|
||||||
|
|
||||||
public static PlayerKeyPair? GetKeys(string accessToken)
|
public static PlayerKeyPair? GetKeys(string accessToken)
|
||||||
{
|
{
|
||||||
|
|
@ -67,19 +72,18 @@ namespace MinecraftClient.Protocol.Keys
|
||||||
return Convert.FromBase64String(key);
|
return Convert.FromBase64String(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] GetSignatureData(string message, string uuid, DateTimeOffset timestamp, ref byte[] salt)
|
public static byte[] ComputeHash(byte[] data)
|
||||||
|
{
|
||||||
|
return sha256Hash.ComputeHash(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] GetSignatureData(string message, Guid uuid, DateTimeOffset timestamp, ref byte[] salt)
|
||||||
{
|
{
|
||||||
List<byte> data = new();
|
List<byte> data = new();
|
||||||
|
|
||||||
data.AddRange(salt);
|
data.AddRange(salt);
|
||||||
|
|
||||||
byte[] UUIDLeastSignificantBits = BitConverter.GetBytes(Convert.ToInt64(uuid[..16], 16));
|
data.AddRange(uuid.ToBigEndianBytes());
|
||||||
Array.Reverse(UUIDLeastSignificantBits);
|
|
||||||
data.AddRange(UUIDLeastSignificantBits);
|
|
||||||
|
|
||||||
byte[] UUIDMostSignificantBits = BitConverter.GetBytes(Convert.ToInt64(uuid.Substring(16, 16), 16));
|
|
||||||
Array.Reverse(UUIDMostSignificantBits);
|
|
||||||
data.AddRange(UUIDMostSignificantBits);
|
|
||||||
|
|
||||||
byte[] timestampByte = BitConverter.GetBytes(timestamp.ToUnixTimeSeconds());
|
byte[] timestampByte = BitConverter.GetBytes(timestamp.ToUnixTimeSeconds());
|
||||||
Array.Reverse(timestampByte);
|
Array.Reverse(timestampByte);
|
||||||
|
|
@ -90,6 +94,39 @@ namespace MinecraftClient.Protocol.Keys
|
||||||
return data.ToArray();
|
return data.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] GetSignatureData(string message, DateTimeOffset timestamp, ref byte[] salt, LastSeenMessageList lastSeenMessages)
|
||||||
|
{
|
||||||
|
List<byte> data = new();
|
||||||
|
|
||||||
|
data.AddRange(salt);
|
||||||
|
|
||||||
|
byte[] timestampByte = BitConverter.GetBytes(timestamp.ToUnixTimeSeconds());
|
||||||
|
Array.Reverse(timestampByte);
|
||||||
|
data.AddRange(timestampByte);
|
||||||
|
|
||||||
|
data.AddRange(Encoding.UTF8.GetBytes(message));
|
||||||
|
|
||||||
|
data.Add(70);
|
||||||
|
|
||||||
|
lastSeenMessages.WriteForSign(data);
|
||||||
|
|
||||||
|
return data.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static byte[] GetSignatureData(byte[]? precedingSignature, Guid sender, byte[] bodySign)
|
||||||
|
{
|
||||||
|
List<byte> data = new();
|
||||||
|
|
||||||
|
if (precedingSignature != null)
|
||||||
|
data.AddRange(precedingSignature);
|
||||||
|
|
||||||
|
data.AddRange(sender.ToBigEndianBytes());
|
||||||
|
|
||||||
|
data.AddRange(bodySign);
|
||||||
|
|
||||||
|
return data.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
// https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
|
// https://github.com/mono/mono/blob/master/mcs/class/System.Json/System.Json/JsonValue.cs
|
||||||
public static string EscapeString(string src)
|
public static string EscapeString(string src)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,10 @@ namespace MinecraftClient.Protocol.Keys
|
||||||
{
|
{
|
||||||
List<string> datas = new List<string>();
|
List<string> datas = new List<string>();
|
||||||
datas.Add(Convert.ToBase64String(PublicKey.Key));
|
datas.Add(Convert.ToBase64String(PublicKey.Key));
|
||||||
datas.Add(Convert.ToBase64String(PublicKey.Signature));
|
if (PublicKey.Signature == null)
|
||||||
|
datas.Add(String.Empty);
|
||||||
|
else
|
||||||
|
datas.Add(Convert.ToBase64String(PublicKey.Signature));
|
||||||
if (PublicKey.SignatureV2 == null)
|
if (PublicKey.SignatureV2 == null)
|
||||||
datas.Add(String.Empty);
|
datas.Add(String.Empty);
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Keys
|
namespace MinecraftClient.Protocol.Keys
|
||||||
{
|
{
|
||||||
|
|
@ -13,6 +14,8 @@ namespace MinecraftClient.Protocol.Keys
|
||||||
|
|
||||||
private readonly RSA rsa;
|
private readonly RSA rsa;
|
||||||
|
|
||||||
|
private byte[]? precedingSignature = null;
|
||||||
|
|
||||||
public PrivateKey(string pemKey)
|
public PrivateKey(string pemKey)
|
||||||
{
|
{
|
||||||
this.Key = KeyUtils.DecodePemKey(pemKey, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----");
|
this.Key = KeyUtils.DecodePemKey(pemKey, "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----");
|
||||||
|
|
@ -26,7 +29,15 @@ namespace MinecraftClient.Protocol.Keys
|
||||||
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
return rsa.SignData(data, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] SignMessage(string message, string uuid, DateTimeOffset timestamp, ref byte[] salt)
|
/// <summary>
|
||||||
|
/// Sign message - 1.19
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message content</param>
|
||||||
|
/// <param name="uuid">Sender uuid</param>
|
||||||
|
/// <param name="timestamp">Timestamp</param>
|
||||||
|
/// <param name="salt">Salt</param>
|
||||||
|
/// <returns>Signature data</returns>
|
||||||
|
public byte[] SignMessage(string message, Guid uuid, DateTimeOffset timestamp, ref byte[] salt)
|
||||||
{
|
{
|
||||||
string messageJson = "{\"text\":\"" + KeyUtils.EscapeString(message) + "\"}";
|
string messageJson = "{\"text\":\"" + KeyUtils.EscapeString(message) + "\"}";
|
||||||
|
|
||||||
|
|
@ -35,5 +46,27 @@ namespace MinecraftClient.Protocol.Keys
|
||||||
return SignData(data);
|
return SignData(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sign message - 1.19.1 and above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message content</param>
|
||||||
|
/// <param name="uuid">Sender uuid</param>
|
||||||
|
/// <param name="timestamp">Timestamp</param>
|
||||||
|
/// <param name="salt">Salt</param>
|
||||||
|
/// <param name="lastSeenMessages">LastSeenMessageList</param>
|
||||||
|
/// <returns>Signature data</returns>
|
||||||
|
public byte[] SignMessage(string message, Guid uuid, DateTimeOffset timestamp, ref byte[] salt, LastSeenMessageList lastSeenMessages)
|
||||||
|
{
|
||||||
|
byte[] bodySignData = KeyUtils.GetSignatureData(message, timestamp, ref salt, lastSeenMessages);
|
||||||
|
byte[] bodyDigest = KeyUtils.ComputeHash(bodySignData);
|
||||||
|
|
||||||
|
byte[] msgSignData = KeyUtils.GetSignatureData(precedingSignature, uuid, bodyDigest);
|
||||||
|
byte[] msgSign = SignData(msgSignData);
|
||||||
|
|
||||||
|
this.precedingSignature = msgSign;
|
||||||
|
|
||||||
|
return msgSign;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,25 +4,27 @@ using System.Linq;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using MinecraftClient.Protocol.Message;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Keys
|
namespace MinecraftClient.Protocol.Keys
|
||||||
{
|
{
|
||||||
public class PublicKey
|
public class PublicKey
|
||||||
{
|
{
|
||||||
public byte[] Key { get; set; }
|
public byte[] Key { get; set; }
|
||||||
public byte[] Signature { get; set; }
|
public byte[]? Signature { get; set; }
|
||||||
public byte[]? SignatureV2 { get; set; }
|
public byte[]? SignatureV2 { get; set; }
|
||||||
|
|
||||||
private readonly RSA rsa;
|
private readonly RSA rsa;
|
||||||
|
|
||||||
public PublicKey(string pemKey, string sig, string? sigV2 = null)
|
public PublicKey(string pemKey, string? sig = null, string? sigV2 = null)
|
||||||
{
|
{
|
||||||
this.Key = KeyUtils.DecodePemKey(pemKey, "-----BEGIN RSA PUBLIC KEY-----", "-----END RSA PUBLIC KEY-----");
|
this.Key = KeyUtils.DecodePemKey(pemKey, "-----BEGIN RSA PUBLIC KEY-----", "-----END RSA PUBLIC KEY-----");
|
||||||
|
|
||||||
this.rsa = RSA.Create();
|
this.rsa = RSA.Create();
|
||||||
rsa.ImportSubjectPublicKeyInfo(this.Key, out _);
|
rsa.ImportSubjectPublicKeyInfo(this.Key, out _);
|
||||||
|
|
||||||
this.Signature = Convert.FromBase64String(sig);
|
if (!string.IsNullOrEmpty(sig))
|
||||||
|
this.Signature = Convert.FromBase64String(sig);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(sigV2))
|
if (!string.IsNullOrEmpty(sigV2))
|
||||||
this.SignatureV2 = Convert.FromBase64String(sigV2!);
|
this.SignatureV2 = Convert.FromBase64String(sigV2!);
|
||||||
|
|
@ -43,12 +45,53 @@ namespace MinecraftClient.Protocol.Keys
|
||||||
return rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
return rsa.VerifyData(data, signature, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool VerifyMessage(string message, string uuid, DateTimeOffset timestamp, ref byte[] salt, ref byte[] signature)
|
/// <summary>
|
||||||
|
/// Verify message - 1.19
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message content</param>
|
||||||
|
/// <param name="uuid">Sender uuid</param>
|
||||||
|
/// <param name="timestamp">Timestamp</param>
|
||||||
|
/// <param name="salt">Salt</param>
|
||||||
|
/// <param name="signature">Message signature</param>
|
||||||
|
/// <returns>Is this message vaild</returns>
|
||||||
|
public bool VerifyMessage(string message, Guid uuid, DateTimeOffset timestamp, ref byte[] salt, ref byte[] signature)
|
||||||
{
|
{
|
||||||
byte[] data = KeyUtils.GetSignatureData(message, uuid, timestamp, ref salt);
|
byte[] data = KeyUtils.GetSignatureData(message, uuid, timestamp, ref salt);
|
||||||
|
|
||||||
return VerifyData(data, signature);
|
return VerifyData(data, signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify message - 1.19.1 and above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">Message content</param>
|
||||||
|
/// <param name="uuid">Sender uuid</param>
|
||||||
|
/// <param name="timestamp">Timestamp</param>
|
||||||
|
/// <param name="salt">Salt</param>
|
||||||
|
/// <param name="signature">Message signature</param>
|
||||||
|
/// <param name="precedingSignature">Preceding message signature</param>
|
||||||
|
/// <param name="lastSeenMessages">LastSeenMessages</param>
|
||||||
|
/// <returns>Is this message vaild</returns>
|
||||||
|
public bool VerifyMessage(string message, Guid uuid, DateTimeOffset timestamp, ref byte[] salt, ref byte[] signature, ref byte[]? precedingSignature, LastSeenMessageList lastSeenMessages)
|
||||||
|
{
|
||||||
|
byte[] bodySignData = KeyUtils.GetSignatureData(message, timestamp, ref salt, lastSeenMessages);
|
||||||
|
byte[] bodyDigest = KeyUtils.ComputeHash(bodySignData);
|
||||||
|
|
||||||
|
byte[] msgSignData = KeyUtils.GetSignatureData(precedingSignature, uuid, bodyDigest);
|
||||||
|
|
||||||
|
return VerifyData(msgSignData, signature);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Verify message head - 1.19.1 and above
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bodyDigest">Message body hash</param>
|
||||||
|
/// <param name="signature">Message signature</param>
|
||||||
|
/// <returns>Is this message header vaild</returns>
|
||||||
|
public bool VerifyHeader(ref byte[] bodyDigest, ref byte[] signature)
|
||||||
|
{
|
||||||
|
return VerifyData(bodyDigest, signature);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ namespace MinecraftClient.Protocol
|
||||||
if (Array.IndexOf(supportedVersions_Protocol16, ProtocolVersion) > -1)
|
if (Array.IndexOf(supportedVersions_Protocol16, ProtocolVersion) > -1)
|
||||||
return new Protocol16Handler(Client, ProtocolVersion, Handler);
|
return new Protocol16Handler(Client, ProtocolVersion, Handler);
|
||||||
|
|
||||||
int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573, 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759 };
|
int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573, 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760 };
|
||||||
|
|
||||||
if (Array.IndexOf(supportedVersions_Protocol18, ProtocolVersion) > -1)
|
if (Array.IndexOf(supportedVersions_Protocol18, ProtocolVersion) > -1)
|
||||||
return new Protocol18Handler(Client, ProtocolVersion, Handler, forgeInfo);
|
return new Protocol18Handler(Client, ProtocolVersion, Handler, forgeInfo);
|
||||||
|
|
@ -263,6 +263,9 @@ namespace MinecraftClient.Protocol
|
||||||
return 758;
|
return 758;
|
||||||
case "1.19":
|
case "1.19":
|
||||||
return 759;
|
return 759;
|
||||||
|
case "1.19.1":
|
||||||
|
case "1.19.2":
|
||||||
|
return 760;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -329,6 +332,7 @@ namespace MinecraftClient.Protocol
|
||||||
case 757: return "1.18.1";
|
case 757: return "1.18.1";
|
||||||
case 758: return "1.18.2";
|
case 758: return "1.18.2";
|
||||||
case 759: return "1.19";
|
case 759: return "1.19";
|
||||||
|
case 760: return "1.19.2";
|
||||||
default: return "0.0";
|
default: return "0.0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -205,6 +205,7 @@ chat.fail=§8Failed to download the file.
|
||||||
chat.from_dir=§8Defaulting to en_GB.lang from your Minecraft directory.
|
chat.from_dir=§8Defaulting to en_GB.lang from your Minecraft directory.
|
||||||
chat.loaded=§8Translations file loaded.
|
chat.loaded=§8Translations file loaded.
|
||||||
chat.not_found=§8Translations file not found: '{0}'\nSome messages won't be properly printed without this file.
|
chat.not_found=§8Translations file not found: '{0}'\nSome messages won't be properly printed without this file.
|
||||||
|
chat.message_chain_broken=Player {0}'s message chain is broken!
|
||||||
|
|
||||||
[general]
|
[general]
|
||||||
# General message/information (i.e. Done)
|
# General message/information (i.e. Done)
|
||||||
|
|
|
||||||
|
|
@ -1110,7 +1110,7 @@ namespace MinecraftClient
|
||||||
/// <returns>UserUUID of the current account</returns>
|
/// <returns>UserUUID of the current account</returns>
|
||||||
protected string GetUserUUID()
|
protected string GetUserUUID()
|
||||||
{
|
{
|
||||||
return Handler.GetUserUUID();
|
return Handler.GetUserUuidStr();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue