예제 #1
0
        /// <summary>
        /// Returns the most appropriate handler for the specified packet type.
        /// </summary>
        /// <param name="packet">The packet to select the handler for.</param>
        /// <returns>An instance of an <see cref="ITcpRequestHandler"/> implementaion.</returns>
        public ITcpRequestHandler SelectForPacket(IInboundPacket packet)
        {
            packet.ThrowIfNull(nameof(packet));

            var packetType = packet.GetType();

            if (this.handlersMap.TryGetValue(packetType, out ITcpRequestHandler handler))
            {
                return(handler);
            }

            foreach (var iType in packetType.GetInterfaces())
            {
                if (this.handlersMap.TryGetValue(iType, out handler))
                {
                    return(handler);
                }
            }

            this.logger.LogWarning($"No handler found for type {packetType}.");

            return(null);
        }
예제 #2
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IFollowInfo followInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IFollowInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            // First stop attacking if we are.
            server.RequestToAttackCreatureAsync(client.PlayerId);

            server.RequestToFollowCreatureAsync(client.PlayerId, followInfo.TargetCreatureId);

            return(null);
        }
예제 #3
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is ISpeechInfo speechInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(ISpeechInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            server.RequestSendMessageAsync(client.PlayerId, speechInfo.SpeechType, speechInfo.ChannelType, speechInfo.Content, speechInfo.Receiver);

            return(null);
        }
예제 #4
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IGameLogInInfo loginInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IGameLogInInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            if (!(client.Connection is ISocketConnection socketConnection))
            {
                this.Logger.LogError($"Expected a {nameof(ISocketConnection)} got a {client.Connection.GetType().Name}.");

                return(null);
            }

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

            // TODO: possibly a friendly name conversion here. Also, the actual values might change per version, so this really should be set by the packet reader.
            client.Type    = Enum.IsDefined(typeof(AgentType), loginInfo.ClientOs) ? (AgentType)loginInfo.ClientOs : AgentType.Windows;
            client.Version = loginInfo.ClientVersion.ToString();

            if (loginInfo.ClientVersion != server.Options.SupportedClientVersion.Numeric)
            {
                this.Logger.LogInformation($"Client attempted to connect with version: {loginInfo.ClientVersion}, OS: {loginInfo.ClientOs}. Expected version: {server.Options.SupportedClientVersion.Numeric}.");

                // TODO: hardcoded messages.
                return(new GameServerDisconnectPacket($"You need client version {server.Options.SupportedClientVersion.Description} to connect to this server.").YieldSingleItem());
            }

            var(playerId, error) = server.RequestPlayerLogIn(loginInfo.AccountIdentifier, loginInfo.Password, loginInfo.CharacterName);

            if (!string.IsNullOrWhiteSpace(error))
            {
                return(new GatewayServerDisconnectPacket(error).YieldSingleItem());
            }

            client.PlayerId = playerId;

            this.clientsManager.Register(client);

            // We don't return anything synchronously in this particular case, the game will send out the login notifications when they are ready.
            return(null);
        }
예제 #5
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IModesInfo modesInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IModesInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            server.RequestToUpdateModesAsync(client.PlayerId, modesInfo.FightMode, modesInfo.ChaseMode, modesInfo.SafeModeOn);

            return(null);
        }
예제 #6
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IBytesInfo debugInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IBytesInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            var sb = new StringBuilder();

            foreach (var b in debugInfo.Bytes)
            {
                sb.AppendFormat("{0:x2} ", b);
            }

            this.Logger.LogInformation($"Default handler drained packet with content:\n\n{sb}");

            return(null);
        }
예제 #7
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is ILookAtInfo lookAtInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(ILookAtInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            server.RequestTextDescriptionAtAsync(client.PlayerId, lookAtInfo.Location, lookAtInfo.StackPosition, lookAtInfo.ThingId);

            return(null);
        }
예제 #8
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IAttackInfo attackInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IAttackInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            // First stop following (formally) if we are.
            server.RequestToFollowCreatureAsync(client.PlayerId);

            // And then start attacking. Game will handle if that implicitly means follow the target of the attack.
            server.RequestToAttackCreatureAsync(client.PlayerId, attackInfo.TargetCreatureId);

            return(null);
        }
