Example #1
0
    def __init__(self):
        """
        Creates a statement handler instance. Loads statements.
        """
        # load function sets
        action_func_set_class = class_from_module(settings.ACTION_FUNC_SET)
        self.action_func_set = action_func_set_class()

        condition_func_set_class = class_from_module(settings.CONDITION_FUNC_SET)
        self.condition_func_set = condition_func_set_class()

        skill_func_set_class = class_from_module(settings.SKILL_FUNC_SET)
        self.skill_func_set = skill_func_set_class()
Example #2
0
    def open_parent_menu(self):
        """Open the parent menu, using `self.parents`.

        Note:
            You probably don't need to call this method directly,
            since the caller can go back to the parent menu using the
            `keys_go_back` automatically.

        """
        parents = list(self.parents)
        if parents:
            parent_class, parent_obj, parent_keys = parents[-1]
            del parents[-1]

            if self.caller.cmdset.has(BuildingMenuCmdSet):
                self.caller.cmdset.remove(BuildingMenuCmdSet)

            try:
                menu_class = class_from_module(parent_class)
            except Exception:
                log_trace("BuildingMenu: attempting to load class {} failed".format(
                    repr(parent_class)))
                return

            # Create the parent menu
            try:
                building_menu = menu_class(self.caller, parent_obj,
                                           keys=parent_keys, parents=tuple(parents))
            except Exception:
                log_trace("An error occurred while creating building menu {}".format(
                    repr(parent_class)))
                return
            else:
                return building_menu.open()
Example #3
0
    def add_channel(self, channel):
        """
        Add an individual channel to the handler. This should be
        called whenever a new channel is created.

        Args:
            channel (Channel): The channel to add.

        Notes:
            To remove a channel, simply delete the channel object and
            run self.update on the handler. This should usually be
            handled automatically by one of the deletion methos of
            the Channel itself.

        """
        global _CHANNEL_COMMAND_CLASS
        if not _CHANNEL_COMMAND_CLASS:
            _CHANNEL_COMMAND_CLASS = class_from_module(settings.CHANNEL_COMMAND_CLASS)

        # map the channel to a searchable command
        cmd = _CHANNEL_COMMAND_CLASS(
                             key=channel.key.strip().lower(),
                             aliases=channel.aliases.all(),
                             locks="cmd:all();%s" % channel.locks,
                             help_category="Channel names",
                             obj=channel,
                             arg_regex=r"\s.*?|/history.*?",
                             is_channel=True)
        # format the help entry
        key = channel.key
        cmd.__doc__ = cmd.__doc__.format(channelkey=key,
                                         lower_channelkey=key.strip().lower(),
                                         channeldesc=channel.attributes.get("desc", default="").strip())
        self.cached_channel_cmds.append(cmd)
        self.cached_cmdsets = {}
Example #4
0
def create_channel(key, aliases=None, desc=None,
                   locks=None, keep_log=True,
                   typeclass=None):
    """
    Create A communication Channel. A Channel serves as a central
    hub for distributing Msgs to groups of people without
    specifying the receivers explicitly. Instead players may
    'connect' to the channel and follow the flow of messages. By
    default the channel allows access to all old messages, but
    this can be turned off with the keep_log switch.

    key - this must be unique.
    aliases - list of alternative (likely shorter) keynames.
    locks - lock string definitions
    """
    typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # create new instance
    new_channel = typeclass(db_key=key)

    # store call signature for the signal
    new_channel._createdict = {"key":key, "aliases":aliases,
            "desc":desc, "locks":locks, "keep_log":keep_log}

    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict can be
    # used.
    new_channel.save()
    return new_channel
