mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-11-07 17:36:07 +00:00
Merge pull request #160 from Pokechu22/1.9-terrain-and-movement
Implementation of terrain and movement for 1.9 by Pokechu22
This commit is contained in:
commit
734abe2296
1 changed files with 148 additions and 32 deletions
|
|
@ -20,6 +20,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
private const int MC18Version = 47;
|
private const int MC18Version = 47;
|
||||||
private const int MC19Version = 107;
|
private const int MC19Version = 107;
|
||||||
|
private const int MC191Version = 108;
|
||||||
private const int MC110Version = 210;
|
private const int MC110Version = 210;
|
||||||
|
|
||||||
private int compression_treshold = 0;
|
private int compression_treshold = 0;
|
||||||
|
|
@ -38,6 +39,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
IAesStream s;
|
IAesStream s;
|
||||||
TcpClient c;
|
TcpClient c;
|
||||||
|
|
||||||
|
int currentDimension;
|
||||||
|
|
||||||
public Protocol18Handler(TcpClient Client, int ProtocolVersion, IMinecraftComHandler Handler, ForgeInfo ForgeInfo)
|
public Protocol18Handler(TcpClient Client, int ProtocolVersion, IMinecraftComHandler Handler, ForgeInfo ForgeInfo)
|
||||||
{
|
{
|
||||||
ConsoleIO.SetAutoCompleteEngine(this);
|
ConsoleIO.SetAutoCompleteEngine(this);
|
||||||
|
|
@ -46,12 +49,6 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
this.protocolversion = ProtocolVersion;
|
this.protocolversion = ProtocolVersion;
|
||||||
this.handler = Handler;
|
this.handler = Handler;
|
||||||
this.forgeInfo = ForgeInfo;
|
this.forgeInfo = ForgeInfo;
|
||||||
|
|
||||||
if (Settings.TerrainAndMovements && protocolversion > MC18Version)
|
|
||||||
{
|
|
||||||
ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version.");
|
|
||||||
Settings.TerrainAndMovements = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Protocol18Handler(TcpClient Client)
|
private Protocol18Handler(TcpClient Client)
|
||||||
|
|
@ -142,6 +139,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
KeepAlive,
|
KeepAlive,
|
||||||
JoinGame,
|
JoinGame,
|
||||||
ChatMessage,
|
ChatMessage,
|
||||||
|
Respawn,
|
||||||
PlayerPositionAndLook,
|
PlayerPositionAndLook,
|
||||||
ChunkData,
|
ChunkData,
|
||||||
MultiBlockChange,
|
MultiBlockChange,
|
||||||
|
|
@ -173,6 +171,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
case 0x00: return PacketIncomingType.KeepAlive;
|
case 0x00: return PacketIncomingType.KeepAlive;
|
||||||
case 0x01: return PacketIncomingType.JoinGame;
|
case 0x01: return PacketIncomingType.JoinGame;
|
||||||
case 0x02: return PacketIncomingType.ChatMessage;
|
case 0x02: return PacketIncomingType.ChatMessage;
|
||||||
|
case 0x07: return PacketIncomingType.Respawn;
|
||||||
case 0x08: return PacketIncomingType.PlayerPositionAndLook;
|
case 0x08: return PacketIncomingType.PlayerPositionAndLook;
|
||||||
case 0x21: return PacketIncomingType.ChunkData;
|
case 0x21: return PacketIncomingType.ChunkData;
|
||||||
case 0x22: return PacketIncomingType.MultiBlockChange;
|
case 0x22: return PacketIncomingType.MultiBlockChange;
|
||||||
|
|
@ -195,6 +194,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
case 0x1F: return PacketIncomingType.KeepAlive;
|
case 0x1F: return PacketIncomingType.KeepAlive;
|
||||||
case 0x23: return PacketIncomingType.JoinGame;
|
case 0x23: return PacketIncomingType.JoinGame;
|
||||||
case 0x0F: return PacketIncomingType.ChatMessage;
|
case 0x0F: return PacketIncomingType.ChatMessage;
|
||||||
|
case 0x33: return PacketIncomingType.Respawn;
|
||||||
case 0x2E: return PacketIncomingType.PlayerPositionAndLook;
|
case 0x2E: return PacketIncomingType.PlayerPositionAndLook;
|
||||||
case 0x20: return PacketIncomingType.ChunkData;
|
case 0x20: return PacketIncomingType.ChunkData;
|
||||||
case 0x10: return PacketIncomingType.MultiBlockChange;
|
case 0x10: return PacketIncomingType.MultiBlockChange;
|
||||||
|
|
@ -234,7 +234,6 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Regular in-game packets
|
// Regular in-game packets
|
||||||
|
|
||||||
switch (getPacketIncomingType(packetID, protocolversion))
|
switch (getPacketIncomingType(packetID, protocolversion))
|
||||||
{
|
{
|
||||||
case PacketIncomingType.KeepAlive:
|
case PacketIncomingType.KeepAlive:
|
||||||
|
|
@ -242,6 +241,16 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
break;
|
break;
|
||||||
case PacketIncomingType.JoinGame:
|
case PacketIncomingType.JoinGame:
|
||||||
handler.OnGameJoined();
|
handler.OnGameJoined();
|
||||||
|
readNextInt(packetData);
|
||||||
|
readNextByte(packetData);
|
||||||
|
if (protocolversion >= MC191Version)
|
||||||
|
this.currentDimension = readNextInt(packetData);
|
||||||
|
else
|
||||||
|
this.currentDimension = (sbyte)readNextByte(packetData);
|
||||||
|
readNextByte(packetData);
|
||||||
|
readNextByte(packetData);
|
||||||
|
readNextString(packetData);
|
||||||
|
readNextBool(packetData);
|
||||||
break;
|
break;
|
||||||
case PacketIncomingType.ChatMessage:
|
case PacketIncomingType.ChatMessage:
|
||||||
string message = readNextString(packetData);
|
string message = readNextString(packetData);
|
||||||
|
|
@ -256,6 +265,12 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
catch (ArgumentOutOfRangeException) { /* No message type */ }
|
catch (ArgumentOutOfRangeException) { /* No message type */ }
|
||||||
handler.OnTextReceived(ChatParser.ParseText(message));
|
handler.OnTextReceived(ChatParser.ParseText(message));
|
||||||
break;
|
break;
|
||||||
|
case PacketIncomingType.Respawn:
|
||||||
|
this.currentDimension = readNextInt(packetData);
|
||||||
|
readNextByte(packetData);
|
||||||
|
readNextByte(packetData);
|
||||||
|
readNextString(packetData);
|
||||||
|
break;
|
||||||
case PacketIncomingType.PlayerPositionAndLook:
|
case PacketIncomingType.PlayerPositionAndLook:
|
||||||
if (Settings.TerrainAndMovements)
|
if (Settings.TerrainAndMovements)
|
||||||
{
|
{
|
||||||
|
|
@ -273,7 +288,11 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
handler.UpdateLocation(location);
|
handler.UpdateLocation(location);
|
||||||
|
|
||||||
if (protocolversion >= MC19Version)
|
if (protocolversion >= MC19Version)
|
||||||
readNextVarInt(packetData);
|
{
|
||||||
|
int teleportID = readNextVarInt(packetData);
|
||||||
|
// Teleport confirm packet
|
||||||
|
SendPacket(0x00, getVarInt(teleportID));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case PacketIncomingType.ChunkData:
|
case PacketIncomingType.ChunkData:
|
||||||
|
|
@ -446,11 +465,13 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
SendPluginChannelPacket("REGISTER", Encoding.UTF8.GetBytes(string.Join("\0", channels)));
|
SendPluginChannelPacket("REGISTER", Encoding.UTF8.GetBytes(string.Join("\0", channels)));
|
||||||
|
|
||||||
byte fmlProtocolVersion = readNextByte(packetData);
|
byte fmlProtocolVersion = readNextByte(packetData);
|
||||||
// There's another value afterwards for the dimension, but we don't need it.
|
|
||||||
|
|
||||||
if (Settings.DebugMessages)
|
if (Settings.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted("§8Forge protocol version : " + fmlProtocolVersion);
|
ConsoleIO.WriteLineFormatted("§8Forge protocol version : " + fmlProtocolVersion);
|
||||||
|
|
||||||
|
if (fmlProtocolVersion >= 1)
|
||||||
|
this.currentDimension = readNextInt(packetData);
|
||||||
|
|
||||||
// Tell the server we're running the same version.
|
// Tell the server we're running the same version.
|
||||||
SendForgeHandshakePacket(FMLHandshakeDiscriminator.ClientHello, new byte[] { fmlProtocolVersion });
|
SendForgeHandshakePacket(FMLHandshakeDiscriminator.ClientHello, new byte[] { fmlProtocolVersion });
|
||||||
|
|
||||||
|
|
@ -581,13 +602,93 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
private void ProcessChunkColumnData(int chunkX, int chunkZ, ushort chunkMask, bool hasSkyLight, bool chunksContinuous, List<byte> cache)
|
private void ProcessChunkColumnData(int chunkX, int chunkZ, ushort chunkMask, bool hasSkyLight, bool chunksContinuous, List<byte> cache)
|
||||||
{
|
{
|
||||||
if (protocolversion < MC19Version && chunksContinuous && chunkMask == 0)
|
if (protocolversion >= MC19Version)
|
||||||
{
|
{
|
||||||
//Unload the entire chunk column
|
// 1.9 and above chunk format
|
||||||
handler.GetWorld()[chunkX, chunkZ] = null;
|
// Unloading chunks is handled by a separate packet
|
||||||
|
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
|
||||||
|
{
|
||||||
|
if ((chunkMask & (1 << chunkY)) != 0)
|
||||||
|
{
|
||||||
|
byte bitsPerBlock = readNextByte(cache);
|
||||||
|
bool usePalette = (bitsPerBlock <= 8);
|
||||||
|
|
||||||
|
int paletteLength = readNextVarInt(cache);
|
||||||
|
int[] palette = new int[paletteLength];
|
||||||
|
for (int i = 0; i < paletteLength; i++)
|
||||||
|
{
|
||||||
|
palette[i] = readNextVarInt(cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bit mask covering bitsPerBlock bits
|
||||||
|
// EG, if bitsPerBlock = 5, valueMask = 00011111 in binary
|
||||||
|
uint valueMask = (uint)((1 << bitsPerBlock) - 1);
|
||||||
|
|
||||||
|
ulong[] dataArray = readNextULongArray(cache);
|
||||||
|
|
||||||
|
Chunk chunk = new Chunk();
|
||||||
|
|
||||||
|
for (int blockY = 0; blockY < Chunk.SizeY; blockY++)
|
||||||
|
{
|
||||||
|
for (int blockZ = 0; blockZ < Chunk.SizeZ; blockZ++)
|
||||||
|
{
|
||||||
|
for (int blockX = 0; blockX < Chunk.SizeX; blockX++)
|
||||||
|
{
|
||||||
|
int blockNumber = (blockY * Chunk.SizeZ + blockZ) * Chunk.SizeX + blockX;
|
||||||
|
|
||||||
|
int startLong = (blockNumber * bitsPerBlock) / 64;
|
||||||
|
int startOffset = (blockNumber * bitsPerBlock) % 64;
|
||||||
|
int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / 64;
|
||||||
|
|
||||||
|
// TODO: In the future a single ushort may not store the entire block id;
|
||||||
|
// the Block code may need to change.
|
||||||
|
ushort blockId;
|
||||||
|
if (startLong == endLong)
|
||||||
|
{
|
||||||
|
blockId = (ushort)((dataArray[startLong] >> startOffset) & valueMask);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
int endOffset = 64 - startOffset;
|
||||||
|
blockId = (ushort)((dataArray[startLong] >> startOffset | dataArray[endLong] << endOffset) & valueMask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usePalette)
|
||||||
|
{
|
||||||
|
// Get the real block ID out of the palette
|
||||||
|
blockId = (ushort)palette[blockId];
|
||||||
|
}
|
||||||
|
|
||||||
|
chunk[blockX, blockY, blockZ] = new Block(blockId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//We have our chunk, save the chunk into the world
|
||||||
|
if (handler.GetWorld()[chunkX, chunkZ] == null)
|
||||||
|
handler.GetWorld()[chunkX, chunkZ] = new ChunkColumn();
|
||||||
|
handler.GetWorld()[chunkX, chunkZ][chunkY] = chunk;
|
||||||
|
|
||||||
|
//Skip block light
|
||||||
|
readData((Chunk.SizeX * Chunk.SizeY * Chunk.SizeZ) / 2, cache);
|
||||||
|
|
||||||
|
//Skip sky light
|
||||||
|
if (this.currentDimension != -1)
|
||||||
|
// Sky light is not sent in the nether
|
||||||
|
readData((Chunk.SizeX * Chunk.SizeY * Chunk.SizeZ) / 2, cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't worry about skipping remaining data since there is no useful data afterwards in 1.9
|
||||||
|
// (plus, it would require parsing the tile entity lists' NBT)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Pre 1.9 chunk format
|
||||||
|
if (chunksContinuous && chunkMask == 0) {
|
||||||
|
//Unload the entire chunk column
|
||||||
|
handler.GetWorld()[chunkX, chunkZ] = null;
|
||||||
|
} else {
|
||||||
//Load chunk data from the server
|
//Load chunk data from the server
|
||||||
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
|
for (int chunkY = 0; chunkY < ChunkColumn.ColumnSize; chunkY++)
|
||||||
{
|
{
|
||||||
|
|
@ -628,6 +729,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
readData(Chunk.SizeX * Chunk.SizeZ, cache);
|
readData(Chunk.SizeX * Chunk.SizeZ, cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Start the updating thread. Should be called after login success.
|
/// Start the updating thread. Should be called after login success.
|
||||||
|
|
@ -755,9 +857,9 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read an unsigned short integer from a cache of bytes and remove it from the cache
|
/// Read an unsigned long integer from a cache of bytes and remove it from the cache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The unsigned short integer value</returns>
|
/// <returns>The unsigned long integer value</returns>
|
||||||
|
|
||||||
private static ulong readNextULong(List<byte> cache)
|
private static ulong readNextULong(List<byte> cache)
|
||||||
{
|
{
|
||||||
|
|
@ -805,6 +907,20 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
return readData(len, cache);
|
return readData(len, cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a length-prefixed array of unsigned long integers and removes it from the cache
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The unsigned long integer values</returns>
|
||||||
|
|
||||||
|
private static ulong[] readNextULongArray(List<byte> cache)
|
||||||
|
{
|
||||||
|
int len = readNextVarInt(cache);
|
||||||
|
ulong[] result = new ulong[len];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
result[i] = readNextULong(cache);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Read a double from a cache of bytes and remove it from the cache
|
/// Read a double from a cache of bytes and remove it from the cache
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue