Пример #1
0
 public void InsertSignpost(Objects.Signpost post)
 {
     World.Insert(post);
     Insert(post, post.X, post.Y);
     Signposts[new Tuple <byte, byte>(post.X, post.Y)] = post;
     GameLog.InfoFormat("Inserted signpost {0}@{1},{2}", post.Map.Name, post.X, post.Y);
 }
Пример #2
0
        public void Redirect(Redirect redirect, bool isLogoff = false)
        {
            GameLog.InfoFormat("Processing redirect");
            GlobalConnectionManifest.RegisterRedirect(this, redirect);
            GameLog.InfoFormat("Redirect: cid {0}", this.ConnectionId);
            GameLog.Info($"Redirect EncryptionKey is {Encoding.ASCII.GetString(redirect.EncryptionKey)}");
            if (isLogoff)
            {
                GlobalConnectionManifest.DeregisterClient(this);
            }
            redirect.Destination.ExpectedConnections.TryAdd(redirect.Id, redirect);

            var endPoint = Socket.RemoteEndPoint as IPEndPoint;

            byte[] addressBytes = IPAddress.IsLoopback(endPoint.Address) ? IPAddress.Loopback.GetAddressBytes() : Game.IpAddress.GetAddressBytes();

            Array.Reverse(addressBytes);

            var x03 = new ServerPacket(0x03);

            x03.Write(addressBytes);
            x03.WriteUInt16((ushort)redirect.Destination.Port);
            x03.WriteByte((byte)(redirect.EncryptionKey.Length + Encoding.ASCII.GetBytes(redirect.Name).Length + 7));
            x03.WriteByte(redirect.EncryptionSeed);
            x03.WriteByte((byte)redirect.EncryptionKey.Length);
            x03.Write(redirect.EncryptionKey);
            x03.WriteString8(redirect.Name);
            x03.WriteUInt32(redirect.Id);
            Thread.Sleep(100);
            Enqueue(x03);
        }
Пример #3
0
        public Client(Socket socket, Server server)
        {
            ClientState = new ClientState(socket);
            Server      = server;
            GameLog.InfoFormat("Connection {0} from {1}:{2}", ConnectionId,
                               ((IPEndPoint)Socket.RemoteEndPoint).Address.ToString(),
                               ((IPEndPoint)Socket.RemoteEndPoint).Port);

            if (server is Lobby)
            {
                EncryptionKey = Game.Config.ApiEndpoints.EncryptionEndpoint != null?GlobalConnectionManifest.RequestEncryptionKey(Game.Config.ApiEndpoints.EncryptionEndpoint.Url, ((IPEndPoint)socket.RemoteEndPoint).Address) : Encoding.ASCII.GetBytes("UrkcnItnI");

                GameLog.InfoFormat($"EncryptionKey is {Encoding.ASCII.GetString(EncryptionKey)}");

                var valid = Game.Config.ApiEndpoints.ValidationEndpoint != null?GlobalConnectionManifest.ValidateEncryptionKey(Game.Config.ApiEndpoints.ValidationEndpoint.Url, new ServerToken { Ip = ((IPEndPoint)socket.RemoteEndPoint).Address.ToString(), Seed = EncryptionKey }) : true;

                if (!valid)
                {
                    GameLog.ErrorFormat("Invalid key from {IP}", ((IPEndPoint)Socket.RemoteEndPoint).Address.ToString());
                    socket.Disconnect(true);
                }
            }

            EncryptionKeyTable = new byte[1024];
            _lastReceived      = DateTime.Now.Ticks;

            GlobalConnectionManifest.RegisterClient(this);

            ConnectedSince = DateTime.Now.Ticks;
        }
Пример #4
0
 public static void DeregisterClient(Client client)
 {
     ConnectedClients.TryRemove(client.ConnectionId, out Client _);
     GameLog.InfoFormat("Deregistering {0}", client.ConnectionId);
     // Send a control message to clean up after World users; Lobby and Login handle themselves
     if (client.ServerType == ServerTypes.World)
     {
         if (!WorldClients.TryRemove(client.ConnectionId, out Client _))
         {
             GameLog.Error("Couldn't deregister cid {id}", client.ConnectionId);
         }
         try
         {
             if (!World.ControlMessageQueue.IsCompleted)
             {
                 World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.CleanupUser,
                                                                          CleanupType.ByConnectionId, client.ConnectionId));
             }
         }
         catch (InvalidOperationException e)
         {
             Game.ReportException(e);
             if (!World.ControlMessageQueue.IsCompleted)
             {
                 GameLog.ErrorFormat("Connection {id}: DeregisterClient failed", client.ConnectionId);
             }
         }
     }
 }
