Пример #1
0
        /// <summary>
        /// Execute the input as if it were a tiny MooScript verb attached to the player.
        /// </summary>
        /// <returns>
        /// If the MooScript returns a value, it will be sent back to the player.
        /// </returns>
        public static string ExecuteImmediate(string input, Player player)
        {
            Verb v = new Verb() {
            name = "inline",
            help = "",
            code = input.Substring(1) + ';'
            };

            var param = new Verb.VerbParameters() {
            input = input,
            self = player.world.findObject( player.id ),
            dobj = Mob.None,
            prep = Verb.Prep.None,
            iobj = Mob.None,
            player = player,
            world = player.world
            };

            object rv;
            using( var ac = new ActorContext( player, player.id ) )
            rv = v.invoke( param );

            // Try to do some reallly basic type massaging to make it viewable on the terminal.
            string rvs;
            if (rv is string) {
            rvs = "\"{0}\"".FormatI(rv);
            } else if (rv is System.Collections.IEnumerable) {
            rvs = string.Join(", ", (from object i in (System.Collections.IEnumerable)rv select i.ToStringI()));
            } else
            rvs = rv.ToStringI();

            return MooCode.PrepareForClient(rvs);
        }
Пример #2
0
 public void Dispose()
 {
     if( _player != null )
     {
     _player.actorContextPop();
     _player = null;
     }
 }
Пример #3
0
        void pulseCallback()
        {
            // Make sure we're not already running.
            if( Interlocked.Increment( ref _pulseTimerRunning ) > 1 )
            {
            Interlocked.Decrement( ref _pulseTimerRunning );
            Log.Error( "Warning: stacked pulseCallback() calls" );
            return;
            }

            using( new UsingAction(
            () =>
            {
                Interlocked.Decrement( ref _pulseTimerRunning );
            }
            ) )
            {
            _ticks += PulseFrequency;
            IEnumerable<int> toCall = _pulses.Keys.ToArray();

            foreach( int id in toCall )
            {
                try
                {
                    Mob m = _world.findObject( id );
                    if( m == null )
                    {
                        bool junk;
                        _pulses.TryRemove( id, out junk );
                        continue;
                    }

                    // FIXME: This will never fire if pulsefreq is not a multiple of PulseFrequency.
                    var freq = m.pulseFreq;
                    if( freq != 0 && (_ticks % freq) == 0 )
                    {
                        var verb = m.pulseVerb;
                        SourcedItem<Verb> v = m.findVerb( verb );
                        if( v == null )
                            continue;

                        // Make a temporary Player object just to pass down a context.
                        Player p = new Player( Perm.IsVerbAntistick( v.source, verb ) ? m.ownerId : v.source.ownerId );

                        var param = new Verb.VerbParameters()
                        {
                            args = new object[] { _ticks },
                            self = m,
                            world = _world,
                            player = p
                        };
                        v.item.invoke( param );

                        _world.waitForMerge();
                    }
                }
                catch( Exception ex )
                {
                    Log.Error( "Error executing pulse handler for {0}: {1}", id, ex );

                    // Try to leave a log on the object.
                    try
                    {
                        Mob m = _world.findObject( id );
                        if( m != null )
                            m.attrSet( Mob.Attributes.PulseError, ex.ToStringI() );
                    }
                    catch( Exception )
                    {
                    }
                }
            }
            }
        }