Example #5
0
def create_object(typeclass=None, key=None, location=None,
                  home=None, permissions=None, locks=None,
                  aliases=None, tags=None, destination=None, report_to=None, nohome=False):
    """

    Create a new in-game object.

    keywords:
        typeclass - class or python path to a typeclass
        key - name of the new object. If not set, a name of #dbref will be set.
        home - obj or #dbref to use as the object's home location
        permissions - a comma-separated string of permissions
        locks - one or more lockstrings, separated by semicolons
        aliases - a list of alternative keys
        tags - a list of tag keys (using no category)
        destination - obj or #dbref to use as an Exit's target

        nohome - this allows the creation of objects without a default home location;
                 only used when creating the default location itself or during unittests
    """
    global _ObjectDB
    if not _ObjectDB:
        from evennia.objects.models import ObjectDB as _ObjectDB


    typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # Setup input for the create command. We use ObjectDB as baseclass here
    # to give us maximum freedom (the typeclasses will load
    # correctly when each object is recovered).

    location = dbid_to_obj(location, _ObjectDB)
    destination = dbid_to_obj(destination, _ObjectDB)
    home = dbid_to_obj(home, _ObjectDB)
    if not home:
        try:
            home = dbid_to_obj(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None
        except _ObjectDB.DoesNotExist:
            raise _ObjectDB.DoesNotExist("settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." %
                                         settings.DEFAULT_HOME)

    # create new instance
    new_object = typeclass(db_key=key, db_location=location,
                              db_destination=destination, db_home=home,
                              db_typeclass_path=typeclass.path)
    # store the call signature for the signal
    new_object._createdict = {"key":key, "location":location, "destination":destination,
                              "home":home, "typeclass":typeclass.path, "permissions":permissions,
                              "locks":locks, "aliases":aliases, "tags": tags, "destination":destination,
                              "report_to":report_to, "nohome":nohome}
    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict can be
    # used.
    new_object.save()
    return new_object
Example #6
0
 def load_classes(self):
     """
     Add all typeclasses from the typeclass path.
     """
     for key in self.module_dict:
         if self.class_dict.has_key(key):
             continue
         cls = class_from_module(self.module_dict[key])
         self.class_dict[key] = cls
         self.trigger_dict[key] = cls.get_event_trigger_types()
Example #7
0
def register_events(path_or_typeclass):
    """
    Register the events in this typeclass.

    Args:
        path_or_typeclass (str or type): the Python path leading to the
                class containing events, or the class itself.

    Returns:
        The typeclass itself.

    Notes:
        This function will read events from the `_events` class variable
        defined in the typeclass given in parameters.  It will add
        the events, either to the script if it exists, or to some
        temporary storage, waiting for the script to be initialized.

    """
    if isinstance(path_or_typeclass, basestring):
        typeclass = class_from_module(path_or_typeclass)
    else:
        typeclass = path_or_typeclass

    typeclass_name = typeclass.__module__ + "." + typeclass.__name__
    try:
        storage = ScriptDB.objects.get(db_key="event_handler")
        assert storage.is_active
        assert storage.ndb.events is not None
    except (ScriptDB.DoesNotExist, AssertionError):
        storage = EVENTS

    # If the script is started, add the event directly.
    # Otherwise, add it to the temporary storage.
    for name, tup in getattr(typeclass, "_events", {}).items():
        if len(tup) == 4:
            variables, help_text, custom_call, custom_add = tup
        elif len(tup) == 3:
            variables, help_text, custom_call = tup
            custom_add = None
        elif len(tup) == 2:
            variables, help_text = tup
            custom_call = None
            custom_add = None
        else:
            variables = help_text = custom_call = custom_add = None

        if isinstance(storage, list):
            storage.append((typeclass_name, name, variables, help_text, custom_call, custom_add))
        else:
            storage.add_event(typeclass_name, name, variables, help_text, custom_call, custom_add)

    return typeclass
Example #8
0
def create_channel(
    key, aliases=None, desc=None, locks=None, keep_log=True, typeclass=None, tags=None
):
    """
    Create A communication Channel. A Channel serves as a central hub
    for distributing Msgs to groups of people without specifying the
    receivers explicitly. Instead accounts may 'connect' to the channel
    and follow the flow of messages. By default the channel allows
    access to all old messages, but this can be turned off with the
    keep_log switch.

    Args:
        key (str): This must be unique.

    Keyword Args:
        aliases (list of str): List of alternative (likely shorter) keynames.
        desc (str): A description of the channel, for use in listings.
        locks (str): Lockstring.
        keep_log (bool): Log channel throughput.
        typeclass (str or class): The typeclass of the Channel (not
            often used).
        tags (list): A list of tags or tuples `(tag, category)`.

    Returns:
        channel (Channel): A newly created channel.

    """
    typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS

    if isinstance(typeclass, str):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # create new instance
    new_channel = typeclass(db_key=key)

    # store call signature for the signal
    new_channel._createdict = dict(
        key=key, aliases=aliases, desc=desc, locks=locks, keep_log=keep_log, tags=tags
    )

    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict can be
    # used.
    new_channel.save()

    signals.SIGNAL_CHANNEL_POST_CREATE.send(sender=new_channel)

    return new_channel
Example #9
0
    def load_data(self):
        """
        This delayed import avoids trying to load Scripts before they are
        initialized.

        """
        if self.typeclass_storage is None:
            self.typeclass_storage = {}
            for key, data in self.loaded_data.items():
                try:
                    typeclass = data.get('typeclass', settings.BASE_SCRIPT_TYPECLASS)
                    self.typeclass_storage[key] = class_from_module(typeclass)
                except ImportError as err:
                    logger.log_err(
                            f"GlobalScriptContainer could not start global script {key}: {err}")
Example #10
0
    def restore(caller):
        """Restore the building menu for the caller.

        Args:
            caller (Account or Object): the caller.

        Note:
            This method should be automatically called if a menu is
            saved in the caller, but the object itself cannot be found.

        """
        menu = caller.db._building_menu
        if menu:
            class_name = menu.get("class")
            if not class_name:
                log_err(
                    "BuildingMenu: on caller {}, a persistent attribute holds building menu data, but no class could be found to restore the menu"
                    .format(caller))
                return

            try:
                menu_class = class_from_module(class_name)
            except Exception:
                log_trace(
                    "BuildingMenu: attempting to load class {} failed".format(
                        repr(class_name)))
                return

            # Create the menu
            obj = menu.get("obj")
            keys = menu.get("keys")
            title = menu.get("title", "")
            parents = menu.get("parents")
            persistent = menu.get("persistent", False)
            try:
                building_menu = menu_class(caller,
                                           obj,
                                           title=title,
                                           keys=keys,
                                           parents=parents,
                                           persistent=persistent)
            except Exception:
                log_trace(
                    "An error occurred while creating building menu {}".format(
                        repr(class_name)))
                return

            return building_menu
Example #11
0
    def open_submenu(self, submenu_class, submenu_obj, parent_keys=None):
        """
        Open a sub-menu, closing the current menu and opening the new one.

        Args:
            submenu_class (str): the submenu class as a Python path.
            submenu_obj (Object): the object to give to the submenu.
            parent_keys (list of str, optional): the parent keys when
                    the submenu is closed.

        Note:
            When the user enters `@` in the submenu, she will go back to
            the current menu, with the `parent_keys` set as its keys.
            Therefore, you should set it on the keys of the choice that
            should be opened when the user leaves the submenu.

        Returns:
            new_menu (BuildingMenu): the new building menu or None.

        """
        parent_keys = parent_keys or []
        parents = list(self.parents)
        parents.append((type(self).__module__ + "." + type(self).__name__,
                        self.obj, parent_keys))
        if self.caller.cmdset.has(BuildingMenuCmdSet):
            self.caller.cmdset.remove(BuildingMenuCmdSet)

        # Shift to the new menu
        try:
            menu_class = class_from_module(submenu_class)
        except Exception:
            log_trace(
                "BuildingMenu: attempting to load class {} failed".format(
                    repr(submenu_class)))
            return

        # Create the submenu
        try:
            building_menu = menu_class(self.caller,
                                       submenu_obj,
                                       parents=parents)
        except Exception:
            log_trace(
                "An error occurred while creating building menu {}".format(
                    repr(submenu_class)))
            return
        else:
            return building_menu.open()
Example #12
0
class AccessHandler:
    """
    Base class to use for .acl lazy property on many things. This is a pretty useless class on its own - subclass
    and reimplement its methods to get something useful out of it.
    """
    permissions = OrderedDict()
    identity_handlers = {key: class_from_module(path) for key, path in settings.ACL_IDENTITY_HANDLER_CLASSES.items()}

    def __init__(self, owner):
        self.owner = owner

    def render(self, looker):
        message = list()

    def check(self, accessor, permission):
        permission = permission.strip().lower()

        def sort_acl(queryset):
            return sorted(queryset, key=lambda x: getattr(x, 'acl_sort', 0))

        def get_acl(deny=False):
            acl_entries = sort_acl(ACLEntry.objects.filter(resource=self.owner, deny=deny))
            gathered = set()
            for entry in acl_entries:
                if entry.identity.check_acl(accessor, entry.mode):
                    gathered += {str(perm) for perm in entry.permissions.all()}
                    if 'all' in gathered:
                        return True
                    if permission in gathered:
                        return True
            return False

        # first we check to see if access should be DENIED. This takes priority over allows.
        if get_acl(deny=True):
            return False
        return get_acl(deny=False)

    def find_identity(self, identity):
        if isinstance(identity, DefaultIdentity):
            return identity, ''
        if ':' not in identity:
            raise ValueError(f"Malformed Identity string: {identity}")
        identity_type, target = identity.split(':', 1)
        identity_type = identity_type.strip().lower()
        if not (handler := self.identity_handlers.get(identity_type, None)):
            raise ValueError(f"Unsupported Identity Type: {identity_type}. Supported: {self.identity_handlers.keys()}")
        if not (found := handler.find(target)):
            raise ValueError(f"Could not find Identity Type {identity_type}: {target}")
Example #13
0
def lazy_import_from_str(clsname):
    """
    Fetches a class from world.msgs.models by name and caches the reference. The idea here is mostly for preventing
    circular references with lazy imports.
    Args:
        clsname: The name of the proxy class in msgs.models to retrieve.

    Returns:
        The Msg proxy class we want to get from the name.
    """
    from evennia.utils.utils import class_from_module
    if clsname in _cached_lazy_imports:
        return _cached_lazy_imports[clsname]
    cls = class_from_module("world.msgs.models." + clsname)
    _cached_lazy_imports[clsname] = cls
    return cls
Example #14
0
    def after_data_loaded(self):
        """
        Init the character.
        """
        super(MudderyCharacter, self).after_data_loaded()

        # get level
        initial = False
        if not self.db.level:
            self.db.level = getattr(self.system, "level", 1)
            initial = True

        # friendly
        self.friendly = getattr(self.system, "friendly", 0)

        # skill's ai
        ai_choose_skill_class = class_from_module(settings.AI_CHOOSE_SKILL)
        self.ai_choose_skill = ai_choose_skill_class()

        # skill's gcd
        self.skill_gcd = GAME_SETTINGS.get("global_cd")
        self.auto_cast_skill_cd = GAME_SETTINGS.get("auto_cast_skill_cd")
        self.gcd_finish_time = 0

        # loop for auto cast skills
        self.auto_cast_loop = None

        # clear target
        self.target = None

        # set reborn time
        self.reborn_time = getattr(self.system, "reborn_time", 0)

        # A temporary character will be deleted after the combat finished.
        self.is_temp = False

        # update equipment positions
        self.reset_equip_positions()

        # load default skills
        self.load_default_skills()

        # load default objects
        self.load_default_objects()

        # refresh the character's properties.
        self.refresh_properties(not initial)
Example #15
0
    def get(self, key):
        """
        Get a typeclass recursively.
        """
        if key in self.class_dict:
            return self.class_dict[key]
        elif key in self.module_dict:
            cls = class_from_module(self.module_dict[key])
            if self.class_dict.has_key(key):
                if self.class_dict[key] != cls:
                    logger.log_infomsg("Typeclass %s is replaced by %s." % (key, cls))

            self.class_dict[key] = cls
            self.trigger_dict[key] = cls.get_event_trigger_types()
            return cls

        logger.log_errmsg("Can not find typeclass key: %s." % key)
Example #16
0
    def load_classes(self):
        """
        Add all typeclasses from the typeclass path.

        To prevent loop import, call this method later.
        """
        if self.all_loaded:
            return

        for key in self.module_dict:
            if key in self.class_dict:
                continue
            cls = class_from_module(self.module_dict[key])
            self.class_dict[key] = cls
            self.trigger_dict[key] = cls.get_event_trigger_types()

        self.all_loaded = True
Example #17
0
    def get(self, key):
        """
        Get a typeclass recursively.
        """
        if key in self.class_dict:
            return self.class_dict[key]
        elif key in self.module_dict:
            cls = class_from_module(self.module_dict[key])
            if key in self.class_dict:
                if self.class_dict[key] != cls:
                    logger.log_infomsg("Typeclass %s is replaced by %s." % (key, cls))

            self.class_dict[key] = cls
            self.trigger_dict[key] = cls.get_event_trigger_types()
            return cls

        logger.log_errmsg("Can not find typeclass key: %s." % key)
Example #18
0
    def after_data_loaded(self):
        """
        Init the character.
        """
        super(MudderyCharacter, self).after_data_loaded()

        # get level
        if not self.db.level:
            self.db.level = getattr(self.dfield, "level", 1)

        # friendly
        self.friendly = getattr(self.dfield, "friendly", 0)
        
        # skill's ai
        ai_choose_skill_class = class_from_module(settings.AI_CHOOSE_SKILL)
        self.ai_choose_skill = ai_choose_skill_class()

        # skill's gcd
        self.skill_gcd = GAME_SETTINGS.get("global_cd")
        self.auto_cast_skill_cd = GAME_SETTINGS.get("auto_cast_skill_cd")
        self.gcd_finish_time = 0
        
        # loop for auto cast skills
        self.auto_cast_loop = None

        # clear target
        self.target = None

        # set reborn time
        self.reborn_time = getattr(self.dfield, "reborn_time", 0)

        # A temporary character will be deleted after the combat finished.
        self.is_temp = False

        # update equipment positions
        self.reset_equip_positions()

        # load default skills
        self.load_default_skills()

        # load default objects
        self.load_default_objects()

        # refresh data
        self.refresh_data()
Example #19
0
 def set_class_from_typeclass(self, typeclass_path=None):
     if typeclass_path:
         try:
             self.__class__ = class_from_module(
                 typeclass_path, defaultpaths=settings.TYPECLASS_PATHS)
         except Exception:
             log_trace()
             try:
                 self.__class__ = class_from_module(
                     self.__settingsclasspath__)
             except Exception:
                 log_trace()
                 try:
                     self.__class__ = class_from_module(
                         self.__defaultclasspath__)
                 except Exception:
                     log_trace()
                     self.__class__ = self._meta.proxy_for_model or self.__class__
         finally:
             self.db_typeclass_path = typeclass_path
     elif self.db_typeclass_path:
         try:
             self.__class__ = class_from_module(self.db_typeclass_path)
         except Exception:
             log_trace()
             try:
                 self.__class__ = class_from_module(
                     self.__defaultclasspath__)
             except Exception:
                 log_trace()
                 self.__dbclass__ = self._meta.proxy_for_model or self.__class__
     else:
         self.db_typeclass_path = "%s.%s" % (self.__module__,
                                             self.__class__.__name__)
     # important to put this at the end since _meta is based on the set __class__
     try:
         self.__dbclass__ = self._meta.proxy_for_model or self.__class__
     except AttributeError:
         err_class = repr(self.__class__)
         self.__class__ = class_from_module(
             "evennia.objects.objects.DefaultObject")
         self.__dbclass__ = class_from_module(
             "evennia.objects.models.ObjectDB")
         self.db_typeclass_path = "evennia.objects.objects.DefaultObject"
         log_trace(
             "Critical: Class %s of %s is not a valid typeclass!\nTemporarily falling back to %s."
             % (err_class, self, self.__class__))
Example #20
0
    def move_to(self, screen, app=None, folder=None, db=None):
        """
        Move to another screen, not adding it to the screen tree.

        This method is used to change the current screen without putting
        the new one in the screen tree: the screen tree is a list of
        screens that were browsed, and is used to go back.  Some screens
        don't need to be put in the screen tree, like confirmation
        messages, error messages, and other such screens.  Most of
        the time, you will use the `next` method, that does the same
        thing but records the new screen in the screen tree.

        Args:
            screen (Screen class or str): the new screen as a class or
                    path leading to it.
            app (App, optional): the screen app.
            db (dict, optional): a dictionary of data to send to the new screen.

        Note:
            If `app` isn't specified, use the current screen's `app`.

        Returns:
            new_screen (Screen): the new screen object.

        """
        app = app or self.app
        if isinstance(screen, str):
            if "." not in screen: # We assume it means a relative import in the current module
                screen = type(app).__module__ + "." + screen

            screen = class_from_module(screen)
        self.close()
        new_screen = screen(self.obj, self.user, self.type, app)
        new_screen.db.clear()
        new_screen._save()
        new_screen._refresh_commands()

        # Before displaying the screen, add the optional data
        if db:
            new_screen.db.update(db)

        new_screen.open()
        new_screen.display()
        return new_screen
Example #21
0
def create_channel(key, aliases=None, desc=None,
                   locks=None, keep_log=True,
                   typeclass=None):
    """
    Create A communication Channel. A Channel serves as a central hub
    for distributing Msgs to groups of people without specifying the
    receivers explicitly. Instead players may 'connect' to the channel
    and follow the flow of messages. By default the channel allows
    access to all old messages, but this can be turned off with the
    keep_log switch.

    Args:
        key (str): This must be unique.

    Kwargs:
        aliases (list of str): List of alternative (likely shorter) keynames.
        desc (str): A description of the channel, for use in listings.
        locks (str): Lockstring.
        keep_log (bool): Log channel throughput.
        typeclass (str or class): The typeclass of the Channel (not
            often used).

    Returns:
        channel (Channel): A newly created channel.

    """
    typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # create new instance
    new_channel = typeclass(db_key=key)

    # store call signature for the signal
    new_channel._createdict = dict(key=key, aliases=aliases, desc=desc, locks=locks, keep_log=keep_log)

    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict can be
    # used.
    new_channel.save()
    return new_channel
Example #22
0
    def open_submenu(self, submenu_class, submenu_obj, parent_keys=None):
        """
        Open a sub-menu, closing the current menu and opening the new one.

        Args:
            submenu_class (str): the submenu class as a Python path.
            submenu_obj (Object): the object to give to the submenu.
            parent_keys (list of str, optional): the parent keys when
                    the submenu is closed.

        Note:
            When the user enters `@` in the submenu, she will go back to
            the current menu, with the `parent_keys` set as its keys.
            Therefore, you should set it on the keys of the choice that
            should be opened when the user leaves the submenu.

        Returns:
            new_menu (BuildingMenu): the new building menu or None.

        """
        parent_keys = parent_keys or []
        parents = list(self.parents)
        parents.append((type(self).__module__ + "." + type(self).__name__, self.obj, parent_keys))
        if self.caller.cmdset.has(BuildingMenuCmdSet):
            self.caller.cmdset.remove(BuildingMenuCmdSet)

        # Shift to the new menu
        try:
            menu_class = class_from_module(submenu_class)
        except Exception:
            log_trace("BuildingMenu: attempting to load class {} failed".format(repr(submenu_class)))
            return

        # Create the submenu
        try:
            building_menu = menu_class(self.caller, submenu_obj, parents=parents)
        except Exception:
            log_trace("An error occurred while creating building menu {}".format(repr(submenu_class)))
            return
        else:
            return building_menu.open()
Example #23
0
def create_channel(key,
                   aliases=None,
                   desc=None,
                   locks=None,
                   keep_log=True,
                   typeclass=None):
    """
    Create A communication Channel. A Channel serves as a central
    hub for distributing Msgs to groups of people without
    specifying the receivers explicitly. Instead players may
    'connect' to the channel and follow the flow of messages. By
    default the channel allows access to all old messages, but
    this can be turned off with the keep_log switch.

    key - this must be unique.
    aliases - list of alternative (likely shorter) keynames.
    locks - lock string definitions
    """
    typeclass = typeclass if typeclass else settings.BASE_CHANNEL_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # create new instance
    new_channel = typeclass(db_key=key)

    # store call signature for the signal
    new_channel._createdict = {
        "key": key,
        "aliases": aliases,
        "desc": desc,
        "locks": locks,
        "keep_log": keep_log
    }

    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict can be
    # used.
    new_channel.save()
    return new_channel
Example #24
0
    def use(self, user, screen=None, app_name=None, folder="app", db=None):
        """Use the computer.

        This method creates a CmdSet on the user, if the computer isn't
        already used.  It also prepares the first screen.

        """
        used = self.db.get("used")
        if used is user:
            user.msg("You already are using it.")
        elif used:
            user.msg("{} is already using it.".format(
                used.get_display_name(user)))
        elif user.cmdset.has("computer"):
            user.msg("It looks like you're already busy, isn't it?")
        else:
            # Add the CmdSet
            self.apps.load(user)
            if app_name:
                app = self.apps.get(app_name, folder)
            else:
                app = None
            if screen:
                Screen = class_from_module(screen)
            else:
                Screen = MainScreen
            self.db["used"] = user
            screen = Screen(self.obj, user, self, app)
            if "screen_tree" not in self.db:
                self.db["screen_tree"] = [
                    (type(screen).__module__ + "." + type(screen).__name__,
                     app_name, folder, None)
                ]
            if db:
                screen.db.update(db)
            screen._save()
            screen.open()
            screen.display()
            user.db._aven_using = self.obj
            user.cmdset.add("commands.high_tech.ComputerCmdSet",
                            permanent=True)
Example #25
0
    def func(self):
        """Main function for this command."""
        field_name, sep, obj_name = self.lhs.partition(" ")
        field_name = field_name.lower()
        operation = "get"
        if field_name.endswith("/add"):
            field_name = field_name[:-4]
            operation = "add"
        elif field_name.endswith("/del"):
            field_name = field_name[:-4]
            operation = "del"
        elif self.rhs:
            operation = "set"

        if not obj_name:
            obj_name = field_name
            field_name = ""

        if not obj_name:
            self.msg("Specify at least an object's name or #ID.")
            return

        # Search for the actual object
        objs = self.caller.search(obj_name, quiet=True)
        if not objs or len(objs) > 1:
            obj = self.caller.search(obj_name, global_search=True)
            if not obj:
                return
        else:
            obj = objs[0]

        # Get the representation value for this object type
        repr = getattr(type(obj), "repr", None)
        if repr is None:
            self.msg("This object has no representation to describe it.")
            return

        repr = class_from_module(repr)
        repr = repr(obj)
        repr.process(self.caller, field_name, self.rhs, operation)
Example #26
0
    def add(self, channel):
        """
        Add an individual channel to the handler. This is called
        whenever a new channel is created.

        Args:
            channel (Channel): The channel to add.

        Notes:
            To remove a channel, simply delete the channel object and
            run self.update on the handler. This should usually be
            handled automatically by one of the deletion methos of
            the Channel itself.

        """
        global _CHANNEL_COMMAND_CLASS
        if not _CHANNEL_COMMAND_CLASS:
            _CHANNEL_COMMAND_CLASS = class_from_module(
                settings.CHANNEL_COMMAND_CLASS)

        # map the channel to a searchable command
        cmd = _CHANNEL_COMMAND_CLASS(
            key=channel.key.strip().lower(),
            aliases=channel.aliases.all(),
            locks="cmd:all();%s" % channel.locks,
            help_category="Channel names",
            obj=channel,
            is_channel=True,
        )
        # format the help entry
        key = channel.key
        cmd.__doc__ = cmd.__doc__.format(
            channelkey=key,
            lower_channelkey=key.strip().lower(),
            channeldesc=channel.attributes.get("desc", default="").strip(),
        )
        self._cached_channel_cmds[channel] = cmd
        self._cached_channels[key] = channel
        self._cached_cmdsets = {}
Example #27
0
    def restore(caller):
        """Restore the building menu for the caller.

        Args:
            caller (Account or Object): the caller.

        Note:
            This method should be automatically called if a menu is
            saved in the caller, but the object itself cannot be found.

        """
        menu = caller.db._building_menu
        if menu:
            class_name = menu.get("class")
            if not class_name:
                log_err("BuildingMenu: on caller {}, a persistent attribute holds building menu "
                        "data, but no class could be found to restore the menu".format(caller))
                return

            try:
                menu_class = class_from_module(class_name)
            except Exception:
                log_trace("BuildingMenu: attempting to load class {} failed".format(repr(class_name)))
                return

            # Create the menu
            obj = menu.get("obj")
            keys = menu.get("keys")
            title = menu.get("title", "")
            parents = menu.get("parents")
            persistent = menu.get("persistent", False)
            try:
                building_menu = menu_class(caller, obj, title=title, keys=keys,
                                           parents=parents, persistent=persistent)
            except Exception:
                log_trace("An error occurred while creating building menu {}".format(repr(class_name)))
                return

            return building_menu
Example #28
0
    def back(self):
        """Go back in the screen tree.

        This method forces moving back in the previous screen.  The
        previous screen is either at the end of the screen tree, or
        one step above, depending on whether the current screen is
        in the screen tree.

        Returns:
            new_screen (Screen or None): the new screen in which the user now is.

        """
        previous = self.previous
        app = folder = None
        if previous:
            previous, app, folder, db = previous
            if isinstance(previous, str):
                previous = class_from_module(previous)

            self.close()
            if app and folder:
                app = self.type.apps.get(app, folder)

            previous = previous(self.obj, self.user, self.type, app)
            previous.db.clear()
            if db:
                previous.db.update(db)

            path = self.path
            tree = self.type.db.get("screen_tree", [])
            if tree and tree[-1][0] == path:
                del tree[-1]
            previous._save()
            previous._refresh_commands()
            previous.open()
            previous.display()
            return previous
        return None
Example #29
0
    def open_parent_menu(self):
        """Open the parent menu, using `self.parents`.

        Note:
            You probably don't need to call this method directly,
            since the caller can go back to the parent menu using the
            `keys_go_back` automatically.

        """
        parents = list(self.parents)
        if parents:
            parent_class, parent_obj, parent_keys = parents[-1]
            del parents[-1]

            if self.caller.cmdset.has(BuildingMenuCmdSet):
                self.caller.cmdset.remove(BuildingMenuCmdSet)

            try:
                menu_class = class_from_module(parent_class)
            except Exception:
                log_trace(
                    "BuildingMenu: attempting to load class {} failed".format(
                        repr(parent_class)))
                return

            # Create the parent menu
            try:
                building_menu = menu_class(self.caller,
                                           parent_obj,
                                           keys=parent_keys,
                                           parents=tuple(parents))
            except Exception:
                log_trace(
                    "An error occurred while creating building menu {}".format(
                        repr(parent_class)))
                return
            else:
                return building_menu.open()
Example #30
0
    def after_data_loaded(self):
        """
        Init the character.
        """
        super(MudderyCharacter, self).after_data_loaded()
        
        # skill's ai
        ai_choose_skill_class = class_from_module(settings.AI_CHOOSE_SKILL)
        self.ai_choose_skill = ai_choose_skill_class()

        # skill's gcd
        self.skill_gcd = GAME_SETTINGS.get("global_cd")
        self.auto_cast_skill_cd = GAME_SETTINGS.get("auto_cast_skill_cd")
        self.gcd_finish_time = 0
        
        # loop for auto cast skills
        self.auto_cast_loop = None

        # clear target
        self.target = None

        # set reborn time
        self.reborn_time = getattr(self.dfield, "reborn_time", 0)

        # A temporary character will be deleted after the combat finished.
        self.is_temp = False

        # update equipment positions
        self.reset_equip_positions()

        # load default skills
        self.load_default_skills()

        # load default objects
        self.load_default_objects()

        # refresh data
        self.refresh_data()
Example #31
0
 def set_class_from_typeclass(self, typeclass_path=None):
     if typeclass_path:
         try:
             self.__class__ = class_from_module(typeclass_path, defaultpaths=settings.TYPECLASS_PATHS)
         except Exception:
             log_trace()
             try:
                 self.__class__ = class_from_module(self.__settingsclasspath__)
             except Exception:
                 log_trace()
                 try:
                     self.__class__ = class_from_module(self.__defaultclasspath__)
                 except Exception:
                     log_trace()
                     self.__class__ = self._meta.proxy_for_model or self.__class__
         finally:
             self.db_typeclass_path = typeclass_path
     elif self.db_typeclass_path:
         try:
             self.__class__ = class_from_module(self.db_typeclass_path)
         except Exception:
             log_trace()
             try:
                 self.__class__ = class_from_module(self.__defaultclasspath__)
             except Exception:
                 log_trace()
                 self.__dbclass__ = self._meta.proxy_for_model or self.__class__
     else:
         self.db_typeclass_path = "%s.%s" % (self.__module__, self.__class__.__name__)
     # important to put this at the end since _meta is based on the set __class__
     try:
         self.__dbclass__ = self._meta.proxy_for_model or self.__class__
     except AttributeError:
         err_class = repr(self.__class__)
         self.__class__ = class_from_module("evennia.objects.objects.DefaultObject")
         self.__dbclass__ = class_from_module("evennia.objects.models.ObjectDB")
         self.db_typeclass_path = "evennia.objects.objects.DefaultObject"
         log_trace("Critical: Class %s of %s is not a valid typeclass!\nTemporarily falling back to %s." % (err_class, self, self.__class__))
 def create_system(self, sys_key, system_typeclass, category_typeclass,
                   channel_typeclass, command_class):
     sys_typeclass = class_from_module(system_typeclass)
     new_system = sys_typeclass.create_channel_system(
         sys_key, category_typeclass, channel_typeclass, command_class)
     return new_system
Example #33
0
from django.conf import settings
from evennia.utils.utils import class_from_module
from athanor_entity.entities.base import AthanorGameEntity


MIXINS = []

for mixin in settings.MIXINS["ENTITY_ITEM"]:
    MIXINS.append(class_from_module(mixin))
MIXINS.sort(key=lambda x: getattr(x, "mixin_priority", 0))


class AthanorItem(AthanorGameEntity):
    pass
Example #34
0
make sure to homogenize self.caller to always be the account object
for easy handling.

"""
import hashlib
import time
from django.conf import settings
from evennia.comms.models import ChannelDB, Msg
from evennia.accounts.models import AccountDB
from evennia.accounts import bots
from evennia.comms.channelhandler import CHANNELHANDLER
from evennia.locks.lockhandler import LockException
from evennia.utils import create, logger, utils, evtable
from evennia.utils.utils import make_iter, class_from_module

COMMAND_DEFAULT_CLASS = class_from_module(settings.COMMAND_DEFAULT_CLASS)
CHANNEL_DEFAULT_TYPECLASS = class_from_module(settings.BASE_CHANNEL_TYPECLASS)

# limit symbol import for API
__all__ = (
    "CmdAddCom",
    "CmdDelCom",
    "CmdAllCom",
    "CmdChannels",
    "CmdCdestroy",
    "CmdCBoot",
    "CmdCemit",
    "CmdCWho",
    "CmdChannelCreate",
    "CmdClock",
    "CmdCdesc",
Example #35
0
    def func(self):
        """Do checks and create account"""

        session = self.caller
        args = self.args.strip()

        # Rate-limit account creation.
        address = session.address

        if isinstance(address, tuple):
            address = address[0]
        if CREATION_THROTTLE.check(address):
            session.msg("|RYou are creating too many accounts. Try again in a few minutes.|n")
            return

        # extract double quoted parts
        parts = [part.strip() for part in re.split(r"\"", args) if part.strip()]
        if len(parts) == 1:
            # this was (hopefully) due to no quotes being found
            parts = parts[0].split(None, 1)
        if len(parts) != 2:
            string = "\n Usage (without <>): create <name> <password>" \
                     "\nIf <name> or <password> contains spaces, enclose it in double quotes."
            session.msg(string)
            return
        accountname, password = parts

        # sanity checks
        if not re.findall(r"^[\w. @+\-']+$", accountname) or not (0 < len(accountname) <= 30):
            # this echoes the restrictions made by django's auth
            # module (except not allowing spaces, for convenience of
            # logging in).
            string = "\n\r Accountname can max be 30 characters or fewer. Letters, spaces, digits and @/./+/-/_/' only."
            session.msg(string)
            return
        # strip excessive spaces in accountname
        accountname = re.sub(r"\s+", " ", accountname).strip()
        if AccountDB.objects.filter(username__iexact=accountname):
            # account already exists (we also ignore capitalization here)
            session.msg("Sorry, there is already an account with the name '%s'." % accountname)
            return
        # Reserve accountnames found in GUEST_LIST
        if settings.GUEST_LIST and accountname.lower() in (guest.lower() for guest in settings.GUEST_LIST):
            string = "\n\r That name is reserved. Please choose another Accountname."
            session.msg(string)
            return

        # Validate password
        Account = utils.class_from_module(settings.BASE_ACCOUNT_TYPECLASS)
        # Have to create a dummy Account object to check username similarity
        valid, error = Account.validate_password(password, account=Account(username=accountname))
        if error:
            errors = [e for suberror in error.messages for e in error.messages]
            string = "\n".join(errors)
            session.msg(string)
            return

        # Check IP and/or name bans
        bans = ServerConfig.objects.conf("server_bans")
        if bans and (any(tup[0] == accountname.lower() for tup in bans) or

                     any(tup[2].match(session.address) for tup in bans if tup[2])):
            # this is a banned IP or name!
            string = "|rYou have been banned and cannot continue from here." \
                     "\nIf you feel this ban is in error, please email an admin.|x"
            session.msg(string)
            session.sessionhandler.disconnect(session, "Good bye! Disconnecting.")
            return

        # everything's ok. Create the new account account.
        try:
            permissions = settings.PERMISSION_ACCOUNT_DEFAULT
            typeclass = settings.BASE_CHARACTER_TYPECLASS
            new_account = _create_account(session, accountname, password, permissions)
            if new_account:
                if MULTISESSION_MODE < 2:
                    default_home = ObjectDB.objects.get_id(settings.DEFAULT_HOME)
                    _create_character(session, new_account, typeclass, default_home, permissions)

                # Update the throttle to indicate a new account was created from this IP
                CREATION_THROTTLE.update(address)

                # tell the caller everything went well.
                string = "A new account '%s' was created. Welcome!"
                if " " in accountname:
                    string += "\n\nYou can now log in with the command 'connect \"%s\" <your password>'."
                else:
                    string += "\n\nYou can now log with the command 'connect %s <your password>'."
                session.msg(string % (accountname, accountname))

        except Exception:
            # We are in the middle between logged in and -not, so we have
            # to handle tracebacks ourselves at this point. If we don't,
            # we won't see any errors at all.
            session.msg("An error occurred. Please e-mail an admin if the problem persists.")
            logger.log_trace()
Example #36
0
    def __init__(self, *args, **kwargs):
        """
        The `__init__` method of typeclasses is the core operational
        code of the typeclass system, where it dynamically re-applies
        a class based on the db_typeclass_path database field rather
        than use the one in the model.

        Args:
            Passed through to parent.

        Kwargs:
            Passed through to parent.

        Notes:
            The loading mechanism will attempt the following steps:

            1. Attempt to load typeclass given on command line
            2. Attempt to load typeclass stored in db_typeclass_path
            3. Attempt to load `__settingsclasspath__`, which is by the
               default classes defined to be the respective user-set
               base typeclass settings, like `BASE_OBJECT_TYPECLASS`.
            4. Attempt to load `__defaultclasspath__`, which is the
               base classes in the library, like DefaultObject etc.
            5. If everything else fails, use the database model.

            Normal operation is to load successfully at either step 1
            or 2 depending on how the class was called. Tracebacks
            will be logged for every step the loader must take beyond
            2.

        """
        typeclass_path = kwargs.pop("typeclass", None)
        super(TypedObject, self).__init__(*args, **kwargs)
        if typeclass_path:
            try:
                self.__class__ = class_from_module(
                    typeclass_path, defaultpaths=settings.TYPECLASS_PATHS)
            except Exception:
                log_trace()
                try:
                    self.__class__ = class_from_module(
                        self.__settingsclasspath__)
                except Exception:
                    log_trace()
                    try:
                        self.__class__ = class_from_module(
                            self.__defaultclasspath__)
                    except Exception:
                        log_trace()
                        self.__class__ = self._meta.proxy_for_model or self.__class__
            finally:
                self.db_typclass_path = typeclass_path
        elif self.db_typeclass_path:
            try:
                self.__class__ = class_from_module(self.db_typeclass_path)
            except Exception:
                log_trace()
                try:
                    self.__class__ = class_from_module(
                        self.__defaultclasspath__)
                except Exception:
                    log_trace()
                    self.__dbclass__ = self._meta.proxy_for_model or self.__class__
        else:
            self.db_typeclass_path = "%s.%s" % (self.__module__,
                                                self.__class__.__name__)
        # important to put this at the end since _meta is based on the set __class__
        self.__dbclass__ = self._meta.proxy_for_model or self.__class__
Example #37
0
the Evennia API.  It is also a severe security risk and should
therefore always be limited to superusers only.

"""
import re
from builtins import range

from django.conf import settings
from evennia.utils.batchprocessors import BATCHCMD, BATCHCODE
from evennia.commands.cmdset import CmdSet
from evennia.utils import logger, utils


_RE_COMMENT = re.compile(r"^#.*?$", re.MULTILINE + re.DOTALL)
_RE_CODE_START = re.compile(r"^# batchcode code:", re.MULTILINE)
_COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)
#from evennia.commands.default.muxcommand import _COMMAND_DEFAULT_CLASS