Пример #5
0
        private void PacketHandler_0x03_Login(Client client, ClientPacket packet)
        {
            var name     = packet.ReadString8();
            var password = packet.ReadString8();

            GameLog.DebugFormat("cid {0}: Login request for {1}", client.ConnectionId, name);

            if (!World.PlayerExists(name))
            {
                client.LoginMessage("That character does not exist", 3);
                GameLog.InfoFormat("cid {0}: attempt to login as nonexistent character {1}", client.ConnectionId, name);
                return;
            }

            if (World.TryGetUser(name, out User loginUser))
            {
                if (loginUser.VerifyPassword(password))
                {
                    GameLog.DebugFormat("cid {0}: password verified for {1}", client.ConnectionId, name);

                    if (Game.World.WorldData.ContainsKey <User>(name))
                    {
                        GameLog.InfoFormat("cid {0}: {1} logging on again, disconnecting previous connection",
                                           client.ConnectionId, name);
                        client.LoginMessage("That character is already online. Please try again.", 3);
                        World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.LogoffUser, name));
                        return;
                    }

                    GameLog.DebugFormat("cid {0} ({1}): logging in", client.ConnectionId, name);
                    client.LoginMessage("\0", 0);
                    client.SendMessage("Welcome to Hybrasyl!", 3);
                    GameLog.DebugFormat("cid {0} ({1}): sending redirect to world", client.ConnectionId, name);

                    var redirect = new Redirect(client, this, Game.World, name, client.EncryptionSeed,
                                                client.EncryptionKey);
                    GameLog.InfoFormat("cid {0} ({1}): login successful, redirecting to world server",
                                       client.ConnectionId, name);
                    loginUser.Login.LastLogin     = DateTime.Now;
                    loginUser.Login.LastLoginFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString();
                    loginUser.Save();
                    client.Redirect(redirect);
                }
                else
                {
                    GameLog.WarningFormat("cid {0} ({1}): password incorrect", client.ConnectionId, name);
                    client.LoginMessage("Incorrect password", 3);
                    loginUser.Login.LastLoginFailure = DateTime.Now;
                    loginUser.Login.LoginFailureCount++;
                    loginUser.Save();
                }
            }
            else
            {
                // Something bad has happened
                client.LoginMessage("An unknown error occurred. Please contact Hybrasyl support.", 3);
            }
        }
Пример #6
0
            // General notes about this god awful packet:

            /* Offsets:
             * 00-0F: no human body + pants
             * 10-1F: male human body + pants
             * 20-2F: female human body, no pants
             * 30-3F: male spirit + pants
             * 40-4F: female spirit, no pants
             * 50-5F: invisible male body + pants
             * 60-6F: invisible female body, no pants
             * 70-7F: male doll body + pants
             * 80-8F: male mounted body + pants
             * 90-9F: female mounted body, no pants
             * A0-FF: no human body + pants
             */

            internal ServerPacket Packet()
            {
                ServerPacket packet = new ServerPacket(OpCode);

                packet.WriteUInt16(X);
                packet.WriteUInt16(Y);
                packet.WriteByte((byte)Direction);
                packet.WriteUInt32(Id);
                packet.WriteUInt16(Helmet);
                GameLog.InfoFormat($"Gender is {Gender}");
                if (!DisplayAsMonster)
                {
                    packet.WriteByte((byte)(((byte)Gender * 16) + BodySpriteOffset));
                    packet.WriteUInt16(Armor);
                    packet.WriteByte(Boots);
                    packet.WriteUInt16(Armor);
                    packet.WriteByte(Shield);
                    packet.WriteUInt16(Weapon);
                    packet.WriteByte(HairColor);
                    packet.WriteByte(BootsColor);
                    packet.WriteByte(FirstAccColor);
                    packet.WriteUInt16(FirstAcc);
                    packet.WriteByte(SecondAccColor);
                    packet.WriteUInt16(SecondAcc);
                    packet.WriteByte(ThirdAccColor);
                    packet.WriteUInt16(ThirdAcc);
                    packet.WriteByte((byte)LanternSize);
                    packet.WriteByte((byte)RestPosition);
                    packet.WriteUInt16(Overcoat);
                    packet.WriteByte(OvercoatColor);
                    packet.WriteByte((byte)SkinColor);
                    packet.WriteBoolean(Invisible);
                    packet.WriteByte(FaceShape);
                }
                else
                {
                    packet.WriteUInt16(MonsterSprite);
                    packet.WriteByte(HairColor);
                    packet.WriteByte(BootsColor);
                    // Unknown
                    packet.WriteByte(0x00);
                    packet.WriteByte(0x00);
                    packet.WriteByte(0x00);
                    packet.WriteByte(0x00);
                    packet.WriteByte(0x00);
                    packet.WriteByte(0x00);
                }
                packet.WriteByte((byte)NameStyle);
                packet.WriteString8(Name ?? string.Empty);
                packet.WriteString8(GroupName ?? string.Empty);

                return(packet);
            }
