/// <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); }
public void Dispose() { if( _player != null ) { _player.actorContextPop(); _player = null; } }
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 ) { } } } } }
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(); }
/// <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 ""; }
public ActorContext( Player player, int id ) { _player = player; _player.actorContextPush( id ); }
public AnonMob( IWorld world, Player player ) { _world = world; _player = player; }