MC 1.14 Basic/Chat support (#703)

Implement MC 1.14 baseline protocol support
Terrain and movements not supported yet for 1.14
This commit is contained in:
ORelio 2019-04-29 00:25:00 +02:00
parent a6e660c974
commit 295d6546b8
6 changed files with 112 additions and 52 deletions

View file

@ -65,7 +65,7 @@ namespace MinecraftClient.Commands
} }
else return CMDDesc; else return CMDDesc;
} }
else return "Please enable terrainandmovements in config to use this command."; else return "Please enable terrainandmovements to use this command.";
} }
} }
} }

View file

@ -167,41 +167,6 @@ namespace MinecraftClient.Mapping
return false; return false;
} }
/// <summary>
/// Get a representation of the location as unsigned long
/// </summary>
/// <remarks>
/// A modulo will be applied if the location is outside the following ranges:
/// X: -33,554,432 to +33,554,431
/// Y: -2,048 to +2,047
/// Z: -33,554,432 to +33,554,431
/// </remarks>
/// <returns>Location representation as ulong</returns>
public ulong GetLong()
{
return ((((ulong)X) & 0x3FFFFFF) << 38) | ((((ulong)Y) & 0xFFF) << 26) | (((ulong)Z) & 0x3FFFFFF);
}
/// <summary>
/// Get a location from an unsigned long.
/// </summary>
/// <returns>Location represented by the ulong</returns>
public static Location FromLong(ulong location)
{
int x = (int)(location >> 38);
int y = (int)((location >> 26) & 0xFFF);
int z = (int)(location << 38 >> 38);
if (x >= 33554432)
x -= 67108864;
if (y >= 2048)
y -= 4096;
if (z >= 33554432)
z -= 67108864;
return new Location(x, y, z);
}
/// <summary> /// <summary>
/// Compare two locations. Locations are equals if the integer part of their coordinates are equals. /// Compare two locations. Locations are equals if the integer part of their coordinates are equals.
/// </summary> /// </summary>

View file

@ -30,7 +30,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.13.2"; public const string MCHighestVersion = "1.14";
public static readonly string BuildInfo = null; public static readonly string BuildInfo = null;
private static Thread offlinePrompt = null; private static Thread offlinePrompt = null;

View file

@ -38,9 +38,7 @@ namespace MinecraftClient.Protocol.Handlers
if (Handler.GetTerrainEnabled()) if (Handler.GetTerrainEnabled())
{ {
ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version."); ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version.");
// Re-enable terrain on next relog on a supported server version
Handler.SetTerrainEnabled(false); Handler.SetTerrainEnabled(false);
Handler.SetTerrainEnabled(true);
} }
} }

View file