# limit symbols for API inclusion
__all__ = ("CmdBatchCommands", "CmdBatchCode")

_HEADER_WIDTH = 70
_UTF8_ERROR = \
"""
 {rDecode error in '%s'.{n

 This file contains non-ascii character(s). This is common if you
 wrote some input in a language that has more letters and special
 symbols than English; such as accents or umlauts.  This is usually
 fine and fully supported! But for Evennia to know how to decode such
 characters in a universal way, the batchfile must be saved with the
Example #38
0
def validate_prototype(prototype, protkey=None, protparents=None,
                       is_prototype_base=True, strict=True, _flags=None):
    """
    Run validation on a prototype, checking for inifinite regress.

    Args:
        prototype (dict): Prototype to validate.
        protkey (str, optional): The name of the prototype definition. If not given, the prototype
            dict needs to have the `prototype_key` field set.
        protpartents (dict, optional): The available prototype parent library. If
            note given this will be determined from settings/database.
        is_prototype_base (bool, optional): We are trying to create a new object *based on this
            object*. This means we can't allow 'mixin'-style prototypes without typeclass/parent
            etc.
        strict (bool, optional): If unset, don't require needed keys, only check against infinite
            recursion etc.
        _flags (dict, optional): Internal work dict that should not be set externally.
    Raises:
        RuntimeError: If prototype has invalid structure.
        RuntimeWarning: If prototype has issues that would make it unsuitable to build an object
            with (it may still be useful as a mix-in prototype).

    """
    assert isinstance(prototype, dict)

    if _flags is None:
        _flags = {"visited": [], "depth": 0, "typeclass": False, "errors": [], "warnings": []}

    if not protparents:
        protparents = {prototype.get('prototype_key', "").lower(): prototype
                       for prototype in search_prototype()}

    protkey = protkey and protkey.lower() or prototype.get('prototype_key', None)

    if strict and not bool(protkey):
        _flags['errors'].append("Prototype lacks a `prototype_key`.")
        protkey = "[UNSET]"

    typeclass = prototype.get('typeclass')
    prototype_parent = prototype.get('prototype_parent', [])

    if strict and not (typeclass or prototype_parent):
        if is_prototype_base:
            _flags['errors'].append("Prototype {} requires `typeclass` "
                                    "or 'prototype_parent'.".format(protkey))
        else:
            _flags['warnings'].append("Prototype {} can only be used as a mixin since it lacks "
                                      "a typeclass or a prototype_parent.".format(protkey))

    if strict and typeclass:
        try:
            class_from_module(typeclass)
        except ImportError as err:
            _flags['errors'].append(
                "{}: Prototype {} is based on typeclass {}, which could not be imported!".format(
                    err, protkey, typeclass))

    # recursively traverese prototype_parent chain

    for protstring in make_iter(prototype_parent):
        protstring = protstring.lower()
        if protkey is not None and protstring == protkey:
            _flags['errors'].append("Prototype {} tries to parent itself.".format(protkey))
        protparent = protparents.get(protstring)
        if not protparent:
            _flags['errors'].append("Prototype {}'s prototype_parent '{}' was not found.".format(
                (protkey, protstring)))
        if id(prototype) in _flags['visited']:
            _flags['errors'].append(
                "{} has infinite nesting of prototypes.".format(protkey or prototype))

        if _flags['errors']:
            raise RuntimeError("Error: " + "\nError: ".join(_flags['errors']))
        _flags['visited'].append(id(prototype))
        _flags['depth'] += 1
        validate_prototype(protparent, protstring, protparents,
                           is_prototype_base=is_prototype_base, _flags=_flags)
        _flags['visited'].pop()
        _flags['depth'] -= 1

    if typeclass and not _flags['typeclass']:
        _flags['typeclass'] = typeclass

    # if we get back to the current level without a typeclass it's an error.
    if strict and is_prototype_base and _flags['depth'] <= 0 and not _flags['typeclass']:
        _flags['errors'].append("Prototype {} has no `typeclass` defined anywhere in its parent\n "
                                "chain. Add `typeclass`, or a `prototype_parent` pointing to a "
                                "prototype with a typeclass.".format(protkey))

    if _flags['depth'] <= 0:
        if _flags['errors']:
            raise RuntimeError("Error: " + "\nError: ".join(_flags['errors']))
        if _flags['warnings']:
            raise RuntimeWarning("Warning: " + "\nWarning: ".join(_flags['warnings']))

    # make sure prototype_locks are set to defaults
    prototype_locks = [lstring.split(":", 1)
                       for lstring in prototype.get("prototype_locks", "").split(';')
                       if ":" in lstring]
    locktypes = [tup[0].strip() for tup in prototype_locks]
    if "spawn" not in locktypes:
        prototype_locks.append(("spawn", "all()"))
    if "edit" not in locktypes:
        prototype_locks.append(("edit", "all()"))
    prototype_locks = ";".join(":".join(tup) for tup in prototype_locks)
    prototype['prototype_locks'] = prototype_locks
Example #39
0
    def swap_typeclass(self,
                       new_typeclass,
                       clean_attributes=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.
        Player will not be affected. To 'move' a player to a different
        object entirely (while retaining this object's type), use
        self.player.swap_object().

        Note that this might be an error prone operation if the
        old/new typeclass was heavily customized - your code
        might expect one and not the other, so be careful to
        bug test your code if using this feature! Often its easiest
        to create a new object and just swap the player over to
        that one instead.

        Args:
            new_typeclass (str or classobj): Type to switch to.
            clean_attributes (bool or list, optional): Will delete all
                attributes stored on this object (but not any of the
                database fields such as name or location). You can't get
                attributes back, but this is often the safest bet to make
                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 (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.

        """

        if not callable(new_typeclass):
            # this is an actual class object - build the path
            new_typeclass = class_from_module(
                new_typeclass, defaultpaths=settings.TYPECLASS_PATHS)

        # if we get to this point, the class is ok.

        if inherits_from(self, "evennia.scripts.models.ScriptDB"):
            if self.interval > 0:
                raise RuntimeError("Cannot use swap_typeclass on time-dependent " \
                                   "Script '%s'.\nStop and start a new Script of the " \
                                   "right type instead." % self.key)

        self.typeclass_path = new_typeclass.path
        self.__class__ = new_typeclass

        if clean_attributes:
            # Clean out old attributes
            if is_iter(clean_attributes):
                for attr in clean_attributes:
                    self.attributes.remove(attr)
                for nattr in clean_attributes:
                    if hasattr(self.ndb, nattr):
                        self.nattributes.remove(nattr)
            else:
                self.attributes.clear()
                self.nattributes.clear()
        if clean_cmdsets:
            # purge all cmdsets
            self.cmdset.clear()
            self.cmdset.remove_default()

        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)()
