Exemple #1
0
        public void Load(string map)
        {
            string path = "PacMan/Map/" + map;

            GameLog.InfoFormat("Loading map [{0}]...", path);

            UnityEngine.Object prefab = Resources.Load(path);
            if (null == prefab)
            {
                iCarus.Exception.Throw <GameException>("Load map failed: " + path);
            }

            GameObject go = (GameObject)GameObject.Instantiate(prefab);

            go.transform.Reset();
            spawnpoints = go.GetComponent <BeanSpawnpoints>();
            if (null == spawnpoints)
            {
                string n = go.name;
                GameObject.Destroy(go);
                iCarus.Exception.Throw <GameException>("<BeanSpawnpoints> is not found on " + n);
            }

            GameLog.InfoFormat("Map [{0}] loaded", path);
        }
Exemple #2
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);
             }
         }
     }
 }
Exemple #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;
    }
 public static void Execute(object obj, ElapsedEventArgs args)
 {
     GameLog.Debug("Job starting");
     try
     {
         foreach (var connection in GlobalConnectionManifest.WorldClients)
         {
             var  client       = connection.Value;
             var  connectionId = connection.Key;
             User user;
             if (Game.World.WorldData.TryGetValueByIndex(connectionId, out user))
             {
                 if (client.IsHeartbeatExpired())
                 {
                     GameLog.InfoFormat("{0} (connection id {1}: heartbeat expired, disconnecting",
                                        user.Name, connectionId);
                     GlobalConnectionManifest.DeregisterClient(client);
                     World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.CleanupUser,
                                                                              CleanupType.ByConnectionId, connectionId));
                 }
             }
         }
     }
     catch (Exception e)
     {
         Game.ReportException(e);
         GameLog.ErrorFormat("Exception occurred in job:", e);
     }
 }
Exemple #5
0
        public void Invoke(User trigger)
        {
            // Run through all the different potential uses. We allow combinations of any
            // use specified in the item XML.
            GameLog.InfoFormat($"User {trigger.Name}: used item {Name}");
            if (Use.Script != null)
            {
                Script invokeScript;
                if (!World.ScriptProcessor.TryGetScript(Use.Script, out invokeScript))
                {
                    trigger.SendSystemMessage("It doesn't work.");
                    return;
                }

                if (!invokeScript.ExecuteFunction("OnUse", trigger, null, this))
                {
                    trigger.SendSystemMessage("It doesn't work.");
                    return;
                }
            }
            if (Use.Effect != null)
            {
                trigger.SendEffect(trigger.Id, Use.Effect.Id, Use.Effect.Speed);
            }
            if (Use.PlayerEffect != null)
            {
                if (Use.PlayerEffect.Gold > 0)
                {
                    trigger.AddGold(new Gold((uint)Use.PlayerEffect.Gold));
                }
                if (Use.PlayerEffect.Hp > 0)
                {
                    trigger.Heal(Use.PlayerEffect.Hp);
                }
                if (Use.PlayerEffect.Mp > 0)
                {
                    trigger.RegenerateMp(Use.PlayerEffect.Mp);
                }
                if (Use.PlayerEffect.Xp > 0)
                {
                    trigger.GiveExperience((uint)Use.PlayerEffect.Xp);
                }
                trigger.UpdateAttributes(StatUpdateFlags.Current | StatUpdateFlags.Experience);
            }
            if (Use.Sound != null)
            {
                trigger.SendSound((byte)Use.Sound.Id);
            }
            if (Use.Teleport != null)
            {
                trigger.Teleport(Use.Teleport.Value, Use.Teleport.X, Use.Teleport.Y);
            }
            if (Use.Consumed)
            {
                Count--;
            }
        }
Exemple #6
0
    public Lobby(int port, bool isDefault = false)
        : base(port, isDefault)
    {
        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;
    }
Exemple #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);
 }
Exemple #8
0
    public UserGroup(User founder)
    {
        Founder    = 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;
    }
Exemple #9
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);
        }
    }
Exemple #10
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();

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

        if (login.VerifyPassword(currentPass))
        {
            // Check if the password is valid.
            if (ValidPassword(newPass, out byte err))
            {
                login.PasswordHash           = HashPassword(newPass);
                login.LastPasswordChange     = DateTime.Now;
                login.LastPasswordChangeFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString();
                login.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);
        }
    }
Exemple #11
0
    public Login(int port, bool isDefault = false)
        : base(port, isDefault)
    {
        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;
    }