Пример #4
0
        static void Main( string[] args )
        {
            if( args.Length != 2 )
            {
            Console.WriteLine( "Please specify the filename of an ImpExporter database config file and a player login name." );
            return;
            }

            // Load up the config.
            ImpExporterConfig cfg = XmlPersistence.Load<ImpExporterConfig>( args[0] );

            // Create a world, sans realtime save and pulse.
            Assembly asm = Assembly.Load( cfg.DatabaseAssembly );
            Type dbType = asm.GetType( cfg.DatabaseClass );
            IDatabase db = (IDatabase)Activator.CreateInstance( dbType );
            db.setup( cfg.ConnectionString, new TableInfo() );
            var coredb = new CoreDatabase( db );
            var worlddb = new WorldDatabase( coredb );
            var world = CanonWorld.FromWorldDatabase( worlddb, true, true );
            world.attributeUrlGenerator = ( obj, name ) => CultureFree.Format( "<attr:{0}.{1}>", obj.name, name );

            // Look up the player. If they passed "anon", then we use an anonymous, pre-login player.
            int mobid;
            if( args[1] == "anon" )
            {
            mobid = Mob.Anon.id;
            }
            else
            {
            using( var token = coredb.token() )
            {
                var users = coredb.select( token, new DBUser() { login = args[1] }, new string[] { "login" } );
                if( users.Count() != 1 )
                {
                    Console.WriteLine( "Couldn't match exactly one user with the login '{0}'", args[1] );
                    return;
                }

                mobid = users.First().@object;
            }
            }

            // Make a shadow world for us to use.
            var shadowWorld = new ShadowWorld( world );
            Mob playerMob = mobid > 0 ? Mob.Wrap( shadowWorld.findObject( mobid ) ) : null;

            // Make a player object.
            Player player = new Player( mobid );
            player.NewOutput = (o) =>
            {
            Console.WriteLine( "{0}", o );
            };
            player.NewSound = (o) =>
            {
            Console.WriteLine( "Would play sound: {0}", o );
            };
            player.NewErrorOutput = (o) =>
            {
            Console.WriteLine( "[error] {0}", o );
            };
            player.world = World.Wrap( shadowWorld );
            if( playerMob != null )
            playerMob.player = player;

            while( true )
            {
            Console.Write( "climoo> " );

            string command = Console.ReadLine();
            if( command == "exit" )
                break;

            string result = MooCore.InputParser.ProcessInput( command, player );
            if( !result.IsNullOrEmpty() )
                Console.WriteLine( result );

            shadowWorld.waitForMerge();
            }

            // Clear out any changes and timers.
            shadowWorld.Dispose();
            world.Dispose();
        }
