public async Task LoginHandler(GameSession session, LoginRequestReqMessage message)
        {
            #region IPINFO

            var ipInfo = new IpInfo2();
            try
            {
                //string info = new WebClient().DownloadString("" + session.RemoteEndPoint.Address);
                var info = new WebClient().DownloadString("http://ip-api.com/json/" + session.RemoteEndPoint.Address);
                ipInfo = JsonConvert.DeserializeObject <IpInfo2>(info);
                if (string.IsNullOrWhiteSpace(ipInfo.countryCode) || string.IsNullOrEmpty(ipInfo.countryCode))
                {
                    ipInfo.countryCode = "UNK";
                }
            }
            catch (Exception)
            {
                ipInfo.countryCode = "UNK";
            }

            #endregion

            Logger.ForAccount(message.AccountId, message.Username)
            .Information("GameServer login from {remoteEndPoint} : Country: {country}", session.RemoteEndPoint,
                         ipInfo.countryCode);

            if (Config.Instance.BlockedCountries.ToList().Contains(ipInfo.countryCode) || Config.Instance
                .BlockedAddresses.ToList().Contains(session.RemoteEndPoint.Address.ToString()))
            {
                Logger.ForAccount(message.AccountId, message.Username)
                .Information("Denied connection from client in blocked country {country}", ipInfo.countryCode);

                await session.SendAsync(new ServerResultAckMessage(ServerResult.IPLocked));

                return;
            }
            //if (message.Version != s_version)
            //{
            //    Logger.ForAccount(message.AccountId, message.Username)
            //        .Error("Invalid client version {version}", message.Version);
            //
            //    session.SendAsync(new LoginReguestAckMessage(GameLoginResult.WrongVersion));
            //    return;
            //}

            if (GameServer.Instance.PlayerManager.Count >= Config.Instance.PlayerLimit)
            {
                Logger.ForAccount(message.AccountId, message.Username)
                .Error("Server is full");

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.ServerFull));

                return;
            }

            #region Validate Login

            AccountDto accountDto;
            using (var db = AuthDatabase.Open())
            {
                accountDto = (await db.FindAsync <AccountDto>(statement => statement
                                                              .Include <BanDto>(join => join.LeftOuterJoin())
                                                              .Where($"{nameof(AccountDto.Id):C} = @Id")
                                                              .WithParameters(new { Id = message.AccountId })))
                             .FirstOrDefault();
            }

            if (accountDto == null)
            {
                Logger.ForAccount(message.AccountId, message.Username)
                .Error("Wrong login(account not existing)");

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                return;
            }


            var sessionId     = Hash.GetUInt32 <CRC32>($"<{accountDto.Username}+{accountDto.Password}>");
            var authsessionId = Hash.GetString <CRC32>($"<{accountDto.Username}+{sessionId}+{message.Datetime}>");
            if (authsessionId != message.AuthToken)
            {
                Logger.ForAccount(message.AccountId, message.Username)
                .Error("Wrong sessionid(2)");

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                return;
            }

            var newsessionId = Hash.GetString <CRC32>($"<{authsessionId}+{sessionId}>");
            if (newsessionId != message.newToken)
            {
                Logger.ForAccount(message.AccountId, message.Username)
                .Error("Wrong sessionid(3)");

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                return;
            }

            var now = DateTimeOffset.Now.ToUnixTimeSeconds();
            var ban = accountDto.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now);
            if (ban != null)
            {
                var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0));
                Logger.ForAccount(message.AccountId, message.Username)
                .Error("Banned until {unbanDate}", unbanDate);

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                return;
            }

            var account = new Account(accountDto);

            #endregion

            if (account.SecurityLevel < Config.Instance.SecurityLevel)
            {
                Logger.ForAccount(account)
                .Error("No permission to enter this server({securityLevel} or above required)",
                       Config.Instance.SecurityLevel);

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.AuthenticationFailed));

                return;
            }

            if (message.KickConnection)
            {
                Logger.ForAccount(account)
                .Information("Kicking old connection");

                var oldPlr = GameServer.Instance.PlayerManager.Get(account.Id);
                GameServer.Instance.PlayerManager.Remove(oldPlr);
                oldPlr?.Disconnect();
            }

            if (GameServer.Instance.PlayerManager.Contains(account.Id))
            {
                Logger.ForAccount(account)
                .Information("Kicking old connection");

                var oldPlr = GameServer.Instance.PlayerManager.Get(account.Id);
                GameServer.Instance.PlayerManager.Remove(oldPlr);
                oldPlr?.Disconnect();
            }

            using (var db = GameDatabase.Open())
            {
                var plrDto = (await db.FindAsync <PlayerDto>(statement => statement
                                                             .Include <PlayerCharacterDto>(join => join.LeftOuterJoin())
                                                             .Include <PlayerDenyDto>(join => join.LeftOuterJoin())
                                                             .Include <PlayerItemDto>(join => join.LeftOuterJoin())
                                                             .Include <PlayerMailDto>(join => join.LeftOuterJoin())
                                                             .Include <PlayerSettingDto>(join => join.LeftOuterJoin())
                                                             .Where($"{nameof(PlayerDto.Id):C} = @Id")
                                                             .WithParameters(new { Id = message.AccountId })))
                             .FirstOrDefault();

                var        expTable = GameServer.Instance.ResourceCache.GetExperience();
                Experience expValue;

                if (plrDto == null)
                {
                    // first time connecting to this server
                    if (!expTable.TryGetValue(Config.Instance.Game.StartLevel, out expValue))
                    {
                        expValue = new Experience {
                            TotalExperience = 0
                        };
                        Logger.Warning("Given start level is not found in the experience table");
                    }

                    plrDto = new PlayerDto
                    {
                        Id              = (int)account.Id,
                        PlayTime        = TimeSpan.FromSeconds(0).ToString(),
                        Level           = Config.Instance.Game.StartLevel,
                        PEN             = Config.Instance.Game.StartPEN,
                        AP              = Config.Instance.Game.StartAP,
                        Coins1          = Config.Instance.Game.StartCoins1,
                        Coins2          = Config.Instance.Game.StartCoins2,
                        TotalExperience = expValue.TotalExperience
                    };

                    await db.InsertAsync(plrDto);
                }
                else
                {
                    if (!TimeSpan.TryParse(plrDto.PlayTime, out _))
                    {
                        plrDto.PlayTime = TimeSpan.FromSeconds(0).ToString();
                    }

                    if (plrDto.Level > 0 && plrDto.TotalExperience == 0)
                    {
                        if (!expTable.TryGetValue(plrDto.Level, out expValue))
                        {
                            expValue = new Experience {
                                TotalExperience = 0
                            };
                            Logger.Warning("Given level is not found in the experience table");
                        }

                        plrDto.TotalExperience = expValue.TotalExperience - 1;
                        await db.UpdateAsync(plrDto);
                    }
                }

                plrDto.DeathMatchInfo = (List <PlayerDeathMatchDto>)(await db.FindAsync <PlayerDeathMatchDto>(
                                                                         statament => statament
                                                                         .Where($"{nameof(PlayerDeathMatchDto.PlayerId):C} = @PlayerId")
                                                                         .WithParameters(new { PlayerId = message.AccountId })));

                plrDto.TouchDownInfo = (List <PlayerTouchDownDto>)(await db.FindAsync <PlayerTouchDownDto>(
                                                                       statament => statament
                                                                       .Where($"{nameof(PlayerTouchDownDto.PlayerId):C} = @PlayerId")
                                                                       .WithParameters(new { PlayerId = message.AccountId })));

                plrDto.ChaserInfo = (List <PlayerChaserDto>)(await db.FindAsync <PlayerChaserDto>(
                                                                 statament => statament
                                                                 .Where($"{nameof(PlayerChaserDto.PlayerId):C} = @PlayerId")
                                                                 .WithParameters(new { PlayerId = message.AccountId })));

                plrDto.BattleRoyalInfo = (List <PlayerBattleRoyalDto>)(await db.FindAsync <PlayerBattleRoyalDto>(
                                                                           statament => statament
                                                                           .Where($"{nameof(PlayerBattleRoyalDto.PlayerId):C} = @PlayerId")
                                                                           .WithParameters(new { PlayerId = message.AccountId })));

                plrDto.CaptainInfo = (List <PlayerCaptainDto>)(await db.FindAsync <PlayerCaptainDto>(
                                                                   statament => statament
                                                                   .Where($"{nameof(PlayerCaptainDto.PlayerId):C} = @PlayerId")
                                                                   .WithParameters(new { PlayerId = message.AccountId })));

                session.Player = new Player(session, account, plrDto);
            }

            if (session.Player == null)
            {
                return;
            }

            GameServer.Instance.PlayerManager.Add(session.Player);

            Logger.ForAccount(account)
            .Information("Login success for {0}", account.Username);

            var result = string.IsNullOrWhiteSpace(account.Nickname)
                ? GameLoginResult.ChooseNickname
                : GameLoginResult.OK;
            //if (result == GameLoginResult.ChooseNickname)
            //{
            //    session.Player.Account.Nickname = session.Player.Account.Username;
            //    session.Player.CharacterManager.CreateFirst(0, 0, 0, 0, 0, 0);
            //    using (var db = AuthDatabase.Open())
            //    {
            //        var mapping = OrmConfiguration
            //            .GetDefaultEntityMapping<AccountDto>()
            //            .Clone()
            //            .UpdatePropertiesExcluding(prop => prop.IsExcludedFromUpdates = true,
            //                nameof(AccountDto.Nickname));

            //        await db.UpdateAsync(
            //            new AccountDto
            //            {
            //                Id = (int) session.Player.Account.Id,
            //                Nickname = session.Player.Account.Username
            //            },
            //            statement => statement.WithEntityMappingOverride(mapping));
            //    }

            //    Logger.ForAccount(account)
            //        .Information($"Created Account for {session.Player.Account.Username}");
            //}
            //else if (!session.Player.CharacterManager.CheckChars())
            //{
            //    session.Player.CharacterManager.CreateFirst(0, 0, 0, 0, 0, 0);
            //}

            await session.SendAsync(new LoginReguestAckMessage(result, session.Player.Account.Id));

            if (!string.IsNullOrWhiteSpace(account.Nickname))
            {
                await LoginAsync(session);
            }
        }
