public async Task OnGameActionRequested(GameActionRequest actionRequest, StateHelper stateHelper)
        {
            // Always roll if it's an option.
            if (actionRequest.PossibleActions.Contains(GameActionType.RollDice))
            {
                // If we can roll the dice.... LET'S DO IT!

                // Always roll ALL THE DICE
                int maxDiceCount = stateHelper.Player.GetMaxCountOfDiceCanRoll();

                // Check if we have another roll.
                int  rollsSoFar = stateHelper.GetState().CurrentTurnState.Rolls;
                bool canReRoll  = stateHelper.Player.GetMaxRollsAllowed() < rollsSoFar;

                // If we can't reroll, auto commit the dice. Otherwise don't, so we can reroll if we want.
                Logger.Log(Log.Info, "Requesting a dice roll! BIG MONEY NO WHAMMIES...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateRollDiceAction(maxDiceCount, !canReRoll));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to roll dice.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, "Trust the dice gods, we roll the dice and commit!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BuildBuilding))
            {
                // WE ARE A BIG ROLLER... let's build.

                // Get all building that are in the marketplace currently.
                List <int> buildable = stateHelper.Marketplace.GetBuildingTypesBuildableInMarketplace();

                // Filter it down to only buildings we can afford.
                List <int> affordable = stateHelper.Player.FilterBuildingIndexesWeCanAfford(buildable);

                // Randomly pick one.
                int buildingIndex = affordable[m_random.RandomInt(0, affordable.Count - 1)];

                // IF WE BUILD IT...
                Logger.Log(Log.Info, $"Requesting to build {stateHelper.BuildingRules[buildingIndex].GetName()}...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateBuildBuildingAction(buildingIndex));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to build building.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We just bought {stateHelper.BuildingRules[buildingIndex].GetName()}!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.EndTurn))
            {
                // If we can't roll the dice or build a building, we must not have enough funds.
                // Just end the turn.

                // End it!
                Logger.Log(Log.Info, "There's nothing to do, requesting turn end...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateEndTurnAction());

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to end our turn.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We have {stateHelper.Player.GetPlayer().Coins} coins and can't buy anything, so we ended the turn.");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.TvStationPayout))
            {
                // Our Tv Station activated! Let's take 5 coins from a player at random.
                GamePlayer randomPlayer = GetRandomPlayer(stateHelper);

                // DO IT!!!
                Logger.Log(Log.Info, $"Our Tv Station was activated, let's take coins from player {randomPlayer.Name}!");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateTvStationPayoutAction(randomPlayer.PlayerIndex));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to tv station payout.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We taken coins from player {randomPlayer.Name} for our tv station!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BusinessCenterSwap))
            {
                // Our Business Center activated! Let's randomly pick a player and building to swap.
                GamePlayer   randomPlayer  = GetRandomPlayer(stateHelper);
                BuildingBase ourBuilding   = GetRandomOwnedNonMajorBuidling(stateHelper, null);
                BuildingBase theirBuilding = GetRandomOwnedNonMajorBuidling(stateHelper, randomPlayer.PlayerIndex);

                GameActionResponse result;
                if (randomPlayer == null || ourBuilding == null || theirBuilding == null)
                {
                    // If there aren't any building we can use, skip the action.
                    Logger.Log(Log.Info, $"Our Business Center was activated, but there weren't the correct building to swap. So we will skip!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(0, 0, 0, true));
                }
                else
                {
                    Logger.Log(Log.Info, $"Our Business Center was activated, swap our {ourBuilding.GetName()} for {randomPlayer.Name}'s {theirBuilding.GetName()}!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(randomPlayer.PlayerIndex, ourBuilding.GetBuildingIndex(), theirBuilding.GetBuildingIndex()));
                }

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to business center swap.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"Business center swap done!");
                }
                return;
            }

            Logger.Log(Log.Error, $"Hmm, we were asked for an action but didn't know what to do with...");
            foreach (GameActionType type in actionRequest.PossibleActions)
            {
                Logger.Log(Log.Error, $"  ... {type.ToString()}");
                await Shutdown("received an unknown action.", null);
            }
        }
        public async Task OnGameActionRequested(GameActionRequest actionRequest, StateHelper stateHelper)
        {
            // OnGameActionRequested is called when the bot actually needs to take an action. Below is an example of how this can
            // be done and what events your bot will need to handle.
            //
            // To see all of the actions your must handle, look at GameActionType.
            //
            // actionRequest.State is the root of the state object for the game. This holds all things like players, coin amounts,
            // what building are in the marketplace, states of the current turn, etc.
            // Essentially, this object is everything you would see on the table when playing the game.
            //
            // The statehelper is a very useful tool that will answer many current state questions. The state helper takes a perspective user
            // when it's created, that it will use as a default player if no player is given.
            // For example, the Player.GetPlayerName function takes an option playerIndex. If not given, it will return your name.
            //
            // There are 4 modules to the state helper. Each helper has functions specific the to topic.
            //     Player
            //         ex. GetPlayer(), GetNumberOfLandmarksOwned(), GetMaxRollsAllowed(), CanHaveExtraTurn()
            //     Marketplace
            //         ex. GetMaxBuildingsInGame(), GetBuiltBuildingsInCurrentGame(), GetBuildingTypesBuildableInMarketplace()
            //     CurrentTurn
            //         ex. CanRollOrReRoll(), GetPossibleActions(), CanTakeAction()
            //     BuildingRules
            //         This helper holds all of the building types and the rules of them. ex. BuildingRules[buildingIndex].GetColor()
            //

            // Always roll if it's an option.
            if (actionRequest.PossibleActions.Contains(GameActionType.RollDice))
            {
                // How many dice can we roll?
                int maxDiceCount = stateHelper.Player.GetMaxCountOfDiceCanRoll();

                // Can we re-roll
                int  rollsSoFar = stateHelper.GetState().CurrentTurnState.Rolls;
                bool canReRoll  = stateHelper.Player.GetMaxRollsAllowed() < rollsSoFar;

                // If we can't reroll, auto commit the dice. Otherwise don't, so we can reroll if we want.
                Logger.Log(Log.Info, "Rolling the dice!");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateRollDiceAction(maxDiceCount, !canReRoll));

                if (!result.Accepted)
                {
                    await Shutdown("failed to roll dice.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, "Done");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.CommitDiceResult))
            {
                // This action is used if you want to see the dice results before they are committed.
                // It's useful to see the results if you have the ability to re-roll, so you can decided to re-roll.
                // But if the `autoCommitResults` flag is set to true when you call `CreateRollDiceAction` this wont' get called,
                // because the server will always do this for you.

                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateCommitDiceResultAction());

                if (!result.Accepted)
                {
                    await Shutdown("failed to commit dice.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, "Done");
                }
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BuildBuilding))
            {
                // Get all building that are in the marketplace currently.
                List <int> buildable = stateHelper.Marketplace.GetBuildingTypesBuildableInMarketplace();

                // Filter it down to only buildings we can afford.
                List <int> affordable = stateHelper.Player.FilterBuildingIndexesWeCanAfford(buildable);

                // Randomly pick one.
                int buildingIndex = affordable[m_random.RandomInt(0, affordable.Count - 1)];

                Logger.Log(Log.Info, $"Requesting to build {stateHelper.BuildingRules[buildingIndex].GetName()}...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateBuildBuildingAction(buildingIndex));

                if (!result.Accepted)
                {
                    await Shutdown("failed to build building.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We just bought {stateHelper.BuildingRules[buildingIndex].GetName()}!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.TvStationPayout))
            {
                // Our Tv Station activated! Let's take 5 coins from a player at random.
                GamePlayer randomPlayer = GetRandomPlayer(stateHelper);

                Logger.Log(Log.Info, $"Our Tv Station was activated, let's take coins from player {randomPlayer.Name}!");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateTvStationPayoutAction(randomPlayer.PlayerIndex));

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to tv station payout.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We taken coins from player {randomPlayer.Name} for our tv station!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.BusinessCenterSwap))
            {
                // Our Business Center activated! Let's randomly pick a player and building to swap.
                GamePlayer   randomPlayer  = GetRandomPlayer(stateHelper);
                BuildingBase ourBuilding   = GetRandomOwnedNonMajorBuidling(stateHelper, null);
                BuildingBase theirBuilding = GetRandomOwnedNonMajorBuidling(stateHelper, randomPlayer.PlayerIndex);

                GameActionResponse result;
                if (randomPlayer == null || ourBuilding == null || theirBuilding == null)
                {
                    // If there aren't any building we can use, skip the action.
                    Logger.Log(Log.Info, $"Our Business Center was activated, but there weren't the correct building to swap. So we will skip!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(0, 0, 0, true));
                }
                else
                {
                    Logger.Log(Log.Info, $"Our Business Center was activated, swap our {ourBuilding.GetName()} for {randomPlayer.Name}'s {theirBuilding.GetName()}!");
                    result = await m_bot.SendAction(GameAction <object> .CreateBusinessCenterSwapAction(randomPlayer.PlayerIndex, ourBuilding.GetBuildingIndex(), theirBuilding.GetBuildingIndex()));
                }

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to respond to business center swap.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"Business center swap done!");
                }
                return;
            }

            if (actionRequest.PossibleActions.Contains(GameActionType.EndTurn))
            {
                // If we can't roll the dice or build a building, we must not have enough funds.
                // Just end the turn.

                Logger.Log(Log.Info, "There's nothing to do, requesting turn end...");
                GameActionResponse result = await m_bot.SendAction(GameAction <object> .CreateEndTurnAction());

                if (!result.Accepted)
                {
                    // If random bot fails, it instantly shuts down.
                    await Shutdown("failed to end our turn.", result.Error);
                }
                else
                {
                    Logger.Log(Log.Info, $"We have {stateHelper.Player.GetPlayer().Coins} coins and can't buy anything, so we ended the turn.");
                }
                return;
            }

            Logger.Log(Log.Error, $"Hmm, we were asked for an action but didn't know what to do with...");
            foreach (GameActionType type in actionRequest.PossibleActions)
            {
                Logger.Log(Log.Error, $"  ... {type.ToString()}");
                await Shutdown("received an unknown action.", null);
            }
        }