/// <summary> /// Reads the next string /// </summary> /// <param name="bytes"></param> /// <returns></returns> public static string GetString(List <byte> bytes) { int strLen = VarInt.ReadNext(bytes); var strRaw = bytes.Read(strLen); return(Encoding.UTF8.GetString(strRaw.ToArray())); }
public void Read(List <byte> buffer) { int paletteLength = VarInt.ReadNext(buffer); for (int i = 0; i < paletteLength; i++) { uint blockState = (uint)VarInt.ReadNext(buffer); _blockStates.Add((uint)i, blockState); } }
/// <summary> /// Populates this chunk with data from a <see cref="ChunkDataPacket"/> /// </summary> /// <param name="packet"></param> public void AddChunkData(ChunkDataPacket packet) { //check if data applies to this chunk if (!packet.Position.Equals(Position)) { Debug.LogWarning($"Chunk at {Position} tried to add data for chunk at {packet.Position}??"); return; } // lock block array to stop block changes from happening var data = new List<byte>(packet.Data); Profiler.BeginSample("Loading chunk sections"); // chunk data for (int s = 0; s < 16; s++) { // check bitmask to see if we're reading data for this section if ((packet.PrimaryBitmask & (1) << s) != 0) { Profiler.BeginSample($"Chunk section: {s}"); // set max block height to the height of this chunk int maxBlockHeight = (s + 1) * 16; if (maxBlockHeight > MaxHeight) MaxHeight = maxBlockHeight; // read bits per block byte bitsPerBlock = data.Read(1)[0]; if (bitsPerBlock < 4) bitsPerBlock = 4; // choose palette type IChunkPalette palette; if (bitsPerBlock <= 8) palette = new IndirectChunkPalette(); else palette = new DirectChunkPalette(); palette.Read(data); // read palette data, bringing chunk data into front of buffer // bitmask that contains bitsperblock set bits uint individualValueMask = (uint)((1 << bitsPerBlock) - 1); // read data into array of longs int dataArrayLength = VarInt.ReadNext(data); ulong[] dataArray = new ulong[dataArrayLength]; for (int i = 0; i < dataArrayLength; i++) { dataArray[i] = PacketHelper.GetUInt64(data); } Profiler.BeginSample("Block data"); // parse block data for (int b = 0; b < 4096; b++) // for section height { int startLong = (b * bitsPerBlock) / 64; int startOffset = (b * bitsPerBlock) % 64; int endLong = ((b + 1) * bitsPerBlock - 1) / 64; uint blockData; if (startLong == endLong) { blockData = (uint)(dataArray[startLong] >> startOffset); } else { int endOffset = 64 - startOffset; blockData = (uint)(dataArray[startLong] >> startOffset | dataArray[endLong] << endOffset); } blockData &= individualValueMask; uint blockState = palette.GetBlockState(blockData); BlockState blk = new BlockState((BlockType)blockState); // add block to block array BlockArray[b + (4096 * s)] = blk; } Profiler.EndSample(); // block data // we don't use sky or block lights // read data to move new data to front of buffer data.Read(2048); if (World.Dimension == World.DimensionType.OVERWORLD) data.Read(2048); /* Profiler.BeginSample("Block lights"); // parse block light data for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x += 2) { // light data takes 4 bits. because of this, we read two light values per byte byte value = data.Read(1)[0]; _blockLights[x, y + (16 * s), z] = value & 0xf; _blockLights[x + 1, y + (16 * s), z] = (value >> 4) & 0xf; } } } Profiler.EndSample(); // block lights // parse sky lights if (World.Dimension == World.DimensionType.OVERWORLD) { Profiler.BeginSample("Sky lights"); // parse block light data for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x += 2) { // light data takes 4 bits. because of this, we read two light values per byte byte value = data.Read(1)[0]; _skylights[x, y + (16 * s), z] = value & 0xf; _skylights[x + 1, y + (16 * s), z] = (value >> 4) & 0xf; } } } Profiler.EndSample(); // sky lights } */ Profiler.EndSample(); // chunk section } else { // fill chunk section with air if full chunk if (packet.GroundUpContinuous) { for (int i = 0; i < 4096; i++) { BlockArray[s + (4096 * s)] = new BlockState(BlockType.AIR); } } } // parse biomes if (packet.GroundUpContinuous) { //throw new NotImplementedException(); } } }
/// <summary> /// Gets the next packet from the server /// </summary> /// <returns></returns> public PacketData ReadNextPacket() { int packetId; byte[] payload; lock (_streamReadLock) { int length = VarInt.ReadNext(ReadBytes); List <byte> buffer = new List <byte>(); // check if data is compressed if (_compressionThreshold >= 0) { int dataLength = VarInt.ReadNext(ReadBytes); length -= VarInt.GetBytes(dataLength).Length; // remove size of data length from rest of packet length if (dataLength != 0) { byte[] compressedBuffer = ReadBytes(length); buffer.AddRange(ZlibStream.UncompressBuffer(compressedBuffer)); } else { buffer.AddRange(ReadBytes(length)); } } else { buffer.AddRange(ReadBytes(length)); } packetId = VarInt.ReadNext(buffer); payload = buffer.ToArray(); } // handles some stuff during login phase if (State == ProtocolState.LOGIN) { // handle compression packet if (packetId == (int)ClientboundIDs.LogIn_SetCompression) { _compressionThreshold = VarInt.ReadNext(new List <byte>(payload)); return(ReadNextPacket()); } // handle protocol encryption packet if (packetId == (int)ClientboundIDs.LogIn_EncryptionRequest) { var encRequestPkt = new EncryptionRequestPacket() { Payload = payload }; var aesSecret = CryptoHandler.GenerateSharedSecret(); var authHash = CryptoHandler.SHAHash(Encoding.ASCII.GetBytes(encRequestPkt.ServerID).Concat(aesSecret, encRequestPkt.PublicKey)); Debug.Log($"Sending hash to Mojang servers: {authHash}"); // check session with mojang if (!MojangAPI.JoinServer(authHash)) { throw new UnityException("Invalid session. (Try restarting game or relogging into Minecraft account)"); } // use pub key to encrypt shared secret using (var rsaProvider = CryptoHandler.DecodeRSAPublicKey(encRequestPkt.PublicKey)) { byte[] encSecret = rsaProvider.Encrypt(aesSecret, false); byte[] encToken = rsaProvider.Encrypt(encRequestPkt.VerifyToken, false); // respond to server with private key var responsePkt = new EncryptionResponsePacket() { SharedSecret = encSecret, VerifyToken = encToken }; WritePacket(responsePkt); // enable aes encryption _aesStream = new AesStream(Client.GetStream(), aesSecret); _encrypted = true; // read the next packet return(ReadNextPacket()); } } } return(new PacketData { ID = packetId, Payload = payload }); }