예제 #1
0
        public void CheckAndProcessMessage(ClientConnection client, dynamic message)
        {
            //TODO: why don't these work?
            //Contract.Requires<ArgumentNullException>(client != null);
            //Contract.Requires<ArgumentNullException>(message != null);

            // new connection... only allow login);
            if (!client.Authenticated && !(message is Login))
            {
                _log.Warn("Non-login message " + message.GetType() + " from " + client.RemoteEndPoint);
                return;
            }

            if (client.Avatar == null
                && !(message is PossessMobile
                     || message is RequestPossessable
                     || message is Logout
                     || message is Login))
            {
                _log.Warn("ERROR: Non-posses message " + message.GetType() + " from " + client.RemoteEndPoint);
                return;
            }

            try
            {
                ProcessMessage(client, message);
                _log.Trace("Processed message " + message);
            }
            catch
            {
                _log.Warn("Unable to process message " + message);
            }
        }
예제 #2
0
        public static void ProcessUseSkill(ClientConnection client, UseSkill message)
        {
            var avatar = client.Avatar as MobileAvatar;
            if (avatar == null)
            {
                client.LogMessage("Requested a skill, but doesn't have an avatar.");
                return;
            }
            Schema.EnumSkillRow esr = Global.ModelSchema.EnumSkill.FindByEnumSkillID(message.SkillId);
            if (esr == null)
            {
                client.LogMessage("Requested an invalid skill " + message.SkillId);
                return;
            }

            // If already performing a skill invocation, just queue the request for later.
            if (avatar.ActivatingSkill != null)
            {
                avatar.SkillQueue.Enqueue(message);
                return;
            }

            if (esr.LeadTime <= 0)
            {
                // process it now
                UseSkillNow(avatar, message);
            }
            else
            {
                // process it later, after lead-time has elapsed
                avatar.ActivatingSkill = message;
                avatar.ActivatingSkillTimestamp = Global.Now;
                avatar.ActivatingSkillLeadTime = TimeSpan.FromSeconds(esr.LeadTime);
            }
        }
        public static void ProcessUseSkill(this World world, ClientConnection client, UseSkill message)
        {
            var source = client.Avatar as CombatantModel;
            if (source == null)
            {
                client.LogMessage("Requested a skill without an avatar.");
                return;
            }

            Schema.EnumSkillRow esr = Global.Schema.EnumSkill.FindByEnumSkillID((int)message.Skill);
            if (esr == null)
            {
                client.LogMessage("Requested an invalid skill " + message.Skill);
                return;
            }

            EntityModel target;
            switch ((EnumTargetType)esr.EnumTargetTypeID)
            {
                case EnumTargetType.TargetSelf:
                    target = source;
                    break;
                case EnumTargetType.TargetMobile:
                    if (message.TargetPhysicalObjectIDs.Length == 0)
                    {
                        world.LogMessage(source, "No target specified, this skill may only be used on Mobiles.");
                        return;
                    }
                    target = world.History.Head.Entities.ValueOrDefault(message.TargetPhysicalObjectIDs[0]);
                    if (target == null)
                    {
                        world.LogMessage(source, "Target " + message.TargetPhysicalObjectIDs[0] + " not found.");
                        return;
                    }
                    break;
                default:
                    world.LogMessage(source, "That skill has an unsupported target type " + esr.EnumTargetTypeID);
                    Log.Error("Unhandled target type " + esr.EnumTargetTypeID + " for skill " + esr.EnumSkillID + " " + esr.EnumSkillName);
                    return;
            }


            if (source.ActivatingSkill != EnumSkill.None)         // queue the request for later.
                world.Apply(new EntityUpdateEvent(
                    source.EnqueueSkill(message.Skill, target),
                    "Enqueuing Skill " + message.Skill));
            else if (esr.LeadTime <= 0)                 // process it now
                world.UseSkillNow(source, esr, target);
            else                                        // process it later, after lead-time has elapsed
                world.Apply(new EntityUpdateEvent(
                    source.StartSkill(message.Skill, target, Global.Now, TimeSpan.FromSeconds(esr.LeadTime)),
                    "Activating Skill " + message.Skill));
        }
        public static void ProcessCancelSkill(this World world, ClientConnection client, CancelSkill message)
        {
            var avatar = client.Avatar as CombatantModel;
            if (avatar == null)
            {
                client.LogMessage("Canceled a skill invocation, but don't have an avatar.");
                return;
            }

            // If already performing invocation, just cancel it
            bool found = false;
            if (avatar.ActivatingSkill != EnumSkill.None)
            // TODO:
            //&& avatar.ActivatingSkill.InvokationId == message.InvokationId)
            {
                world.Apply(new EntityUpdateEvent(avatar.StartSkill(EnumSkill.None, null, Global.Now, TimeSpan.FromSeconds(0)),
                    "Started using skill"));
                found = true;
            }
            else
            {
                // TODO: search for it in queued skill invocations
                // just generate a new queue with the invocation missing
                /*
                var newQueue = new Queue<UseSkill>();
                foreach (UseSkill m in avatar.SkillQueue)
                {
                    if (m.InvokationId == message.InvokationId)
                    {
                        // don't add it
                        found = true;
                    }
                    else
                        newQueue.Enqueue(m);
                }
                avatar.SkillQueue = newQueue;
                 */
                avatar.EmptyQueue();
            }
            if (found)
                client.LogMessage("Successfully canceled invocation " + message.InvokationId);
            else
                client.LogMessage("Failed to cancel invocation " + message.InvokationId);
        }