Example #40
0
def create_script(typeclass=None, key=None, obj=None, player=None, locks=None,
                  interval=None, start_delay=None, repeats=None,
                  persistent=None, autostart=True, report_to=None, desc=None):
    """
    Create a new script. All scripts are a combination of a database
    object that communicates with the database, and an typeclass that
    'decorates' the database object into being different types of
    scripts.  It's behaviour is similar to the game objects except
    scripts has a time component and are more limited in scope.

    Kwargs:
        typeclass (class or str): Class or python path to a typeclass.
        key (str): Name of the new object. If not set, a name of
            #dbref will be set.
        obj (Object): The entity on which this Script sits. If this
            is `None`, we are creating a "global" script.
        player (Player): The player on which this Script sits. It is
            exclusiv to `obj`.
        locks (str): one or more lockstrings, separated by semicolons.
        interval (int): The triggering interval for this Script, in
            seconds. If unset, the Script will not have a timing
            component.
        start_delay (bool): If `True`, will wait `interval` seconds
            before triggering the first time.
        repeats (int): The number of times to trigger before stopping.
            If unset, will repeat indefinitely.
        persistent (bool): If this Script survives a server shutdown
            or not (all Scripts will survive a reload).
        autostart (bool): If this Script will start immediately when
            created or if the `start` method must be called explicitly.
        report_to (Object): The object to return error messages to.
        desc (str): Optional description of script


    See evennia.scripts.manager for methods to manipulate existing
    scripts in the database.

    """
    global _ScriptDB
    if not _ScriptDB:
        from evennia.scripts.models import ScriptDB as _ScriptDB

    typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # validate input
    kwarg = {}
    if key: kwarg["db_key"] = key
    if player: kwarg["db_player"] = dbid_to_obj(player, _ScriptDB)
    if obj: kwarg["db_obj"] = dbid_to_obj(obj, _ScriptDB)
    if interval: kwarg["db_interval"] = interval
    if start_delay: kwarg["db_start_delay"] = start_delay
    if repeats: kwarg["db_repeats"] = repeats
    if persistent: kwarg["db_persistent"] = persistent
    if desc: kwarg["db_desc"] = desc

    # create new instance
    new_script = typeclass(**kwarg)

    # store the call signature for the signal
    new_script._createdict = dict(key=key, obj=obj, player=player, locks=locks, interval=interval,
                                  start_delay=start_delay, repeats=repeats, persistent=persistent,
                                  autostart=autostart, report_to=report_to)
    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict
    # can be used.
    new_script.save()
    return new_script