Example #2
0
        public async Task LoginHandler(GameSession session, LoginRequestReqMessage message)
        {
            #region IPINFO

            var ipInfo = new IpInfo2();
            try
            {
                var info = new WebClient().DownloadString("http://ip-api.com/json/" + session.RemoteEndPoint.Address);
                ipInfo = JsonConvert.DeserializeObject <IpInfo2>(info);
                if (string.IsNullOrWhiteSpace(ipInfo.countryCode) || string.IsNullOrEmpty(ipInfo.countryCode))
                {
                    ipInfo.countryCode = "UNK";
                }
            }
            catch (Exception)
            {
                ipInfo.countryCode = "UNK";
            }

            #endregion

            #region Validate Login

            AccountDto accountDto;
            using (var db = AuthDatabase.Open())
            {
                accountDto = (await DbUtil.FindAsync <AccountDto>(db, statement => statement
                                                                  .Include <BanDto>(join => join.LeftOuterJoin())
                                                                  .Where($"{nameof(AccountDto.Id):C} = @Id")
                                                                  .WithParameters(new { Id = message.AccountId })))
                             .FirstOrDefault();
            }

            if (accountDto == null)
            {
                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                await session.CloseAsync();

                return;
            }

            message.AccountId = (ulong)accountDto.Id;
            message.Username  = accountDto.Username;

            Logger.ForAccount(accountDto)
            .Information("GameServer login from {remoteEndPoint} : Country: {country}", session.RemoteEndPoint,
                         ipInfo.countryCode);

            if (Config.Instance.BlockedCountries.ToList().Contains(ipInfo.countryCode))
            {
                Logger.ForAccount(accountDto)
                .Warning("Denied connection from client in blocked country {country}", ipInfo.countryCode);

                await session.SendAsync(new ServerResultAckMessage(ServerResult.IPLocked));

                await session.CloseAsync();

                return;
            }

            if (Config.Instance.BlockedAddresses.ToList().Contains(session.RemoteEndPoint.Address.ToString()))
            {
                Logger.ForAccount(accountDto)
                .Warning("Denied connection from client of blocked ip {adress}", session.RemoteEndPoint);

                await session.SendAsync(new ServerResultAckMessage(ServerResult.IPLocked));

                await session.CloseAsync();

                return;
            }

            // if (message.Version != s_version)
            // {
            //     Logger.ForAccount(message.AccountId, message.Username)
            //         .Warning("Invalid client version {version}", message.Version);
            //
            //     session.SendAsync(new LoginReguestAckMessage(GameLoginResult.WrongVersion));
            //     return;
            // }

            if (GameServer.Instance.PlayerManager.Count >= Config.Instance.PlayerLimit)
            {
                Logger.ForAccount(accountDto)
                .Warning("Server is full");

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.ServerFull));

                await session.CloseAsync();

                return;
            }

            var sessionId     = Hash.GetUInt32 <CRC32>($"<{accountDto.Username}+{accountDto.Password}+{session.RemoteEndPoint.Address.MapToIPv4()}+{Config.Instance.AuthAPI.ApiKey}>");
            var authsessionId = Hash.GetString <CRC32>($"<{accountDto.Username}+{sessionId}+{message.Datetime}>");
            if (authsessionId != message.AuthToken)
            {
                Logger.ForAccount(accountDto)
                .Warning("Wrong sessionid(2)");

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                await session.CloseAsync();

                return;
            }

            var newsessionId = Hash.GetString <CRC32>($"<{authsessionId}+{sessionId}>");
            if (newsessionId != message.newToken)
            {
                Logger.ForAccount(accountDto)
                .Warning("Wrong sessionid(3)");

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                await session.CloseAsync();

                return;
            }

            var now = DateTimeOffset.Now.ToUnixTimeSeconds();
            var ban = accountDto.Bans.FirstOrDefault(b => b.Date + (b.Duration ?? 0) > now);
            if (ban != null)
            {
                var unbanDate = DateTimeOffset.FromUnixTimeSeconds(ban.Date + (ban.Duration ?? 0));
                Logger.ForAccount(accountDto)
                .Warning("Banned until {unbanDate}", unbanDate);

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.SessionTimeout));

                await session.CloseAsync();

                return;
            }

            var account = new Account(accountDto);

            #endregion

            if (account.SecurityLevel < Config.Instance.SecurityLevel)
            {
                Logger.ForAccount(account).Warning("No permission to enter this server({securityLevel} or above required)",
                                                   Config.Instance.SecurityLevel);

                await session.SendAsync(new LoginReguestAckMessage(GameLoginResult.AuthenticationFailed));

                await session.CloseAsync();

                return;
            }

            if (GameServer.Instance.PlayerManager.Contains(account.Id))
            {
                Logger.ForAccount(account)
                .Information("Kicking old connection");

                var oldPlr = GameServer.Instance.PlayerManager.Get(account.Id);
                GameServer.Instance.PlayerManager.Remove(oldPlr);
                oldPlr?.Session.CloseAsync();
            }

            Logger.ForAccount(account)
            .Information("Login success");

            await Task.Run(async() =>
            {
                using (var db = GameDatabase.Open())
                {
                    var plrDto = (await DbUtil.FindAsync <PlayerDto>(db, statement => statement
                                                                     .Include <PlayerCharacterDto>(join => join.LeftOuterJoin())
                                                                     .Include <PlayerDenyDto>(join => join.LeftOuterJoin())
                                                                     .Include <PlayerFriendDto>(join => join.LeftOuterJoin())
                                                                     .Include <PlayerSettingDto>(join => join.LeftOuterJoin())
                                                                     .Include <PlayerItemDto>(join => join.LeftOuterJoin())
                                                                     .Include <PlayerMailDto>(join => join.LeftOuterJoin())
                                                                     .Where($"{nameof(PlayerDto.Id):C} = @Id")
                                                                     .WithParameters(new { Id = message.AccountId })))
                                 .FirstOrDefault();

                    var plrStatsDto = (await DbUtil.FindAsync <PlayerDto>(db, statement => statement
                                                                          .Include <PlayerDeathMatchDto>(join => join.LeftOuterJoin())
                                                                          .Include <PlayerTouchDownDto>(join => join.LeftOuterJoin())
                                                                          .Include <PlayerChaserDto>(join => join.LeftOuterJoin())
                                                                          .Include <PlayerBattleRoyalDto>(join => join.LeftOuterJoin())
                                                                          .Include <PlayerCaptainDto>(join => join.LeftOuterJoin())
                                                                          .Where($"{nameof(PlayerDto.Id):C} = @Id")
                                                                          .WithParameters(new { Id = message.AccountId })))
                                      .FirstOrDefault();

                    var expTable = GameServer.Instance.ResourceCache.GetExperience();
                    Experience expValue;

                    if (plrDto == null)
                    {
                        // first time connecting to this server
                        if (!expTable.TryGetValue(Config.Instance.Game.StartLevel, out expValue))
                        {
                            expValue = new Experience {
                                TotalExperience = 0
                            };
                            Logger.Warning("Given start level is not found in the experience table");
                        }

                        plrDto = new PlayerDto
                        {
                            Id              = (int)account.Id,
                            PlayTime        = TimeSpan.FromSeconds(0).ToString(),
                            Level           = Config.Instance.Game.StartLevel,
                            PEN             = Config.Instance.Game.StartPEN,
                            AP              = Config.Instance.Game.StartAP,
                            Coins1          = Config.Instance.Game.StartCoins1,
                            Coins2          = Config.Instance.Game.StartCoins2,
                            TotalExperience = expValue.TotalExperience,
                        };

                        try
                        {
                            await DbUtil.InsertAsync(db, plrDto);
                        }
                        catch (Exception e)
                        {
                            session.Channel.Pipeline.FireExceptionCaught(e);
                            return;
                        }
                    }
                    else
                    {
                        if (!TimeSpan.TryParse(plrDto.PlayTime, out _))
                        {
                            plrDto.PlayTime = TimeSpan.FromSeconds(0).ToString();
                        }

                        if (!expTable.TryGetValue(plrDto.Level, out expValue))
                        {
                            expValue = new Experience {
                                TotalExperience = 0
                            };
                            Logger.Warning("Given level is not found in the experience table");
                        }

                        // Adjust total exp to correct range
                        if (plrDto.TotalExperience < expValue.TotalExperience)
                        {
                            plrDto.TotalExperience = expValue.TotalExperience;
                            await DbUtil.UpdateAsync(db, plrDto);
                        }

                        // Adjust total exp to minexp of current level
                        if (plrDto.Level > 0 && plrDto.TotalExperience == 0)
                        {
                            plrDto.TotalExperience = expValue.TotalExperience - 1;
                            await DbUtil.UpdateAsync(db, plrDto);
                        }
                    }

                    if (plrStatsDto != null)
                    {
                        plrDto.DeathMatchInfo  = plrStatsDto.DeathMatchInfo;
                        plrDto.TouchDownInfo   = plrStatsDto.TouchDownInfo;
                        plrDto.ChaserInfo      = plrStatsDto.ChaserInfo;
                        plrDto.BattleRoyalInfo = plrStatsDto.BattleRoyalInfo;
                        plrDto.CaptainInfo     = plrStatsDto.CaptainInfo;
                    }

                    session.Player = new Player(session, account, plrDto);
                }

                if (session.Player == null)
                {
                    Logger.ForAccount(account)
                    .Error("PlayerInfo failed - Missing playerInstance");
                    return;
                }

                GameServer.Instance.PlayerManager.Add(session.Player);

                var result = string.IsNullOrWhiteSpace(account.Nickname)
                  ? GameLoginResult.ChooseNickname
                  : GameLoginResult.OK;

                result = session.Player.CharacterManager.Any() ? result : GameLoginResult.ChooseNickname;

                if (session.UpdateShop)
                {
                    await ShopService.ShopUpdateMsg(session, false);
                    session.UpdateShop = false;
                }

                await session.SendAsync(new LoginReguestAckMessage(result, session.Player.Account.Id));

                if (result == GameLoginResult.OK)
                {
                    await LoginAsync(session);
                }
            });
        }