Пример #1
0
        public override void Initialize()
        {
            Actor();

            this.Response("who he is", (actor, npc, topic) =>
            {
                Core.SendLocaleMessage(actor, "\"Name's Bjorn,\" <the0> gasps. \"You going to buy something, or..?\"", this);
                GlobalRules.ConsiderPerformRule("introduce self", this);
                return(PerformResult.Stop);
            });

            Perform <MudObject, MudObject, MudObject>("topic response")
            .When((actor, npc, topic) => topic == null)
            .Do((actor, npc, topic) =>
            {
                Core.SendLocaleMessage(actor, "\"Eh?\" <the0> asks.", this);
                return(PerformResult.Stop);
            });

            Short = "Bjorn";

            AddNoun("shopkeeper", "shop", "keeper", "keep");
            AddNoun("bjorn", "b").When(a => GlobalRules.ConsiderValueRule <bool>("actor knows actor?", a, this));

            this.Wear("overalls", ClothingLayer.Outer, ClothingBodyPart.Legs);
            this.Wear("simple white shirt", ClothingLayer.Outer, ClothingBodyPart.Torso);
            this.Wear("kufi", ClothingLayer.Outer, ClothingBodyPart.Head);

            Perform <MudObject, MudObject>("describe in locale").Do((actor, item) =>
            {
                Core.SendMessage(actor, "The shopkeeper leans on the counter.");
                return(PerformResult.Continue);
            });
        }
Пример #2
0
        public override void Initialize()
        {
            Actor();

            this.SetProperty("gender", Gender.Female);
            Long = "The most striking feature of this tree is not it's size - it's the face hacked crudely into the trunk. As you watch, it shifts, as if muttering to itself.";

            this.Response("who she is", (actor, npc, topic) =>
            {
                Core.SendLocaleMessage(actor, "The breeze whistles between the trees. It almost sounds like words.... \"...Forest...\", the wind says.", this);
                GlobalRules.ConsiderPerformRule("introduce self", this);
                return(PerformResult.Stop);
            });

            Perform <MudObject, MudObject, MudObject>("topic response")
            .When((actor, npc, topic) => topic == null)
            .Do((actor, npc, topic) =>
            {
                Core.SendLocaleMessage(actor, "The wind whistles.", this);
                return(PerformResult.Stop);
            });

            Short = "Mother Tree";

            AddNoun("mother", "tree", "oak", "forest");

            Perform <MudObject, MudObject>("describe in locale").Do((actor, item) =>
            {
                Core.SendMessage(actor, "The wind whistles through the leaves.");
                return(PerformResult.Continue);
            });
        }
Пример #3
0
        /// <summary>
        /// Process commands in a single thread, until there are no more queued commands.
        /// Heartbeat is called between every command.
        /// </summary>
        public static void ProcessCommands()
        {
            if ((Core.Flags & StartupFlags.SingleThreaded) != StartupFlags.SingleThreaded)
            {
                throw new InvalidOperationException("ProcessCommands should only be called in single threaded mode.");
            }

            while (PendingCommands.Count > 0 && !ShuttingDown)
            {
                GlobalRules.ConsiderPerformRule("heartbeat");

                Core.SendPendingMessages();

                PendingCommand PendingCommand = null;

                try
                {
                    PendingCommand = PendingCommands.FirstOrDefault();
                    if (PendingCommand != null)
                    {
                        PendingCommands.Remove(PendingCommand);
                    }
                }
                catch (Exception e)
                {
                    LogCommandError(e);
                    PendingCommand = null;
                }

                if (PendingCommand != null)
                {
                    NextCommand = PendingCommand;

                    //Reset flags that the last command may have changed
                    CommandTimeoutEnabled = true;
                    SilentFlag            = false;
                    GlobalRules.LogRules(null);

                    try
                    {
                        var handler = NextCommand.Actor.GetProperty <ClientCommandHandler>("command handler");
                        if (handler != null)
                        {
                            handler.HandleCommand(NextCommand);
                        }
                    }
                    catch (Exception e)
                    {
                        LogCommandError(e);
                        Core.DiscardPendingMessages();
                    }
                    if (PendingCommand.ProcessingCompleteCallback != null)
                    {
                        PendingCommand.ProcessingCompleteCallback();
                    }
                }
            }
        }
