public void Update() { if (m_Socket.Poll(0, SelectMode.SelectRead)) { int read = m_Socket.ReceiveFrom(m_Buffer, m_Buffer.Length, SocketFlags.None, ref endpoint); if (read > 0) { var reader = new ByteInputStream(m_Buffer); var header = new SQPHeader(); header.FromStream(ref reader); switch (m_State) { case SQPClientState.Idle: break; case SQPClientState.WaitingForChallange: if ((SQPMessageType)header.Type == SQPMessageType.ChallangeResponse) { if (endpoint.Equals(m_Server)) { ChallangeId = header.ChallangeId; SendServerInfoQuery(); } } break; case SQPClientState.WaitingForResponse: if ((SQPMessageType)header.Type == SQPMessageType.QueryResponse) { reader.Reset(); var rsp = new SQP.ServerInfo(); rsp.FromStream(ref reader); Debug.Log(string.Format("ServerName: {0}, BuildId: {1}, Current Players: {2}, Max Players: {3}, GameType: {4}, Map: {5}, Port: {6}", rsp.ServerInfoData.ServerName, rsp.ServerInfoData.BuildId, (ushort)rsp.ServerInfoData.CurrentPlayers, (ushort)rsp.ServerInfoData.MaxPlayers, rsp.ServerInfoData.GameType, rsp.ServerInfoData.Map, (ushort)rsp.ServerInfoData.Port)); m_State = SQPClientState.Success; StartTime = NetworkUtils.stopwatch.ElapsedMilliseconds; } break; default: break; } } } var now = NetworkUtils.stopwatch.ElapsedMilliseconds; if (now - StartTime > 1000000) { Debug.Log("Failed"); m_State = SQPClientState.Failure; } }
static public unsafe void Write <TOutputStream>(ref TOutputStream output, NetworkSchema schema, byte[] inputData, byte[] baselineData, byte[] fieldsChangedPrediction, byte fieldMask, ref uint entity_hash) where TOutputStream : NetworkCompression.IOutputStream { GameDebug.Assert(baselineData != null); var inputStream = new ByteInputStream(inputData); var baselineStream = new ByteInputStream(baselineData); int numFields = schema.fields.Count; GameDebug.Assert(fieldsChangedPrediction.Length >= numFields / 8, "Not enough bits in fieldsChangedPrediction for all fields"); for (int i = 0, l = fieldsNotPredicted.Length; i < l; ++i) { fieldsNotPredicted[i] = 0; } // calculate bitmask of fields that need to be encoded for (int fieldIndex = 0; fieldIndex < schema.fields.Count; ++fieldIndex) { var field = schema.fields[fieldIndex]; // Skip fields that are masked out bool masked = (field.fieldMask & fieldMask) != 0; byte fieldByteOffset = (byte)((uint)fieldIndex >> 3); byte fieldBitOffset = (byte)((uint)fieldIndex & 0x7); switch (field.fieldType) { case NetworkSchema.FieldType.Bool: { uint value = inputStream.ReadBits(1); uint baseline = baselineStream.ReadUInt8(); if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Int: { uint value = inputStream.ReadBits(field.bits); uint baseline = (uint)baselineStream.ReadBits(field.bits); if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.UInt: { uint value = inputStream.ReadBits(field.bits); uint baseline = (uint)baselineStream.ReadBits(field.bits); if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Float: { uint value = inputStream.ReadBits(field.bits); uint baseline = (uint)baselineStream.ReadBits(field.bits); if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, value); if (value != baseline) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Vector2: { uint vx = inputStream.ReadBits(field.bits); uint vy = inputStream.ReadBits(field.bits); uint bx = baselineStream.ReadUInt32(); uint by = baselineStream.ReadUInt32(); if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vx); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vy); if (vx != bx || vy != by) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Vector3: { uint vx = inputStream.ReadBits(field.bits); uint vy = inputStream.ReadBits(field.bits); uint vz = inputStream.ReadBits(field.bits); uint bx = baselineStream.ReadUInt32(); uint by = baselineStream.ReadUInt32(); uint bz = baselineStream.ReadUInt32(); if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vx); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vy); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vz); if (vx != bx || vy != by || vz != bz) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.Quaternion: { uint vx = inputStream.ReadBits(field.bits); uint vy = inputStream.ReadBits(field.bits); uint vz = inputStream.ReadBits(field.bits); uint vw = inputStream.ReadBits(field.bits); uint bx = baselineStream.ReadUInt32(); uint by = baselineStream.ReadUInt32(); uint bz = baselineStream.ReadUInt32(); uint bw = baselineStream.ReadUInt32(); if (!masked) { entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vx); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vy); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vz); entity_hash = NetworkUtils.SimpleHashStreaming(entity_hash, vw); if (vx != bx || vy != by || vz != bz || vw != bw) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } break; } case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: { // TODO : Do a better job of string and buffer diffs? byte[] valueBuffer; int valueOffset; int valueLength; inputStream.GetByteArray(out valueBuffer, out valueOffset, out valueLength, field.arraySize); byte[] baselineBuffer = null; int baselineOffset = 0; int baselineLength = 0; baselineStream.GetByteArray(out baselineBuffer, out baselineOffset, out baselineLength, field.arraySize); if (!masked) { entity_hash += 0; // TODO client side has no easy way to hash strings. enable this when possible: NetworkUtils.SimpleHash(valueBuffer, valueLength); if (valueLength != baselineLength || NetworkUtils.MemCmp(valueBuffer, valueOffset, baselineBuffer, baselineOffset, valueLength) != 0) { fieldsNotPredicted[fieldByteOffset] |= (byte)(1 << fieldBitOffset); } } } break; } } inputStream.Reset(); baselineStream.Reset(); int skipContext = schema.id * NetworkConfig.maxContextsPerSchema + NetworkConfig.firstSchemaContext; // Client needs fieldsNotPredicted. We send the delta between it and fieldsChangedPrediction { for (int i = 0; i * 8 < numFields; i++) { byte deltaFields = (byte)(fieldsNotPredicted[i] ^ fieldsChangedPrediction[i]); output.WritePackedNibble((uint)(deltaFields & 0xF), skipContext + i * 2); output.WritePackedNibble((uint)((deltaFields >> 4) & 0xF), skipContext + i * 2 + 1); } } int startBitPosition = 0; for (int fieldIndex = 0; fieldIndex < numFields; ++fieldIndex) { var field = schema.fields[fieldIndex]; int fieldStartContext = field.startContext; startBitPosition = output.GetBitPosition2(); byte fieldByteOffset = (byte)((uint)fieldIndex >> 3); byte fieldBitOffset = (byte)((uint)fieldIndex & 0x7); var notPredicted = ((fieldsNotPredicted[fieldByteOffset] & (1 << fieldBitOffset)) != 0); switch (field.fieldType) { case NetworkSchema.FieldType.Bool: { uint value = inputStream.ReadBits(1); /*uint unused_baseline = */ baselineStream.ReadUInt8(); if (notPredicted) { output.WriteRawBits(value, 1); NetworkSchema.AddStatsToFieldBool(field, (value != 0), false, output.GetBitPosition2() - startBitPosition); } break; } case NetworkSchema.FieldType.Int: { uint value = inputStream.ReadBits(field.bits); uint baseline = (uint)baselineStream.ReadBits(field.bits); if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(value, baseline, fieldStartContext); NetworkSchema.AddStatsToFieldInt(field, (int)value, (int)baseline, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(value, field.bits); NetworkSchema.AddStatsToFieldInt(field, (int)value, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.UInt: { uint value = inputStream.ReadBits(field.bits); uint baseline = (uint)baselineStream.ReadBits(field.bits); if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(value, baseline, fieldStartContext); NetworkSchema.AddStatsToFieldUInt(field, value, baseline, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(value, field.bits); NetworkSchema.AddStatsToFieldUInt(field, value, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Float: { uint value = inputStream.ReadBits(field.bits); uint baseline = (uint)baselineStream.ReadBits(field.bits); if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(value, baseline, fieldStartContext); NetworkSchema.AddStatsToFieldFloat(field, value, baseline, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(value, field.bits); NetworkSchema.AddStatsToFieldFloat(field, value, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Vector2: { uint vx = inputStream.ReadBits(field.bits); uint vy = inputStream.ReadBits(field.bits); uint bx = baselineStream.ReadUInt32(); uint by = baselineStream.ReadUInt32(); if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(vx, bx, fieldStartContext + 0); output.WritePackedUIntDelta(vy, by, fieldStartContext + 1); NetworkSchema.AddStatsToFieldVector2(field, vx, vy, bx, by, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(vx, field.bits); output.WriteRawBits(vy, field.bits); NetworkSchema.AddStatsToFieldVector2(field, vx, vy, 0, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Vector3: { uint vx = inputStream.ReadBits(field.bits); uint vy = inputStream.ReadBits(field.bits); uint vz = inputStream.ReadBits(field.bits); uint bx = baselineStream.ReadUInt32(); uint by = baselineStream.ReadUInt32(); uint bz = baselineStream.ReadUInt32(); if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(vx, bx, fieldStartContext + 0); output.WritePackedUIntDelta(vy, by, fieldStartContext + 1); output.WritePackedUIntDelta(vz, bz, fieldStartContext + 2); NetworkSchema.AddStatsToFieldVector3(field, vx, vy, vz, bx, by, bz, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(vx, field.bits); output.WriteRawBits(vy, field.bits); output.WriteRawBits(vz, field.bits); NetworkSchema.AddStatsToFieldVector3(field, vx, vy, vz, 0, 0, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.Quaternion: { // TODO : Figure out what to do with quaternions uint vx = inputStream.ReadBits(field.bits); uint vy = inputStream.ReadBits(field.bits); uint vz = inputStream.ReadBits(field.bits); uint vw = inputStream.ReadBits(field.bits); uint bx = baselineStream.ReadUInt32(); uint by = baselineStream.ReadUInt32(); uint bz = baselineStream.ReadUInt32(); uint bw = baselineStream.ReadUInt32(); if (notPredicted) { if (field.delta) { output.WritePackedUIntDelta(vx, bx, fieldStartContext + 0); output.WritePackedUIntDelta(vy, by, fieldStartContext + 1); output.WritePackedUIntDelta(vz, bz, fieldStartContext + 2); output.WritePackedUIntDelta(vw, bw, fieldStartContext + 3); NetworkSchema.AddStatsToFieldQuaternion(field, vx, vy, vz, vw, bx, by, bz, bw, output.GetBitPosition2() - startBitPosition); } else { output.WriteRawBits(vx, field.bits); output.WriteRawBits(vy, field.bits); output.WriteRawBits(vz, field.bits); output.WriteRawBits(vw, field.bits); NetworkSchema.AddStatsToFieldQuaternion(field, vx, vy, vz, vw, 0, 0, 0, 0, output.GetBitPosition2() - startBitPosition); } } break; } case NetworkSchema.FieldType.String: case NetworkSchema.FieldType.ByteArray: { // TODO : Do a better job of string and buffer diffs? byte[] valueBuffer; int valueOffset; int valueLength; inputStream.GetByteArray(out valueBuffer, out valueOffset, out valueLength, field.arraySize); byte[] baselineBuffer = null; int baselineOffset = 0; int baselineLength = 0; baselineStream.GetByteArray(out baselineBuffer, out baselineOffset, out baselineLength, field.arraySize); if (notPredicted) { output.WritePackedUInt((uint)valueLength, fieldStartContext); output.WriteRawBytes(valueBuffer, valueOffset, valueLength); if (field.fieldType == NetworkSchema.FieldType.String) { NetworkSchema.AddStatsToFieldString(field, valueBuffer, valueOffset, valueLength, output.GetBitPosition2() - startBitPosition); } else { NetworkSchema.AddStatsToFieldByteArray(field, valueBuffer, valueOffset, valueLength, output.GetBitPosition2() - startBitPosition); } } } break; } } }
public void Update() { if (m_Socket.Poll(0, SelectMode.SelectRead)) { int read = m_Socket.ReceiveFrom(m_Buffer, m_Buffer.Length, SocketFlags.None, ref endpoint); if (read > 0) { var reader = new ByteInputStream(m_Buffer); var header = new SQPHeader(); header.FromStream(ref reader); SQPMessageType type = (SQPMessageType)header.Type; switch (type) { case SQPMessageType.ChallangeRequest: { if (!m_OutstandingTokens.ContainsKey(endpoint)) { uint token = GetNextToken(); //Debug.Log("token generated: " + token); var writer = new ByteOutputStream(m_Buffer); var rsp = new ChallangeResponse(); rsp.Header.ChallangeId = token; rsp.ToStream(ref writer); m_Socket.SendTo(m_Buffer, writer.GetBytePosition(), SocketFlags.None, endpoint); m_OutstandingTokens.Add(endpoint, token); } } break; case SQPMessageType.QueryRequest: { uint token; if (!m_OutstandingTokens.TryGetValue(endpoint, out token)) { //Debug.Log("Failed to find token!"); return; } m_OutstandingTokens.Remove(endpoint); reader.Reset(); var req = new QueryRequest(); req.FromStream(ref reader); if ((SQPChunkType)req.RequestedChunks == SQPChunkType.ServerInfo) { var rsp = m_ServerInfo; var writer = new ByteOutputStream(m_Buffer); rsp.QueryHeader.Header.ChallangeId = token; rsp.ToStream(ref writer); m_Socket.SendTo(m_Buffer, writer.GetBytePosition(), SocketFlags.None, endpoint); } } break; default: break; } } } }
public void Update() { if (m_Socket.Poll(0, SelectMode.SelectRead)) { int read = m_Socket.ReceiveFrom(m_Buffer, m_Buffer.Length, SocketFlags.None, ref endpoint); if (read > 0) { var reader = new ByteInputStream(m_Buffer); var header = new SQPHeader(); header.FromStream(ref reader); foreach (var q in m_Queries) { if (q.m_Server == null || !endpoint.Equals(q.m_Server)) { continue; } switch (q.m_State) { case SQPClientState.Idle: // Just ignore if we get extra data break; case SQPClientState.WaitingForChallange: if ((SQPMessageType)header.Type == SQPMessageType.ChallangeResponse) { q.ChallangeId = header.ChallangeId; q.RTT = NetworkUtils.stopwatch.ElapsedMilliseconds - q.StartTime; // We restart timer so we can get an RTT that is an average between two measurements q.StartTime = NetworkUtils.stopwatch.ElapsedMilliseconds; SendServerInfoQuery(q); } break; case SQPClientState.WaitingForResponse: if ((SQPMessageType)header.Type == SQPMessageType.QueryResponse) { reader.Reset(); q.m_ServerInfo.FromStream(ref reader); // We report the average of two measurements q.RTT = (q.RTT + (NetworkUtils.stopwatch.ElapsedMilliseconds - q.StartTime)) / 2; /* * GameDebug.Log(string.Format("ServerName: {0}, BuildId: {1}, Current Players: {2}, Max Players: {3}, GameType: {4}, Map: {5}, Port: {6}", * m_ServerInfo.ServerInfoData.ServerName, * m_ServerInfo.ServerInfoData.BuildId, * (ushort)m_ServerInfo.ServerInfoData.CurrentPlayers, * (ushort)m_ServerInfo.ServerInfoData.MaxPlayers, * m_ServerInfo.ServerInfoData.GameType, * m_ServerInfo.ServerInfoData.Map, * (ushort)m_ServerInfo.ServerInfoData.Port)); */ q.validResult = true; q.m_State = SQPClientState.Idle; } break; default: break; } } } } foreach (var q in m_Queries) { // Timeout if stuck in any state but idle for too long if (q.m_State != SQPClientState.Idle) { var now = NetworkUtils.stopwatch.ElapsedMilliseconds; if (now - q.StartTime > 3000) { q.m_State = SQPClientState.Idle; } } } }