Example #41
0
def create_account(
    key,
    email,
    password,
    typeclass=None,
    is_superuser=False,
    locks=None,
    permissions=None,
    tags=None,
    attributes=None,
    report_to=None,
):
    """
    This creates a new account.

    Args:
        key (str): The account's name. This should be unique.
        email (str or None): Email on valid [email protected] form. If
            the empty string, will be set to None.
        password (str): Password in cleartext.

    Kwargs:
        typeclass (str): The typeclass to use for the account.
        is_superuser (bool): Wether or not this account is to be a superuser
        locks (str): Lockstring.
        permission (list): List of permission strings.
        tags (list): List of Tags on form `(key, category[, data])`
        attributes (list): List of Attributes on form
             `(key, value [, category, [,lockstring [, default_pass]]])`
        report_to (Object): An object with a msg() method to report
            errors to. If not given, errors will be logged.

    Returns:
        Account: The newly created Account.
    Raises:
        ValueError: If `key` already exists in database.


    Notes:
        Usually only the server admin should need to be superuser, all
        other access levels can be handled with more fine-grained
        permissions or groups. A superuser bypasses all lock checking
        operations and is thus not suitable for play-testing the game.

    """
    global _AccountDB
    if not _AccountDB:
        from evennia.accounts.models import AccountDB as _AccountDB

    typeclass = typeclass if typeclass else settings.BASE_ACCOUNT_TYPECLASS
    locks = make_iter(locks) if locks is not None else None
    permissions = make_iter(permissions) if permissions is not None else None
    tags = make_iter(tags) if tags is not None else None
    attributes = make_iter(attributes) if attributes is not None else None

    if isinstance(typeclass, str):
        # a path is given. Load the actual typeclass.
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # setup input for the create command. We use AccountDB as baseclass
    # here to give us maximum freedom (the typeclasses will load
    # correctly when each object is recovered).

    if not email:
        email = None
    if _AccountDB.objects.filter(username__iexact=key):
        raise ValueError("An Account with the name '%s' already exists." % key)

    # this handles a given dbref-relocate to an account.
    report_to = dbid_to_obj(report_to, _AccountDB)

    # create the correct account entity, using the setup from
    # base django auth.
    now = timezone.now()
    email = typeclass.objects.normalize_email(email)
    new_account = typeclass(
        username=key,
        email=email,
        is_staff=is_superuser,
        is_superuser=is_superuser,
        last_login=now,
        date_joined=now,
    )
    if password is not None:
        # the password may be None for 'fake' accounts, like bots
        valid, error = new_account.validate_password(password, new_account)
        if not valid:
            raise error

        new_account.set_password(password)

    new_account._createdict = dict(locks=locks,
                                   permissions=permissions,
                                   report_to=report_to,
                                   tags=tags,
                                   attributes=attributes)
    # saving will trigger the signal that calls the
    # at_first_save hook on the typeclass, where the _createdict
    # can be used.
    new_account.save()

    # note that we don't send a signal here, that is sent from the Account.create helper method
    # instead.

    return new_account