예제 #5
0
        void ProcessMessage(ClientConnection client, Login loginMessage)
        {
            if (World.UserLookup(loginMessage.Username, loginMessage.Password))
            {
                // login succeeded, check there is not an existing connection for this player
                ClientConnection current;
                if (World.Users.TryGetValue(loginMessage.Username, out current))
                    current.Close();

                _log.Info("User " + loginMessage.Username + " logged in");
                client.AuthenticatedUsername = loginMessage.Username;
                World.Users.Add(loginMessage.Username, client);
            }
            else
            {
                _log.Info("Login failed for username '" + loginMessage.Username + "'");
                client.Close();
            }
        }
예제 #6
0
        public static void ProcessCancelSkill(ClientConnection client, CancelSkill message)
        {
            var avatar = client.Avatar as MobileAvatar;
            if (avatar == null)
            {
                client.LogMessage("Canceled a skill invocation, but don't have an avatar.");
                return;
            }

            // If already performing invocation, just cancel it
            bool found = false;
            if (avatar.ActivatingSkill != null && avatar.ActivatingSkill.InvokationId == message.InvokationId)
            {
                avatar.ActivatingSkill = null;
                found = true;
            }
            else
            {
                // search for it in queued skill invocations
                // just generate a new queue with the invocation missing
                var newQueue = new Queue<UseSkill>();
                foreach (UseSkill m in avatar.SkillQueue)
                {
                    if (m.InvokationId == message.InvokationId)
                    {
                        // don't add it
                        found = true;
                    }
                    else
                        newQueue.Enqueue(m);
                }
                avatar.SkillQueue = newQueue;
            }
            if (found)
                client.LogMessage("Successfully canceled invocation " + message.InvokationId);
            else
                client.LogMessage("Failed to cancel invocation " + message.InvokationId);
        }
예제 #7
0
        public void SendPartyTalk(ClientConnection client, string party, string message)
        {
            // TODO: which name to use?
            var name = client.Avatar == null ? client.AuthenticatedUsername : client.Avatar.Name;

            // TODO: can probably simplify this
            HashSet<string> members;
            if (Party.TryGetValue(party, out members))
            {
                foreach (var m in members)
                {
                    ClientConnection cc;
                    if (Users.TryGetValue(m, out cc))
                        cc.Communication(name, message, Strive.Network.Messages.CommunicationType.PartyTalk);
                }
            }
        }
예제 #8
0
        /// <summary>
        /// if a new client has entered the world,
        /// notify them about surrounding physical objects
        /// this routine will send the client mobile's
        /// position as one of the 'nearby' mobiles.
        /// </summary>
        public void SendInitialWorldView(ClientConnection client)
        {

            client.Send(Weather);

            // TODO: Just subscribe them to the cubes instead?
            //foreach (EntityModel p in GetNearby(client.Avatar))
            //client.Send(p);
        }
예제 #9
0
 public void SendPartyTalk(ClientConnection client, string message)
 {
     string party;
     if (InParty.TryGetValue(client, out party))
         SendPartyTalk(client, party, message);
 }
예제 #10
0
        void ProcessMessage(ClientConnection client, TransferPartyLeadership message)
        {
            var avatar = client.Avatar;
            ClientConnection target;
            if (!World.Users.TryGetValue(message.Leader, out target))
            {
                client.LogMessage("Invalid target");
                return;
            }

            if (client.AuthenticatedUsername == message.Leader)
            {
                client.LogMessage("You are already the leader");
                return;
            }

            HashSet<string> party;
            if (!World.Party.TryGetValue(client.AuthenticatedUsername, out party))
            {
                client.LogMessage("You are not the leader of a party");
                return;
            }

            // TODO: use character names instead of username??
            if (!party.Contains(message.Leader))
            {
                client.LogMessage(message.Leader + " is not in your party");
                return;
            }

            World.TransferLeadership(client.AuthenticatedUsername, message.Leader);
            World.SendPartyTalk(client, "Party leadership has been transferred to " + message.Leader);
        }
