Example #1
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="message">The message to handle.</param>
        /// <param name="connection">A reference to the connection from where this message is comming from, for context.</param>
        /// <returns>A value tuple with a value indicating whether the handler intends to respond, and a collection of <see cref="IOutgoingPacket"/>s that compose that response.</returns>
        public override (bool IntendsToRespond, IEnumerable <IOutgoingPacket> ResponsePackets) HandleRequest(INetworkMessage message, IConnection connection)
        {
            connection.ThrowIfNull(nameof(connection));

            var responsePackets = new List <IOutgoingPacket>();

            var newConnectionInfo = message.ReadNewConnectionInfo();

            if (newConnectionInfo.Version != this.ProtocolConfiguration.ClientVersion.Numeric)
            {
                // TODO: hardcoded messages.
                responsePackets.Add(new LoginServerDisconnectPacket($"You need client version {this.ProtocolConfiguration.ClientVersion.Description} to connect to this server."));

                return(true, responsePackets);
            }

            // Make a copy of the message in case we fail to decrypt using the first set of keys.
            var messageCopy = message.Copy();

            message.RsaDecrypt(useCipKeys: this.ProtocolConfiguration.UsingCipsoftRsaKeys);

            // If GetByte() here is not Zero, it means the RSA decrypt was unsuccessful, lets try with the other set of RSA keys...
            if (message.GetByte() != 0)
            {
                message = messageCopy;

                message.RsaDecrypt(useCipKeys: !this.ProtocolConfiguration.UsingCipsoftRsaKeys);

                if (message.GetByte() != 0)
                {
                    // These RSA keys are also unsuccessful... give up.
                    // loginPacket = new AccountLoginPacket(inboundMessage);

                    // connection.SetXtea(loginPacket?.XteaKey);

                    //// TODO: hardcoded messages.
                    // if (gameConfig.UsingCipsoftRSAKeys)
                    // {
                    //    this.SendDisconnect(connection, $"The RSA encryption keys used by your client cannot communicate with this game server.\nPlease use an IP changer that does not replace the RSA Keys.\nWe recommend using Tibia Loader's 7.7 client.\nYou may also download the client from our website.");
                    // }
                    // else
                    // {
                    //    this.SendDisconnect(connection, $"The RSA encryption keys used by your client cannot communicate with this game server.\nPlease use an IP changer that replaces the RSA Keys.\nWe recommend using OTLand's IP changer with a virgin 7.7 client.\nYou may also download the client from our website.");
                    // }
                    return(false, null);
                }
            }

            var accLoginInfo = message.ReadAccountLoginInfo();

            // Associate the xTea key to allow future validate packets from this connection.
            connection.SetupAuthenticationKey(accLoginInfo.XteaKey);

            using var unitOfWork = new OpenTibiaUnitOfWork(this.ApplicationContext.DefaultDatabaseContext);

            // validate credentials.
            var accounts = unitOfWork.Accounts.FindMany(u => u.Number == accLoginInfo.AccountNumber && u.Password.Equals(accLoginInfo.Password));
            var account  = accounts.FirstOrDefault();

            if (account == null)
            {
                // TODO: hardcoded messages.
                responsePackets.Add(new LoginServerDisconnectPacket("Please enter a valid account number and password."));

                return(true, responsePackets);
            }

            var charactersFound = unitOfWork.Characters.FindMany(p => p.AccountId == account.Id);

            if (!charactersFound.Any())
            {
                // TODO: hardcoded messages.
                responsePackets.Add(new LoginServerDisconnectPacket($"You don't have any characters in your account.\nPlease create a new character in our web site: {this.GameConfiguration.World.WebsiteUrl}"));

                return(true, responsePackets);
            }

            var charList = new List <ICharacterListItem>();

            foreach (var character in charactersFound)
            {
                charList.Add(new CharacterListItem(
                                 character.Name,
                                 IPAddress.Parse(this.GameConfiguration.PublicAddressBinding.Ipv4Address),
                                 this.GameConfiguration.PublicAddressBinding.Port,
                                 this.GameConfiguration.World.Name));
            }

            responsePackets.Add(new MessageOfTheDayPacket(this.GameConfiguration.World.MessageOfTheDay));
            responsePackets.Add(new CharacterListPacket(charList, (ushort)(account.PremiumDays + account.TrialOrBonusPremiumDays)));

            return(true, responsePackets);
        }