Example #42
0
    def func(self):
        """Implement the command"""

        caller = self.caller
        nlim = int(self.args) if self.args and self.args.isdigit() else 10
        nobjs = ObjectDB.objects.count()
        Character = class_from_module(settings.BASE_CHARACTER_TYPECLASS)
        nchars = Character.objects.all_family().count()
        Room = class_from_module(settings.BASE_ROOM_TYPECLASS)
        nrooms = Room.objects.all_family().count()
        Exit = class_from_module(settings.BASE_EXIT_TYPECLASS)
        nexits = Exit.objects.all_family().count()
        nother = nobjs - nchars - nrooms - nexits
        nobjs = nobjs or 1  # fix zero-div error with empty database

        # total object sum table
        totaltable = self.styled_table(
            "|wtype|n", "|wcomment|n", "|wcount|n", "|w%|n", border="table", align="l"
        )
        totaltable.align = "l"
        totaltable.add_row(
            "Characters",
            "(BASE_CHARACTER_TYPECLASS + children)",
            nchars,
            "%.2f" % ((float(nchars) / nobjs) * 100),
        )
        totaltable.add_row(
            "Rooms",
            "(BASE_ROOM_TYPECLASS + children)",
            nrooms,
            "%.2f" % ((float(nrooms) / nobjs) * 100),
        )
        totaltable.add_row(
            "Exits",
            "(BASE_EXIT_TYPECLASS + children)",
            nexits,
            "%.2f" % ((float(nexits) / nobjs) * 100),
        )
        totaltable.add_row("Other", "", nother, "%.2f" % ((float(nother) / nobjs) * 100))

        # typeclass table
        typetable = self.styled_table(
            "|wtypeclass|n", "|wcount|n", "|w%|n", border="table", align="l"
        )
        typetable.align = "l"
        dbtotals = ObjectDB.objects.get_typeclass_totals()
        for stat in dbtotals:
            typetable.add_row(
                stat.get("typeclass", "<error>"),
                stat.get("count", -1),
                "%.2f" % stat.get("percent", -1),
            )

        # last N table
        objs = ObjectDB.objects.all().order_by("db_date_created")[max(0, nobjs - nlim) :]
        latesttable = self.styled_table(
            "|wcreated|n", "|wdbref|n", "|wname|n", "|wtypeclass|n", align="l", border="table"
        )
        latesttable.align = "l"
        for obj in objs:
            latesttable.add_row(
                utils.datetime_format(obj.date_created), obj.dbref, obj.key, obj.path
            )

        string = "\n|wObject subtype totals (out of %i Objects):|n\n%s" % (nobjs, totaltable)
        string += "\n|wObject typeclass distribution:|n\n%s" % typetable
        string += "\n|wLast %s Objects created:|n\n%s" % (min(nobjs, nlim), latesttable)
        caller.msg(string)
Example #43
0
def create_player(key, email, password,
                  typeclass=None,
                  is_superuser=False,
                  locks=None, permissions=None,
                  report_to=None):

    """
    This creates a new player.

    Args:
        key (str): The player's name. This should be unique.
        email (str): Email on valid [email protected] form. This is
            technically required but if set to `None`, an email of
            `[email protected]` will be used as a placeholder.
        password (str): Password in cleartext.

    Kwargs:
        is_superuser (bool): Wether or not this player is to be a superuser
        locks (str): Lockstring.
        permission (list): List of permission strings.
        report_to (Object): An object with a msg() method to report
            errors to. If not given, errors will be logged.

    Raises:
        ValueError: If `key` already exists in database.

    Notes:
        Usually only the server admin should need to be superuser, all
        other access levels can be handled with more fine-grained
        permissions or groups. A superuser bypasses all lock checking
        operations and is thus not suitable for play-testing the game.

    """
    global _PlayerDB
    if not _PlayerDB:
        from evennia.players.models import PlayerDB as _PlayerDB

    typeclass = typeclass if typeclass else settings.BASE_PLAYER_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass.
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # setup input for the create command. We use PlayerDB as baseclass
    # here to give us maximum freedom (the typeclasses will load
    # correctly when each object is recovered).

    if not email:
        email = "*****@*****.**"
    if _PlayerDB.objects.filter(username__iexact=key):
        raise ValueError("A Player with the name '%s' already exists." % key)

    # this handles a given dbref-relocate to a player.
    report_to = dbid_to_obj(report_to, _PlayerDB)

    # create the correct player entity, using the setup from
    # base django auth.
    now = timezone.now()
    email = typeclass.objects.normalize_email(email)
    new_player = typeclass(username=key, email=email,
                           is_staff=is_superuser, is_superuser=is_superuser,
                           last_login=now, date_joined=now)
    new_player.set_password(password)
    new_player._createdict = dict(locks=locks, permissions=permissions, report_to=report_to)
    # saving will trigger the signal that calls the
    # at_first_save hook on the typeclass, where the _createdict
    # can be used.
    new_player.save()
    return new_player