Пример #4
0
        private void UpdateGlobalRules()
        {
            var newRules = GetAllGlobalCSRules();

            if (newRules?.Count > 0)
            {
                GlobalCSRules.Clear();
                GlobalCSRules = newRules;
                GlobalRules.UpdateGlobalRules();
            }
        }
Пример #5
0
        /// <summary>
        /// Run update rule on all objects that have been marked.
        /// </summary>
        public static void UpdateMarkedObjects()
        {
            // Updating an object may mark further objects for update. Avoid an infinite loop.
            var startCount = MarkedObjects.Count;

            for (int i = 0; i < startCount; ++i)
            {
                GlobalRules.ConsiderPerformRule("update", MarkedObjects[i]);
            }
            MarkedObjects.RemoveRange(0, startCount);
        }
Пример #6
0
        /// <summary>
        /// Process the Heartbeat. It is assumed that this function is called periodically by the command processing loop.
        /// When called, this function will invoke the "heartbeat" rulebook if enough time has passed since the last
        /// invokation.
        /// </summary>
        internal static void Heartbeat()
        {
            var now = DateTime.Now;

            var timeSinceLastBeat = now - TimeOfLastHeartbeat;

            if (timeSinceLastBeat.TotalMilliseconds >= SettingsObject.HeartbeatInterval)
            {
                Core.TimeOfDay     += Core.SettingsObject.ClockAdvanceRate;
                TimeOfLastHeartbeat = now;
                CurrentHeartbeat   += 1;

                var heartbeatObjects = new HashSet <MudObject>();
                foreach (var client in Clients.ConnectedClients)
                {
                    foreach (var visibleObject in Core.EnumerateVisibleTree(Core.FindLocale(client.Player)))
                    {
                        heartbeatObjects.Add(visibleObject);
                    }
                }

                foreach (var heartbeatObject in heartbeatObjects)
                {
                    HeartbeatSet.Add(heartbeatObject);
                    heartbeatObject.CurrentHeartbeat = CurrentHeartbeat;
                }

                HeartbeatSet.RemoveWhere(o => o.CurrentHeartbeat < (CurrentHeartbeat - Core.SettingsObject.LiveHeartbeats));

                foreach (var heartbeatObject in HeartbeatSet)
                {
                    GlobalRules.ConsiderPerformRule("heartbeat", heartbeatObject);
                }

                //In case heartbeat rules emitted messages.
                Core.SendPendingMessages();
            }

            for (var i = 0; i < ActiveTimers.Count;)
            {
                var timerFireTime = ActiveTimers[i].StartTime + ActiveTimers[i].Interval;
                if (timerFireTime <= now)
                {
                    ActiveTimers[i].Action();
                    SendPendingMessages();
                    ActiveTimers.RemoveAt(i);
                }
                else
                {
                    ++i;
                }
            }
        }
Пример #7
0
        /// <summary>
        /// Actually carryout the command, following all of it's rules, including the before and after command rules.
        /// </summary>
        /// <param name="Command"></param>
        /// <param name="Match"></param>
        /// <param name="Actor"></param>
        /// <returns>The result of the command's procedural rules.</returns>
        private static PerformResult ExecuteCommand(CommandEntry Command, PossibleMatch Match, MudObject Actor)
        {
            var result = PerformResult.Stop;

            Match.Upsert("COMMAND", Command);
            if (GlobalRules.ConsiderMatchBasedPerformRule("before command", Match, Actor) == PerformResult.Continue)
            {
                result = Command.ProceduralRules.Consider(Match, Actor);
                GlobalRules.ConsiderMatchBasedPerformRule("after command", Match, Actor);
            }
            GlobalRules.ConsiderPerformRule("after every command", Actor);
            return(result);
        }