Example #2
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="message">The message to handle.</param>
        /// <param name="connection">A reference to the connection from where this message is comming from, for context.</param>
        /// <returns>A value tuple with a value indicating whether the handler intends to respond, and a collection of <see cref="IOutgoingPacket"/>s that compose that response.</returns>
        public override (bool IntendsToRespond, IEnumerable <IOutgoingPacket> ResponsePackets) HandleRequest(INetworkMessage message, IConnection connection)
        {
            var loginInfo = message.ReadCharacterLoginInfo();

            var responsePackets = new List <IOutgoingPacket>();

            if (loginInfo.Version != this.ProtocolConfiguration.ClientVersion.Numeric)
            {
                responsePackets.Add(new GameServerDisconnectPacket($"You need client version {this.ProtocolConfiguration.ClientVersion.Description} to connect to this server."));

                return(true, responsePackets);
            }

            if (this.Game.Status == WorldState.Loading)
            {
                responsePackets.Add(new GameServerDisconnectPacket("The game is just starting.\nPlease try again in a few minutes."));

                return(true, responsePackets);
            }

            // Associate the xTea key to allow future validate packets from this connection.
            connection.SetupAuthenticationKey(loginInfo.XteaKey);
            connection.Authenticate(loginInfo.XteaKey);

            using var unitOfWork = new OpenTibiaUnitOfWork(this.ApplicationContext.DefaultDatabaseContext);

            AccountEntity   account   = unitOfWork.Accounts.FindOne(a => a.Number == loginInfo.AccountNumber && a.Password.Equals(loginInfo.Password));
            CharacterEntity character = null;

            var failureReason = string.Empty;

            if (account == null)
            {
                failureReason = "The account number and password combination is invalid.";
            }
            else
            {
                character = unitOfWork.Characters.FindOne(c => c.AccountId.Equals(account.Id) && c.Name.Equals(loginInfo.CharacterName));

                CharacterEntity otherCharacterOnline = unitOfWork.Characters.FindOne(c => c.IsOnline && c.AccountId == account.Id && !c.Name.Equals(loginInfo.CharacterName));

                if (character == null)
                {
                    failureReason = "The character selected was not found in this account.";
                }
                else
                {
                    // Check bannishment.
                    if (account.Banished)
                    {
                        // Lift if time is up
                        if (account.Banished && account.BanishedUntil > DateTimeOffset.UtcNow)
                        {
                            failureReason = "Your account is bannished.";
                        }
                        else
                        {
                            account.Banished = false;
                        }
                    }
                    else if (account.Deleted)
                    {
                        failureReason = "Your account is disabled.\nPlease contact us for more information.";
                    }
                    else if (otherCharacterOnline != null)
                    {
                        failureReason = "Another character in your account is online.";
                    }
                    else if (this.Game.Status != WorldState.Open)
                    {
                        // Check if game is open to public
                        failureReason = "The server is not open to the public yet.\nCheck for news on our webpage.";
                    }
                }
            }

            if (failureReason == string.Empty)
            {
                try
                {
                    // Set player status to online.
                    character.IsOnline = true;

                    var player = this.Game.PlayerRequest_Login(character, connection);

                    responsePackets.Add(new SelfAppearPacket(player.Id, true, player));

                    // Add MapDescription
                    var mapDescription = this.Game.GetDescriptionOfMapForPlayer(player, player.Location);

                    responsePackets.Add(new MapDescriptionPacket(player.Location, mapDescription));

                    responsePackets.Add(new MagicEffectPacket(player.Location, AnimatedEffect.BubbleBlue));

                    responsePackets.Add(new PlayerInventoryPacket(player));

                    // Adds a text message
                    responsePackets.Add(new PlayerStatsPacket(player));

                    responsePackets.Add(new PlayerSkillsPacket(player));

                    responsePackets.Add(new WorldLightPacket(this.Game.WorldLightLevel, this.Game.WorldLightColor));

                    responsePackets.Add(new CreatureLightPacket(player));

                    // Adds a text message
                    responsePackets.Add(new TextMessagePacket(MessageType.StatusDefault, "This is a test message"));

                    // std::string tempstring = g_config.getString(ConfigManager::LOGIN_MSG);
                    // if (tempstring.size() > 0)
                    // {
                    //    AddTextMessage(msg, MSG_STATUS_DEFAULT, tempstring.c_str());
                    // }

                    // if (player->getLastLoginSaved() != 0)
                    // {
                    //    tempstring = "Your last visit was on ";
                    //    time_t lastLogin = player->getLastLoginSaved();
                    //    tempstring += ctime(&lastLogin);
                    //    tempstring.erase(tempstring.length() - 1);
                    //    tempstring += ".";

                    // AddTextMessage(msg, MSG_STATUS_DEFAULT, tempstring.c_str());
                    // }
                    // else
                    // {
                    //    tempstring = "Welcome to ";
                    //    tempstring += g_config.getString(ConfigManager::SERVER_NAME);
                    //    tempstring += ". Please choose an outfit.";
                    //    sendOutfitWindow(player);
                    // }

                    // Add any Vips here.

                    // for (VIPListSet::iterator it = player->VIPList.begin(); it != player->VIPList.end(); it++)
                    // {
                    //    bool online;
                    //    std::string vip_name;
                    //    if (IOPlayer::instance()->getNameByGuid((*it), vip_name))
                    //    {
                    //        online = (g_game.getPlayerByName(vip_name) != NULL);
                    //
                    // msg->AddByte(0xD2);
                    // msg->AddU32(guid);
                    // msg->AddString(name);
                    // msg->AddByte(isOnline ? 1 : 0);
                    //    }
                    // }

                    // Send condition icons
                    responsePackets.Add(new PlayerConditionsPacket(player));
                }
                catch (Exception ex)
                {
                    this.Logger.Error($"Unexpected error handling player login request: {ex.Message}");

                    failureReason = "Internal server error.";
                }
            }

            if (failureReason != string.Empty)
            {
                responsePackets.Clear();

                responsePackets.Add(new GameServerDisconnectPacket(failureReason.ToString()));
            }

            // save any changes to the entities.
            unitOfWork.Complete();

            return(true, responsePackets);
        }