Example #44
0
def create_object(typeclass=None, key=None, location=None, home=None,
                  permissions=None, locks=None, aliases=None, tags=None,
                  destination=None, report_to=None, nohome=False):
    """

    Create a new in-game object.

    Kwargs:
        typeclass (class or str): Class or python path to a typeclass.
        key (str): Name of the new object. If not set, a name of
            #dbref will be set.
        home (Object or str): Obj or #dbref to use as the object's
            home location.
        permissions (str): A comma-separated string of permissions.
        locks (str): one or more lockstrings, separated by semicolons.
        aliases (list): A list of alternative keys.
        tags (list): List of tag keys (using no category).
        destination (Object or str): Obj or #dbref to use as an Exit's
            target.
        report_to (Object): The object to return error messages to.
        nohome (bool): This allows the creation of objects without a
            default home location; only used when creating the default
            location itself or during unittests.

    Returns:
        object (Object): A newly created object of the given typeclass.

    Raises:
        ObjectDB.DoesNotExist: If trying to create an Object with
            `location` or `home` that can't be found.

    """
    global _ObjectDB
    if not _ObjectDB:
        from evennia.objects.models import ObjectDB as _ObjectDB

    typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # Setup input for the create command. We use ObjectDB as baseclass here
    # to give us maximum freedom (the typeclasses will load
    # correctly when each object is recovered).

    location = dbid_to_obj(location, _ObjectDB)
    destination = dbid_to_obj(destination, _ObjectDB)
    home = dbid_to_obj(home, _ObjectDB)
    if not home:
        try:
            home = dbid_to_obj(settings.DEFAULT_HOME, _ObjectDB) if not nohome else None
        except _ObjectDB.DoesNotExist:
            raise _ObjectDB.DoesNotExist("settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed." %
                                         settings.DEFAULT_HOME)

    # create new instance
    new_object = typeclass(db_key=key, db_location=location,
                           db_destination=destination, db_home=home,
                           db_typeclass_path=typeclass.path)
    # store the call signature for the signal
    new_object._createdict = dict(key=key, location=location, destination=destination, home=home,
                                  typeclass=typeclass.path, permissions=permissions, locks=locks,
                                  aliases=aliases, tags=tags, report_to=report_to, nohome=nohome)
    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict can be
    # used.
    new_object.save()
    return new_object
Example #45
0
def create_script(typeclass, key=None, obj=None, player=None, locks=None,
                  interval=None, start_delay=None, repeats=None,
                  persistent=None, autostart=True, report_to=None):
    """
    Create a new script. All scripts are a combination
    of a database object that communicates with the
    database, and an typeclass that 'decorates' the
    database object into being different types of scripts.
    It's behaviour is similar to the game objects except
    scripts has a time component and are more limited in
    scope.

    Argument 'typeclass' can be either an actual
    typeclass object or a python path to such an object.
    Only set key here if you want a unique name for this
    particular script (set it in config to give
    same key to all scripts of the same type). Set obj
    to tie this script to a particular object.

    See evennia.scripts.manager for methods to manipulate existing
    scripts in the database.

    report_to is an obtional object to receive error messages.
              If report_to is not set, an Exception with the
              error will be raised. If set, this method will
              return None upon errors.
    """
    global _ScriptDB
    if not _ScriptDB:
        from evennia.scripts.models import ScriptDB as _ScriptDB

    typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # validate input
    kwarg = {}
    if key: kwarg["db_key"] = key
    if player: kwarg["db_player"] = dbid_to_obj(player, _ScriptDB)
    if obj: kwarg["db_obj"] = dbid_to_obj(obj, _ScriptDB)
    if interval: kwarg["db_interval"] = interval
    if start_delay: kwarg["db_start_delay"] = start_delay
    if repeats: kwarg["db_repeats"] = repeats
    if persistent: kwarg["db_persistent"] = persistent

    # create new instance
    new_script = typeclass(**kwarg)

    # store the call signature for the signal
    new_script._createdict = {"key":key, "obj":obj, "player":player,
                              "locks":locks, "interval":interval,
                              "start_delay":start_delay, "repeats":repeats,
                              "persistent":persistent, "autostart":autostart,
                              "report_to":report_to}

    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the tyepclass, where the _createdict
    # can be used.
    new_script.save()
    return new_script
Example #46
0
    def swap_typeclass(self,
                       new_typeclass,
                       clean_attributes=False,
                       run_start_hooks=True,
                       no_default=True):
        """
        This performs an in-situ swap of the typeclass. This means
        that in-game, this object will suddenly be something else.
        Player will not be affected. To 'move' a player to a different
        object entirely (while retaining this object's type), use
        self.player.swap_object().

        Note that this might be an error prone operation if the
        old/new typeclass was heavily customized - your code
        might expect one and not the other, so be careful to
        bug test your code if using this feature! Often its easiest
        to create a new object and just swap the player over to
        that one instead.

        Arguments:
        new_typeclass (path/classobj) - type to switch to
        clean_attributes (bool/list) - will delete all attributes
                           stored on this object (but not any
                           of the database fields such as name or
                           location). You can't get attributes back,
                           but this is often the safest bet to make
                           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 - trigger the start hooks of the object, as if
                          it was created for the first time.
        no_default - if this is active, 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.
        Returns:
          boolean True/False depending on if the swap worked or not.

        """

        if not callable(new_typeclass):
            # this is an actual class object - build the path
            new_typeclass = class_from_module(
                new_typeclass, defaultpaths=settings.TYPECLASS_PATHS)

        # if we get to this point, the class is ok.

        if inherits_from(self, "evennia.scripts.models.ScriptDB"):
            if self.interval > 0:
                raise RuntimeError("Cannot use swap_typeclass on time-dependent " \
                                   "Script '%s'.\nStop and start a new Script of the " \
                                   "right type instead." % self.key)

        self.typeclass_path = new_typeclass.path
        self.__class__ = new_typeclass

        if clean_attributes:
            # Clean out old attributes
            if is_iter(clean_attributes):
                for attr in clean_attributes:
                    self.attributes.remove(attr)
                for nattr in clean_attributes:
                    if hasattr(self.ndb, nattr):
                        self.nattributes.remove(nattr)
            else:
                #print "deleting attrs ..."
                self.attributes.clear()
                self.nattributes.clear()

        if run_start_hooks:
            # fake this call to mimic the first save
            self.at_first_save()
Example #47
0
"""
This model instantiate a script_handler.
"""

from evennia.utils.utils import class_from_module
from django.conf import settings


# load script handler from settings.SCRIPT_HANDLER
scriptclass = class_from_module(settings.SCRIPT_HANDLER)
SCRIPT_HANDLER = scriptclass()
Example #48
0
def create_script(
    typeclass=None,
    key=None,
    obj=None,
    account=None,
    locks=None,
    interval=None,
    start_delay=None,
    repeats=None,
    persistent=None,
    autostart=True,
    report_to=None,
    desc=None,
    tags=None,
    attributes=None,
):
    """
    Create a new script. All scripts are a combination of a database
    object that communicates with the database, and an typeclass that
    'decorates' the database object into being different types of
    scripts.  It's behaviour is similar to the game objects except
    scripts has a time component and are more limited in scope.

    Kwargs:
        typeclass (class or str): Class or python path to a typeclass.
        key (str): Name of the new object. If not set, a name of
            #dbref will be set.
        obj (Object): The entity on which this Script sits. If this
            is `None`, we are creating a "global" script.
        account (Account): The account on which this Script sits. It is
            exclusiv to `obj`.
        locks (str): one or more lockstrings, separated by semicolons.
        interval (int): The triggering interval for this Script, in
            seconds. If unset, the Script will not have a timing
            component.
        start_delay (bool): If `True`, will wait `interval` seconds
            before triggering the first time.
        repeats (int): The number of times to trigger before stopping.
            If unset, will repeat indefinitely.
        persistent (bool): If this Script survives a server shutdown
            or not (all Scripts will survive a reload).
        autostart (bool): If this Script will start immediately when
            created or if the `start` method must be called explicitly.
        report_to (Object): The object to return error messages to.
        desc (str): Optional description of script
        tags (list): List of tags or tuples (tag, category).
        attributes (list): List if tuples (key, value) or (key, value, category)
           (key, value, lockstring) or (key, value, lockstring, default_access).

    See evennia.scripts.manager for methods to manipulate existing
    scripts in the database.

    """
    global _ScriptDB
    if not _ScriptDB:
        from evennia.scripts.models import ScriptDB as _ScriptDB

    typeclass = typeclass if typeclass else settings.BASE_SCRIPT_TYPECLASS

    if isinstance(typeclass, str):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # validate input
    kwarg = {}
    if key:
        kwarg["db_key"] = key
    if account:
        kwarg["db_account"] = dbid_to_obj(account, _AccountDB)
    if obj:
        kwarg["db_obj"] = dbid_to_obj(obj, _ObjectDB)
    if interval:
        kwarg["db_interval"] = max(0, interval)
    if start_delay:
        kwarg["db_start_delay"] = start_delay
    if repeats:
        kwarg["db_repeats"] = max(0, repeats)
    if persistent:
        kwarg["db_persistent"] = persistent
    if desc:
        kwarg["db_desc"] = desc
    tags = make_iter(tags) if tags is not None else None
    attributes = make_iter(attributes) if attributes is not None else None

    # create new instance
    new_script = typeclass(**kwarg)

    # store the call signature for the signal
    new_script._createdict = dict(
        key=key,
        obj=obj,
        account=account,
        locks=locks,
        interval=interval,
        start_delay=start_delay,
        repeats=repeats,
        persistent=persistent,
        autostart=autostart,
        report_to=report_to,
        desc=desc,
        tags=tags,
        attributes=attributes,
    )
    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict
    # can be used.
    new_script.save()

    if not new_script.id:
        # this happens in the case of having a repeating script with `repeats=1` and
        # `start_delay=False` - the script will run once and immediately stop before save is over.
        return None

    signals.SIGNAL_SCRIPT_POST_CREATE.send(sender=new_script)

    return new_script
