private async Task <ContentResult> NewGameRequestHelper(string roomid, string playerid, string roomtype, Player player) { // Request a newgame in the room we want to join int key = Partitioners.GetRoomPartition(roomid); string url = this.proxy + $"NewGame/?playerid={playerid}&roomid={roomid}" + $"&playerdata={JsonConvert.SerializeObject(player)}" + $"&roomtype={roomtype}" + $"&PartitionKind=Int64Range&PartitionKey={key}"; HttpResponseMessage response = await this.httpClient.GetAsync(url); if ((int)response.StatusCode == 404) { this.RenewProxy(); url = this.proxy + $"NewGame/?playerid={playerid}&roomid={roomid}" + $"&playerdata={JsonConvert.SerializeObject(player)}" + $"&roomtype={roomtype}" + $"&PartitionKind=Int64Range&PartitionKey={key}"; response = await this.httpClient.GetAsync(url); } // If this was successful we are now in agreement state, otherwise we may be in a failure state, handled below string responseMessage = await response.Content.ReadAsStringAsync(); return((int)response.StatusCode == 200 ? new ContentResult { StatusCode = 200, Content = roomtype } : new ContentResult { StatusCode = 500, Content = responseMessage }); }
public async Task <IActionResult> UpdateGameAsync(string playerid, string roomid, string player) { //Unpackage the player data from its JSON representation Player p = JsonConvert.DeserializeObject <Player>(player); int key = Partitioners.GetRoomPartition(roomid); string url = this.proxy + $"UpdateGame/?roomid={roomid}&playerid={playerid}" + $"&playerdata={JsonConvert.SerializeObject(p)}&PartitionKind=Int64Range&PartitionKey={key}"; HttpResponseMessage response = await this.httpClient.GetAsync(url); if ((int)response.StatusCode == 404) { this.RenewProxy(); url = this.proxy + $"UpdateGame/?roomid={roomid}&playerid={playerid}" + $"&playerdata={JsonConvert.SerializeObject(p)}&PartitionKind=Int64Range&PartitionKey={key}"; response = await this.httpClient.GetAsync(url); } return(this.StatusCode((int)response.StatusCode, await response.Content.ReadAsStringAsync())); }
public async Task <IActionResult> EndGameAsync(string playerid, string roomid) { int key = Partitioners.GetRoomPartition(roomid); string url = this.proxy + $"EndGame/?roomid={roomid}&playerid={playerid}&PartitionKind=Int64Range&PartitionKey={key}"; HttpResponseMessage response = await this.httpClient.GetAsync(url); if ((int)response.StatusCode == 404) { this.RenewProxy(); url = this.proxy + $"EndGame/?roomid={roomid}&playerid={playerid}&PartitionKind=Int64Range&PartitionKey={key}"; response = await this.httpClient.GetAsync(url); } return(this.StatusCode((int)response.StatusCode, await response.Content.ReadAsStringAsync())); }
public async Task <IActionResult> GetGameAsync(string roomid) { int key = Partitioners.GetRoomPartition(roomid); string url = this.proxy + $"GetGame/?roomid={roomid}&PartitionKind=Int64Range&PartitionKey={key}"; HttpResponseMessage response = await this.httpClient.GetAsync(url); //Renew the proxy if the stateful service has moved if ((int)response.StatusCode == 404) { this.RenewProxy(); url = this.proxy + $"GetGame/?roomid={roomid}&PartitionKind=Int64Range&PartitionKey={key}"; response = await this.httpClient.GetAsync(url); } return(this.StatusCode((int)response.StatusCode, await response.Content.ReadAsStringAsync())); }
public async Task <IActionResult> NewGame(string playerid, string roomid, string roomtype) { try { if (!PlayerManager.IsActive) { return new ContentResult { StatusCode = 500, Content = "Service is still starting up. Please retry." } } ; IReliableDictionary <string, PlayerPackage> playdict = await this.stateManager.GetOrAddAsync <IReliableDictionary <string, PlayerPackage> >(PlayersDictionaryName); PlayerPackage playerPackage; //for handing up player information if login is needed in scenario 2 using (ITransaction tx = this.stateManager.CreateTransaction()) { ConditionalValue <PlayerPackage> playerOption = await playdict.TryGetValueAsync(tx, playerid, LockMode.Update); ///////////////////////////////////////////////// // SCENARIO 1: PLAYER DOES NOT HAVE AN ACCOUNT // ///////////////////////////////////////////////// if (!playerOption.HasValue) { //State: Player does not exist / Cannot be in a game Random rand = new Random(Environment.TickCount); //Generate a new player with a random position Player newPlayer = new Player( rand.Next() % 100 - 6, rand.Next() % 96 - 6, this.startingColors[rand.Next() % this.startingColors.Length]); //Package the new player with its baseline statistics PlayerPackage newPlayerPackage = new PlayerPackage(newPlayer, LogState.LoggedIn, 1, DateTime.UtcNow, roomid); await playdict.AddAsync(tx, playerid, newPlayerPackage); await tx.CommitAsync(); return(await this.NewGameRequestHelper(roomid, playerid, roomtype, newPlayer)); } ////////////////////////////////////////////////////// // SCENARIO 2: PLAYER HAS ACCOUNT AND IS LOGGED OUT // ////////////////////////////////////////////////////// if (playerOption.Value.State == LogState.LoggedOut) { /* * Scenario: We think player is logged out (LO-N), in which case this is normal functionality. * The state could also be (LO-LI), which could happen if an EndGame failed halfway through. * If this is the case, there are two scenarios: The first is that the room we are about to log into was * the room that failed to log out, in which case we will override that data since we have the most updated * data and the situation is resolved. The second case is that we are trying to log into a different room. * In this case we trust that the protocol has removed that clients access to the player, which means the * player will eventually be cleaned up by the timeout, keeping the game consistent. */ //Grab our player data and update the package PlayerPackage updatedPlayerPackage = playerOption.Value; updatedPlayerPackage.State = LogState.LoggedIn; updatedPlayerPackage.RoomId = roomid; updatedPlayerPackage.NumLogins++; await playdict.SetAsync(tx, playerid, updatedPlayerPackage); //finish our transaction await tx.CommitAsync(); // Request a newgame in the room we want to join return(await this.NewGameRequestHelper(roomid, playerid, roomtype, playerOption.Value.Player)); } await tx.CommitAsync(); playerPackage = playerOption.Value; } // end of tx ///////////////////////////////////////////////////// // SCENARIO 3: PLAYER HAS ACCOUNT AND IS LOGGED IN // ///////////////////////////////////////////////////// if (playerPackage.State == LogState.LoggedIn) { // Scenario: This state will generally be the success state, where the player thinks they are logged in and the // appropriate room has the game. However, during login, it is possible that the process crashed between the time // that the login transaction marked the data as logged in and that data being put in the room. We must check to // verify that this is not the state we are in. int key = Partitioners.GetRoomPartition(playerPackage.RoomId); // We first ask if the room has the data to determine which of the above states we are in. string url = this.proxy + $"Exists/?playerid={playerid}&roomid={playerPackage.RoomId}&PartitionKind=Int64Range&PartitionKey={key}"; HttpResponseMessage response = await this.httpClient.GetAsync(url); if ((int)response.StatusCode == 404) { this.RenewProxy(); url = this.proxy + $"Exists/?playerid={playerid}&roomid={playerPackage.RoomId}&PartitionKind=Int64Range&PartitionKey={key}"; response = await this.httpClient.GetAsync(url); } string responseMessage = await response.Content.ReadAsStringAsync(); if ((int)response.StatusCode == 200) { //Player is logged in, so we must deny this request if (responseMessage == "true") { return new ContentResult { StatusCode = 400, Content = "This player is already logged in" } } ; //Player is not logged in, so we can log into whichever room we want if (responseMessage == "false") { using (ITransaction tx1 = this.stateManager.CreateTransaction()) { playerPackage.RoomId = roomid; playerPackage.NumLogins++; await playdict.SetAsync(tx1, playerid, playerPackage); await tx1.CommitAsync(); } return(await this.NewGameRequestHelper(roomid, playerid, roomtype, playerPackage.Player)); } Environment.FailFast("If returning a success code, the message must be either true or false."); } else { return(new ContentResult { StatusCode = 500, Content = "Something went wrong, please retry" }); } } Environment.FailFast("Players must exist with a valid state attached to them"); return(new ContentResult { StatusCode = 500 }); } catch (Exception e) { return(exceptionHandler(e)); } }