Exemple #12
0
    public void Redirect(Redirect redirect, bool isLogoff = false, int transmitDelay = 0)
    {
        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;

        if (Game.RedirectTarget != null)
        {
            addressBytes = Game.RedirectTarget.GetAddressBytes();
        }
        else
        {
            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);
        x03.TransmitDelay = transmitDelay == 0 ? 250 : transmitDelay;
        Enqueue(x03);
    }
Exemple #13
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();
     }
 }
Exemple #14
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);
    }
Exemple #15
0
 void OnNetStatusChanged(UdpConnector connector, NetConnectionStatus status, string reason)
 {
     GameLog.InfoFormat("Connection status changed {0} {1}", status, reason);
 }
Exemple #16
0
 void OnConnectionStatusChanged(NetConnection connection, string reason)
 {
     GameLog.InfoFormat("Connection status changed {0} {1} {2}", connection.RemoteEndPoint, connection.Status, reason);
 }
Exemple #17
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 (Game.World.WorldData.TryGetAuthInfo(name, out AuthInfo login))
        {
            if (string.IsNullOrEmpty(login.PasswordHash))
            {
                client.LoginMessage("ERROR: Authentication information corrupt [HYB-LOGIN-01]", 3);
                return;
            }

            if (login.VerifyPassword(password))
            {
                GameLog.DebugFormat("cid {0}: password verified for {1}", client.ConnectionId, name);

                if (login.CurrentState == UserState.Redirect && login.StateChangeDuration < 1000)
                {
                    client.LoginMessage("That character is already logging in. Please try again.", 3);
                    return;
                }

                if (login.IsLoggedIn)
                {
                    login.CurrentState = UserState.Disconnected;
                    // Is the user actually in world?
                    if (Game.World.TryGetActiveUser(login.Username, out _))
                    {
                        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));
                        login.Save();
                        return;
                    }
                }

                // Make sure user can be deserialized without errors
                if (!Game.World.WorldData.TryGetUser(name, out _))
                {
                    // Something bad has happened
                    client.LoginMessage("An unknown error occurred. Please contact Hybrasyl support.", 3);
                    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);
                login.LastLogin       = DateTime.Now;
                login.LastLoginFrom   = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString();
                login.CurrentState    = UserState.Redirect;
                login.LastStateChange = login.LastLogin;
                login.Save();
                client.Redirect(redirect);
            }
            else
            {
                GameLog.WarningFormat("cid {0} ({1}): password incorrect", client.ConnectionId, name);
                client.LoginMessage("Incorrect password", 3);
                login.LastLoginFailure = DateTime.Now;
                login.LoginFailureCount++;
                login.LastLoginFailureFrom = ((IPEndPoint)client.Socket.RemoteEndPoint).Address.ToString();
                login.CurrentState         = UserState.Login;
                login.LastStateChange      = login.LastLoginFailure;
                login.Save();
            }
        }
        else
        {
            client.LoginMessage("That character does not exist", 3);
            GameLog.InfoFormat("cid {0}: attempt to login as nonexistent character {1}", client.ConnectionId, name);
            return;
        }
    }
    public static ServerPacketStructures.MessagingResponse SendMessage(GuidReference senderRef, ushort boardId, string recipient, string subject, string body)
    {
        var response = string.Empty;
        var success  = true;

        var senderSentMail = Game.World.WorldData.GetOrCreate <SentMail>(senderRef);

        // Don't allow blank title or subject
        if (string.IsNullOrWhiteSpace(subject))
        {
            success  = false;
            response = "The message had no subject.";
        }
        else if (string.IsNullOrWhiteSpace(body))
        {
            success  = false;
            response = "You can't send empty messages.";
        }
        else if (!body.IsAscii() || !subject.IsAscii())
        {
            success  = false;
            response = "You can't use special characters in a message (ASCII only).";
        }
        else if (boardId == ushort.MaxValue - 1)
        {
            success  = false;
            response = "You can't post messages here.";
        }

        // Handle plugin response

        if (!Game.World.TryGetActiveUser(senderRef.UserName, out _))
        {
            // Currently a user must be online to send mail, so if we get here, something really wacky is happening
            return(UnknownError);
        }
        try
        {
            IMessageHandler handler;
            Xml.MessageType type;
            if (boardId == 0)
            {
                type = Xml.MessageType.Mail;
            }
            else
            {
                type = Xml.MessageType.BoardMessage;
            }

            var message = new Plugins.Message(type, senderRef.UserName, recipient, subject, body);

            handler = Game.World.ResolveMessagingPlugin(type, message);

            if (handler is IProcessingMessageHandler pmh && success)
            {
                var msg  = new Plugins.Message(Xml.MessageType.Mail, senderRef.UserName, recipient, subject, body);
                var resp = pmh.Process(msg);
                if (!pmh.Passthrough)
                {
                    // TODO: implement cast / resolve duplication
                    var hmsg = new Message(recipient, senderRef.UserName, subject, body);
                    senderSentMail.ReceiveMessage((Message)hmsg);

                    // Plugin is "last destination" for message
                    return(new ServerPacketStructures.MessagingResponse()
                    {
                        ResponseType = BoardResponseType.EndResult,
                        ResponseSuccess = resp.Success,
                        ResponseString = resp.PluginResponse
                    });
                }
                else if (resp.Transformed)
                {
                    // Update message if transformed, and keep going
                    recipient = resp.Message.Recipient;
                    subject   = resp.Message.Subject;
                    body      = resp.Message.Text;
                }
            }
        }
        catch (Exception e)
        {
            Game.ReportException(e);
            success  = false;
            response = "An unknown error occurred. Sorry!";
        }

        // Annoyingly board replies use the same packet path as sending mail replies, so we need to handle
        // both here
        if (boardId == 0 && success)
        {
            var receiverRef = Game.World.WorldData.GetGuidReference(recipient);
            if (receiverRef == null)
            {
                success  = false;
                response = "Sadly, no record of that person exists in the realm.";
            }
            else
            {
                var mailbox = Game.World.WorldData.GetOrCreate <Mailbox>(receiverRef);
                var msg     = new Message(recipient, senderRef.UserName, subject, body);
                try
                {
                    if ((DateTime.Now - senderSentMail.LastMailMessageSent).TotalSeconds < Constants.MAIL_MESSAGE_COOLDOWN &&
                        senderSentMail.LastMailRecipient == recipient)
                    {
                        success  = false;
                        response = $"You've sent too much mail to {recipient} recently. Give it a rest.";
                    }
                    else if (mailbox.ReceiveMessage(msg))
                    {
                        response = $"Your letter to {recipient} was sent.";
                        GameLog.InfoFormat("mail: {0} sent message to {1}", senderRef.UserName, recipient);
                        World.ControlMessageQueue.Add(new HybrasylControlMessage(ControlOpcodes.MailNotifyUser,
                                                                                 recipient));
                        senderSentMail.LastMailRecipient   = recipient;
                        senderSentMail.LastMailMessageSent = DateTime.Now;
                    }
                    else
                    {
                        success  = false;
                        response = $"{recipient}'s mailbox is full or locked. A copy was kept in your sent mailbox. Sorry!";
                    }
                }
                catch (MessageStoreLocked e)
                {
                    Game.ReportException(e);
                    success  = false;
                    response = $"{recipient} cannot receive mail at this time. Sorry!";
                }
                senderSentMail.ReceiveMessage((Message)msg.Clone());
            }
        }
        else if (success)
        {
            if (Game.World.WorldData.TryGetValueByIndex(boardId, out Board board))
            {
                if (Game.World.WorldData.TryGetAuthInfo(senderRef.UserName, out AuthInfo ainfo))
                {
                    if (ainfo.IsPrivileged || board.CheckAccessLevel(ainfo.Username, BoardAccessLevel.Write))
                    {
                        var msg = new Message(board.DisplayName, senderRef.UserName, subject, body);
                        if (board.ReceiveMessage(msg))
                        {
                            response = "The message was sent.";
                            success  = true;
                            var sentMsg = (Message)msg.Clone();
                            sentMsg.Recipient = board.DisplayName;
                            senderSentMail.ReceiveMessage(sentMsg);
                        }
                        else
                        {
                            response = "The message could not be sent.";
                        }
                    }
                    else
                    {
                        response = "You don't have permission to do that.";
                    }
                }
                else
                {
                    response = "Authentication information could not be verified.";
                }
            }
            else
            {
                response = "Board not found.";
            }
        }

        return(new ServerPacketStructures.MessagingResponse()
        {
            ResponseType = BoardResponseType.EndResult,
            ResponseString = response,
            ResponseSuccess = success
        });
    }