Exemplo n.º 1
0
        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
            });
        }
Exemplo n.º 2
0
        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()));
        }
Exemplo n.º 3
0
        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()));
        }
Exemplo n.º 4
0
        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()));
        }
Exemplo n.º 5
0
        public async Task <IActionResult> NewGameAsync(string playerid, string roomid, string roomtype)
        {
            // Only accept nonempty alphanumeric usernames under 20 characters long
            // this should have been handled in javascript, may point to aggressive behavior
            // also verify no one tries to make a room other than those provided
            Regex names = new Regex(@"(?i)([a-z?0-9?\-?]\s?){0,10}");

            if (!names.IsMatch(playerid))
            {
                return(this.StatusCode(400, this.Json("Invalid username.")));
            }
            if (!names.IsMatch(roomid))
            {
                return(this.StatusCode(400, this.Json("Invalid room name.")));
            }
            try
            {
                Enum.Parse(typeof(RoomTypes), roomtype);
            }
            catch
            {
                return(this.StatusCode(400, this.Json("This is not a valid room type.")));
            }

            int    key = Partitioners.GetPlayerPartition(playerid);             //Direct query to correct partition
            string url = this.proxy + $"NewGame/?playerid={playerid}&roomid={roomid}&roomtype={roomtype}&PartitionKind=Int64Range&PartitionKey={key}";
            HttpResponseMessage response = await this.httpClient.GetAsync(url); //Send the request and wait for the response

            // A 404 tells us that our proxy is old, so we renew it
            if ((int)response.StatusCode == 404)
            {
                this.RenewProxy();

                url      = this.proxy + $"NewGame/?playerid={playerid}&roomid={roomid}&roomtype={roomtype}&PartitionKind=Int64Range&PartitionKey={key}";
                response = await this.httpClient.GetAsync(url); //Send the request and wait for the response
            }

            // Forward the response we get to the client
            return(this.StatusCode((int)response.StatusCode, this.Json(await response.Content.ReadAsStringAsync())));
        }
Exemplo n.º 6
0
        public async Task <IActionResult> EndGame(string roomid, string playerid)
        {
            try
            {
                if (!RoomManager.IsActive)
                {
                    return new ContentResult {
                               StatusCode = 500, Content = "Service is still starting up. Please retry."
                    }
                }
                ;

                IReliableDictionary <string, Room> roomdict =
                    await this.stateManager.GetOrAddAsync <IReliableDictionary <string, Room> >(RoomDictionaryName);

                Room   room;
                Player player; //want to maintain this information between our transactions

                //Transaction one: Send the PlayerManager the updated player data
                using (ITransaction tx = this.stateManager.CreateTransaction())
                {
                    ConditionalValue <Room> roomOption = await roomdict.TryGetValueAsync(tx, roomid);

                    //make sure room exists
                    if (!roomOption.HasValue)
                    {
                        return new ContentResult {
                                   StatusCode = 400, Content = "This room does not exist"
                        }
                    }
                    ;

                    //Hand the room data up so that transaction two does not have to gather it again
                    room = roomOption.Value;

                    IReliableDictionary <string, ActivePlayer> activeroomdict =
                        await this.stateManager.GetOrAddAsync <IReliableDictionary <string, ActivePlayer> >(roomid);

                    //try to get the player  data
                    ConditionalValue <ActivePlayer> playerOption = await activeroomdict.TryGetValueAsync(tx, playerid);

                    if (!playerOption.HasValue)
                    {
                        return new ContentResult {
                                   StatusCode = 400, Content = "This player is not in this room"
                        }
                    }
                    ;

                    player = playerOption.Value.Player;

                    //now that we have it, we are finished with the transaction.
                    await tx.CommitAsync();
                }

                // We send the data to the PlayerManager to update data and mark that player as offline. We do not want to
                // remove data until we are sure it is stored in the PlayerManager.

                int    key = Partitioners.GetPlayerPartition(playerid);
                string url = this.proxy + $"EndGame/?playerid={playerid}" +
                             $"&playerdata={JsonConvert.SerializeObject(player)}" +
                             $"&PartitionKind=Int64Range&PartitionKey={key}";
                HttpResponseMessage response = await this.httpClient.GetAsync(url);

                if ((int)response.StatusCode == 404)
                {
                    this.RenewProxy();

                    url = this.proxy + $"EndGame/?playerid={playerid}" +
                          $"&playerdata={JsonConvert.SerializeObject(player)}" +
                          $"&PartitionKind=Int64Range&PartitionKey={key}";
                    response = await this.httpClient.GetAsync(url);
                }

                string responseMessage = await response.Content.ReadAsStringAsync();

                if ((int)response.StatusCode != 200)
                {
                    return new ContentResult {
                               StatusCode = 500, Content = responseMessage
                    }
                }
                ;

                //Transaction two: remove the player from the room
                using (ITransaction tx1 = this.stateManager.CreateTransaction())
                {
                    IReliableDictionary <string, ActivePlayer> activeroomdict =
                        await this.stateManager.GetOrAddAsync <IReliableDictionary <string, ActivePlayer> >(roomid);

                    //Remove the player from the active room
                    await activeroomdict.TryRemoveAsync(tx1, playerid);

                    //Deincrement the number of players in the room
                    room.NumPlayers--;

                    // If that number is now 0, remove that room from the room dictionary
                    if (room.NumPlayers == 0)
                    {
                        await roomdict.TryRemoveAsync(tx1, roomid);
                    }
                    else
                    {
                        await roomdict.SetAsync(tx1, roomid, room);
                    }

                    await tx1.CommitAsync();
                }

                return(new ContentResult {
                    StatusCode = 200, Content = "Successfully logged out"
                });
            }
            catch (Exception e)
            {
                return(exceptionHandler(e));
            }
        }
Exemplo n.º 7
0
        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));
            }
        }