예제 #11
0
        void ProcessMessage(ClientConnection client, MyPosition message)
        {
            var avatar = client.Avatar;
            if (avatar == null)
            {
                client.LogMessage("Position message sent, but have no avatar.");
                return;
            }

            if (message.Position != avatar.Position)
                World.Apply(new EntityUpdateEvent(
                    avatar.Move(message.MobileState, message.Position, message.Rotation, Global.Now),
                    "Player movement"));
        }
예제 #12
0
        public static void AcceptCallback(IAsyncResult ar)
        {
            try
            {
                // Get the socket that handles the client request.
                var listener = (Listener)ar.AsyncState;
                lock (listener)
                {
                    if (listener._tcpSocket == null)
                        return;

                    Socket socket;
                    try
                    {
                        socket = listener._tcpSocket.EndAccept(ar);
                    }
                    catch (ArgumentException)
                    {
                        // TODO: hmmm I really wish there was a nicer way
                        // this is the result of a previous binding, we discard it
                        return;
                    }

                    // Create the state object.
                    var client = new ClientConnection();
                    client.Start(socket);
                    listener.Clients.Add(client);
                    listener._log.Info("New connection from " + client.RemoteEndPoint);

                    // The next connection
                    listener._tcpSocket.BeginAccept(
                        new AsyncCallback(AcceptCallback),
                        listener);
                }
            }
            catch (ObjectDisposedException)
            {
                // the underlying socket was closed
            }
        }
예제 #13
0
        void ProcessMessage(ClientConnection client, PossessMobile message)
        {
            var avatar = World.History.Head.Entities.ValueOrDefault(message.InstanceId);
            if (avatar != null)
            {
                // reconnected, replace existing connection with the new
                ClientConnection possessedBy;
                if (World.Possession.TryGetValue(avatar.Id, out possessedBy))
                {
                    if (possessedBy == client)
                    {
                        client.LogMessage("You already possess " + avatar);
                        return;
                    }
                    else
                    {
                        _log.Info("Mobile " + avatar + " has been taken over by " + client);
                        possessedBy.LogMessage("You lost control of " + avatar);
                        possessedBy.Avatar = null;
                    }
                }
                if (client.Avatar != null && client.Avatar.Id != avatar.Id)
                {
                    // TODO: omg releasing this sends a combatant which crashes
                    // release control of previous avatar
                    //World.Possession.Remove(client.Avatar.Id);
                }
                World.Possession[avatar.Id] = client;
                client.Avatar = avatar;
                client.LogMessage("You are now controlling " + avatar);
            }
            else
            {
                // try to load the character
                avatar = World.LoadMobile(message.InstanceId);
                if (avatar == null)
                {
                    _log.Warn("Character " + message.InstanceId + " not found.");
                    //TODO: rely on world loading
                    //client.Close();
                    //return;
                    avatar = new CombatantModel(
                        Global.Rand.Next(), client.AuthenticatedUsername, "RTSRobot",
                        new Vector3D(), Quaternion.Identity, 100, 100, Common.EnumMobileState.Standing, 1.7f,
                        20, 20, 20, 20, 20);
                }

                World.Possession[avatar.Id] = client;
                client.Avatar = avatar;

                // try to add the character to the world
                World.Apply(new EntityUpdateEvent(avatar, "Loaded for possession"));
            }
            World.SendInitialWorldView(client);
        }
예제 #14
0
 void ProcessMessage(ClientConnection client, CreateMission c)
 {
     // TODO: would like to at least set the id
     // ObjectInstanceId = Global.Rand.Next(),
     World.Apply(new MissionUpdateEvent(c.Mission, "Created by " + client.AuthenticatedUsername));
 }
예제 #15
0
 void ProcessMessage(ClientConnection client, ReloadWorld message)
 {
     _log.Info("ReloadWorld received.");
     World.Load();
     foreach (ClientConnection c in Listener.Clients
         .Where(c => c.Avatar != null
             && c.Status == ConnectionStatus.Connected))
     {
         // re-spawn their mobile
         c.DropAll();
         ProcessMessage(c, new PossessMobile(c.Avatar.Id));
     }
 }