Пример #5
0
        /// <summary>
        /// Process a line of input from the player: parse and execute any action.
        /// </summary>
        public static string ProcessInput(string input, Player player)
        {
            // Ignore empty lines.
            if( input.Length == 0 )
            return "";

            // Does the input start with a special character?
            if (input[0] == ';') {
            // Execute this as a chunk of MooScript, as if it was attached
            // to the player.
            return ExecuteImmediate(input, player);
            }
            if (input[0] == '"')
            input = "say " + input.Substring(1);
            if (input[0] == ':')
            input = "emote " + input.Substring(1);
            if (input[0] == '@')
            input = "whisper " + input.Substring(1);

            // Split the input.
            string[] pieces = input.Trim().Split(' ', '\t', '\n', '\r');
            if (pieces.Length == 0)
            return "";

            // For now, the verb is always one word.
            string verb = pieces[0];
            if (verb.EqualsI("/me") || verb == ":") verb = "emote";

            // Start gathering values for the verb call.
            var param = new Verb.VerbParameters() {
            input = input,
            inputwords = pieces,
            self = null,
            world = player.world,
            player = player
            };

            // Try for a #1._processInput verb first. If one exists and it returns anything
            // besides false, we'll let it deal with everything else.
            var root = player.world.findObject( 1 );
            var playerMob = player.world.findObject( player.id );
            Verb rootProcess = root.verbGet("_processInput");
            if (rootProcess != null) {
            param.self = root;
            param.caller = playerMob;
            try
            {
                // This verb doesn't get any special permissions. It's just processing input from the user.
                object results;
                using( var ac = new ActorContext( player, player.id ) )
                    results = rootProcess.invoke(param);
                if (results == null || (results is bool && (bool)results == false)) {
                    // Proceed jolly onwards...
                } else {
                    // Our work here is finished.
                    return "";
                }
            }
            catch( Exception ex )
            {
                // Just assume it didn't handle it. Sucks to get in a loop here if you
                // mess up your global handler..!
                Log.Error( "Error while processing _processInput: {0}", ex );
            }
            param.self = null;
            param.caller = null;
            }

            // Look for complete wildcard verbs on the player and in the player's location.
            // If we find one that matches, stop processing anything else.
            var selectedVerb = SearchWildcardVerbsFrom(playerMob, verb, param);
            if (!selectedVerb.Any())
            selectedVerb = SearchWildcardVerbsFrom(playerMob.location, verb, param);
            if (selectedVerb.Any()) {
            var v = selectedVerb.First();

            param.self = v.foundOn;
            using( var ac = new ActorContext( player, v.definedOn.ownerId ) )
                v.verb.invoke(param);

            return "";
            }

            // Skip forward until we find a preposition.
            var remaining = pieces.Skip(1);
            var start = remaining;
            Verb.PrepMatch p = Verb.PrepMatch.None;
            string dobjName = null;
            for (int skip=0; skip<remaining.Count(); ++skip) {
            var chunk = remaining.Skip(skip);
            p = Verb.MatchPrep(chunk);
            if (p.isReal) {
                // Skip over the preposition after saving its words.
                param.prepwords = p.words.ToArray();
                remaining = chunk.Skip(param.prepwords.Length);

                // What came before it is the direct object.
                param.dobjwords = start.Take(skip).ToArray();
                dobjName = string.Join(" ", param.dobjwords);
                break;
            }
            }

            if (p.prep == Verb.Prep.None) {
            // No preposition -> the rest of the string is the direct object.
            param.dobjwords = remaining.ToArray();
            dobjName = string.Join(" ", param.dobjwords);
            remaining = new string[0];
            }

            // For now, the indirect object is always the rest of the phrase.
            string iobjName = null;
            if (remaining.Count() > 0) {
            param.iobjwords = remaining.ToArray();
            iobjName = string.Join(" ", param.iobjwords);
            }

            // Look for objects around the player that might match the direct and indirect objects.
            Mob dobj = ObjectMatch(dobjName, playerMob);
            Mob iobj = ObjectMatch(iobjName, playerMob);

            // Save the objects we found so we can verb-search.
            param.dobj = dobj;
            param.prep = p.prep;
            param.iobj = iobj;

            // Look for a matching verb.
            selectedVerb = SearchVerbsFrom(playerMob, verb, param);
            if (selectedVerb.Count() == 0)
            selectedVerb = SearchVerbsFrom(playerMob.location, verb, param);
            if (selectedVerb.Count() == 0 && dobj != null)
            selectedVerb = SearchVerbsFrom(dobj, verb, param);
            if (selectedVerb.Count() == 0 && iobj != null)
            selectedVerb = SearchVerbsFrom(iobj, verb, param);

            // Couldn't find one?
            if (selectedVerb.Count() != 1) {
            // Try for a "_huh" verb on the room the player is in.
            SourcedItem<Verb> huh = playerMob.location.findVerb("_huh");
            if (huh != null) {
                param.self = playerMob.location;
                using( var ac = new ActorContext( player, huh.source.id ) )
                    huh.item.invoke(param);
                return "";
            }

            // Nothin' doin'. Just return a default error.
            return "Sorry, I don't know what that means.";
            }

            // Execute the verb.
            var v2 = selectedVerb.First();
            param.self = v2.foundOn;
            using( var ac = new ActorContext( player, v2.definedOn.ownerId ) )
            v2.verb.invoke(param);

            // Any output will come from the script.
            return "";
        }
Пример #6
0
 public ActorContext( Player player, int id )
 {
     _player = player;
     _player.actorContextPush( id );
 }
Пример #7
0
 public AnonMob( IWorld world, Player player )
 {
     _world = world;
     _player = player;
 }