public void Handshake(byte[] bytes, int offset) { Type targetType = typeof(T); Type[] allTypes = targetType.Assembly.GetTypes(); Type[] namespaceSchemaTypes = Array.FindAll(allTypes, t => ( t.Namespace == targetType.Namespace && typeof(Schema.Schema).IsAssignableFrom(targetType) )); Schema.Reflection reflection = new Schema.Reflection(); Schema.Iterator it = new Schema.Iterator { Offset = offset }; reflection.Decode(bytes, it); for (var i = 0; i < reflection.types.Count; i++) { Type schemaType = Array.Find(namespaceSchemaTypes, t => CompareTypes(t, reflection.types[i])); if (schemaType == null) { throw new Exception("Local schema mismatch from server. Use \"schema-codegen\" to generate up-to-date local definitions."); } Schema.Context.GetInstance().SetTypeId(schemaType, reflection.types[i].id); } }
protected async void ParseMessage(byte[] bytes) { byte code = bytes[0]; if (code == Protocol.JOIN_ROOM) { var offset = 1; SerializerId = System.Text.Encoding.UTF8.GetString(bytes, offset + 1, bytes[offset]); offset += SerializerId.Length + 1; if (SerializerId == "schema") { try { serializer = new SchemaSerializer <T>(); } catch (Exception e) { DisplaySerializerErrorHelp(e, "Consider using the \"schema-codegen\" and providing the same room state for matchmaking instead of \"" + typeof(T).Name + "\""); } } else if (SerializerId == "fossil-delta") { try { serializer = (ISerializer <T>) new FossilDeltaSerializer(); } catch (Exception e) { DisplaySerializerErrorHelp(e, "Consider using \"IndexedDictionary<string, object>\" instead of \"" + typeof(T).Name + "\" for matchmaking."); } } else { try { serializer = (ISerializer <T>) new NoneSerializer(); } catch (Exception e) { DisplaySerializerErrorHelp(e, "Consider setting state in the server-side using \"this.setState(new " + typeof(T).Name + "())\""); } } if (bytes.Length > offset) { serializer.Handshake(bytes, offset); } OnJoin?.Invoke(); // Acknowledge JOIN_ROOM await Connection.Send(new byte[] { Protocol.JOIN_ROOM }); } else if (code == Protocol.ERROR) { Schema.Iterator it = new Schema.Iterator { Offset = 1 }; var errorCode = Decode.DecodeNumber(bytes, it); var errorMessage = Decode.DecodeString(bytes, it); OnError?.Invoke((int)errorCode, errorMessage); } else if (code == Protocol.ROOM_DATA_SCHEMA) { Schema.Iterator it = new Schema.Iterator { Offset = 1 }; var typeId = Decode.DecodeNumber(bytes, it); Type messageType = Schema.Context.GetInstance().Get(typeId); var message = (Schema.Schema)Activator.CreateInstance(messageType); message.Decode(bytes, it); IMessageHandler handler = null; OnMessageHandlers.TryGetValue("s" + message.GetType(), out handler); if (handler != null) { handler.Invoke(message); } else { Debug.LogWarning("room.OnMessage not registered for Schema of type: '" + message.GetType() + "'"); } } else if (code == Protocol.LEAVE_ROOM) { await Leave(); } else if (code == Protocol.ROOM_STATE) { Debug.Log("ROOM_STATE"); SetState(bytes, 1); } else if (code == Protocol.ROOM_STATE_PATCH) { Debug.Log("ROOM_STATE_PATCH"); Patch(bytes, 1); } else if (code == Protocol.ROOM_DATA) { IMessageHandler handler = null; object type; Schema.Iterator it = new Schema.Iterator { Offset = 1 }; if (Decode.NumberCheck(bytes, it)) { type = Decode.DecodeNumber(bytes, it); OnMessageHandlers.TryGetValue("i" + type, out handler); } else { type = Decode.DecodeString(bytes, it); OnMessageHandlers.TryGetValue(type.ToString(), out handler); } if (handler != null) { // // MsgPack deserialization can be optimized: // https://github.com/deniszykov/msgpack-unity3d/issues/23 // var message = (bytes.Length > it.Offset) ? MsgPack.Deserialize(handler.Type, new MemoryStream(bytes, it.Offset, bytes.Length - it.Offset, false)) : null; handler.Invoke(message); } else { Debug.LogWarning("room.OnMessage not registered for: '" + type + "'"); } } }
protected async void ParseMessage(byte[] bytes) { byte code = bytes[0]; Debug.Log("BYTE =>" + code); if (code == Protocol.JOIN_ROOM) { var offset = 1; SerializerId = System.Text.Encoding.UTF8.GetString(bytes, offset + 1, bytes[offset]); offset += SerializerId.Length + 1; if (SerializerId == "schema") { serializer = new SchemaSerializer <T>(); } else if (SerializerId == "fossil-delta") { serializer = (ISerializer <T>) new FossilDeltaSerializer(); } if (bytes.Length > offset) { serializer.Handshake(bytes, offset); } OnJoin?.Invoke(); // Acknowledge JOIN_ROOM await Connection.Send(new byte[] { Protocol.JOIN_ROOM }); } else if (code == Protocol.ERROR) { Schema.Iterator it = new Schema.Iterator { Offset = 1 }; var errorCode = Decode.DecodeNumber(bytes, it); var errorMessage = Decode.DecodeString(bytes, it); OnError?.Invoke((int)errorCode, errorMessage); } else if (code == Protocol.ROOM_DATA_SCHEMA) { Type messageType = Schema.Context.GetInstance().Get(bytes[1]); var message = (Schema.Schema)Activator.CreateInstance(messageType); message.Decode(bytes, new Schema.Iterator { Offset = 2 }); IMessageHandler handler = null; OnMessageHandlers.TryGetValue("s" + message.GetType(), out handler); if (handler != null) { handler.Invoke(message); } else { Debug.LogError("room.OnMessage not registered for Schema message: " + message.GetType()); } } else if (code == Protocol.LEAVE_ROOM) { await Leave(); } else if (code == Protocol.ROOM_STATE) { Debug.Log("ROOM_STATE"); SetState(bytes, 1); } else if (code == Protocol.ROOM_STATE_PATCH) { Debug.Log("ROOM_STATE_PATCH"); Patch(bytes, 1); } else if (code == Protocol.ROOM_DATA) { IMessageHandler handler = null; object type; Schema.Iterator it = new Schema.Iterator { Offset = 1 }; if (Decode.NumberCheck(bytes, it)) { type = Decode.DecodeNumber(bytes, it); OnMessageHandlers.TryGetValue("i" + type, out handler); } else { type = Decode.DecodeString(bytes, it); OnMessageHandlers.TryGetValue(type.ToString(), out handler); } if (handler != null) { // // MsgPack deserialization can be optimized: // https://github.com/deniszykov/msgpack-unity3d/issues/23 // var message = (bytes.Length > it.Offset) ? MsgPack.Deserialize(handler.Type, new MemoryStream(bytes, it.Offset, bytes.Length - it.Offset, false)) : null; handler.Invoke(message); } else { Debug.LogError("room.OnMessage not registered for: " + type); } } }
public bool NumberCheck(byte[] bytes, Iterator it) { byte prefix = bytes[it.Offset]; return(prefix < 0x80 || (prefix >= 0xca && prefix <= 0xd3)); }
public object DecodeNumber(byte[] bytes, Iterator it) { byte prefix = bytes[it.Offset++]; if (prefix < 0x80) { // positive fixint return(prefix); } else if (prefix == 0xca) { // float 32 return(DecodeFloat32(bytes, it)); } else if (prefix == 0xcb) { // float 64 return(DecodeFloat64(bytes, it)); } else if (prefix == 0xcc) { // uint 8 return(DecodeUint8(bytes, it)); } else if (prefix == 0xcd) { // uint 16 return(DecodeUint16(bytes, it)); } else if (prefix == 0xce) { // uint 32 return(DecodeUint32(bytes, it)); } else if (prefix == 0xcf) { // uint 64 return(DecodeUint64(bytes, it)); } else if (prefix == 0xd0) { // int 8 return(DecodeInt8(bytes, it)); } else if (prefix == 0xd1) { // int 16 return(DecodeInt16(bytes, it)); } else if (prefix == 0xd2) { // int 32 return(DecodeInt32(bytes, it)); } else if (prefix == 0xd3) { // int 64 return(DecodeInt64(bytes, it)); } else if (prefix > 0xdf) { // negative fixint return((0xff - prefix + 1) * -1); } return(double.NaN); }
public bool IndexChangeCheck(byte[] bytes, Iterator it) { return(bytes[it.Offset] == (byte)SPEC.INDEX_CHANGE); }
/* * Bool checks */ public bool NilCheck(byte[] bytes, Iterator it) { return(bytes[it.Offset] == (byte)SPEC.NIL); }
public bool DecodeBoolean(byte[] bytes, Iterator it) { return(DecodeUint8(bytes, it) > 0); }
public uint DecodeUint8(byte[] bytes, Iterator it) { return(bytes[it.Offset++]); }
public int DecodeInt8(byte[] bytes, Iterator it) { return(((int)DecodeUint8(bytes, it)) << 24 >> 24); }