private void ProcessShowHandRSP(ShowHandRSP message, ClientRecord record, HandHistory history)
 {
     foreach (var handInfo in message.Info)
     {
         AddShowCardsAction(history, GetPlayer(history, handInfo.SeatID + 1), GetCards(handInfo));
     }
 }
 private void ProcessRoundStartBRC(RoundStartBRC message, ClientRecord record, HandHistory history)
 {
     if (message.Board != null)
     {
         foreach (int card_value in message.Board)
         {
             history.CommunityCards.Add(ConvertToCard(card_value));
         }
     }
 }
        private void ProcessWinnerRSP(WinnerRSP message, ClientRecord record, HandHistory history)
        {
            foreach (var winner in message.Winner)
            {
                var player = GetPlayer(history, winner.SeatID + 1);

                // Note that pots are raked therefore it's not correct to use following condition for ties: winning < pot
                // Following condition should be used instead: winning <= pot / 2. Works for raked and not raked pots.
                HandActionType handActionType = winner.Chips <= record.Pots[winner.PoolID] / 2 ? HandActionType.TIES : HandActionType.WINS;

                history.HandActions.Add(new WinningsAction(
                                            player.PlayerName,
                                            handActionType,
                                            winner.Chips,
                                            winner.PoolID
                                            ));

                player.Win += winner.Chips;
            }
        }
        private void ProcessActionBRC(ActionBRC message, ClientRecord record, HandHistory history)
        {
            var playerName = GetPlayerName(history, message.SeatID + 1);

            if (BlindActionMapping.ContainsKey(message.ActionType))
            {
                history.HandActions.Add(new HandAction(
                                            playerName,
                                            BlindActionMapping[message.ActionType],
                                            message.Chips,
                                            Street.Preflop
                                            ));
            }
            else if (ActionMapping.ContainsKey(message.ActionType))
            {
                HandAction action;

                var handActionType = ActionMapping[message.ActionType];
                if (InvestingHandActionTypes.Contains(handActionType) && message.HandChips == 0)
                {
                    action = new AllInAction(
                        playerName,
                        message.Chips,
                        history.CommunityCards.Street,
                        false, // TODO: Find out when IsRaiseAllIn should be true
                        ActionMapping[message.ActionType]
                        );
                }
                else
                {
                    action = new HandAction(
                        playerName,
                        ActionMapping[message.ActionType],
                        message.Chips,
                        history.CommunityCards.Street
                        );
                }

                history.HandActions.Add(action);
            }
        }
        private void ProcessEnterRoomRSP(EnterRoomRSP message, ClientRecord record)
        {
            if (message.RoomType == RoomType.PineRoom)
            {
                return;
            }

            bool      isTournament = TournamentRoomTypes.Contains(message.RoomType);
            IRoomInfo roomInfo     = isTournament ? (IRoomInfo)message.SngRoomInfo : (IRoomInfo)message.RoomInfo;

            record.RoomID     = roomInfo.RoomID;
            record.TableID    = message.TableStatus.Tid;
            record.IsOmaha    = message.RoomType == RoomType.OmahaRoom;
            record.RoomName   = roomInfo.RoomName.Length > 0 ? roomInfo.RoomName : roomInfo.TempID;
            record.Ante       = roomInfo.Ante;
            record.BigBlind   = roomInfo.Blind;
            record.MaxPlayers = roomInfo.SeatNum;

            record.IsTournament = isTournament;

            if (isTournament)
            {
                var utcNow = DateTime.UtcNow;

                long startTimestamp = message.RoomType == RoomType.MttRoom ? message.MttRoomInfo.MttStartTime : DateTimeToTimestamp(utcNow);
                record.TournamentID              = $"{record.RoomID}-{startTimestamp}";
                record.TournamentName            = $"{record.RoomName}";
                record.TournamentBuyIn           = message.SngRoomInfo.BuyIn;
                record.TournamentReBuy           = message.MttRoomInfo.ReBuyIn;
                record.TournamentAddOn           = message.MttRoomInfo.AddOnBuyIn;
                record.TournamentBounty          = message.MttRoomInfo.HunterReward;
                record.TournamentHasFixedRewards = message.SngRoomInfo.FixedReward;
                record.TournamentStartDate       = message.RoomType == RoomType.MttRoom ? TimestampToDateTime(message.MttRoomInfo.MttStartTime) : utcNow;
            }

            foreach (var seat in message.TableStatus.Seat.Where(s => s.Player != null))
            {
                record.Players[seat.SeatID] = UserBriefToRoomPlayer(seat.Player);
            }
        }
        private void ProcessHandCardRSP(HandCardRSP message, ClientRecord record, HandHistory history)
        {
            var roomHero = record.Players.Values.FirstOrDefault(p => p.ID == record.HeroUid);

            if (roomHero == null)
            {
                LogProvider.Log.Warn($"Hero is not seated in hand {history.HandId}, room {record.RoomID}, user {record.HeroUid}");
                return;
            }

            var hero = history.Players.FirstOrDefault(p => p.PlayerName == roomHero.ID.ToString());

            if (hero == null)
            {
                LogProvider.Log.Warn($"Hero not found for hand {history.HandId}, room {record.RoomID}, user {record.HeroUid}");
                return;
            }

            history.Hero = hero;

            hero.HoleCards = HoleCards.FromCards(hero.PlayerName, GetCards(message));
        }
        private bool ValidatePackages(ClientRecord record)
        {
            var dealerInfoPackage = record.Packages.FirstOrDefault(x => x.PackageType == PackageType.DealerInfoRSP);

            if (dealerInfoPackage == null)
            {
                LogProvider.Log.Warn(this, $"Hand cannot be built because DealerInfoRSP message is missing. [{record.Port}]");
                return(false);
            }

            var isValid = false;

            ParsePackage <DealerInfoRSP>(dealerInfoPackage, x =>
            {
                isValid = record.Packages.Any(p => p.PackageType == PackageType.WinnerRSP);
                if (!isValid)
                {
                    LogProvider.Log.Warn(this, $"Hand GameID = {x.GameID} cannot be built because WinnerRSP message is missing. [{record.Port}]");
                }
            });

            return(isValid);
        }
 private void ProcessRoundOverBRC(RoundOverBRC message, ClientRecord record, HandHistory history)
 {
     record.Pots = message.Pool;
 }
        private HandHistory BuildHand(ClientRecord record)
        {
            HandHistory history = null;

            try
            {
                if (!ValidatePackages(record))
                {
                    return(history);
                }

                var isGameStarted = false;

                foreach (var package in record.Packages)
                {
                    if (package.PackageType == PackageType.DealerInfoRSP)
                    {
                        history = new HandHistory
                        {
                            DateOfHandUtc = package.Timestamp.ToUniversalTime()
                        };

                        ParsePackage <DealerInfoRSP>(package, m => ProcessDealerInfoRSP(m, record, history));
                        isGameStarted = true;
                        continue;
                    }

                    if (!isGameStarted)
                    {
                        continue;
                    }

                    switch (package.PackageType)
                    {
                    case PackageType.RoundStartBRC:
                        ParsePackage <RoundStartBRC>(package, m => ProcessRoundStartBRC(m, record, history));
                        break;

                    case PackageType.RoundOverBRC:
                        ParsePackage <RoundOverBRC>(package, m => ProcessRoundOverBRC(m, record, history));
                        break;

                    case PackageType.ActionBRC:
                        ParsePackage <ActionBRC>(package, m => ProcessActionBRC(m, record, history));
                        break;

                    case PackageType.HandCardRSP:
                        ParsePackage <HandCardRSP>(package, m => ProcessHandCardRSP(m, record, history));
                        break;

                    case PackageType.ShowHandRSP:
                        ParsePackage <ShowHandRSP>(package, m => ProcessShowHandRSP(m, record, history));
                        break;

                    case PackageType.WinnerRSP:
                        ParsePackage <WinnerRSP>(package, m => ProcessWinnerRSP(m, record, history));
                        break;

                    case PackageType.ShowMyCardBRC:
                        ParsePackage <ShowMyCardBRC>(package, m => ProcessShowMyCardBRC(m, record, history));
                        break;

                    case PackageType.UserSngOverRSP:
                        ParsePackage <UserSngOverRSP>(package, m => ProcessUserSngOverRSP(m, record, history));
                        break;
                    }
                }

                AdjustHandHistory(history);

                return(history);
            }
            catch (Exception e)
            {
                LogProvider.Log.Error(this, $"Failed to build hand #{history?.HandId ?? 0} room #{history?.GameDescription.Identifier ?? 0} [{record.Port}]", e);
                return(null);
            }
            finally
            {
                record.Packages.Clear();
            }
        }
        private void ProcessDealerInfoRSP(DealerInfoRSP message, ClientRecord record, HandHistory history)
        {
            if (!TryParseHandID(message.GameID, out long handId))
            {
                //throw new DHInternalException(new NonLocalizableString($"Failed to parse hand id from '{noticeResetGame.GameId}'."));
                throw new Exception($"Failed to parse hand id from '{message.GameID}'.");
            }

            LogProvider.Log.Info($"Parsed GameID = {message.GameID} into HandID = {handId}");

            history.HandId = handId;

            TournamentDescriptor tournament = null;

            if (record.IsTournament)
            {
                const int RakeProportion = 10;

                long rake           = record.TournamentHasFixedRewards ? 0 : record.TournamentBuyIn / RakeProportion;
                long prizePoolValue = record.TournamentBuyIn - rake - record.TournamentBounty;

                tournament = new TournamentDescriptor
                {
                    TournamentId   = record.TournamentID,
                    TournamentName = record.TournamentName,
                    StartDate      = record.TournamentStartDate,
                    BuyIn          = Buyin.FromBuyinRake(prizePoolValue, rake, Currency.All, record.TournamentBounty > 0, record.TournamentBounty),
                    Rebuy          = record.TournamentReBuy,
                    Addon          = record.TournamentAddOn,
                    Speed          = TournamentSpeed.Regular, // I didn't discover any reliable way to determine tournament speed from protocol messages
                };
            }

            history.GameDescription = new GameDescriptor(
                EnumPokerSites.PPPoker,
                record.IsOmaha ? GameType.PotLimitOmaha : GameType.NoLimitHoldem,
                Limit.FromSmallBlindBigBlind(record.SmallBlind, record.BigBlind, Currency.All, record.Ante > 0, record.Ante),
                TableType.FromTableTypeDescriptions(record.Ante > 0 ? TableTypeDescription.Ante : TableTypeDescription.Regular),
                SeatType.FromMaxPlayers(record.MaxPlayers),
                tournament
                );

            history.GameDescription.Identifier = record.RoomID;
            history.TableName = $"{record.RoomName}-{record.TableID}";

            foreach (var stackInfo in message.Stacks)
            {
                if (!record.Players.ContainsKey(stackInfo.SeatID))
                {
                    throw new Exception($"Can't find a player sitting on seat #{stackInfo.SeatID} for hand {handId}. Total known players: {record.Players.Count}. Total participating players: {message.Stacks.Length}.");
                }

                var roomPlayer = record.Players[stackInfo.SeatID];

                var player = new Player
                {
                    PlayerName    = roomPlayer.ID.ToString(),
                    PlayerNick    = roomPlayer.Name,
                    StartingStack = stackInfo.Chips,
                    SeatNumber    = stackInfo.SeatID + 1,
                    IsSittingOut  = false
                };

                history.Players.Add(player);
            }

            history.DealerButtonPosition = message.Dealer + 1;
        }
 private void ProcessStandUpBRC(StandUpBRC message, ClientRecord record)
 {
     record.Players.Remove(message.SeatID);
 }
 private void ProcessSitDownBRC(SitDownBRC message, ClientRecord record)
 {
     record.Players[message.SeatID] = UserBriefToRoomPlayer(message.Brief);
 }
 private void ProcessSitDownRSP(SitDownRSP message, ClientRecord record)
 {
     record.HeroUid = record.Players[message.SeatID].ID;
 }
 private void ProcessGetUserMarksRSP(GetUserMarksRSP message, ClientRecord record)
 {
     record.HeroUid = message.Uid;
 }
 private void ProcessSelUserInfoRSP(SelUserInfoRSP message, ClientRecord record)
 {
     record.HeroUid = message.Brief.Uid;
 }
 private void ProcessShowMyCardBRC(ShowMyCardBRC message, ClientRecord record, HandHistory history)
 {
     AddShowCardsAction(history, GetPlayer(history, message.SeatID + 1), GetCards(message));
 }
 private void ProcessUserSngOverRSP(UserSngOverRSP message, ClientRecord record, HandHistory history)
 {
     history.GameDescription.Tournament.FinishPosition = message.Rank;
     history.GameDescription.Tournament.TotalPrize     = message.Money;
 }
 private void ProcessBlindStatusBRC(BlindStatusBRC message, ClientRecord record)
 {
     record.BigBlind = message.Blind;
     record.Ante     = message.Ante;
 }