public void Leave()
            {
                if (!_roomJoined)
                {
                    return;
                }

                OrLog(LogLevel.Verbose, "MessageSend RelayCode.LEAVE");

                var header = new Header();

                //header.Ver = 0;
                header.RelayCode   = (byte)RelayCode.LEAVE;
                header.ContentCode = (byte)0;
                header.Mask        = (byte)0;
                header.DestCode    = (byte)DestinationCode.StrictBroadcast;
                //msg.LoginSeed = LoginGuid; //Convert.ToBase64String(content)
                header.SrcPid     = (PlayerId)Player.ID;
                header.SrcOid     = (ObjectId)Player.ObjectId;
                header.DestLen    = (UInt16)0;
                header.ContentLen = (UInt16)JoinGuid.Length;

                var headerSize  = Marshal.SizeOf <Header>(header);
                var headerBytes = new byte[headerSize];
                var gch         = GCHandle.Alloc(headerBytes, GCHandleType.Pinned);

                Marshal.StructureToPtr(header, gch.AddrOfPinnedObject(), false);
                gch.Free();

                var joinSeedSize = header.ContentLen;
                var messageBytes = new byte[headerSize + joinSeedSize];
                var stream       = new MemoryStream(messageBytes);
                var message      = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write(headerBytes);
                    message.Write(JoinGuid);
                    statefullQueue.Enqueue(messageBytes);
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                }
                message.Close();
                stream.Close();

                JoinGuid = new byte[] { };
            }
            public void SetPropertiesListedInLobby(string[] list, bool isCreateRoom)
            {
                if (!inRoom && !_roomJoined)
                {
                    return;
                }

                OrLog(LogLevel.Verbose, "MessageSend RelayCode.SET_LOBBY_MAP");

                var converted = ToExplodeBytes(list);

                var header = new Header();

                //header.Ver = 0;
                header.RelayCode   = (byte)RelayCode.SET_LOBBY_MAP;
                header.ContentCode = (byte)0;
                header.Mask        = (byte)0;
                header.DestCode    = (byte)DestinationCode.StrictBroadcast;
                header.SrcPid      = (PlayerId)0; // didn't assign yet.
                header.SrcOid      = (ObjectId)0; // didn't assign yet.
                header.DestLen     = (UInt16)0;
                header.ContentLen  = (UInt16)converted.Length;

                var headerSize  = Marshal.SizeOf <Header>(header);
                var headerBytes = new byte[headerSize];
                var gch         = GCHandle.Alloc(headerBytes, GCHandleType.Pinned);

                Marshal.StructureToPtr(header, gch.AddrOfPinnedObject(), false);
                gch.Free();

                var propertiesSize = header.ContentLen;
                var messageBytes   = new byte[headerSize + propertiesSize];
                var stream         = new MemoryStream(messageBytes);
                var message        = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write(headerBytes);
                    message.Write(converted);
                    statefullQueue.Enqueue(messageBytes);
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                }
                message.Close();
                stream.Close();
            }
            public void SetMaster(UserSession player)
            {
                if (!_roomJoined)
                {
                    return;
                }

                OrLog(LogLevel.Verbose, "MessageSend RelayCode.SET_MASTER");
                OrLog(LogLevel.Info, "Set Master player:" + player.ID.ToString());

                var header = new Header();

                //header.Ver = 0;
                header.RelayCode   = (byte)RelayCode.SET_MASTER;
                header.ContentCode = (byte)0;
                header.Mask        = (byte)0;
                header.DestCode    = (byte)DestinationCode.StrictBroadcast;
                header.SrcPid      = (PlayerId)Player.ID;
                header.SrcOid      = (ObjectId)Player.ObjectId;
                header.DestLen     = (UInt16)0;
                header.ContentLen  = (UInt16)0;

                var headerSize    = Marshal.SizeOf <Header>(header);
                var masterPidSize = sizeof(PlayerId);
                var headerBytes   = new byte[headerSize];
                var gch           = GCHandle.Alloc(headerBytes, GCHandleType.Pinned);

                Marshal.StructureToPtr(header, gch.AddrOfPinnedObject(), false);
                gch.Free();

                var messageBytes = new byte[headerSize + masterPidSize];
                var stream       = new MemoryStream(messageBytes);
                var message      = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write(headerBytes);
                    message.Write((PlayerId)player.ID);
                    statefullQueue.Enqueue(messageBytes);
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                }
                message.Close();
                stream.Close();
            }
            public IEnumerator PrepareAndJoinRoom(string roomName, string[] propKeys)
            {
                OrLog(LogLevel.Verbose, "post PrepareAndJoinRoom start");

                // create request message data.
                var newGuid      = Guid.NewGuid().ToByteArray();
                var joinSeedSize = newGuid.Length;

                var messageBytes = new byte[sizeof(UInt16) + joinSeedSize];
                var stream       = new MemoryStream(messageBytes);
                var message      = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write((UInt16)joinSeedSize);
                    message.Write(newGuid);
                    OrLog(LogLevel.Verbose, "prepare join: " + BitConverter.ToString(messageBytes));
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                }
                message.Close();
                stream.Close();

                yield return(StartCoroutine(JoinRoomPreparePolling(roomName, messageBytes, propKeys)));

                if (prepareAndJoinRoomAbort)
                {
                    yield break;
                }
                yield return(StartCoroutine(JoinRoomPrepareComplate(roomName, messageBytes)));

                if (prepareAndJoinRoomAbort)
                {
                    yield break;
                }
                yield return(StartCoroutine(JoinRoom(roomName, newGuid)));

                OrLog(LogLevel.Verbose, "post PrepareAndJoinRoom end");
                yield break;
            }
            private IEnumerator CreateRoom(string roomName, UInt16 maxPlayer, RoomOptions presetRoomOptions, bool ignoreExist)
            {
                createAndJoinRoomAbort = false;
                OrLog(LogLevel.Verbose, "room name: " + roomName);
                OrLog(LogLevel.Verbose, "room max player: " + maxPlayer);
                var messageBytes = new byte[sizeof(UInt16)];
                var stream       = new MemoryStream(messageBytes);
                var message      = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write(maxPlayer);
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                }
                message.Close();

                UnityWebRequest webRequest = UnityWebRequest.Put(BASE_URL + _serverAddress + ":" + _entryPort + "/room/create/" + roomName, messageBytes);

                webRequest.method = "POST";
                webRequest.SetRequestHeader("User-Agent", UA_UNITY_CDK);
                webRequest.SetRequestHeader("Content-Type", "application/octet-stream");
                //webRequest.SetRequestHeader("Content-Length", messageBytes.Length.ToString()); // auto setting.
                yield return(webRequest.SendWebRequest());

                if (webRequest.isNetworkError)
                {
                    OrLogError(LogLevel.Info, webRequest.error);
                    OnOpenRelayCreateRoomFailedCall((short)webRequest.responseCode, "failed polling");//TODO error handle case;
                    yield break;
                }

                var streamReader  = new MemoryStream(webRequest.downloadHandler.data);
                var messageReader = new EndiannessBinaryReader(streamReader);

                if (webRequest.responseCode != 200)
                {
                    OrLog(LogLevel.Verbose, "post create room failed. http status code:" + webRequest.responseCode);
                    OnOpenRelayCreateRoomFailedCall((short)webRequest.responseCode, " failed polling");

                    yield break;
                }

                var responseCode = (ResponseCode)messageReader.ReadUInt16();

                OrLog(LogLevel.Verbose, "read bytes responseCode:" + responseCode.ToString());
                messageReader.ReadUInt16();// read alignment

                if (ignoreExist && responseCode == ResponseCode.OPENRELAY_RESPONSE_CODE_NG_CREATE_ROOM_ALREADY_EXISTS)
                {
                    OrLog(LogLevel.Verbose, "ResponseCode.OPENRELAY_RESPONSE_CODE_NG_CREATE_ROOM_ALREADY_EXISTS, but ignore ");
                }
                else if (!ignoreExist && responseCode == ResponseCode.OPENRELAY_RESPONSE_CODE_NG_CREATE_ROOM_ALREADY_EXISTS)
                {
                    createAndJoinRoomAbort = true;
                    OrLogError(LogLevel.Info, "post create room failed. http status code:" + webRequest.responseCode);
                    OrLogError(LogLevel.Info, "post create room failed. response code:" + responseCode);
                    OnOpenRelayCreateRoomFailedCall((short)webRequest.responseCode, " failed polling");

                    yield break;
                }
                else if (responseCode != ResponseCode.OPENRELAY_RESPONSE_CODE_OK_ROOM_ASSGIN_AND_CREATED)
                {
                    OrLogError(LogLevel.Info, "post create room failed. http status code:" + webRequest.responseCode);
                    OrLogError(LogLevel.Info, "post create room failed. response code:" + responseCode);
                    OnOpenRelayCreateRoomFailedCall((short)webRequest.responseCode, " failed polling");

                    yield break;
                }

                var responseSize  = Marshal.SizeOf(typeof(RoomResponse));
                var responseBytes = messageReader.ReadBytes(responseSize);

                OrLog(LogLevel.VeryVerbose, "raw response:" + BitConverter.ToString(responseBytes));
                var          ptr = Marshal.AllocCoTaskMem(responseSize);
                var          gch = GCHandle.Alloc(responseBytes, GCHandleType.Pinned);
                RoomResponse response;

                try
                {
                    response = Marshal.PtrToStructure <RoomResponse>(gch.AddrOfPinnedObject());
                    OrLog(LogLevel.Verbose, "read bytes created room Id:" + BitConverter.ToString(response.Id));
                    OrLog(LogLevel.Verbose, "read bytes created room Capacity:" + response.Capacity.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room StfDealPort:" + response.StfDealPort.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room StfSubPort:" + response.StfSubPort.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room StlDealPort:" + response.StlDealPort.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room StlSubPort:" + response.StlSubPort.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room QueuingPolicy:" + response.QueuingPolicy.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room Flags:" + response.Flags.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room NameLen:" + response.NameLen.ToString());
                    OrLog(LogLevel.Verbose, "read bytes created room FilterLen:" + response.FilterLen.ToString());
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "handle error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                    OrLogError(LogLevel.Verbose, "post create room failed ");
                    gch.Free();

                    yield break;
                }
                gch.Free();

                //if (0 < response.NameLen)
                //{
                var name = messageReader.ReadBytes(256);

                OrLog(LogLevel.Verbose, "read bytes created room Name:" + Encoding.UTF8.GetString(name));
                //}
                //if (0 < response.FilterLen)
                //{
                var filter = messageReader.ReadBytes(256);

                OrLog(LogLevel.Verbose, "read bytes created room Filter:" + BitConverter.ToString(filter));
                //}
                var listenMode = messageReader.ReadByte();

                OrLog(LogLevel.Verbose, "read bytes get room listen mode:" + listenMode);
                messageReader.ReadBytes(3); // alignment 3bytes for 4byte alignment.
                var ipv4Bytes = messageReader.ReadBytes(4);
                var ipv4Addr  = new IPAddress(ipv4Bytes).ToString();

                //var ipv4Addr = _settings.ServerAddress; // TODO ISSUE 24 provisional fix
                OrLog(LogLevel.Verbose, "read bytes get room listen ipv4 addr:" + ipv4Addr);
                var ipv6Bytes = messageReader.ReadBytes(16);
                var ipv6Addr  = new IPAddress(ipv6Bytes).ToString();

                OrLog(LogLevel.Verbose, "read bytes get room listen ipv6 addr:" + ipv6Addr);
                _room = new RoomInfo(roomName,
                                     response.Id,
                                     listenMode,
                                     ipv4Addr,
                                     ipv6Addr,
                                     response.StfDealPort.ToString(),
                                     response.StfSubPort.ToString(),
                                     response.StlDealPort.ToString(),
                                     response.StlSubPort.ToString(),
                                     response.Capacity,
                                     presetRoomOptions
                                     );

                subscriberListener.Start();
                dealerListener.Start();

                _room = new RoomInfo(
                    dealerListener.SetProperties,
                    dealerListener.SetPropertiesListedInLobby,
                    _room);

                OnCreatedRoomCall();
                OrLog(LogLevel.Verbose, "OnCreatedRoomCall");
                OrLog(LogLevel.Verbose, "post create room end");
            }
            public void SetProperties(Hashtable table, bool isCreateRoom)
            {
                var keysLength = table.Keys.Count;

                if (keysLength == 0)
                {
                    return;                 // ignore blank record update.
                }
                var keys   = new string[keysLength];
                var values = new object[keysLength];

                table.Keys.CopyTo(keys, 0);
                table.Values.CopyTo(values, 0);
                for (int index = 0; index < keysLength; index++)
                {
                    _room.Properties[keys[index]] = values[index];
                }

                if (!_roomJoined && !_PropertiesInitializing)
                {
                    return;
                }

                OrLog(LogLevel.Verbose, "MessageSend RelayCode.SET_LEGACY_MAP");

                var converted = ToBytes(table);
                var keysBytes = ToExplodeBytes(keys);

                var header = new Header();

                //header.Ver = 0;
                header.RelayCode   = (byte)RelayCode.SET_LEGACY_MAP;
                header.ContentCode = (byte)0;
                header.Mask        = (byte)0;
                header.DestCode    = (byte)DestinationCode.StrictBroadcast;
                header.SrcPid      = (PlayerId)Player.ID;
                header.SrcOid      = (ObjectId)Player.ObjectId;
                header.DestLen     = (UInt16)0;

                var keysBytesLen      = (UInt16)keysBytes.Length;
                var alignmentLen      = keysBytesLen % 4;
                var convertedBytesLen = (UInt16)converted.Length;

                header.ContentLen = (UInt16)(sizeof(UInt16) + sizeof(UInt16) + keysBytesLen + alignmentLen + convertedBytesLen);

                var headerSize  = Marshal.SizeOf <Header>(header);
                var headerBytes = new byte[headerSize];
                var gch         = GCHandle.Alloc(headerBytes, GCHandleType.Pinned);

                Marshal.StructureToPtr(header, gch.AddrOfPinnedObject(), false);
                gch.Free();

                var messageBytes = new byte[headerSize + header.ContentLen];
                var stream       = new MemoryStream(messageBytes);
                var message      = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write(headerBytes);
                    message.Write(keysBytesLen);
                    message.Write(convertedBytesLen);
                    message.Write(keysBytes);
                    if (alignmentLen > 0)
                    {
                        message.Write(new byte[alignmentLen]);
                    }
                    message.Write(converted);
                    statefullQueue.Enqueue(messageBytes);
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                }
                message.Close();
                stream.Close();
            }
            public byte[] Join(string roomName, byte[] newGuid)
            {
                if (_roomJoinComplete)
                {
                    return(JoinGuid);
                }

                OrLog(LogLevel.Verbose, "MessageSend RelayCode.JOIN");

                JoinGuid = newGuid;
                var nameBytes = Encoding.UTF8.GetBytes(_player.NickName);

                OrLog(LogLevel.Verbose, "send name bytes: " + BitConverter.ToString(nameBytes));
                var joinSeedSize = JoinGuid.Length;
                var alignmentLen = joinSeedSize % 4;
                var nameSize     = nameBytes.Length;

                var header = new Header();

                //header.Ver = 0;
                header.RelayCode   = (byte)RelayCode.JOIN;
                header.ContentCode = (byte)0;
                header.Mask        = (byte)0;
                header.DestCode    = (byte)DestinationCode.StrictBroadcast;
                header.SrcPid      = (PlayerId)Player.ID; // didn't assign yet.
                header.SrcOid      = (ObjectId)0;         // didn't assign yet.
                header.DestLen     = (UInt16)0;
                header.ContentLen  = (UInt16)(sizeof(UInt16) + sizeof(UInt16) + joinSeedSize + alignmentLen + nameSize);

                var headerSize  = Marshal.SizeOf <Header>(header);
                var headerBytes = new byte[headerSize];
                var gch         = GCHandle.Alloc(headerBytes, GCHandleType.Pinned);

                Marshal.StructureToPtr(header, gch.AddrOfPinnedObject(), false);
                gch.Free();

                var messageBytes = new byte[headerSize + header.ContentLen];
                var stream       = new MemoryStream(messageBytes);
                var message      = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write(headerBytes);
                    message.Write((UInt16)joinSeedSize);
                    message.Write((UInt16)nameSize);
                    message.Write(JoinGuid);
                    if (alignmentLen > 0)
                    {
                        message.Write(new byte[alignmentLen]);
                    }
                    message.Write(nameBytes);
                    OrLog(LogLevel.VeryVerbose, "prepare join: " + BitConverter.ToString(messageBytes));
                    statefullQueue.Enqueue(messageBytes);
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                    JoinGuid = new byte[] { };
                }
                message.Close();
                stream.Close();

                _roomJoinComplete = true;
                return(JoinGuid);
            }
            private void SyncPrivate(RelayCode relayCode, byte contentCode, byte[] content, ObjectId senderOid, BroadcastFilter filter)
            {
                if (!_roomJoined)
                {
                    OrLog(LogLevel.VeryVerbose, "Couldnt send Sync");
                    return;
                }

                if (filter.DestCode == DestinationCode.MasterOnly)
                {
                    OrLog(LogLevel.VeryVerbose, "send receivers type master client " + filter.DestCode + " master client id is :" + MasterClient.ID.ToString());
                }
                else if (filter.DestCode == DestinationCode.Include && filter.Destinations.Length > 0)
                {
                    OrLog(LogLevel.VeryVerbose, "send receivers type include " + filter.DestCode);
                    foreach (var t in filter.Destinations)
                    {
                        OrLog(LogLevel.VeryVerbose, "send target id " + t.ToString());
                    }
                }
                else if (filter.DestCode == DestinationCode.Exclude && filter.Destinations.Length > 0)
                {
                    OrLog(LogLevel.VeryVerbose, "send receivers type exclude " + filter.DestCode);
                    foreach (var t in filter.Destinations)
                    {
                        OrLog(LogLevel.VeryVerbose, "send target id " + t.ToString());
                    }
                }
                //else if(options.DestCode == DestinationCode.All)
                //else if (options.DestCode == DestinationCode.Broadcast)
                else
                {
                    OrLog(LogLevel.VeryVerbose, "send receivers type all " + filter.DestCode);
                }

                var headerBytes = Header.CreateHeader(
                    Definitions.FrameVersion,
                    relayCode,
                    (byte)contentCode,
                    0,
                    (byte)filter.DestCode,
                    (PlayerId)LoginId,
                    (ObjectId)senderOid,
                    (UInt16)filter.Destinations.Length,
                    (UInt16)content.Length
                    );

                var destPidsSize = sizeof(UInt16) * filter.Destinations.Length;
                var contentSize  = content.Length;
                var messageBytes = new byte[headerBytes.Length + destPidsSize + contentSize];
                var stream       = new MemoryStream(messageBytes);
                var message      = new EndiannessBinaryWriter(stream);

                try
                {
                    message.Write(headerBytes);
                    if (destPidsSize > 0)
                    {
                        message.Write(new byte[destPidsSize]);
                        Buffer.BlockCopy(filter.Destinations, 0, messageBytes, headerBytes.Length, destPidsSize);
                    }
                    message.Write(content);
                    OrLog(LogLevel.VeryVerbose, "prepare Sync: " + BitConverter.ToString(messageBytes));
                    statefullQueue.Enqueue(messageBytes);
                }
                catch (Exception e)
                {
                    OrLogError(LogLevel.Info, "error: " + e.Message);
                    OrLogError(LogLevel.Verbose, "stacktrace: " + e.StackTrace);
                }
                message.Close();
                stream.Close();
            }