Пример #8
0
        public void AddRule(BestPracticeRule rule, bool global = false)
        {
            rule.ID = GetUniqueId(rule.ID);
            if (global)
            {
                GlobalRules.Add(rule);
            }
            else
            {
                LocalRules.Add(rule);
            }

            DoCollectionChanged(NotifyCollectionChangedAction.Add, rule);
        }
Пример #9
0
        /// <summary>
        /// Process the Heartbeat. It is assumed that this function is called periodically by the command processing loop.
        /// When called, this function will invoke the "heartbeat" rulebook if enough time has passed since the last
        /// invokation.
        /// </summary>
        internal static void Heartbeat()
        {
            var now = DateTime.Now;
            var timeSinceLastBeat = now - TimeOfLastHeartbeat;

            if (timeSinceLastBeat.TotalMilliseconds >= SettingsObject.HeartbeatInterval)
            {
                TimeOfLastHeartbeat = now;
                GlobalRules.ConsiderPerformRule("heartbeat");

                //In case heartbeat rules emitted messages.
                Core.SendPendingMessages();
            }
        }
Пример #10
0
        public string GetUniqueId(string id)
        {
            int suffix = 1;
            var testId = id;

            while (
                GlobalRules.Contains(testId) ||
                LocalRules.Contains(testId)
                )
            {
                suffix++;
                testId = id + "_" + suffix;
            }
            return(testId);
        }
Пример #11
0
        private void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.OldItems != null)
            {
                foreach (var item in e.OldItems)
                {
                    //if (!((IGlobalCSSheet)item).FixStyle && ((IGlobalCSSheet)item).Component != null && !StyleSheetIsNeeded(((IGlobalCSSheet)item).Component))
                    //{
                    //    GlobalRulesSheets.Remove(GlobalRulesSheets.First(x => x.Component?.GetType() == ((IGlobalCSSheet)item).Component.GetType()));
                    //    RemoveOneStyleSheet((IGlobalCSSheet)item);
                    //    GlobalRules.UpdateGlobalRules();
                    //}
                    //else if (!((IGlobalCSSheet)item).FixStyle && ((IGlobalCSSheet)item).Component != null && ((IGlobalCSSheet)item).IsGlobal)
                    //{
                    //    GlobalCSSheets.First(x => x.Component?.GetType() == ((IGlobalCSSheet)item).Component.GetType()).IsGlobal = true;
                    //}
                    if (!((IGlobalCSSheet)item).FixStyle && ((IGlobalCSSheet)item).ComponentType != null && !StyleSheetIsNeeded(((IGlobalCSSheet)item).ComponentType))
                    {
                        GlobalRulesSheets.Remove(GlobalRulesSheets.First(x => x.ComponentType == ((IGlobalCSSheet)item).ComponentType));
                        RemoveOneStyleSheet((IGlobalCSSheet)item);
                        GlobalRules?.UpdateGlobalRules();
                        //Debug.WriteLine($"Removed StyleSheet for {((IGlobalCSSheet)item).ComponentType}");
                    }
                    else if (!((IGlobalCSSheet)item).FixStyle && ((IGlobalCSSheet)item).ComponentType != null && ((IGlobalCSSheet)item).IsGlobal)
                    {
                        GlobalCSSheets.First(x => x.ComponentType == ((IGlobalCSSheet)item).ComponentType).IsGlobal = true;
                    }
                }
            }

            if (e.NewItems != null)
            {
                foreach (var item in e.NewItems)
                {
                    if (!ComponentStyleExist(((IGlobalCSSheet)item).ComponentType))
                    {
                        //Debug.WriteLine($"Added StyleSheet for {((IGlobalCSSheet)item).ComponentType}");
                        GlobalRulesSheets.Add((IGlobalCSSheet)item);
                        ((IGlobalCSSheet)item).IsGlobal = true;
                        AddOneStyleSheet((IGlobalCSSheet)item);
                        GlobalRules?.UpdateGlobalRules();
                    }
                }
            }
        }
