X-Git-Url: https://mudpy.org/gitweb?p=mudpy.git;a=blobdiff_plain;f=mudpy%2Fmisc.py;h=a23b834f857842769d41fe7c9d527a8c59755096;hp=170a4c334aaa4fb0e3d6e1688db9eadea4a489af;hb=124dd5e224bc2d2cc8af5db6d9e3fc55ed1a8426;hpb=c4e35cb2515d57a6a562ecf9803769a55a220692 diff --git a/mudpy/misc.py b/mudpy/misc.py index 170a4c3..a23b834 100644 --- a/mudpy/misc.py +++ b/mudpy/misc.py @@ -23,89 +23,61 @@ class Element: """An element of the universe.""" - def __init__(self, key, universe, origin=None, old_style=False): + def __init__(self, key, universe, origin=None): """Set up a new element.""" - # TODO(fungi): This can be removed after the transition is complete - self.old_style = old_style - # keep track of our key name self.key = key # keep track of what universe it's loading into self.universe = universe - # clone attributes if this is replacing another element - if self.old_style and self.key in self.universe.contents: - old_element = self.universe.contents[self.key] - for attribute in vars(old_element).keys(): - exec("self." + attribute + " = old_element." + attribute) - if self.owner: - self.owner.avatar = self - - # i guess this is a new element then - else: - - # set of facet keys from the universe - self.facethash = dict() + # set of facet keys from the universe + self.facethash = dict() - # not owned by a user by default (used for avatars) - self.owner = None + # not owned by a user by default (used for avatars) + self.owner = None - # no contents in here by default - self.contents = {} + # no contents in here by default + self.contents = {} - # parse out appropriate category and subkey names, add to list - if self.key.find(":") > 0: - # TODO(fungi) this can be removed once old_style Elements - # are no longer needed - self.category, self.subkey = self.key.split(":", 1) - elif self.key.find(".") > 0: - self.category, self.subkey = self.key.split(".", 1)[-2:] - else: - self.category = "other" - self.subkey = self.key - if self.category not in self.universe.categories: - self.universe.categories[self.category] = {} + if self.key.find(".") > 0: + self.group, self.subkey = self.key.split(".")[-2:] + else: + self.group = "other" + self.subkey = self.key + if self.group not in self.universe.groups: + self.universe.groups[self.group] = {} - # get an appropriate origin - if not origin: - self.universe.add_category(self.category) - origin = self.universe.files[ - self.universe.origins[self.category]["fallback"]] + # get an appropriate origin + if not origin: + self.universe.add_group(self.group) + origin = self.universe.files[ + self.universe.origins[self.group]["fallback"]] # record or reset a pointer to the origin file self.origin = self.universe.files[origin.source] # add or replace this element in the universe self.universe.contents[self.key] = self - self.universe.categories[self.category][self.subkey] = self + self.universe.groups[self.group][self.subkey] = self def reload(self): """Create a new element and replace this one.""" - Element(self.key, self.universe, self.origin, old_style=self.old_style) + Element(self.key, self.universe, self.origin) del(self) def destroy(self): """Remove an element from the universe and destroy it.""" - if self.old_style: - del self.origin.data[self.key] - else: - for facet in dict(self.facethash): - self.remove_facet(facet) - del self.universe.categories[self.category][self.subkey] + for facet in dict(self.facethash): + self.remove_facet(facet) + del self.universe.groups[self.group][self.subkey] del self.universe.contents[self.key] del self def facets(self): """Return a list of non-inherited facets for this element.""" - if self.old_style: - try: - return self.origin.data[self.key].keys() - except (AttributeError, KeyError): - return [] - else: - return self.facethash + return self.facethash def has_facet(self, facet): """Return whether the non-inherited facet exists.""" @@ -113,9 +85,7 @@ class Element: def remove_facet(self, facet): """Remove a facet from the element.""" - if self.old_style and self.has_facet(facet): - del self.origin.data[self.key][facet] - elif ".".join((self.key, facet)) in self.origin.data: + if ".".join((self.key, facet)) in self.origin.data: del self.origin.data[".".join((self.key, facet))] if facet in self.facethash: del self.facethash[facet] @@ -141,10 +111,7 @@ class Element: if default is None: default = "" try: - if self.old_style: - return self.origin.data[self.key][facet] - else: - return self.origin.data[".".join((self.key, facet))] + return self.origin.data[".".join((self.key, facet))] except (KeyError, TypeError): pass if self.has_facet("inherit"): @@ -162,21 +129,25 @@ class Element: # updated data from files raise PermissionError("Altering elements in read-only files is " "disallowed") + # Coerce some values to appropriate data types + # TODO(fungi) Move these to a separate validation mechanism if facet in ["loglevel"]: value = int(value) elif facet in ["administrator"]: value = bool(value) - if not self.has_facet(facet) or not self.get(facet) == value: - if self.old_style: - if self.key not in self.origin.data: - self.origin.data[self.key] = {} - self.origin.data[self.key][facet] = value - else: - node = ".".join((self.key, facet)) - self.origin.data[node] = value - self.facethash[facet] = self.origin.data[node] + + # The canonical node for this facet within its origin + node = ".".join((self.key, facet)) + + if node not in self.origin.data or self.origin.data[node] != value: + # Be careful to only update the origin's contents when required, + # since that affects whether the backing file gets written + self.origin.data[node] = value self.origin.modified = True + # Make sure this facet is included in the element's facets + self.facethash[facet] = self.origin.data[node] + def append(self, facet, value): """Append value to a list.""" newlist = self.get(facet) @@ -214,8 +185,8 @@ class Element: 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 self.universe.categories["command"].values(): + # has to be in the commands group + if command not in self.universe.groups["command"].values(): result = False # avatars of administrators can run any command @@ -309,9 +280,9 @@ class Element: def portals(self): """Map the portal directions for an area to neighbors.""" portals = {} - if re.match(r"""^area:-?\d+,-?\d+,-?\d+$""", self.key): + if re.match(r"""^area\.-?\d+,-?\d+,-?\d+$""", self.key): coordinates = [(int(x)) - for x in self.key.split(":")[1].split(",")] + for x in self.key.split(".")[-1].split(",")] offsets = dict( (x, self.universe.contents["mudpy.movement.%s" % x].get("vector") @@ -319,7 +290,7 @@ class Element: for portal in self.get("gridlinks"): adjacent = map(lambda c, o: c + o, coordinates, offsets[portal]) - neighbor = "area:" + ",".join( + neighbor = "area." + ",".join( [(str(x)) for x in adjacent] ) if neighbor in self.universe.contents: @@ -353,7 +324,7 @@ class Universe: def __init__(self, filename="", load=False): """Initialize the universe.""" - self.categories = {} + self.groups = {} self.contents = {} self.directions = set() self.loading = False @@ -409,18 +380,18 @@ class Universe: # start loading from the initial file mudpy.data.Data(self.filename, self) - # load default storage locations for categories + # load default storage locations for groups if hasattr(self, "contents") and "mudpy.filing" in self.contents: self.origins.update(self.contents["mudpy.filing"].get( - "categories", {})) + "groups", {})) - # add some builtin categories we know we'll need - for category in ("account", "actor", "internal"): - self.add_category(category) + # add some builtin groups we know we'll need + for group in ("account", "actor", "internal"): + self.add_group(group) # make a list of inactive avatars inactive_avatars = [] - for account in self.categories.get("account", {}).values(): + for account in self.groups.get("account", {}).values(): for avatar in account.get("avatars"): try: inactive_avatars.append(self.contents[avatar]) @@ -515,18 +486,18 @@ class Universe: def get_time(self): """Convenience method to get the elapsed time counter.""" - return self.categories["internal"]["counters"].get("elapsed") + return self.groups["internal"]["counters"].get("elapsed") - def add_category(self, category, fallback=None): - """Set up category tracking/metadata.""" - if category not in self.origins: - self.origins[category] = {} + def add_group(self, group, fallback=None): + """Set up group tracking/metadata.""" + if group not in self.origins: + self.origins[group] = {} if not fallback: fallback = mudpy.data.find_file( - ".".join((category, "yaml")), universe=self) - if "fallback" not in self.origins[category]: - self.origins[category]["fallback"] = fallback - flags = self.origins[category].get("flags", None) + ".".join((group, "yaml")), universe=self) + if "fallback" not in self.origins[group]: + self.origins[group]["fallback"] = fallback + flags = self.origins[group].get("flags", None) if fallback not in self.files: mudpy.data.Data(fallback, self, flags=flags) @@ -945,7 +916,7 @@ class User: """Instantiate a new, unconfigured avatar for this user.""" counter = 0 while ("avatar_%s_%s" % (self.account.get("name"), counter) - in universe.categories.get("actor", {}).keys()): + in universe.groups.get("actor", {}).keys()): counter += 1 self.avatar = Element( "actor.avatar_%s_%s" % (self.account.get("name"), counter), @@ -1400,31 +1371,31 @@ def on_pulse(): user.pulse() # add an element for counters if it doesn't exist - if "counters" not in universe.categories.get("internal", {}): + if "counters" not in universe.groups.get("internal", {}): Element("internal.counters", universe) # update the log every now and then - if not universe.categories["internal"]["counters"].get("mark"): + if not universe.groups["internal"]["counters"].get("mark"): log(str(len(universe.userlist)) + " connection(s)") - universe.categories["internal"]["counters"].set( + universe.groups["internal"]["counters"].set( "mark", universe.contents["mudpy.timing"].get("status") ) else: - universe.categories["internal"]["counters"].set( - "mark", universe.categories["internal"]["counters"].get( + universe.groups["internal"]["counters"].set( + "mark", universe.groups["internal"]["counters"].get( "mark" ) - 1 ) # periodically save everything - if not universe.categories["internal"]["counters"].get("save"): + if not universe.groups["internal"]["counters"].get("save"): universe.save() - universe.categories["internal"]["counters"].set( + universe.groups["internal"]["counters"].set( "save", universe.contents["mudpy.timing"].get("save") ) else: - universe.categories["internal"]["counters"].set( - "save", universe.categories["internal"]["counters"].get( + universe.groups["internal"]["counters"].set( + "save", universe.groups["internal"]["counters"].get( "save" ) - 1 ) @@ -1433,8 +1404,8 @@ def on_pulse(): time.sleep(universe.contents["mudpy.timing"].get("increment")) # increase the elapsed increment counter - universe.categories["internal"]["counters"].set( - "elapsed", universe.categories["internal"]["counters"].get( + universe.groups["internal"]["counters"].set( + "elapsed", universe.groups["internal"]["counters"].get( "elapsed", 0 ) + 1 ) @@ -1510,7 +1481,7 @@ def get_menu(state, error=None, choices=None): def menu_echo_on(state): """True if echo is on, false if it is off.""" - return universe.categories["menu"][state].get("echo", True) + return universe.groups["menu"][state].get("echo", True) def get_echo_message(state): @@ -1523,7 +1494,7 @@ def get_echo_message(state): def get_default_menu_choice(state): """Return the default choice for a menu.""" - return universe.categories["menu"][state].get("default") + return universe.groups["menu"][state].get("default") def get_formatted_default_menu_choice(state): @@ -1543,7 +1514,7 @@ def get_menu_description(state, error): # try to get an error message matching the condition # and current state - description = universe.categories[ + description = universe.groups[ "menu"][state].get("error_" + error) if not description: description = "That is not a valid choice..." @@ -1553,7 +1524,7 @@ def get_menu_description(state, error): else: # try to get a menu description for the current state - description = universe.categories["menu"][state].get("description") + description = universe.groups["menu"][state].get("description") # return the description or error message if description: @@ -1563,7 +1534,7 @@ def get_menu_description(state, error): def get_menu_prompt(state): """Try to get a prompt, if it was defined.""" - prompt = universe.categories["menu"][state].get("prompt") + prompt = universe.groups["menu"][state].get("prompt") if prompt: prompt += " " return prompt @@ -1571,7 +1542,7 @@ def get_menu_prompt(state): def get_menu_choices(user): """Return a dict of choice:meaning.""" - menu = universe.categories["menu"][user.state] + menu = universe.groups["menu"][user.state] create_choices = menu.get("create") if create_choices: choices = eval(create_choices) @@ -1582,7 +1553,7 @@ def get_menu_choices(user): creates = {} for facet in menu.facets(): if facet.startswith("demand_") and not eval( - universe.categories["menu"][user.state].get(facet) + universe.groups["menu"][user.state].get(facet) ): ignores.append(facet.split("_", 2)[1]) elif facet.startswith("create_"): @@ -1615,17 +1586,17 @@ def get_formatted_menu_choices(state, choices): def get_menu_branches(state): """Return a dict of choice:branch.""" branches = {} - for facet in universe.categories["menu"][state].facets(): + for facet in universe.groups["menu"][state].facets(): if facet.startswith("branch_"): branches[ facet.split("_", 2)[1] - ] = universe.categories["menu"][state].get(facet) + ] = universe.groups["menu"][state].get(facet) return branches def get_default_branch(state): """Return the default branch.""" - return universe.categories["menu"][state].get("branch") + return universe.groups["menu"][state].get("branch") def get_choice_branch(user, choice): @@ -1642,17 +1613,17 @@ def get_choice_branch(user, choice): def get_menu_actions(state): """Return a dict of choice:branch.""" actions = {} - for facet in universe.categories["menu"][state].facets(): + for facet in universe.groups["menu"][state].facets(): if facet.startswith("action_"): actions[ facet.split("_", 2)[1] - ] = universe.categories["menu"][state].get(facet) + ] = universe.groups["menu"][state].get(facet) return actions def get_default_action(state): """Return the default action.""" - return universe.categories["menu"][state].get("action") + return universe.groups["menu"][state].get("action") def get_choice_action(user, choice): @@ -1727,8 +1698,8 @@ def handler_entering_account_name(user): user.error = "bad_name" # if that account exists, time to request a password - elif name in universe.categories.get("account", {}): - user.account = universe.categories["account"][name] + elif name in universe.groups.get("account", {}): + user.account = universe.groups["account"][name] user.state = "checking_password" # otherwise, this could be a brand new user @@ -1876,8 +1847,8 @@ def handler_active(user): command_name = command_name.lower() # the command matches a command word for which we have data - if command_name in universe.categories["command"]: - command = universe.categories["command"][command_name] + if command_name in universe.groups["command"]: + command = universe.groups["command"][command_name] else: command = None @@ -1944,8 +1915,8 @@ def command_help(actor, parameters): if parameters and actor.owner: # is the command word one for which we have data? - if parameters in universe.categories["command"]: - command = universe.categories["command"][parameters] + if parameters in universe.groups["command"]: + command = universe.groups["command"][parameters] else: command = None @@ -1973,8 +1944,8 @@ def command_help(actor, parameters): if see_also: really_see_also = "" for item in see_also: - if item in universe.categories["command"]: - command = universe.categories["command"][item] + if item in universe.groups["command"]: + command = universe.groups["command"][item] if actor.can_run(command): if really_see_also: really_see_also += ", " @@ -1995,10 +1966,10 @@ def command_help(actor, parameters): # give a sorted list of commands with descriptions if provided output = "These are the commands available to you:$(eol)$(eol)" - sorted_commands = list(universe.categories["command"].keys()) + sorted_commands = list(universe.groups["command"].keys()) sorted_commands.sort() for item in sorted_commands: - command = universe.categories["command"][item] + command = universe.groups["command"][item] if actor.can_run(command): description = command.get("description") if not description: @@ -2132,15 +2103,15 @@ def command_show(actor, parameters): if not parameters: message = "What do you want to show?" elif arguments[0] == "time": - message = universe.categories["internal"]["counters"].get( + message = universe.groups["internal"]["counters"].get( "elapsed" ) + " increments elapsed since the world was created." - elif arguments[0] == "categories": - message = "These are the element categories:$(eol)" - categories = list(universe.categories.keys()) - categories.sort() - for category in categories: - message += "$(eol) $(grn)" + category + "$(nrm)" + elif arguments[0] == "groups": + message = "These are the element groups:$(eol)" + groups = list(universe.groups.keys()) + groups.sort() + for group in groups: + message += "$(eol) $(grn)" + group + "$(nrm)" elif arguments[0] == "files": message = "These are the current files containing the universe:$(eol)" filenames = sorted(universe.files) @@ -2154,22 +2125,22 @@ def command_show(actor, parameters): if universe.files[filename].flags: message += (" $(yel)[%s]$(nrm)" % ",".join(universe.files[filename].flags)) - elif arguments[0] == "category": + elif arguments[0] == "group": if len(arguments) != 2: - message = "You must specify one category." - elif arguments[1] in universe.categories: + message = "You must specify one group." + elif arguments[1] in universe.groups: message = ('These are the elements in the "' + arguments[1] - + '" category:$(eol)') + + '" group:$(eol)') elements = [ ( - universe.categories[arguments[1]][x].key - ) for x in universe.categories[arguments[1]].keys() + universe.groups[arguments[1]][x].key + ) for x in universe.groups[arguments[1]].keys() ] elements.sort() for element in elements: message += "$(eol) $(grn)" + element + "$(nrm)" else: - message = 'Category "' + arguments[1] + '" does not exist.' + message = 'Group "' + arguments[1] + '" does not exist.' elif arguments[0] == "file": if len(arguments) != 2: message = "You must specify one file." @@ -2191,12 +2162,8 @@ def command_show(actor, parameters): + '"):$(eol)') facets = element.facets() for facet in sorted(facets): - if element.old_style: - message += ("$(eol) $(grn)%s: $(red)%s$(nrm)" % - (facet, escape_macros(element.get(facet)))) - else: - message += ("$(eol) $(grn)%s: $(red)%s$(nrm)" % - (facet, str(facets[facet]))) + message += ("$(eol) $(grn)%s: $(red)%s$(nrm)" % + (facet, str(facets[facet]))) else: message = 'Element "' + arguments[1] + '" does not exist.' elif arguments[0] == "result": @@ -2270,7 +2237,7 @@ def command_create(actor, parameters): ' Warning: "' + filename + '" is not yet ' "included in any other file and will not be read " "on startup unless this is remedied.") - Element(element, universe, filename, old_style=True) + Element(element, universe, filename) log(logline, 6) elif len(arguments) > 2: message = "You can only specify an element and a filename."