Example #1
0
        /// <summary>
        /// Tries to parse the parameters for the command
        /// </summary>
        /// <param name="commandType">the command's method type</param>
        /// <param name="neededParms">what paramaters are considered required by the command</param>
        private void ParseParamaters(Type commandType, IEnumerable <CommandParameterAttribute> neededParms, bool hasContainer)
        {
            //HUGE conceit for CacheReferenceType.Container usage
            // : We need to store all the found CommandUsage.Subjects and validate them once we get to the container
            Type subjectType = typeof(IEntity);

            //Flip through each remaining word and parse them
            foreach (var currentNeededParm in neededParms.OrderBy(parm => parm.Usage))
            {
                //why continue if we ran out of stuff
                if (CommandStringRemainder.Count() == 0)
                {
                    break;
                }

                if (hasContainer && currentNeededParm.Usage == CommandUsage.Subject)
                {
                    subjectType = currentNeededParm.ParameterType;
                }

                foreach (var seekType in currentNeededParm.CacheTypes)
                {
                    switch (seekType)
                    {
                    case CacheReferenceType.Code:
                        SeekInCode(commandType, currentNeededParm);
                        break;

                    case CacheReferenceType.Entity:
                        //So damn ugly, make this not use reflection if possible
                        MethodInfo entityMethod = GetType().GetMethod("SeekInLiveWorld")
                                                  .MakeGenericMethod(new Type[] { currentNeededParm.ParameterType });
                        entityMethod.Invoke(this, new object[] { commandType, currentNeededParm, commandType.GetCustomAttribute <CommandRangeAttribute>(), hasContainer });
                        break;

                    case CacheReferenceType.Container:
                        MethodInfo containerMethod = GetType().GetMethod("SeekInLiveWorldContainer")
                                                     .MakeGenericMethod(new Type[] { currentNeededParm.ParameterType });
                        containerMethod.Invoke(this, new object[] { commandType, currentNeededParm, subjectType });
                        break;

                    case CacheReferenceType.Reference:
                        MethodInfo referenceMethod = GetType().GetMethod("SeekInReferenceData")
                                                     .MakeGenericMethod(new Type[] { currentNeededParm.ParameterType });
                        referenceMethod.Invoke(this, new object[] { commandType, currentNeededParm });
                        break;

                    case CacheReferenceType.Help:
                        SeekInReferenceData <Help>(commandType, currentNeededParm);
                        break;

                    case CacheReferenceType.Data:
                        MethodInfo dataMethod = GetType().GetMethod("SeekInBackingData")
                                                .MakeGenericMethod(new Type[] { currentNeededParm.ParameterType });
                        dataMethod.Invoke(this, new object[] { commandType, currentNeededParm });
                        break;

                    case CacheReferenceType.Text:
                        //Text just means grab the remainder of the command string and dump it into a param
                        switch (currentNeededParm.Usage)
                        {
                        case CommandUsage.Supporting:
                            Supporting = string.Join(" ", CommandStringRemainder);
                            break;

                        case CommandUsage.Subject:
                            Subject = string.Join(" ", CommandStringRemainder);
                            break;

                        case CommandUsage.Target:
                            Target = string.Join(" ", CommandStringRemainder);
                            break;
                        }

                        //empty the remainder
                        CommandStringRemainder = Enumerable.Empty <string>();
                        //We return here to end the parsing
                        return;
                    }
                }
            }
        }