Пример #12
0
        public override void Initialize()
        {
            Actor();

            this.Response("who he is", (actor, npc, topic) =>
            {
                Core.SendLocaleMessage(actor, "\"Jaygmunder,\" <the0> gasps. \"You can call me Jay though.\"", this);
                GlobalRules.ConsiderPerformRule("introduce self", this);
                return(PerformResult.Stop);
            });

            this.Response("his mechanical suit", "\"Huh, my suit? Whhat about it? When you get old, you'll need some help getting around too.\" <the0> sighs. \"Not that it does me much good now. I have't got any plasma for it.\"");

            this.Response("his plush chair", "\"Yeah it's pretty nice.\" <the0> pauses to stroke the arm of his chair. \"I'd let you sit in it if I could get up. Need plasma for that, though.\"");

            this.Response("plasma", (actor, nps, topic) =>
            {
                Core.SendLocaleMessage(actor, "\"The red stuff? In the bags? You know what plasma is, don't you?\"");
                var quest = Core.GetObject("Homestead.PlasmaQuest");
                if (GlobalRules.ConsiderValueRule <bool>("quest available?", actor, quest))
                {
                    Core.SendMessage(actor, "\"Think you can grab some for me?\" <the0> asks.", this);
                    this.OfferQuest(actor, quest);
                }
                return(PerformResult.Stop);
            });

            Perform <MudObject, MudObject, MudObject>("topic response")
            .When((actor, npc, topic) => topic == null)
            .Do((actor, npc, topic) =>
            {
                Core.SendLocaleMessage(actor, "\"Wut?\" <the0> asks.", this);
                return(PerformResult.Stop);
            });

            Short = "Jaygmundre";

            AddNoun("jaygmundre", "jay", "j").When(a => GlobalRules.ConsiderValueRule <bool>("actor knows actor?", a, this));

            this.Wear("mechanical suit", ClothingLayer.Outer, ClothingBodyPart.Torso);
        }
Пример #13
0
    public override void Initialize()
    {
        Actor();

        this.Response("who he is", (actor, npc, topic) =>
        {
            SendLocaleMessage(actor, "\"I am Soranus,\" <the0> says.", this);
            GlobalRules.ConsiderPerformRule("introduce self", this);
            return(PerformResult.Stop);
        });

        this.Response("the entrails", "\"These things?\" <the0> asks. \"Nothing special. They're for the wolves.\"");

        this.Response("wolves", (actor, npc, topic) =>
        {
            SendLocaleMessage(actor, "^<the0> grins, expossing a pair of wicked yellow canines. \"Oh don't worry, they aren't here now.\"", this);
            var quest = GetObject("palantine/entrail_quest");
            if (GlobalRules.ConsiderValueRule <bool>("quest available?", actor, quest))
            {
                SendMessage(actor, "\"Would you mind feeding them for me?\" <the0> asks.", this);
                this.OfferQuest(actor, quest);
            }
            return(PerformResult.Stop);
        });

        Perform <MudObject, MudObject, MudObject>("topic response")
        .When((actor, npc, topic) => topic == null)
        .Do((actor, npc, topic) =>
        {
            SendLocaleMessage(actor, "\"This is my default response,\" <the0> says, showing his sharp little teeth.", this);
            return(PerformResult.Stop);
        });

        Short = "Soranus";

        AddNoun("soranus").When(a => GlobalRules.ConsiderValueRule <bool>("actor knows actor?", a, this));

        this.Wear("toga", ClothingLayer.Outer, ClothingBodyPart.Torso);
        this.Wear(GetObject("palantine/entrails"));
    }