Пример #7
0
 public bool StartExchange()
 {
     GameLog.InfoFormat("Starting exchange between {0} and {1}", _source.Name, _target.Name);
     _active = true;
     _source.Condition.InExchange = true;
     _target.Condition.InExchange = true;
     _source.ActiveExchange       = this;
     _target.ActiveExchange       = this;
     // Send "open window" packet to both clients
     _target.SendExchangeInitiation(_source);
     _source.SendExchangeInitiation(_target);
     return(true);
 }
Пример #8
0
        public Lobby(int port)
            : base(port)
        {
            GameLog.InfoFormat("LobbyConstructor: port is {0}", port);

            PacketHandlers = new LobbyPacketHandler[256];
            for (int i = 0; i < 256; ++i)
            {
                PacketHandlers[i] = (c, p) => GameLog.WarningFormat("Lobby: Unhandled opcode 0x{0:X2}", p.Opcode);
            }
            PacketHandlers[0x00] = PacketHandler_0x00_ClientVersion;
            PacketHandlers[0x57] = PacketHandler_0x57_ServerTable;
        }
Пример #9
0
        // Chart for all error password-related error codes were provided by kojasou@ on
        // https://github.com/hybrasyl/server/pull/11.
        private void PacketHandler_0x26_ChangePassword(Client client, ClientPacket packet)
        {
            var name        = packet.ReadString8();
            var currentPass = packet.ReadString8();
            // Clientside validation ensures that the same string is typed twice for the new
            // password, and the new password is only sent to the server once. We can assume
            // that they matched if 0x26 request is sent from the client.
            var newPass = packet.ReadString8();

            // TODO: REDIS

            User player;

            if (!World.TryGetUser(name, out player))
            {
                client.LoginMessage(GetPasswordError(0x0E), 0x0E);
                GameLog.InfoFormat("cid {0}: Password change attempt on nonexistent player {1}", client.ConnectionId, name);
                return;
            }

            if (player.VerifyPassword(currentPass))
            {
                // Check if the password is valid.
                byte err = 0x00;
                if (ValidPassword(newPass, out err))
                {
                    player.Password.Hash            = HashPassword(newPass);
                    player.Password.LastChanged     = DateTime.Now;
                    player.Password.LastChangedFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString();
                    player.Save();
                    // Let the user know the good news.
                    client.LoginMessage("Your password has been changed successfully.", 0x0);
                    GameLog.InfoFormat("Password successfully changed for `{0}`", name);
                }
                else
                {
                    client.LoginMessage(GetPasswordError(err), err);
                    GameLog.ErrorFormat("Invalid new password proposed during password change attempt for `{0}`", name);
                }
            }
            // The current password is incorrect. Don't allow any changes to happen.
            else
            {
                client.LoginMessage(GetPasswordError(0x0F), 0x0F);
                GameLog.ErrorFormat("Invalid current password during password change attempt for `{0}`", name);
            }
        }
Пример #10
0
        public UserGroup(User founder)
        {
            Members    = new List <User>();
            ClassCount = new Dictionary <Xml.Class, uint>();
            foreach (var cl in Enum.GetValues(typeof(Xml.Class)).Cast <Xml.Class>())
            {
                ClassCount[cl] = 0;
            }

            GameLog.InfoFormat("Creating new group with {0} as founder.", founder.Name);
            // Distribute full experience to everyone with a bonus if a member of each
            // class is present.
            ExperienceDistributionFunc = Distribution_AllClassBonus;

            Add(founder);
            CreatedOn = DateTime.Now;
        }
Пример #11
0
 public void StartListening()
 {
     Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
     Listener.Bind(new IPEndPoint(IPAddress.Any, Port));
     Active = true;
     Listener.Listen(100);
     GameLog.InfoFormat("Starting TcpListener: {0}:{1}", IPAddress.Any.ToString(), Port);
     while (true)
     {
         if (StopToken.IsCancellationRequested)
         {
             Active = false;
             return;
         }
         AllDone.Reset();
         Listener.BeginAccept(new AsyncCallback(AcceptConnection), Listener);
         AllDone.WaitOne();
     }
 }