예제 #16
0
 void ProcessMessage(ClientConnection client, InviteToParty message)
 {
     if (World.Party[client.AuthenticatedUsername] == null)
     {
         client.LogMessage("You are not the leader of a party");
         return;
     }
     var target = World.Users[message.User];
     if (target == null)
         client.LogMessage("Invalid target");
     else
     {
         World.InvitedToParty[target.AuthenticatedUsername]
             .Add(client.AuthenticatedUsername, Global.Now);
         // TODO: probably want a graphical thing or something for invites
         target.LogMessage("You have been invited to party '" + client.AuthenticatedUsername + "'");
     }
 }
예제 #17
0
 void ProcessMessage(ClientConnection client, RequestSkillList message)
 {
     client.SkillList(
         Global.Schema.EnumSkill
             .Select(e => Global.Schema.MobileHasSkill.FindByTemplateObjectIDEnumSkillID(
                 client.Avatar.Id, (int)e.EnumSkillID))
             .Where(mhs => mhs != null)
             .Select(mhs => new Tuple<int, double>(mhs.EnumSkillID, mhs.Rating))
             .ToArray());
 }
예제 #18
0
        void ProcessMessage(ClientConnection client, JoinParty message)
        {
            Dictionary<string, DateTime> invitation;
            if (!World.InvitedToParty.TryGetValue(client.AuthenticatedUsername, out invitation))
            {
                client.LogMessage("You are not currently invited to join a party");
                return;
            }

            // make sure they are trying to join the party they were invited to
            if (!invitation.ContainsKey(message.Leader))
            {
                client.LogMessage("You are not currently invited to join " + message.Leader);
                return;
            }

            HashSet<string> party;
            if (!World.Party.TryGetValue(message.Leader, out party))
            {
                client.LogMessage("That party does not exist anymore");
                return;
            }

            World.SendPartyTalk(client, message.Leader, client.Avatar.Name + " has joined your ");
            party.Add(client.AuthenticatedUsername);
            client.LogMessage("You are now in party '" + message.Leader + "'.");

            //World.InvitedToParty.Remove(message.Leader);
        }
예제 #19
0
 void ProcessMessage(ClientConnection client, LeaveParty message)
 {
     World.LeaveParty(client, client.AuthenticatedUsername);
     client.LogMessage("You have left party");
 }
예제 #20
0
 void ProcessMessage(ClientConnection client, Pong message)
 {
     client.Latency = (DateTime.Now - client.PingedAt).Milliseconds;
     World.Weather.Latency = client.Latency;
     client.Send(World.Weather);
 }
예제 #21
0
        public void LeaveParty(ClientConnection client, string member)
        {
            var followers = Party[member];
            if (followers != null && followers.Count > 0)
                TransferLeadership(member, followers.First());
            followers.Remove(member);
            InParty[client] = null;

            // TODO: which name to use?
            SendPartyTalk(client, member + " has left your party");
        }
예제 #22
0
 void ProcessMessage(ClientConnection client, Logout message)
 {
     if (client.Avatar != null)
     {
         // remove from world.
         // TODO: do I want to remove the avatar?
         // World.Remove((EntityModel)client.Avatar);
     }
     _log.Info("Logged out '" + client.AuthenticatedUsername + "'.");
     client.Close();
 }
예제 #23
0
 internal void RemoveClient(ClientConnection client)
 {
     HashSet<string> party;
     if (Party.TryGetValue(client.AuthenticatedUsername, out party))
         TransferLeadership(client.AuthenticatedUsername, party.First());
     Users.Remove(client.AuthenticatedUsername);
 }
예제 #24
0
 void ProcessMessage(ClientConnection client, CancelSkill message)
 {
     World.ProcessCancelSkill(client, message);
 }