@ -33,6 +33,7 @@ namespace MinecraftClient.Protocol.Handlers
private const int MC1121Version = 338; private const int MC1121Version = 338;
private const int MC1122Version = 340; private const int MC1122Version = 340;
private const int MC113Version = 393; private const int MC113Version = 393;
private const int MC114Version = 477;
private int compression_treshold = 0; private int compression_treshold = 0;
private bool autocomplete_received = false; private bool autocomplete_received = false;
@ -64,6 +65,12 @@ namespace MinecraftClient.Protocol.Handlers
if (protocolversion >= MC113Version) if (protocolversion >= MC113Version)
Block.Palette = new Palette113(); Block.Palette = new Palette113();
else Block.Palette = new Palette112(); else Block.Palette = new Palette112();
if (Handler.GetTerrainEnabled() && protocolversion >= MC114Version)
{
ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version.");
Handler.SetTerrainEnabled(false);
}
} }
private Protocol18Handler(TcpClient Client) private Protocol18Handler(TcpClient Client)
@ -232,13 +239,11 @@ namespace MinecraftClient.Protocol.Handlers
case 0x20: return PacketIncomingType.ChunkData; case 0x20: return PacketIncomingType.ChunkData;
case 0x10: return PacketIncomingType.MultiBlockChange; case 0x10: return PacketIncomingType.MultiBlockChange;
case 0x0B: return PacketIncomingType.BlockChange; case 0x0B: return PacketIncomingType.BlockChange;
//MapChunkBulk removed in 1.9
case 0x1D: return PacketIncomingType.UnloadChunk; case 0x1D: return PacketIncomingType.UnloadChunk;
case 0x2D: return PacketIncomingType.PlayerListUpdate; case 0x2D: return PacketIncomingType.PlayerListUpdate;
case 0x0E: return PacketIncomingType.TabCompleteResult; case 0x0E: return PacketIncomingType.TabCompleteResult;
case 0x18: return PacketIncomingType.PluginMessage; case 0x18: return PacketIncomingType.PluginMessage;
case 0x1A: return PacketIncomingType.KickPacket; case 0x1A: return PacketIncomingType.KickPacket;
//NetworkCompressionTreshold removed in 1.9
case 0x33: return PacketIncomingType.ResourcePackSend; case 0x33: return PacketIncomingType.ResourcePackSend;
default: return PacketIncomingType.UnknownPacket; default: return PacketIncomingType.UnknownPacket;
} }
@ -255,18 +260,16 @@ namespace MinecraftClient.Protocol.Handlers
case 0x20: return PacketIncomingType.ChunkData; case 0x20: return PacketIncomingType.ChunkData;
case 0x10: return PacketIncomingType.MultiBlockChange; case 0x10: return PacketIncomingType.MultiBlockChange;
case 0x0B: return PacketIncomingType.BlockChange; case 0x0B: return PacketIncomingType.BlockChange;
//MapChunkBulk removed in 1.9
case 0x1D: return PacketIncomingType.UnloadChunk; case 0x1D: return PacketIncomingType.UnloadChunk;
case 0x2E: return PacketIncomingType.PlayerListUpdate; case 0x2E: return PacketIncomingType.PlayerListUpdate;
case 0x0E: return PacketIncomingType.TabCompleteResult; case 0x0E: return PacketIncomingType.TabCompleteResult;
case 0x18: return PacketIncomingType.PluginMessage; case 0x18: return PacketIncomingType.PluginMessage;
case 0x1A: return PacketIncomingType.KickPacket; case 0x1A: return PacketIncomingType.KickPacket;
//NetworkCompressionTreshold removed in 1.9
case 0x34: return PacketIncomingType.ResourcePackSend; case 0x34: return PacketIncomingType.ResourcePackSend;
default: return PacketIncomingType.UnknownPacket; default: return PacketIncomingType.UnknownPacket;
} }
} }
else // MC 1.13+ else if (protocolversion < MC114Version) // MC 1.13 to 1.13.2
{ {
switch (packetID) switch (packetID)
{ {
@ -278,17 +281,36 @@ namespace MinecraftClient.Protocol.Handlers
case 0x22: return PacketIncomingType.ChunkData; case 0x22: return PacketIncomingType.ChunkData;
case 0x0F: return PacketIncomingType.MultiBlockChange; case 0x0F: return PacketIncomingType.MultiBlockChange;
case 0x0B: return PacketIncomingType.BlockChange; case 0x0B: return PacketIncomingType.BlockChange;
//MapChunkBulk removed in 1.9
case 0x1F: return PacketIncomingType.UnloadChunk; case 0x1F: return PacketIncomingType.UnloadChunk;
case 0x30: return PacketIncomingType.PlayerListUpdate; case 0x30: return PacketIncomingType.PlayerListUpdate;
case 0x10: return PacketIncomingType.TabCompleteResult; case 0x10: return PacketIncomingType.TabCompleteResult;
case 0x19: return PacketIncomingType.PluginMessage; case 0x19: return PacketIncomingType.PluginMessage;
case 0x1B: return PacketIncomingType.KickPacket; case 0x1B: return PacketIncomingType.KickPacket;
//NetworkCompressionTreshold removed in 1.9
case 0x37: return PacketIncomingType.ResourcePackSend; case 0x37: return PacketIncomingType.ResourcePackSend;
default: return PacketIncomingType.UnknownPacket; default: return PacketIncomingType.UnknownPacket;
} }
} }
else // MC 1.14
{
switch (packetID)
{
case 0x20: return PacketIncomingType.KeepAlive;
case 0x25: return PacketIncomingType.JoinGame;
case 0x0E: return PacketIncomingType.ChatMessage;
case 0x3A: return PacketIncomingType.Respawn;
case 0x35: return PacketIncomingType.PlayerPositionAndLook;
case 0x21: return PacketIncomingType.ChunkData;
case 0x0F: return PacketIncomingType.MultiBlockChange;
case 0x0B: return PacketIncomingType.BlockChange;
case 0x1D: return PacketIncomingType.UnloadChunk;
case 0x33: return PacketIncomingType.PlayerListUpdate;
case 0x10: return PacketIncomingType.TabCompleteResult;
case 0x18: return PacketIncomingType.PluginMessage;
case 0x1A: return PacketIncomingType.KickPacket;
case 0x39: return PacketIncomingType.ResourcePackSend;
default: return PacketIncomingType.UnknownPacket;
}
}
} }
/// <summary> /// <summary>
@ -380,7 +402,7 @@ namespace MinecraftClient.Protocol.Handlers
case PacketOutgoingType.TeleportConfirm: return 0x00; case PacketOutgoingType.TeleportConfirm: return 0x00;
} }
} }
else // MC 1.13+ else if (protocol < MC114Version) // MC 1.13 to 1.13.2
{ {
switch (packet) switch (packet)
{ {
@ -396,6 +418,22 @@ namespace MinecraftClient.Protocol.Handlers
case PacketOutgoingType.TeleportConfirm: return 0x00; case PacketOutgoingType.TeleportConfirm: return 0x00;
} }
} }
else // MC 1.14
{
switch (packet)
{
case PacketOutgoingType.KeepAlive: return 0x0F;
case PacketOutgoingType.ResourcePackStatus: return 0x1F;
case PacketOutgoingType.ChatMessage: return 0x03;
case PacketOutgoingType.ClientStatus: return 0x04;
case PacketOutgoingType.ClientSettings: return 0x05;
case PacketOutgoingType.PluginMessage: return 0x0B;
case PacketOutgoingType.TabComplete: return 0x06;
case PacketOutgoingType.PlayerPosition: return 0x11;
case PacketOutgoingType.PlayerPositionAndLook: return 0x12;
case PacketOutgoingType.TeleportConfirm: return 0x00;
}
}
throw new System.ComponentModel.InvalidEnumArgumentException("Unknown PacketOutgoingType (protocol=" + protocol + ")", (int)packet, typeof(PacketOutgoingType)); throw new System.ComponentModel.InvalidEnumArgumentException("Unknown PacketOutgoingType (protocol=" + protocol + ")", (int)packet, typeof(PacketOutgoingType));
} }
@ -436,11 +474,14 @@ namespace MinecraftClient.Protocol.Handlers
this.currentDimension = readNextInt(packetData); this.currentDimension = readNextInt(packetData);
else else
this.currentDimension = (sbyte)readNextByte(packetData); this.currentDimension = (sbyte)readNextByte(packetData);
readNextByte(packetData); if (protocolversion < MC114Version)
readNextByte(packetData); // Difficulty - 1.13 and below
readNextByte(packetData); readNextByte(packetData);
readNextString(packetData); readNextString(packetData);
if (protocolversion >= MC114Version)
readNextVarInt(packetData); // View distance - 1.14 and above
if (protocolversion >= MC18Version) if (protocolversion >= MC18Version)
readNextBool(packetData); // Reduced debug info - 1.8 and above readNextBool(packetData); // Reduced debug info - 1.8 and above
break; break;
case PacketIncomingType.ChatMessage: case PacketIncomingType.ChatMessage:
string message = readNextString(packetData); string message = readNextString(packetData);
@ -457,7 +498,8 @@ namespace MinecraftClient.Protocol.Handlers
break; break;
case PacketIncomingType.Respawn: case PacketIncomingType.Respawn:
this.currentDimension = readNextInt(packetData); this.currentDimension = readNextInt(packetData);
readNextByte(packetData); if (protocolversion < MC114Version)
readNextByte(packetData); // Difficulty - 1.13 and below
readNextByte(packetData); readNextByte(packetData);
readNextString(packetData); readNextString(packetData);
handler.OnRespawn(); handler.OnRespawn();
@ -509,6 +551,10 @@ namespace MinecraftClient.Protocol.Handlers
} }
else else
{ {
//TODO skip NBT Heightmaps field for 1.14
//if (protocolversion >= MC114Version)
// readNextNBT(packetData);
//TODO update Material.cs for 1.14
int dataSize = readNextVarInt(packetData); int dataSize = readNextVarInt(packetData);
ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, packetData); ProcessChunkColumnData(chunkX, chunkZ, chunkMask, 0, false, chunksContinuous, packetData);
} }
@ -561,7 +607,7 @@ namespace MinecraftClient.Protocol.Handlers
byte blockMeta = readNextByte(packetData); byte blockMeta = readNextByte(packetData);
handler.GetWorld().SetBlock(new Location(blockX, blockY, blockZ), new Block(blockId, blockMeta)); handler.GetWorld().SetBlock(new Location(blockX, blockY, blockZ), new Block(blockId, blockMeta));
} }
else handler.GetWorld().SetBlock(Location.FromLong(readNextULong(packetData)), new Block((ushort)readNextVarInt(packetData))); else handler.GetWorld().SetBlock(readNextLocation(packetData), new Block((ushort)readNextVarInt(packetData)));
} }
break; break;
case PacketIncomingType.MapChunkBulk: case PacketIncomingType.MapChunkBulk:
@ -1218,6 +1264,35 @@ namespace MinecraftClient.Protocol.Handlers
return BitConverter.ToUInt64(rawValue, 0); return BitConverter.ToUInt64(rawValue, 0);
} }
/// <summary>
/// Read a Location encoded as an ulong field and remove it from the cache
/// </summary>
/// <returns>The Location value</returns>
private Location readNextLocation(List<byte> cache)
{
ulong locEncoded = readNextULong(cache);
int x, y, z;
if (protocolversion >= MC114Version)
{
x = (int)(locEncoded >> 38);
y = (int)(locEncoded & 0xFFF);
z = (int)(locEncoded << 26 >> 38);
}
else
{
x = (int)(locEncoded >> 38);
y = (int)((locEncoded >> 26) & 0xFFF);
z = (int)(locEncoded << 38 >> 38);
}
if (x >= 33554432)
x -= 67108864;
if (y >= 2048)
y -= 4096;
if (z >= 33554432)
z -= 67108864;
return new Location(x, y, z);
}
/// <summary> /// <summary>
/// Read several little endian unsigned short integers at once from a cache of bytes and remove them from the cache /// Read several little endian unsigned short integers at once from a cache of bytes and remove them from the cache
/// </summary> /// </summary>
@ -1462,6 +1537,25 @@ namespace MinecraftClient.Protocol.Handlers
return concatBytes(getVarInt(bytes.Length), bytes); return concatBytes(getVarInt(bytes.Length), bytes);
} }
/// <summary>
/// Get a byte array representing the given location encoded as an unsigned short
/// </summary>
/// <remarks>
/// A modulo will be applied if the location is outside the following ranges:
/// X: -33,554,432 to +33,554,431
/// Y: -2,048 to +2,047
/// Z: -33,554,432 to +33,554,431
/// </remarks>
/// <returns>Location representation as ulong</returns>
private byte[] GetLocation(Location location)
{
if (protocolversion >= MC114Version)
{
return BitConverter.GetBytes(((((ulong)location.X) & 0x3FFFFFF) << 38) | ((((ulong)location.Z) & 0x3FFFFFF) << 12) | (((ulong)location.Y) & 0xFFF));
}
else return BitConverter.GetBytes(((((ulong)location.X) & 0x3FFFFFF) << 38) | ((((ulong)location.Y) & 0xFFF) << 26) | (((ulong)location.Z) & 0x3FFFFFF));
}
/// <summary> /// <summary>
/// Easily append several byte arrays /// Easily append several byte arrays
/// </summary> /// </summary>

View file

@ -111,7 +111,7 @@ namespace MinecraftClient.Protocol
int[] supportedVersions_Protocol16 = { 51, 60, 61, 72, 73, 74, 78 }; int[] supportedVersions_Protocol16 = { 51, 60, 61, 72, 73, 74, 78 };
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 }; int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477 };
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);
throw new NotSupportedException("The protocol version no." + ProtocolVersion + " is not supported."); throw new NotSupportedException("The protocol version no." + ProtocolVersion + " is not supported.");
@ -200,6 +200,9 @@ namespace MinecraftClient.Protocol
return 401; return 401;
case "1.13.2": case "1.13.2":
return 404; return 404;
case "1.14":
case "1.14.0":
return 477;
default: default:
return 0; return 0;
} }