Пример #12
0
        private void PacketHandler_0x57_ServerTable(Client client, ClientPacket packet)
        {
            var mismatch = packet.ReadByte();

            if (mismatch == 1)
            {
                var x56 = new ServerPacket(0x56);
                x56.WriteUInt16((ushort)Game.ServerTable.Length);
                x56.Write(Game.ServerTable);
                GameLog.InfoFormat("ServerTable: Sent: {0}", BitConverter.ToString(x56.ToArray()));
                client.Enqueue(x56);
            }
            else
            {
                var server   = packet.ReadByte();
                var redirect = new Redirect(client, this, Game.Login, "socket", client.EncryptionSeed, client.EncryptionKey);
                client.Redirect(redirect);
            }
        }
Пример #13
0
        public Login(int port)
            : base(port)
        {
            GameLog.InfoFormat("LoginConstructor: port is {0}", port);

            PacketHandlers = new LoginPacketHandler[256];

            for (int i = 0; i < 256; ++i)
            {
                PacketHandlers[i] = (c, p) => GameLog.WarningFormat("Login: Unhandled opcode 0x{0:X2}", p.Opcode);
            }

            PacketHandlers[0x02] = PacketHandler_0x02_CreateA;
            PacketHandlers[0x03] = PacketHandler_0x03_Login;
            PacketHandlers[0x04] = PacketHandler_0x04_CreateB;
            PacketHandlers[0x10] = PacketHandler_0x10_ClientJoin;
            PacketHandlers[0x26] = PacketHandler_0x26_ChangePassword;
            PacketHandlers[0x4B] = PacketHandler_0x4B_RequestNotification;
            PacketHandlers[0x68] = PacketHandler_0x68_RequestHomepage;
        }
Пример #14
0
 /// <summary>
 /// Confirm the exchange. Once both sides confirm, perform the exchange.
 /// </summary>
 /// <returns>Boolean indicating success.</returns>
 public void ConfirmExchange(User requestor)
 {
     if (_source == requestor)
     {
         GameLog.InfoFormat("Exchange: source ({0}) confirmed", _source.Name);
         _sourceConfirmed = true;
         _target.SendExchangeConfirmation(false);
     }
     if (_target == requestor)
     {
         GameLog.InfoFormat("Exchange: target ({0}) confirmed", _target.Name);
         _targetConfirmed = true;
         _source.SendExchangeConfirmation(false);
     }
     if (_sourceConfirmed && _targetConfirmed)
     {
         GameLog.Info("Exchange: Both sides confirmed");
         _source.SendExchangeConfirmation();
         _target.SendExchangeConfirmation();
         PerformExchange();
     }
 }
Пример #15
0
 public static void DeregisterClient(Client client)
 {
     ((IDictionary)ConnectedClients).Remove(client.ConnectionId);
     GameLog.InfoFormat("Deregistering {0}", client.ConnectionId);
     // Send a control message to clean up after World users; Lobby and Login handle themselves
     if (client.ServerType == ServerTypes.World)
     {
         ((IDictionary)WorldClients).Remove(client.ConnectionId);
         // This will also handle removing the user from WorldClients if necessary
         try
         {
             World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.CleanupUser, client.ConnectionId));
         }
         catch (InvalidOperationException)
         {
             if (!World.ControlMessageQueue.IsCompleted)
             {
                 GameLog.ErrorFormat("Connection {id}: DeregisterClient failed", client.ConnectionId);
             }
         }
     }
 }
Пример #16
0
        /// <summary>
        /// Determine whether either heartbeat has "expired" (meaning REAP_HEARTBEAT_INTERVAL has
        /// passed since we received a heartbeat response).
        /// </summary>
        /// <returns>True or false, indicating expiration.</returns>
        public bool IsHeartbeatExpired()
        {
            // If we have no record of sending a heartbeat, obviously it hasn't expired
            if (_tickHeartbeatSent == 0 && _byteHeartbeatSent == 0)
            {
                return(false);
            }

            var tickSpan = new TimeSpan(_tickHeartbeatReceived - _tickHeartbeatSent);
            var byteSpan = new TimeSpan(_byteHeartbeatReceived - _byteHeartbeatSent);

            GameLog.DebugFormat("cid {0}: tick heartbeat elapsed seconds {1}, byte heartbeat elapsed seconds {2}",
                                ConnectionId, tickSpan.TotalSeconds, byteSpan.TotalSeconds);

            if (tickSpan.TotalSeconds > Constants.REAP_HEARTBEAT_INTERVAL ||
                byteSpan.TotalSeconds > Constants.REAP_HEARTBEAT_INTERVAL)
            {
                // DON'T FEAR THE REAPER
                GameLog.InfoFormat("cid {0}: heartbeat expired", ConnectionId);
                return(true);
            }
            return(false);
        }