예제 #25
0
파일: World.cs 프로젝트: 628426/Strive.NET
        public void SendInitialWorldView(ClientConnection client)
        {
            // if a new client has entered the world,
            // notify them about surrounding physical objects
            // NB: this routine will send the client mobile's
            // position as one of the 'nearby' mobiles.

            // TODO: figure out how to make client.Avatar the right type
            var mob = (MobileAvatar)client.Avatar;
            client.Send(Weather);

            // TODO: zomg I don't know if this divtruncate is right
            int squareX = DivTruncate((int)(mob.Position.X - _lowX), Square.SquareSize);
            int squareZ = DivTruncate((int)(mob.Position.Z - _lowZ), Square.SquareSize);
            int i, j;
            var nearbyPhysicalObjects = new List<PhysicalObject>();
            // TODO: use xorder, zorder to descide the resolution?
            for (i = -1; i <= 1; i++)
            {
                for (j = -1; j <= 1; j++)
                {
                    // check that neighbor exists
                    if (squareX + i < 0 || squareX + i >= _squaresInX
                        || squareZ + j < 0 || squareZ + j >= _squaresInZ
                        || _square[squareX + i, squareZ + j] == null)
                        continue;

                    // add all neighboring physical objects
                    // to the clients world view
                    // that are in scope

                    /** TODO:
     * could only send based upon a radius, but this makes
     * relocations harder... maybe be better to just use squares
    // NB: using Manhattan distance not Cartesian
    float distx = Math.Abs(p.Position.X - mob.Position.X);
    float distz = Math.Abs(p.Position.Z - mob.Position.Z);
    if ( distx <= Constants.objectScopeRadius && distz <= Constants.objectScopeRadius )
    */

                    nearbyPhysicalObjects.AddRange(
                        _square[squareX + i, squareZ + j].PhysicalObjects);
                }
            }
            /*
                ToClient.AddPhysicalObjects message = new ToClient.AddPhysicalObjects(
                    nearbyPhysicalObjects
                );
                client.Send( message );
                */
            foreach (PhysicalObject p in nearbyPhysicalObjects)
                client.Send(ToClient.AddPhysicalObject.CreateMessage(p));

            for (int k = 0; k < Constants.TerrainZoomOrder; k++)
            {
                int tbx = DivTruncate((int)mob.Position.X, Constants.TerrainPieceSize) - Constants.xRadius[k];
                int tbz = DivTruncate((int)mob.Position.Z, Constants.TerrainPieceSize) - Constants.zRadius[k];

                // Normalize to a 'grid' point
                tbx = DivTruncate(tbx, Constants.scale[k]) * Constants.scale[k];
                tbz = DivTruncate(tbz, Constants.scale[k]) * Constants.scale[k];

                for (i = 0; i <= Constants.xRadius[k] * 2; i += Constants.scale[k])
                {
                    for (j = 0; j <= Constants.zRadius[k] * 2; j += Constants.scale[k])
                    {
                        int tx = tbx + i;
                        int tz = tbz + j;
                        int terrainX = tx - (int)_lowX / Constants.TerrainPieceSize;
                        int terrainZ = tz - (int)_lowZ / Constants.TerrainPieceSize;
                        if (terrainX >= 0 && terrainX < _squaresInX * Square.SquareSize / Constants.TerrainPieceSize && terrainZ >= 0 && terrainZ < _squaresInZ * Square.SquareSize / Constants.TerrainPieceSize)
                        {
                            Terrain t = _terrain[terrainX, terrainZ];
                            if (t != null)
                            {
                                if (// there is no higher zoom order
                                    k == (Constants.TerrainZoomOrder - 1)
                                    // this is not a higher order point
                                    || (tx % Constants.scale[k + 1]) != 0 || (tz % Constants.scale[k + 1]) != 0)
                                    client.Send(ToClient.AddPhysicalObject.CreateMessage(t));
                            }
                        }
                    }
                }
            }
        }
예제 #26
0
        void ProcessMessage(ClientConnection client, Communicate message)
        {
            // TODO: chat as character or user?
            string name = client.Avatar == null ? client.AuthenticatedUsername : client.Avatar.Name;

            if (message.CommunicationType == CommunicationType.Chat)
                World.SendToUsers(new Network.Messages.ToClient.Communication(
                    name, message.Message, message.CommunicationType));
            else if (message.CommunicationType == CommunicationType.PartyTalk)
                World.SendPartyTalk(client, message.Message);
            else
                _log.Error("Unexpected CommunicationType " + message.CommunicationType);
        }
예제 #27
0
        void ProcessMessage(ClientConnection client, ProduceEntity p)
        {
            var factory = World.History.Head.Entities.ValueOrDefault(p.FactoryId);
            if (factory == null)
            {
                client.LogMessage("Could not find factory " + p.FactoryId);
                return;
            }

            World.Apply(new ProductionStartedEvent(
                factory.Id, p.Id,
                client.AuthenticatedUsername + " producing " + p.Name + " from " + factory));
        }
예제 #28
0
 void ProcessMessage(ClientConnection client, RequestWhoList message)
 {
     client.WhoList(
         Listener.Clients
         .Select(c => c.Avatar)
         .Except(null)
         .Select(a => new Tuple<int, string>(a.Id, a.Name))
         .ToArray());
 }
예제 #29
0
 void ProcessMessage(ClientConnection client, UseSkill message)
 {
     World.ProcessUseSkill(client, message);
 }
예제 #30
0
 void ProcessMessage(ClientConnection client, RequestPossessable message)
 {
     //Strive.Data.MultiverseFactory.refreshMultiverseForPlayer(Global.modelSchema, client.PlayerID);
     client.CanPossess(GetPossessable(client.AuthenticatedUsername));
 }