예제 #1
0
    /// <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()));
    }
예제 #2
0
    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);
        }
    }
예제 #3
0
	/// <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();
			}
		}
	}
예제 #4
0
    /// <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
        });
    }