Пример #14
0
        /// <summary>
        /// Format a list of mud objects using commas and a coordinating conjunction. EG, into the form 'a, b, and c'.
        /// </summary>
        /// <param name="Recipient">The actor that will, eventually, see the output.</param>
        /// <param name="ListObject">Either a MudObject or a List<MudObject>. The actual items to format.</param>
        /// <param name="FormattedMessage">Append the formatted message to this StringBuilder.</param>
        /// <param name="CoordinatingConjunction">The word that separates the final item of a list from those proceeding it. EG, and, or, nor.</param>
        private static void FormatList(
            MudObject Recipient,
            Object ListObject,
            StringBuilder FormattedMessage,
            String CoordinatingConjunction)
        {
            // ListObject can be a MudObject or a List<MudObject>. The algorithm expects a list, so transform it.
            List <MudObject> list = null;

            if (ListObject is MudObject)
            {
                list = new List <MudObject>();
                list.Add(ListObject as MudObject);
            }
            else
            {
                list = ListObject as List <MudObject>;
            }

            // If ListObject was neither a MudObject nor a List<MudObject>...
            if (list == null)
            {
                return;
            }

            for (int x = 0; x < list.Count; ++x)
            {
                FormattedMessage.Append(GlobalRules.ConsiderValueRule <String>("printed name", Recipient, list[x], list[x].GetProperty <String>("article")));
                if (x != list.Count - 1)
                {
                    FormattedMessage.Append(", ");
                }
                if (x == list.Count - 2 && !String.IsNullOrEmpty(CoordinatingConjunction))
                {
                    FormattedMessage.Append(CoordinatingConjunction + " ");
                }
            }
        }
Пример #15
0
        public void UpdateLighting()
        {
            Light = LightingLevel.Dark;

            if (RoomType == RMUD.RoomType.Exterior)
            {
                Light = AmbientExteriorLightingLevel;
            }

            foreach (var item in MudObject.EnumerateVisibleTree(this))
            {
                var lightingLevel = GlobalRules.ConsiderValueRule <LightingLevel>("light level", item);
                if (lightingLevel > Light)
                {
                    Light = lightingLevel;
                }
            }

            if (AmbientLighting > Light)
            {
                Light = AmbientLighting;
            }
        }
Пример #16
0
        private static void ProcessThreadedCommands()
        {
            if ((Core.Flags & StartupFlags.SingleThreaded) == StartupFlags.SingleThreaded)
            {
                throw new InvalidOperationException("ProcessThreadedCommands should never be called in single threaded mode.");
            }

            IndividualCommandThread = new Thread(ProcessCommandsWorkerThread);
            IndividualCommandThread.Start();

            while (!ShuttingDown)
            {
                System.Threading.Thread.Sleep(10);
                DatabaseLock.WaitOne();
                Heartbeat();
                DatabaseLock.ReleaseMutex();

                while (PendingCommands.Count > 0 && !ShuttingDown)
                {
                    PendingCommand PendingCommand = null;

                    PendingCommandLock.WaitOne();

                    try
                    {
                        PendingCommand = PendingCommands.FirstOrDefault(pc =>
                        {
                            return(true);
                            //if (pc.Actor.ConnectedClient == null) return true;
                            //else return (DateTime.Now - pc.Actor.ConnectedClient.TimeOfLastCommand).TotalMilliseconds > SettingsObject.AllowedCommandRate;
                        });
                        if (PendingCommand != null)
                        {
                            PendingCommands.Remove(PendingCommand);
                        }
                    }
                    catch (Exception e)
                    {
                        LogCommandError(e);
                        PendingCommand = null;
                    }

                    PendingCommandLock.ReleaseMutex();

                    if (PendingCommand != null)
                    {
                        DatabaseLock.WaitOne();

                        NextCommand = PendingCommand;

                        //Reset flags that the last command may have changed
                        CommandTimeoutEnabled = true;
                        SilentFlag            = false;
                        GlobalRules.LogRules(null);

                        CommandReadyHandle.Set(); //Signal worker thread to proceed.
                        if (!CommandFinishedHandle.WaitOne(SettingsObject.CommandTimeOut))
                        {
                            if (!CommandTimeoutEnabled) //Timeout is disabled, go ahead and wait for infinity.
                            {
                                CommandFinishedHandle.WaitOne();
                            }
                            else
                            {
                                //Kill the command processor thread.
                                IndividualCommandThread.Abort();
                                ClearPendingMessages();
                                if (PendingCommand.Actor.ConnectedClient != null)
                                {
                                    PendingCommand.Actor.ConnectedClient.Send("Command timeout.\r\n");
                                    LogError(String.Format("Command timeout. {0} - {1}", PendingCommand.Actor.ConnectedClient.ConnectionDescription, PendingCommand.RawCommand));
                                }
                                else
                                {
                                    LogError(String.Format("Command timeout [No client] - {1}", PendingCommand.RawCommand));
                                }
                                IndividualCommandThread = new Thread(ProcessCommandsWorkerThread);
                                IndividualCommandThread.Start();
                            }
                        }

                        if (PendingCommand.ProcessingCompleteCallback != null)
                        {
                            PendingCommand.ProcessingCompleteCallback();
                        }

                        DatabaseLock.ReleaseMutex();
                    }
                }
            }

            IndividualCommandThread.Abort();
            if (Core.OnShutDown != null)
            {
                Core.OnShutDown();
            }
        }