예제 #9
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IWalkOnDemandInfo walkOnDemandInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IWalkOnDemandInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            server.RequestToUpdateWalkPlanAsync(client.PlayerId, new[] { walkOnDemandInfo.Direction });

            return(null);
        }
예제 #10
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is ITurnOnDemandInfo turnOnDemandInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(ITurnOnDemandInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            // TODO: cancel other pending actions.
            server.RequestToTurnCreatureAsync(client.PlayerId, turnOnDemandInfo.Direction);

            return(null);
        }
예제 #11
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IActionWithoutContentInfo actionInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IActionWithoutContentInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            switch (actionInfo.Action)
            {
            case InboundPacketType.AutoMoveCancel:
                server.RequestToCancelPlayerOperationsAsync(client.PlayerId, OperationCategory.Movement);
                break;

            case InboundPacketType.HeartbeatResponse:
                // NO-OP.
                break;

            case InboundPacketType.Heartbeat:
                server.SendHeartbeatResponseAsync(client);
                break;

            case InboundPacketType.LogOut:
                server.RequestPlayerLogOutAsync(client.PlayerId);
                break;

            case InboundPacketType.StartOutfitChange:
                // this.Game.RequestPlayerOutfitChange(client.PlayerId);
                break;

            case InboundPacketType.StopAllActions:
                server.RequestToCancelPlayerOperationsAsync(client.PlayerId);
                break;
            }

            return(null);
        }
예제 #12
0
 /// <summary>
 /// Handles the contents of a request packet.
 /// </summary>
 /// <param name="tcpServerInstance">A reference to the tcp server instance which owns the listener at which this request landed.</param>
 /// <param name="incomingPacket">The packet to handle.</param>
 /// <param name="client">A reference to the client from where this request originated from, for context.</param>
 /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
 public abstract IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer tcpServerInstance, IInboundPacket incomingPacket, IClient client);
예제 #13
0
        /// <summary>
        /// Handles the contents of a network message.
        /// </summary>
        /// <param name="server">A reference to the tcp server instance which owns the listener at which this request landed.</param>
        /// <param name="incomingPacket">The packet to handle.</param>
        /// <param name="client">A reference to the client from where this request originated from, for context.</param>
        /// <returns>A collection of <see cref="IOutboundPacket"/>s that compose that synchronous response, if any.</returns>
        public override IEnumerable <IOutboundPacket> HandleRequestPacket(ITcpServer server, IInboundPacket incomingPacket, IClient client)
        {
            server.ThrowIfNull(nameof(server));
            incomingPacket.ThrowIfNull(nameof(incomingPacket));
            client.ThrowIfNull(nameof(client));

            if (!(incomingPacket is IGatewayLoginInfo accountLoginInfo))
            {
                this.Logger.LogError($"Expected packet info of type {nameof(IGatewayLoginInfo)} but got {incomingPacket.GetType().Name}.");

                return(null);
            }

            if (!(client.Connection is ISocketConnection socketConnection))
            {
                this.Logger.LogError($"Expected a {nameof(ISocketConnection)} got a {client.Connection.GetType().Name}.");

                return(null);
            }

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

            if (accountLoginInfo.ClientVersion != server.Options.SupportedClientVersion.Numeric)
            {
                this.Logger.LogInformation($"Client attempted to connect with version: {accountLoginInfo.ClientVersion}, OS: {accountLoginInfo.ClientOs}. Expected version: {server.Options.SupportedClientVersion.Numeric}.");

                // TODO: hardcoded messages.
                return(new GatewayServerDisconnectPacket($"You need client version {server.Options.SupportedClientVersion.Description} to connect to this server.").YieldSingleItem());
            }

            var(characters, premDays, error) = server.DoAccountLogin(accountLoginInfo.AccountName, accountLoginInfo.Password);

            if (!string.IsNullOrWhiteSpace(error))
            {
                return(new GatewayServerDisconnectPacket(error).YieldSingleItem());
            }

            return(new IOutboundPacket[]
            {
                new MessageOfTheDayPacket(server.InformationalMessage),
                new CharacterListPacket(characters, (ushort)premDays),
            });
        }