From 80befa96b6010ad59c76bbbff3e8be7605cb6e8c Mon Sep 17 00:00:00 2001 From: Griatch Date: Wed, 31 Aug 2016 21:02:15 +0200 Subject: [PATCH] Added an /update switch and a corresponding update command to the typeclass switch system, this allows to soft-update a typeclass and re-run only its at_object_creation, which seems to be the most common use-case. --- evennia/commands/default/building.py | 26 +++++++++++++++++++------- evennia/typeclasses/models.py | 17 ++++++++++------- 2 files changed, 29 insertions(+), 14 deletions(-) diff --git a/evennia/commands/default/building.py b/evennia/commands/default/building.py index c5e66655cb..e5b6baf5c2 100644 --- a/evennia/commands/default/building.py +++ b/evennia/commands/default/building.py @@ -1563,11 +1563,14 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS): @type '' @parent '' @swap - this is a shorthand for using /force/reset flags. + @update - this is a shorthand for using the /force/reload flag. Switch: - show - display the current typeclass of object - reset - clean out *all* the attributes on the object - - basically making this a new clean object. + show - display the current typeclass of object (default) + update - *only* re-run at_object_creation on this object + meaning locks or other properties set later may remain. + reset - clean out *all* the attributes and properties on the + object - basically making this a new clean object. force - change to the typeclass also if the object already has a typeclass of the same name. Example: @@ -1580,7 +1583,7 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS): of the new typeclass will be run on the object. If you have clashing properties on the old class, use /reset. By default you are protected from changing to a typeclass of the same name as the - one you already have, use /force to override this protection. + one you already have - use /force to override this protection. The given typeclass must be identified by its location using python dot-notation pointing to the correct module and class. If @@ -1592,7 +1595,7 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS): """ key = "@typeclass" - aliases = ["@type", "@parent", "@swap"] + aliases = ["@type", "@parent", "@swap", "@update"] locks = "cmd:perm(typeclass) or perm(Builders)" help_category = "Building" @@ -1624,6 +1627,9 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS): if self.cmdstring == "@swap": self.switches.append("force") self.switches.append("reset") + elif self.cmdstring == "@update": + self.switches.append("force") + self.switches.append("update") if not obj.access(caller, 'edit'): caller.msg("You are not allowed to do that.") @@ -1637,11 +1643,14 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS): if is_same and not 'force' in self.switches: string = "%s already has the typeclass '%s'. Use /force to override." % (obj.name, new_typeclass) else: + update = "update" in self.switches reset = "reset" in self.switches + hooks = "at_object_creation" if update else "all" old_typeclass_path = obj.typeclass_path # we let this raise exception if needed - obj.swap_typeclass(new_typeclass, clean_attributes=reset, clean_cmdsets=reset) + obj.swap_typeclass(new_typeclass, clean_attributes=reset, + clean_cmdsets=reset, run_start_hooks=hooks) if is_same: string = "%s updated its existing typeclass (%s).\n" % (obj.name, obj.path) @@ -1649,7 +1658,10 @@ class CmdTypeclass(COMMAND_DEFAULT_CLASS): string = "%s changed typeclass from %s to %s.\n" % (obj.name, old_typeclass_path, obj.typeclass_path) - string += "Creation hooks were run." + if update: + string += "Only the at_object_creation hook was run (update mode)." + else: + string += "All object creation hooks were run." if reset: string += " All old attributes where deleted before the swap." else: diff --git a/evennia/typeclasses/models.py b/evennia/typeclasses/models.py index c9b14bb75b..ed52d9570d 100644 --- a/evennia/typeclasses/models.py +++ b/evennia/typeclasses/models.py @@ -414,7 +414,7 @@ class TypedObject(SharedMemoryModel): return any(hasattr(cls, "path") and cls.path in typeclass for cls in self.__class__.mro()) def swap_typeclass(self, new_typeclass, clean_attributes=False, - run_start_hooks=True, no_default=True, clean_cmdsets=False): + run_start_hooks="all", no_default=True, clean_cmdsets=False): """ This performs an in-situ swap of the typeclass. This means that in-game, this object will suddenly be something else. @@ -438,16 +438,16 @@ class TypedObject(SharedMemoryModel): sure nothing in the new typeclass clashes with the old one. If you supply a list, only those named attributes will be cleared. - run_start_hooks (bool, optional): Trigger the start hooks - of the object, as if it was created for the first time. + run_start_hooks (str or None, optional): This is either None, + to not run any hooks, "all" to run all hooks defined by + at_first_start, or a string giving the name of the hook + to run (for example 'at_object_creation'). This will + always be called without arguments. no_default (bool, optiona): If set, the swapper will not allow for swapping to a default typeclass in case the given one fails for some reason. Instead the old one will be preserved. clean_cmdsets (bool, optional): Delete all cmdsets on the object. - Returns: - result (bool): True/False depending on if the swap worked - or not. """ @@ -483,9 +483,12 @@ class TypedObject(SharedMemoryModel): self.cmdset.clear() self.cmdset.remove_default() - if run_start_hooks: + if run_start_hooks == 'all': # fake this call to mimic the first save self.at_first_save() + elif run_start_hooks: + # a custom hook-name to call. + getattr(self, run_start_hooks)() # # Lock / permission methods