Example #2
0
        /// <summary>
        /// Where we do the parsing, creates the context and parsed everything on creation
        /// </summary>
        /// <param name="fullCommand">the initial unparsed input string</param>
        /// <param name="actor">the entity issuing the command</param>
        public Context(string fullCommand, IActor actor)
        {
            commandsAssembly = Assembly.GetAssembly(typeof(CommandParameterAttribute));
            entitiesAssembly = Assembly.GetAssembly(typeof(IEntity));

            OriginalCommandString = fullCommand;
            Actor = actor;

            Location = (ILocation)Actor.CurrentLocation;

            AccessErrors           = new List <string>();
            CommandStringRemainder = Enumerable.Empty <string>();

            LoadedCommands = commandsAssembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(ICommand)));

            //NPCs can't use anything player rank can't use
            if (Actor.GetType().GetInterfaces().Contains(typeof(IPlayer)))
            {
                LoadedCommands = LoadedCommands.Where(comm => comm.GetCustomAttributes <CommandPermissionAttribute>().Any(att => att.MinimumRank <= ((ICharacter)Actor.DataTemplate).GamePermissionsRank));
            }
            else
            {
                LoadedCommands = LoadedCommands.Where(comm => comm.GetCustomAttributes <CommandPermissionAttribute>().Any(att => att.MinimumRank == StaffRank.Player));
            }

            //find out command's type
            var commandType = ParseCommand();

            if (commandType == null)
            {
                AccessErrors.Add("Unknown Command."); //TODO: Add generic errors class for rando error messages
                return;
            }

            //Log people using and even attempting to use admin commands in game
            if (commandType.GetCustomAttributes <CommandPermissionAttribute>().Any(att => att.MinimumRank == StaffRank.Admin))
            {
                LoggingUtility.LogAdminCommandUsage(OriginalCommandString, ((ICharacter)Actor.DataTemplate).AccountHandle);
            }

            try
            {
                //find the parameters
                var parmList = commandType.GetCustomAttributes <CommandParameterAttribute>();

                var hasContainer = parmList.Any(parm => parm.CacheTypes.Any(crt => crt == CacheReferenceType.Container));
                //why bother if we have no parms to find?
                if (CommandStringRemainder.Count() > 0)
                {
                    ParseParamaters(commandType, parmList, hasContainer);
                }

                //Did we get errors from the parameter parser? if so bail
                if (AccessErrors.Count > 0)
                {
                    return;
                }

                Command = Activator.CreateInstance(commandType) as ICommand;

                if (
                    (parmList.Any(parm => !parm.Optional && parm.Usage == CommandUsage.Subject) && Subject == null) ||
                    (parmList.Any(parm => !parm.Optional && parm.Usage == CommandUsage.Target) && Target == null) ||
                    (parmList.Any(parm => !parm.Optional && parm.Usage == CommandUsage.Supporting) && Supporting == null)
                    )
                {
                    AccessErrors.Add("Invalid command targets specified.");
                    AccessErrors.AddRange(Command.RenderSyntaxHelp());
                    return;
                }

                //Parms we got doesn't equal parms we loaded
                if (CommandStringRemainder.Count() != 0)
                {
                    AccessErrors.Add(string.Format("I could not find {0}.", string.Join(" ", CommandStringRemainder)));
                    AccessErrors.AddRange(Command.RenderSyntaxHelp());
                    return;
                }

                //double check container stuff
                if (hasContainer && Subject != null && Subject.GetType().GetInterfaces().Any(typ => typ == typeof(ICollection)))
                {
                    var collection = (ICollection <IEntity>)Subject;
                    if (collection.Count() == 1)
                    {
                        Subject = collection.First();
                    }
                    else
                    {
                        AccessErrors.Add("Invalid command targets specified.");
                        AccessErrors.AddRange(Command.RenderSyntaxHelp());
                        return;
                    }
                }

                Command.Actor          = Actor;
                Command.OriginLocation = Location;
                Command.Surroundings   = Surroundings;

                Command.Subject    = Subject;
                Command.Target     = Target;
                Command.Supporting = Supporting;
            }
            catch (MethodAccessException mEx)
            {
                Command = Activator.CreateInstance(commandType) as ICommand;
                AccessErrors.Add(mEx.Message);
                AccessErrors = AccessErrors.Concat(Command.RenderSyntaxHelp()).ToList();
            }
        }