Example #49
0
    def __init__(self, *args, **kwargs):
        """
        The `__init__` method of typeclasses is the core operational
        code of the typeclass system, where it dynamically re-applies
        a class based on the db_typeclass_path database field rather
        than use the one in the model.

        Args:
            Passed through to parent.

        Kwargs:
            Passed through to parent.

        Notes:
            The loading mechanism will attempt the following steps:

            1. Attempt to load typeclass given on command line
            2. Attempt to load typeclass stored in db_typeclass_path
            3. Attempt to load `__settingsclasspath__`, which is by the
               default classes defined to be the respective user-set
               base typeclass settings, like `BASE_OBJECT_TYPECLASS`.
            4. Attempt to load `__defaultclasspath__`, which is the
               base classes in the library, like DefaultObject etc.
            5. If everything else fails, use the database model.

            Normal operation is to load successfully at either step 1
            or 2 depending on how the class was called. Tracebacks
            will be logged for every step the loader must take beyond
            2.

        """
        typeclass_path = kwargs.pop("typeclass", None)
        super(TypedObject, self).__init__(*args, **kwargs)
        if typeclass_path:
            try:
                self.__class__ = class_from_module(typeclass_path, defaultpaths=settings.TYPECLASS_PATHS)
            except Exception:
                log_trace()
                try:
                    self.__class__ = class_from_module(self.__settingsclasspath__)
                except Exception:
                    log_trace()
                    try:
                        self.__class__ = class_from_module(self.__defaultclasspath__)
                    except Exception:
                        log_trace()
                        self.__class__ = self._meta.proxy_for_model or self.__class__
            finally:
                self.db_typclass_path = typeclass_path
        elif self.db_typeclass_path:
            try:
                self.__class__ = class_from_module(self.db_typeclass_path)
            except Exception:
                log_trace()
                try:
                    self.__class__ = class_from_module(self.__defaultclasspath__)
                except Exception:
                    log_trace()
                    self.__dbclass__ = self._meta.proxy_for_model or self.__class__
        else:
            self.db_typeclass_path = "%s.%s" % (self.__module__, self.__class__.__name__)
        # important to put this at the end since _meta is based on the set __class__
        self.__dbclass__ = self._meta.proxy_for_model or self.__class__
Example #50
0
def create_object(
    typeclass=None,
    key=None,
    location=None,
    home=None,
    permissions=None,
    locks=None,
    aliases=None,
    tags=None,
    destination=None,
    report_to=None,
    nohome=False,
    attributes=None,
    nattributes=None,
):
    """

    Create a new in-game object.

    Kwargs:
        typeclass (class or str): Class or python path to a typeclass.
        key (str): Name of the new object. If not set, a name of
            #dbref will be set.
        home (Object or str): Obj or #dbref to use as the object's
            home location.
        permissions (list): A list of permission strings or tuples (permstring, category).
        locks (str): one or more lockstrings, separated by semicolons.
        aliases (list): A list of alternative keys or tuples (aliasstring, category).
        tags (list): List of tag keys or tuples (tagkey, category) or (tagkey, category, data).
        destination (Object or str): Obj or #dbref to use as an Exit's
            target.
        report_to (Object): The object to return error messages to.
        nohome (bool): This allows the creation of objects without a
            default home location; only used when creating the default
            location itself or during unittests.
        attributes (list): Tuples on the form (key, value) or (key, value, category),
           (key, value, lockstring) or (key, value, lockstring, default_access).
            to set as Attributes on the new object.
        nattributes (list): Non-persistent tuples on the form (key, value). Note that
            adding this rarely makes sense since this data will not survive a reload.

    Returns:
        object (Object): A newly created object of the given typeclass.

    Raises:
        ObjectDB.DoesNotExist: If trying to create an Object with
            `location` or `home` that can't be found.

    """
    global _ObjectDB
    if not _ObjectDB:
        from evennia.objects.models import ObjectDB as _ObjectDB

    typeclass = typeclass if typeclass else settings.BASE_OBJECT_TYPECLASS

    # convenience converters to avoid common usage mistake
    permissions = make_iter(permissions) if permissions is not None else None
    locks = make_iter(locks) if locks is not None else None
    aliases = make_iter(aliases) if aliases is not None else None
    tags = make_iter(tags) if tags is not None else None
    attributes = make_iter(attributes) if attributes is not None else None

    if isinstance(typeclass, str):
        # a path is given. Load the actual typeclass
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # Setup input for the create command. We use ObjectDB as baseclass here
    # to give us maximum freedom (the typeclasses will load
    # correctly when each object is recovered).

    location = dbid_to_obj(location, _ObjectDB)
    destination = dbid_to_obj(destination, _ObjectDB)
    home = dbid_to_obj(home, _ObjectDB)
    if not home:
        try:
            home = dbid_to_obj(settings.DEFAULT_HOME,
                               _ObjectDB) if not nohome else None
        except _ObjectDB.DoesNotExist:
            raise _ObjectDB.DoesNotExist(
                "settings.DEFAULT_HOME (= '%s') does not exist, or the setting is malformed."
                % settings.DEFAULT_HOME)

    # create new instance
    new_object = typeclass(
        db_key=key,
        db_location=location,
        db_destination=destination,
        db_home=home,
        db_typeclass_path=typeclass.path,
    )
    # store the call signature for the signal
    new_object._createdict = dict(
        key=key,
        location=location,
        destination=destination,
        home=home,
        typeclass=typeclass.path,
        permissions=permissions,
        locks=locks,
        aliases=aliases,
        tags=tags,
        report_to=report_to,
        nohome=nohome,
        attributes=attributes,
        nattributes=nattributes,
    )
    # this will trigger the save signal which in turn calls the
    # at_first_save hook on the typeclass, where the _createdict can be
    # used.
    new_object.save()

    signals.SIGNAL_OBJECT_POST_CREATE.send(sender=new_object)

    return new_object
Example #51
0
    def swap_typeclass(self, new_typeclass, clean_attributes=False,
                       run_start_hooks=True, no_default=True):
        """
        This performs an in-situ swap of the typeclass. This means
        that in-game, this object will suddenly be something else.
        Player will not be affected. To 'move' a player to a different
        object entirely (while retaining this object's type), use
        self.player.swap_object().

        Note that this might be an error prone operation if the
        old/new typeclass was heavily customized - your code
        might expect one and not the other, so be careful to
        bug test your code if using this feature! Often its easiest
        to create a new object and just swap the player over to
        that one instead.

        Args:
            new_typeclass (str or classobj): Type to switch to.
            clean_attributes (bool or list, optional): Will delete all
                attributes stored on this object (but not any of the
                database fields such as name or location). You can't get
                attributes back, but this is often the safest bet to make
                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.
            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.
        Returns:
            result (bool): True/False depending on if the swap worked
                or not.

        """

        if not callable(new_typeclass):
            # this is an actual class object - build the path
            new_typeclass = class_from_module(new_typeclass, defaultpaths=settings.TYPECLASS_PATHS)

        # if we get to this point, the class is ok.


        if inherits_from(self, "evennia.scripts.models.ScriptDB"):
            if self.interval > 0:
                raise RuntimeError("Cannot use swap_typeclass on time-dependent " \
                                   "Script '%s'.\nStop and start a new Script of the " \
                                   "right type instead." % self.key)

        self.typeclass_path = new_typeclass.path
        self.__class__ = new_typeclass

        if clean_attributes:
            # Clean out old attributes
            if is_iter(clean_attributes):
                for attr in clean_attributes:
                    self.attributes.remove(attr)
                for nattr in clean_attributes:
                    if hasattr(self.ndb, nattr):
                        self.nattributes.remove(nattr)
            else:
                self.attributes.clear()
                self.nattributes.clear()

        if run_start_hooks:
            # fake this call to mimic the first save
            self.at_first_save()
Example #52
0
"""
General Character commands usually available to all characters
"""
import re
from django.conf import settings
from evennia.utils import utils, evtable
from evennia.typeclasses.attributes import NickTemplateInvalid

COMMAND_DEFAULT_CLASS = utils.class_from_module(settings.COMMAND_DEFAULT_CLASS)

# limit symbol import for API
__all__ = (
    "CmdHome",
    "CmdLook",
    "CmdNick",
    "CmdInventory",
    "CmdSetDesc",
    "CmdGet",
    "CmdDrop",
    "CmdGive",
    "CmdSay",
    "CmdWhisper",
    "CmdPose",
    "CmdAccess",
)


class CmdHome(COMMAND_DEFAULT_CLASS):
    """
    move to your character's home location
Example #53
0
def create_player(key, email, password,
                  typeclass=None,
                  is_superuser=False,
                  locks=None, permissions=None,
                  report_to=None):

    """
    This creates a new player.

    key - the player's name. This should be unique.
    email - email on valid [email protected] form.
    password - password in cleartext
    is_superuser - wether or not this player is to be a superuser
    locks - lockstring
    permission - list of permissions
    report_to - an object with a msg() method to report errors to. If
                not given, errors will be logged.

    Will return the Player-typeclass or None/raise Exception if the
    Typeclass given failed to load.

    Concerning is_superuser:
     Usually only the server admin should need to be superuser, all
     other access levels can be handled with more fine-grained
     permissions or groups. A superuser bypasses all lock checking
     operations and is thus not suitable for play-testing the game.

    """
    global _PlayerDB
    if not _PlayerDB:
        from evennia.players.models import PlayerDB as _PlayerDB

    typeclass = typeclass if typeclass else settings.BASE_PLAYER_TYPECLASS

    if isinstance(typeclass, basestring):
        # a path is given. Load the actual typeclass.
        typeclass = class_from_module(typeclass, settings.TYPECLASS_PATHS)

    # setup input for the create command. We use PlayerDB as baseclass
    # here to give us maximum freedom (the typeclasses will load
    # correctly when each object is recovered).

    if not email:
        email = "*****@*****.**"
    if _PlayerDB.objects.filter(username__iexact=key):
        raise ValueError("A Player with the name '%s' already exists." % key)

    # this handles a given dbref-relocate to a player.
    report_to = dbid_to_obj(report_to, _PlayerDB)

    # create the correct player entity, using the setup from
    # base django auth.
    now = timezone.now()
    email = typeclass.objects.normalize_email(email)
    new_player = typeclass(username=key, email=email,
                           is_staff=is_superuser, is_superuser=is_superuser,
                           last_login=now, date_joined=now)
    new_player.set_password(password)
    new_player._createdict = {"locks":locks, "permissions":permissions,
                              "report_to":report_to}
    # saving will trigger the signal that calls the
    # at_first_save hook on the typeclass, where the _createdict
    # can be used.
    new_player.save()
    return new_player