From: Jeremy Stanley Date: Thu, 24 Nov 2005 00:06:25 +0000 (+0000) Subject: Imported from archive. X-Git-Tag: 0.0.1~327 X-Git-Url: https://mudpy.org/gitweb?p=mudpy.git;a=commitdiff_plain;h=de087a3d44be4d4d2de2c4dc322ccab7c106aae4 Imported from archive. * mudpy.py (Element.can_run, User.can_run): Moved this method from the User class to the Element class, allowing for future flexibility. (Element.new_event, Universe.get_time): Began adding framework for event elements and queues. (command_create, command_delete, command_destroy, command_error) (command_halt, command_help, command_look, command_move) (command_quit, command_reload, command_say, command_set) (command_show): Adjusted commands and messaging to be relative to an actor element instead of a user object. --- diff --git a/command b/command index a789137..907335a 100644 --- a/command +++ b/command @@ -2,69 +2,69 @@ read_only = yes [command:create] -action = command_create(user, parameters) +action = command_create(actor, parameters) administrative = yes description = Create a new element in the universe. help = Ways to create an element:$(eol)$(eol) create actor:fred$(eol) create other:garply foo/bar/baz [command:delete] -action = command_delete(user, parameters) +action = command_delete(actor, parameters) administrative = yes description = Delete an existing facet from an element. help = You can delete any facet of an element as follows:$(eol)$(eol) delete location:boardroom terrain [command:destroy] -action = command_destroy(user, parameters) +action = command_destroy(actor, parameters) administrative = yes description = Destroy an existing element in the universe. help = You can destroy any element in the universe as follows:$(eol)$(eol) destroy prop:dagger [command:halt] -action = command_halt(user, parameters) +action = command_halt(actor, parameters) administrative = yes description = Shut down the world. help = This will save all active accounts, disconnect all clients and stop the entire program. [command:help] -action = command_help(user, parameters) +action = command_help(actor, parameters) description = List commands or get help on one. help = This will list all comand words available to you along with a brief description or, alternatively, give you detailed information on one command. [command:look] -action = command_look(user, parameters) +action = command_look(actor, parameters) description = Look around. help = With the look command, you can see where you are. [command:move] -action = command_move(user, parameters) +action = command_move(actor, parameters) description = Move in a specific direction. help = You move in a direction by entering:$(eol) move north [command:quit] -action = command_quit(user) +action = command_quit(actor) description = Leave Example. help = This will save your account and disconnect your client connection. [command:reload] -action = command_reload(user) +action = command_reload(actor) administrative = yes description = Reload code modules and data. help = This will reload all python code modules, reload configuration files and re-read data files. [command:say] -action = command_say(user, parameters) +action = command_say(actor, parameters) description = State something out loud. help = This allows you to speak to other characters within the same room. If you end your sentence with specific punctuation, the aparent speech action (ask, exclaim, et cetera) will be adapted accordingly. It will also add punctuation and capitalize your message where needed. [command:set] -action = command_set(user, parameters) +action = command_set(actor, parameters) administrative = yes description = Set a facet of an element. help = Invoke it like this:$(eol)$(eol) set actor:dominique description You see nothing special. [command:show] -action = command_show(user, parameters) +action = command_show(actor, parameters) administrative = yes description = Show element data. -help = Here are the possible incantations:$(eol)$(eol) show categories$(eol) show category actor$(eol) show element location:1:2:3:4$(eol) show files$(eol) show log 20$(eol) show result user.avatar.get("name")$(eol) show time +help = Here are the possible incantations:$(eol)$(eol) show categories$(eol) show category actor$(eol) show element location:1:2:3:4$(eol) show files$(eol) show log 20$(eol) show result avatar.get("name")$(eol) show time diff --git a/example/second_square/prop b/example/second_square/prop index 64d1fd8..798b9d8 100644 --- a/example/second_square/prop +++ b/example/second_square/prop @@ -1,5 +1,4 @@ [prop:fountain] impression = An inviting public fountain bubbles here, tempting you with thirst. keywords = fountain water -location = location:0,0,0 diff --git a/mudpy.py b/mudpy.py index 4155214..d1c434f 100644 --- a/mudpy.py +++ b/mudpy.py @@ -38,7 +38,7 @@ sys.excepthook = excepthook class Element: """An element of the universe.""" - def __init__(self, key, universe, filename=""): + def __init__(self, key, universe, filename=None): """Set up a new element.""" # not owned by a user by default (used for avatars) @@ -47,6 +47,9 @@ class Element: # no contents in here by default self.contents = {} + # an event queue for the element + self.events = {} + # keep track of our key name self.key = key @@ -78,7 +81,6 @@ class Element: def destroy(self): """Remove an element from the universe and destroy it.""" - log("Destroying: " + self.key + ".", 2) self.origin.data.remove_section(self.key) del universe.categories[self.category][self.subkey] del universe.contents[self.key] @@ -172,9 +174,38 @@ class Element: newlist = self.getlist(facet) newlist.append(value) self.set(facet, newlist) + + def new_event(self, action, when=None): + """Create, attach and enqueue an event element.""" + + # if when isn't specified, that means now + if not when: when = universe.get_time() + + # events are elements themselves + event = Element("event:" + self.key + ":" + counter) + def send(self, message, eol="$(eol)"): """Convenience method to pass messages to an owner.""" if self.owner: self.owner.send(message, eol) + + def can_run(self, command): + """Check if the user can run this command object.""" + + # has to be in the commands category + if command not in universe.categories["command"].values(): result = False + + # avatars of administrators can run any command + elif self.owner and self.owner.account.getboolean("administrator"): result = True + + # everyone can run non-administrative commands + elif not command.getboolean("administrative"): result = True + + # otherwise the command cannot be run by this actor + else: result = False + + # pass back the result + return result + def go_to(self, location): """Relocate the element to a specific location.""" current = self.get("location") @@ -304,6 +335,9 @@ class DataFile: file_descriptor.flush() file_descriptor.close() + # unset the modified flag + self.modified = False + class Universe: """The universe.""" def __init__(self, filename=""): @@ -313,7 +347,9 @@ class Universe: self.default_origins = {} self.files = {} self.private_files = [] - self.loglist = [] + self.loglines = {} + self.pending_events_long = {} + self.pending_events_short = {} self.userlist = [] self.terminate_world = False self.reload_modules = False @@ -362,6 +398,10 @@ class Universe: # note that we're now ready for user connections log("Waiting for connection(s)...") + def get_time(self): + """Convenience method to get the elapsed time counter.""" + return self.categories["internal"]["counters"].getint("elapsed") + class User: """This is a connected user.""" @@ -702,24 +742,6 @@ class User: # replace the input with our cleaned-up text self.partial_input = text - def can_run(self, command): - """Check if the user can run this command object.""" - - # has to be in the commands category - if command not in universe.categories["command"].values(): result = False - - # administrators can run any command - elif self.account.getboolean("administrator"): result = True - - # everyone can run non-administrative commands - elif not command.getboolean("administrative"): result = True - - # otherwise the command cannot be run by this user - else: result = False - - # pass back the result - return result - def new_avatar(self): """Instantiate a new, unconfigured avatar for this user.""" counter = 0 @@ -818,8 +840,44 @@ def log(message, level=0): # add to the recent log list for line in lines: - while 0 < len(universe.loglist) >= max_log_lines: del universe.loglist[0] - universe.loglist.append(timestamp + " " + line) + while 0 < len(universe.loglines) >= max_log_lines: del universe.loglines[0] + universe.loglines.append((level, timestamp + " " + line)) + +def get_loglines(level, start, stop=0): + """Return a specific range of loglines filtered by level.""" + + # begin with a blank message + message = "" + + # filter the log lines + loglines = filter(lambda x,y: x>=level, universe.loglines) + + # we need this in several places + count = len(loglines) + + # don't proceed if there are no lines + if count: + + # can't start before the begining or at the end + if start > count: start = count + if start < 1: start = 1 + + # can't stop before we start + if stop >= start: stop = start - 1 + + # some preamble + message += "There are " + str(len(universe.loglist)) + message += " log lines in memory and " + str(count) + message += " at or above level " + str(level) + "." + message += " The lines from " + str(stop) + message += " to " + str(start) + " are:$(eol)$(eol)" + + # add the text from the selected lines + for line in loglines[-start:-stop]: + message += " " + line[1] + "$(eol)" + + # pass it back + return message def wrap_ansi_text(text, width): """Wrap text with arbitrary width while ignoring ANSI colors.""" @@ -1387,48 +1445,51 @@ def handler_active(user): else: command = None # if it's allowed, do it - if user.can_run(command): exec(command.get("action")) + if user.avatar.can_run(command): exec(command.get("action")) # otherwise, give an error - elif command_name: command_error(user, input_data) + elif command_name: command_error(user.avatar, input_data) # if no input, just idle back with a prompt else: user.send("", just_prompt=True) -def command_halt(user, parameters): +def command_halt(actor, parameters): """Halt the world.""" + if actor.owner: - # see if there's a message or use a generic one - if parameters: message = "Halting: " + parameters - else: message = "User " + user.account.get("name") + " halted the world." + # see if there's a message or use a generic one + if parameters: message = "Halting: " + parameters + else: message = "User " + actor.owner.account.get("name") + " halted the world." - # let everyone know - broadcast(message, add_prompt=False) - log(message, 8) + # let everyone know + broadcast(message, add_prompt=False) + log(message, 8) - # set a flag to terminate the world - universe.terminate_world = True + # set a flag to terminate the world + universe.terminate_world = True -def command_reload(user): +def command_reload(actor): """Reload all code modules, configs and data.""" + if actor.owner: - # let the user know and log - user.send("Reloading all code modules, configs and data.") - log("User " + user.account.get("name") + " reloaded the world.", 8) + # let the user know and log + actor.send("Reloading all code modules, configs and data.") + log("User " + actor.owner.account.get("name") + " reloaded the world.", 8) - # set a flag to reload - universe.reload_modules = True + # set a flag to reload + universe.reload_modules = True -def command_quit(user): +def command_quit(actor): """Leave the world and go back to the main menu.""" - user.deactivate_avatar() - user.state = "main_utility" + if actor.owner: + actor.owner.deactivate_avatar() + actor.owner.state = "main_utility" -def command_help(user, parameters): +def command_help(actor, parameters): """List available commands and provide help for commands.""" # did the user ask for help on a specific command word? - if parameters: + if parameters and actor.owner: # is the command word one for which we have data? if parameters in universe.categories["command"]: @@ -1436,7 +1497,7 @@ def command_help(user, parameters): else: command = None # only for allowed commands - if user.can_run(command): + if actor.can_run(command): # add a description if provided description = command.get("description") @@ -1465,7 +1526,7 @@ def command_help(user, parameters): sorted_commands.sort() for item in sorted_commands: command = universe.categories["command"][item] - if user.can_run(command): + if actor.can_run(command): description = command.get("description") if not description: description = "(no short description provided)" @@ -1475,25 +1536,25 @@ def command_help(user, parameters): output += "$(eol)Enter \"help COMMAND\" for help on a command named \"COMMAND\"." # send the accumulated output to the user - user.send(output) + actor.send(output) -def command_move(user, parameters): +def command_move(actor, parameters): """Move the avatar in a given direction.""" - if parameters in universe.contents[user.avatar.get("location")].portals(): - user.avatar.move_direction(parameters) - else: user.send("You cannot go that way.") + if parameters in universe.contents[actor.get("location")].portals(): + actor.move_direction(parameters) + else: actor.send("You cannot go that way.") -def command_look(user, parameters): +def command_look(actor, parameters): """Look around.""" - if parameters: user.send("You can't look at or in anything yet.") - else: user.avatar.look_at(user.avatar.get("location")) + if parameters: actor.send("You can't look at or in anything yet.") + else: actor.look_at(actor.get("location")) -def command_say(user, parameters): +def command_say(actor, parameters): """Speak to others in the same room.""" # check for replacement macros - if replace_macros(user, parameters, True) != parameters: - user.send("You cannot speak $_(replacement macros).") + if replace_macros(actor.owner, parameters, True) != parameters: + actor.send("You cannot speak $_(replacement macros).") # the user entered a message elif parameters: @@ -1528,14 +1589,14 @@ def command_say(user, parameters): message = message.replace(" " + word + " ", " " + word.capitalize() + " ") # tell the room - user.avatar.echo_to_location(user.avatar.get("name") + " " + action + "s, \"" + message + "\"") - user.send("You " + action + ", \"" + message + "\"") + actor.echo_to_location(actor.get("name") + " " + action + "s, \"" + message + "\"") + actor.send("You " + action + ", \"" + message + "\"") # there was no message else: - user.send("What do you want to say?") + actor.send("What do you want to say?") -def command_show(user, parameters): +def command_show(actor, parameters): """Show program data.""" message = "" if parameters.find(" ") < 1: @@ -1578,7 +1639,7 @@ def command_show(user, parameters): elif arguments[0] == "log": if match("^\d+$", arguments[1]) and int(arguments[1]) > 0: linecount = int(arguments[1]) - if linecount > len(universe.loglist): linecount = len(universe.loglist) + if linecount > len(universe.loglines): linecount = len(universe.loglist) message = "There are " + str(len(universe.loglist)) + " log lines in memory." message += " The most recent " + str(linecount) + " lines are:$(eol)$(eol)" for line in universe.loglist[-linecount:]: @@ -1587,11 +1648,12 @@ def command_show(user, parameters): if not message: if parameters: message = "I don't know what \"" + parameters + "\" is." else: message = "What do you want to show?" - user.send(message) + actor.send(message) -def command_create(user, parameters): +def command_create(actor, parameters): """Create an element if it does not exist.""" if not parameters: message = "You must at least specify an element to create." + elif not actor.owner: message = "" else: arguments = parameters.split() if len(arguments) == 1: arguments.append("") @@ -1600,7 +1662,7 @@ def command_create(user, parameters): if element in universe.contents: message = "The \"" + element + "\" element already exists." else: message = "You create \"" + element + "\" within the universe." - logline = user.account.get("name") + " created an element: " + element + logline = actor.owner.account.get("name") + " created an element: " + element if filename: logline += " in file " + filename if filename not in universe.files: @@ -1608,20 +1670,21 @@ def command_create(user, parameters): Element(element, universe, filename) log(logline, 6) elif len(arguments) > 2: message = "You can only specify an element and a filename." - user.send(message) + actor.send(message) -def command_destroy(user, parameters): +def command_destroy(actor, parameters): """Destroy an element if it exists.""" - if not parameters: message = "You must specify an element to destroy." - else: - if parameters not in universe.contents: message = "The \"" + parameters + "\" element does not exist." + if actor.owner: + if not parameters: message = "You must specify an element to destroy." else: - universe.contents[parameters].destroy() - message = "You destroy \"" + parameters + "\" within the universe." - log(user.account.get("name") + " destroyed an element: " + parameters, 6) - user.send(message) + if parameters not in universe.contents: message = "The \"" + parameters + "\" element does not exist." + else: + universe.contents[parameters].destroy() + message = "You destroy \"" + parameters + "\" within the universe." + log(actor.owner.account.get("name") + " destroyed an element: " + parameters, 6) + actor.send(message) -def command_set(user, parameters): +def command_set(actor, parameters): """Set a facet of an element.""" if not parameters: message = "You must specify an element, a facet and a value." else: @@ -1634,9 +1697,9 @@ def command_set(user, parameters): else: universe.contents[element].set(facet, value) message = "You have successfully (re)set the \"" + facet + "\" facet of element \"" + element + "\". Try \"show element " + element + "\" for verification." - user.send(message) + actor.send(message) -def command_delete(user, parameters): +def command_delete(actor, parameters): """Delete a facet from an element.""" if not parameters: message = "You must specify an element and a facet." else: @@ -1650,9 +1713,9 @@ def command_delete(user, parameters): else: universe.contents[element].remove_facet(facet) message = "You have successfully deleted the \"" + facet + "\" facet of element \"" + element + "\". Try \"show element " + element + "\" for verification." - user.send(message) + actor.send(message) -def command_error(user, input_data): +def command_error(actor, input_data): """Generic error for an unrecognized command word.""" # 90% of the time use a generic error @@ -1664,7 +1727,7 @@ def command_error(user, input_data): message = "Arglebargle, glop-glyf!?!" # send the error message - user.send(message) + actor.send(message) # if there is no universe, create an empty one if not "universe" in locals(): universe = Universe()