internal static PlayObject ConvertToPlayObject(RoomSystemProperty property) { if (property == null) { return(null); } var obj = new PlayObject(); if (property.Open != null) { obj["open"] = property.Open; } if (property.Visible != null) { obj["visible"] = property.Visible; } if (property.MaxMembers > 0) { obj["maxPlayerCount"] = property.MaxMembers; } if (!string.IsNullOrEmpty(property.ExpectMembers)) { obj["expectedUserIds"] = JsonConvert.DeserializeObject <List <string> >(property.ExpectMembers); } return(obj); }
public IEnumerator ChangePropertiesWithSameValue() { var f = false; var roomName = "cp5_r"; var c = Utils.NewClient("cp5"); var props = new PlayObject { { "ready", true } }; c.Connect().OnSuccess(_ => { return(c.CreateRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c.Room.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c.Room.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c.Player.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { c.Player.SetCustomProperties(props); _ = c.Close(); f = true; }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f) { yield return(null); } }
public IEnumerator ChangePlayerPropertiesWithCAS() { var f = false; var roomName = "cp3_r"; var c = Utils.NewClient("cp3"); c.Connect().OnSuccess(_ => { return(c.CreateRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { var props = new PlayObject { { "id", 1 }, { "nickname", "lean" } }; return(c.Player.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { var newProps = new PlayObject { { "nickname", "cloud" } }; var expectedValues = new PlayObject { { "id", 2 } }; return(c.Player.SetCustomProperties(newProps, expectedValues)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { Assert.AreEqual(c.Player.CustomProperties["nickname"], "lean"); f = true; }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f) { yield return(null); } _ = c.Close(); }
public IEnumerator ChangeRoomPropertiesWithCAS() { var f = false; var roomName = "cp1_r"; var c = Utils.NewClient("cp1"); c.Connect().OnSuccess(_ => { var options = new RoomOptions { CustomRoomProperties = new PlayObject { { "id", 1 }, { "gold", 100 } } }; return(c.CreateRoom(roomName, options)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { var newProps = new PlayObject { { "gold", 200 }, }; var expectedValues = new PlayObject { { "id", 2 } }; return(c.SetRoomCustomProperties(newProps, expectedValues)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { Assert.AreEqual(c.Room.CustomProperties["gold"], 100); f = true; }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f) { yield return(null); } _ = c.Close(); }
public IEnumerator GetPlayerPropertiesWhenJoinRoom() { var f = false; var roomName = "cp4_r"; var c0 = Utils.NewClient("cp4_0"); var c1 = Utils.NewClient("cp4_1"); c0.Connect().OnSuccess(_ => { return(c0.CreateRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { var props = new PlayObject { { "ready", true } }; return(c0.Player.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.JoinRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { var master = c1.Room.Master; Assert.AreEqual(master.CustomProperties.GetBool("ready"), true); f = true; }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f) { yield return(null); } _ = c0.Close(); _ = c1.Close(); }
public IEnumerator MatchRandom() { var f = false; var roomName = "jr8_r"; var c0 = Utils.NewClient("jr8_0"); var c1 = Utils.NewClient("jr8_1"); var c2 = Utils.NewClient("jr8_2"); var c3 = Utils.NewClient("jr8_xxx"); var props = new PlayObject { { "lv", 5 } }; c0.Connect().OnSuccess(_ => { var roomOptions = new RoomOptions { MaxPlayerCount = 3, CustomRoomProperties = props, CustomRoomPropertyKeysForLobby = new List <string> { "lv" } }; return(c0.CreateRoom(roomName, roomOptions)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { Debug.Log("c1 connected"); return(c1.MatchRandom("jr8_1", new PlayObject { { "lv", 5 } }, new List <string> { "jr8_xxx" })); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(t => { var roomId = t.Result; Assert.AreEqual(roomId, roomName); return(c1.JoinRoom(roomId)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c2.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c2.JoinRandomRoom(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().ContinueWith(t => { PlayException e = (PlayException)t.Exception.InnerException; Assert.AreEqual(e.Code, 4301); _ = c2.Close(); return(c3.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c3.JoinRandomRoom(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(async _ => { await c0.Close(); await c1.Close(); await c3.Close(); f = true; }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f) { yield return(null); } }
/// <summary> /// 设置玩家自定义属性 /// </summary> /// <param name="actorId">玩家 Actor Id</param> /// <param name="properties">自定义属性</param> /// <param name="expectedValues">用于 CAS 的期望属性</param> public async Task SetPlayerCustomProperties(int actorId, PlayObject properties, PlayObject expectedValues = null) { if (Room == null) { throw new Exception("You are not in room yet."); } await Room.SetPlayerCustomProperties(actorId, properties, expectedValues); }
/// <summary> /// 发送自定义事件 /// </summary> /// <param name="eventId">事件 Id</param> /// <param name="eventData">事件参数</param> /// <param name="options">事件选项</param> public Task SendEvent(byte eventId, PlayObject eventData = null, SendEventOptions options = null) { if (Room == null) { throw new Exception("You are not in room yet."); } return(Room.SendEvent(eventId, eventData, options)); }
public static byte[] Serialize(object obj) { Weapon weapon = obj as Weapon; var playObject = new PlayObject { { "name", weapon.Name }, { "attack", weapon.Attack } }; return(CodecUtils.SerializePlayObject(playObject)); }
/// <summary> /// 反序列化 PlayObject 对象 /// </summary> /// <returns>PlayObject 对象</returns> /// <param name="bytes">要反序列化的字节码</param> public static PlayObject DeserializePlayObject(byte[] bytes) { var collection = GenericCollection.Parser.ParseFrom(bytes); var playObject = new PlayObject(); foreach (var entry in collection.MapEntryValue) { playObject[entry.Key] = Deserialize(entry.Val); } return(playObject); }
public IEnumerator ChangePlayerProperties() { var f0 = false; var f1 = false; var roomName = "cp2_r"; var c0 = Utils.NewClient("cp2_0"); var c1 = Utils.NewClient("cp2_1"); c0.Connect().OnSuccess(_ => { return(c0.CreateRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { c0.OnPlayerCustomPropertiesChanged += (player, changedProps) => { var props = player.CustomProperties; Assert.AreEqual(props.GetString("nickname"), "LeanCloud"); Assert.AreEqual(props.GetInt("gold"), 100); var attr = props["attr"] as PlayObject; Assert.AreEqual(attr.GetInt("hp"), 10); Assert.AreEqual(attr.GetInt("mp"), 20); Debug.Log("c0 check done"); f0 = true; }; return(c1.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.JoinRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { c1.OnPlayerCustomPropertiesChanged += (player, changedProps) => { var p = player.CustomProperties; Assert.AreEqual(p.GetString("nickname"), "LeanCloud"); Assert.AreEqual(p.GetInt("gold"), 100); var attr = p["attr"] as PlayObject; Assert.AreEqual(attr.GetInt("hp"), 10); Assert.AreEqual(attr.GetInt("mp"), 20); Debug.Log("c1 check done"); f1 = true; }; var props = new PlayObject { { "nickname", "LeanCloud" }, { "gold", 100 }, { "attr", new PlayObject { { "hp", 10 }, { "mp", 20 } } } }; return(c1.Player.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f0 || !f1) { yield return(null); } _ = c0.Close(); _ = c1.Close(); }
public static byte[] Serialize(object obj) { Hero hero = obj as Hero; var playObject = new PlayObject { { "name", hero.Name }, { "score", hero.Score }, { "hp", hero.Hp }, { "mp", hero.Mp }, { "weapons", new PlayArray(hero.Weapons) } }; return(CodecUtils.SerializePlayObject(playObject)); }
internal void MergeCustomProperties(PlayObject changedProps) { if (changedProps == null) { return; } lock (CustomProperties) { foreach (var entry in changedProps) { CustomProperties[entry.Key] = entry.Value; } } }
/// <summary> /// 设置房间的自定义属性 /// </summary> /// <param name="properties">自定义属性</param> /// <param name="expectedValues">期望属性,用于 CAS 检测</param> public async Task SetCustomProperties(PlayObject properties, PlayObject expectedValues = null) { if (state != State.Game) { throw new PlayException(PlayExceptionCode.StateError, $"Error state: {state}"); } var changedProps = await gameConn.SetRoomCustomProperties(properties, expectedValues); if (!changedProps.IsEmpty) { MergeCustomProperties(changedProps); } }
/// <summary> /// 设置玩家的自定义属性 /// </summary> /// <param name="actorId">玩家 Id</param> /// <param name="properties">自定义属性</param> /// <param name="expectedValues">期望属性,用于 CAS 检测</param> /// <returns></returns> public async Task SetPlayerCustomProperties(int actorId, PlayObject properties, PlayObject expectedValues) { if (state != State.Game) { throw new PlayException(PlayExceptionCode.StateError, $"Error state: {state}"); } var res = await gameConn.SetPlayerCustomProperties(actorId, properties, expectedValues); if (!res.Item2.IsEmpty) { var playerId = res.Item1; var player = GetPlayer(playerId); var changedProps = res.Item2; player.MergeCustomProperties(changedProps); } }
/// <summary> /// 发送自定义事件 /// </summary> /// <param name="eventId">事件 Id</param> /// <param name="eventData">事件参数</param> /// <param name="options">事件选项</param> /// <returns></returns> public Task SendEvent(byte eventId, PlayObject eventData, SendEventOptions options) { if (state != State.Game) { throw new PlayException(PlayExceptionCode.StateError, $"Error state: {state}"); } var opts = options; if (opts == null) { opts = new SendEventOptions { ReceiverGroup = ReceiverGroup.All }; } return(gameConn.SendEvent(eventId, eventData, opts)); }
public void PlayObject() { var playObj = new PlayObject { ["i"] = 123, ["b"] = true, ["str"] = "hello, world" }; var subPlayObj = new PlayObject { ["si"] = 345, ["sb"] = true, ["sstr"] = "code" }; playObj.Add("obj", subPlayObj); var subPlayArr = new PlayArray { 666, true, "engineer" }; playObj.Add("arr", subPlayArr); var genericValue = CodecUtils.Serialize(playObj); Debug.Log(genericValue); var newPlayObj = CodecUtils.Deserialize(genericValue) as PlayObject; Assert.AreEqual(newPlayObj["i"], 123); Assert.AreEqual(newPlayObj["b"], true); Assert.AreEqual(newPlayObj["str"], "hello, world"); var newSubPlayObj = newPlayObj["obj"] as PlayObject; Assert.AreEqual(newSubPlayObj["si"], 345); Assert.AreEqual(newSubPlayObj["sb"], true); Assert.AreEqual(newSubPlayObj["sstr"], "code"); var newSubPlayArr = newPlayObj["arr"] as PlayArray; Assert.AreEqual(newSubPlayArr[0], 666); Assert.AreEqual(newSubPlayArr[1], true); Assert.AreEqual(newSubPlayArr[2], "engineer"); // Dictionary to PlayObject var dict = new Dictionary <string, int> { { "hello", 123 }, { "world", 456 } }; var dictObj = new PlayObject(dict); Assert.AreEqual(dictObj["hello"], 123); Assert.AreEqual(dictObj["world"], 456); }
/// <summary> /// 序列化 PlayObject 对象 /// </summary> /// <returns>The play object.</returns> /// <param name="playObject">PlayObject 对象</param> public static byte[] SerializePlayObject(PlayObject playObject) { if (playObject == null) { return(null); } var collection = new GenericCollection(); foreach (var entry in playObject) { collection.MapEntryValue.Add(new GenericCollection.Types.MapEntry { Key = entry.Key as string, Val = Serialize(entry.Value) }); } return(collection.ToByteArray()); }
internal async Task <PlayObject> SetRoomCustomProperties(PlayObject properties, PlayObject expectedValues) { var request = NewRequest(); request.UpdateProperty = new UpdatePropertyRequest { Attr = ByteString.CopyFrom(CodecUtils.SerializePlayObject(properties)) }; if (expectedValues != null) { request.UpdateProperty.ExpectAttr = ByteString.CopyFrom(CodecUtils.SerializePlayObject(expectedValues)); } var res = await SendRequest(CommandType.Conv, OpType.Update, request); var props = CodecUtils.DeserializePlayObject(res.Response.UpdateProperty.Attr); return(props); }
public IEnumerator ChangeRoomProperties() { var roomName = "cp0_r"; var f0 = false; var f1 = false; var c0 = Utils.NewClient("cp0_0"); var c1 = Utils.NewClient("cp0_1"); c0.Connect().OnSuccess(_ => { return(c0.CreateRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { c0.OnRoomCustomPropertiesChanged += changedProps => { var props = c0.Room.CustomProperties; Assert.AreEqual(props.GetString("name"), "leancloud"); Assert.AreEqual(props.GetInt("gold"), 1000); f0 = true; }; return(c1.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.JoinRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { c1.OnRoomCustomPropertiesChanged += changedProps => { var props = c1.Room.CustomProperties; Assert.AreEqual(props.GetString("name"), "leancloud"); Assert.AreEqual(props.GetInt("gold"), 1000); f1 = true; }; var newProps = new PlayObject { { "name", "leancloud" }, { "gold", 1000 }, }; return(c0.SetRoomCustomProperties(newProps)); }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f0 || !f1) { yield return(null); } _ = c0.Close(); _ = c1.Close(); }
internal Task SendEvent(byte eventId, PlayObject eventData, SendEventOptions options) { var direct = new DirectCommand { EventId = eventId }; if (eventData != null) { direct.Msg = ByteString.CopyFrom(CodecUtils.SerializePlayObject(eventData)); } direct.ReceiverGroup = (int)options.ReceiverGroup; if (options.TargetActorIds != null) { direct.ToActorIds.AddRange(options.TargetActorIds); } _ = Send(CommandType.Direct, OpType.None, new Body { Direct = direct }); return(Task.FromResult(true)); }
internal async Task JoinRandom(PlayObject matchProperties, List <string> expectedUserIds) { state = State.Joining; try { LobbyInfo lobbyInfo = await Client.lobbyService.Authorize(); LobbyRoomResult lobbyRoom = await Client.lobbyService.JoinRandomRoom(matchProperties, expectedUserIds); gameConn = new GameConnection(); await gameConn.Connect(Client.AppId, lobbyRoom.Url, Client.GameVersion, Client.UserId, lobbyInfo.SessionToken); Protocol.RoomOptions options = await gameConn.JoinRoom(lobbyRoom.RoomId, expectedUserIds); Init(options); state = State.Game; } catch (Exception e) { state = State.Closed; throw e; } }
public IEnumerator CustomEventWithTargetIds() { var f = false; var roomName = "ce1_r"; var c0 = Utils.NewClient("ce1_0"); var c1 = Utils.NewClient("ce1_1"); c0.Connect().OnSuccess(_ => { return(c0.CreateRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { c0.OnCustomEvent += (eventId, eventData, senderId) => { Assert.AreEqual(eventId, 2); Assert.AreEqual(eventData["name"], "aaa"); Assert.AreEqual(eventData["count"], 100); f = true; }; return(c1.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.JoinRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { var eventData = new PlayObject { { "name", "aaa" }, { "count", 100 }, }; var options = new SendEventOptions { TargetActorIds = new List <int> { 1, 2 } }; return(c1.SendEvent(2, eventData, options)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { Debug.Log("send event done"); }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f) { yield return(null); } _ = c0.Close(); _ = c1.Close(); }
/// <summary> /// 随机加入房间 /// </summary> /// <param name="matchProperties">匹配属性</param> /// <param name="expectedUserIds">期望用户 Id 列表</param> /// <returns>房间</returns> public async Task <Room> JoinRandomRoom(PlayObject matchProperties = null, List <string> expectedUserIds = null) { if (Room != null) { throw new Exception("You are already in room."); } // 关闭 Lobby if (lobby != null) { await lobby.Close(); } try { Room = new Room(this); await Room.JoinRandom(matchProperties, expectedUserIds); return(Room); } catch (Exception e) { Room = null; throw e; } }
public IEnumerator SetNullProperty() { var f0 = false; var f1 = false; var roomName = "cp6_r"; var c = Utils.NewClient("cp6"); c.Connect().OnSuccess(_ => { return(c.CreateRoom(roomName)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { c.OnRoomCustomPropertiesChanged += (__) => { if (c.Room.CustomProperties.GetString("name") == "leancloud") { f0 = true; Debug.Log("============== f0 is true"); } if (c.Room.CustomProperties.IsNull("name")) { f1 = true; Debug.Log("============== f1 is true"); } }; var props = new PlayObject { { "name", "leancloud" } }; return(c.Room.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { var props = new PlayObject { { "name", null } }; return(c.Room.SetCustomProperties(props)); }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f0 || !f1) { yield return(null); } _ = c.Close(); }
internal async Task <LobbyRoomResult> MatchRandom(string piggybackUserId, PlayObject matchProperties, List <string> expectedUserIds) { LobbyInfo lobbyInfo = await gameRouter.Authorize(); string path = "/1/multiplayer/lobby/match/room"; string fullUrl = $"{lobbyInfo.Url}{path}"; Dictionary <string, object> body = new Dictionary <string, object> { { "gameVersion", client.GameVersion }, { "sdkVersion", Config.SDKVersion }, { "protocolVersion", Config.ProtocolVersion }, { "piggybackPeerId", piggybackUserId } }; if (matchProperties != null) { body.Add("expectAttr", matchProperties.Data); } if (expectedUserIds != null) { body.Add("expectMembers", expectedUserIds); } return(await Request(fullUrl, lobbyInfo.SessionToken, body)); }
internal void MergeSystemProperties(PlayObject changedProps) { if (changedProps == null) { return; } if (changedProps.TryGetBool("open", out var open)) { Open = open; } if (changedProps.TryGetBool("visible", out var visible)) { Visible = visible; } if (changedProps.TryGetInt("maxPlayerCount", out var maxPlayerCount)) { MaxPlayerCount = maxPlayerCount; } if (changedProps.TryGetValue("expectedUserIds", out object expectedUserIds)) { ExpectedUserIds = expectedUserIds as List <string>; } }
/// <summary> /// 设置玩家的自定义属性 /// </summary> /// <param name="properties">Properties.</param> /// <param name="expectedValues">Expected values.</param> public Task SetCustomProperties(PlayObject properties, PlayObject expectedValues = null) { return(Room.SetPlayerCustomProperties(ActorId, properties, expectedValues)); }
/// <summary> /// 匹配房间(不加入) /// </summary> /// <param name="piggybackUserId">占位用户 Id</param> /// <param name="matchProperties">匹配属性</param> /// <returns>房间 Id</returns> public async Task <string> MatchRandom(string piggybackUserId, PlayObject matchProperties = null, List <string> expectedUserIds = null) { var lobbyRoom = await lobbyService.MatchRandom(piggybackUserId, matchProperties, expectedUserIds); return(lobbyRoom.RoomId); }
public IEnumerator JoinRandomWithMatchProperties() { var f = false; var roomName = "jrt7_r"; var c0 = Utils.NewClient("jrt7_0"); var c1 = Utils.NewClient("jrt7_1"); var c2 = Utils.NewClient("jrt7_2"); var c3 = Utils.NewClient("jrt7_3"); var c4 = Utils.NewClient("jrt7_2"); var props = new PlayObject { { "lv", 2 } }; c0.Connect().OnSuccess(_ => { var roomOptions = new RoomOptions { MaxPlayerCount = 3, CustomRoomProperties = props, CustomRoomPropertyKeysForLobby = new List <string> { "lv" } }; return(c0.CreateRoom(roomName, roomOptions)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c1.JoinRandomRoom(props, new List <string> { "jrt7_2" })); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c2.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c2.JoinRandomRoom(new PlayObject { { "lv", 3 } })); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().ContinueWith(async t => { PlayException e = (PlayException)t.Exception.InnerException; Assert.AreEqual(e.Code, 4301); await c2.Close(); return(c3.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(t => { return(c3.JoinRandomRoom(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().ContinueWith(async t => { PlayException e = (PlayException)t.Exception.InnerException; Assert.AreEqual(e.Code, 4301); await c3.Close(); return(c4.Connect()); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(_ => { return(c4.JoinRandomRoom(props)); }, TaskScheduler.FromCurrentSynchronizationContext()).Unwrap().OnSuccess(async _ => { await c0.Close(); await c1.Close(); await c4.Close(); f = true; }, TaskScheduler.FromCurrentSynchronizationContext()); while (!f) { yield return(null); } }