Пример #17
0
        /// <summary>
        /// Parse and format a message intended for a specific recipient.
        /// </summary>
        /// <param name="Recipient"></param>
        /// <param name="Message">The message, possibly containing specifiers.</param>
        /// <param name="Objects">Specifier indicies refer to this list of objects.</param>
        /// <returns></returns>
        public static String FormatMessage(MudObject Recipient, String Message, params Object[] Objects)
        {
            //A leading @ indicates that the message should be interpretted as an entry in the global message table.
            if (Message[0] == '@')
            {
                Message = Core.GetMessage(Message.Substring(1));
            }

            var formattedMessage = new StringBuilder();
            var iterator         = new StringIterator(Message);

            while (!iterator.AtEnd)
            {
                if (iterator.Next == '<') //We have located a specifier.
                {
                    var type  = "";
                    var index = 0;
                    if (MessageFormatParser.ReadSpecifier(iterator, out type, out index))
                    {
                        if (index < 0 || index >= Objects.Length)
                        {
                            continue;                                       //A blank in the output is preferable to crashing.
                        }
                        #region Expand Specifier
                        if (type == "the" && Objects[index] is MudObject)
                        {
                            //'the' overrides the object's article property.
                            formattedMessage.Append(GlobalRules.ConsiderValueRule <String>("printed name", Recipient, Objects[index], "the"));
                        }
                        else if (type == "a" && Objects[index] is MudObject)
                        {
                            formattedMessage.Append(GlobalRules.ConsiderValueRule <String>("printed name", Recipient, Objects[index], (Objects[index] as MudObject).GetProperty <String>("article")));
                        }
                        else if (type == "l") //No connective clause is used for this style of list. eg 1, 2, 3.
                        {
                            FormatList(Recipient, Objects[index], formattedMessage, "");
                        }
                        else if (type == "lor") //Use or. eg 1, 2, or 3.
                        {
                            FormatList(Recipient, Objects[index], formattedMessage, "or");
                        }
                        else if (type == "land") //Use and. eg 1, 2, and 3.
                        {
                            FormatList(Recipient, Objects[index], formattedMessage, "and");
                        }
                        else if (type == "lnor") //Use nor. eg 1, 2, nor 3.
                        {
                            FormatList(Recipient, Objects[index], formattedMessage, "nor");
                        }
                        else if (type == "s")
                        {
                            if (Objects[index] == null)
                            {
                                formattedMessage.Append("%NULL%");
                            }
                            else
                            {
                                formattedMessage.Append(Objects[index].ToString());
                            }
                        }
                        #endregion
                    }
                }
                else
                {
                    formattedMessage.Append(iterator.Next);
                    iterator.Advance();
                }
            }

            Message = formattedMessage.ToString();
            formattedMessage.Clear();
            iterator = new StringIterator(Message);

            //Apply the ^ transform: Capitalize the letter following the ^ and remove the ^.
            while (!iterator.AtEnd)
            {
                if (iterator.Next == '^')
                {
                    iterator.Advance();
                    if (iterator.AtEnd)
                    {
                        break;
                    }
                    formattedMessage.Append(new String(iterator.Next, 1).ToUpper());
                    iterator.Advance();
                }
                else
                {
                    formattedMessage.Append(iterator.Next);
                    iterator.Advance();
                }
            }

            return(formattedMessage.ToString());
        }