Exemple #1
0
def menu_setattr(menu, choice, obj, string):
    """
    Set the value at the specified attribute.

    Args:
        menu (BuildingMenu): the menu object.
        choice (Chocie): the specific choice.
        obj (Object): the object to modify.
        string (str): the string with the new value.

    Note:
        This function is supposed to be used as a default to
        `BuildingMenu.add_choice`, when an attribute name is specified
        (in the `attr` argument) but no function `on_nomatch` is defined.

    """
    attr = getattr(choice, "attr", None) if choice else None
    if choice is None or string is None or attr is None or menu is None:
        log_err(
            dedent("""
                The `menu_setattr` function was called to set the attribute {} of object {} to {},
                but the choice {} of menu {} or another information is missing.
            """.format(attr, obj, repr(string), choice,
                       menu)).strip("\n")).strip()
        return

    for part in attr.split(".")[:-1]:
        obj = getattr(obj, part)

    setattr(obj, attr.split(".")[-1], string)
    return True
Exemple #2
0
def check_permission(prototype_key, action, default=True):
    """
    Helper function to check access to actions on given prototype.

    Args:
        prototype_key (str): The prototype to affect.
        action (str): One of "spawn" or "edit".
        default (str): If action is unknown or prototype has no locks

    Returns:
        passes (bool): If permission for action is granted or not.

    """
    if action == 'edit':
        if prototype_key in _MODULE_PROTOTYPES:
            mod = _MODULE_PROTOTYPE_MODULES.get(prototype_key, "N/A")
            logger.log_err("{} is a read-only prototype "
                           "(defined as code in {}).".format(prototype_key, mod))
            return False

    prototype = search_prototype(key=prototype_key)
    if not prototype:
        logger.log_err("Prototype {} not found.".format(prototype_key))
        return False

    lockstring = prototype.get("prototype_locks")

    if lockstring:
        return check_lockstring(None, lockstring,
                                default=default, access_type=action)
    return default
Exemple #3
0
    def func(self):
        """Call the proper menu or redirect to nomatch."""
        raw_string = self.args.rstrip()
        if self.menu is None:
            log_err(
                "When CMDNOMATCH was called, the building menu couldn't be found"
            )
            self.caller.msg(
                "|rThe building menu couldn't be found, remove the CmdSet.|n")
            self.caller.cmdset.delete(BuildingMenuCmdSet)
            return

        choice = self.menu.current_choice
        if raw_string in self.menu.keys_go_back:
            if self.menu.keys:
                self.menu.move(back=True)
            elif self.menu.parents:
                self.menu.open_parent_menu()
            else:
                self.menu.display()
        elif choice:
            if choice.nomatch(raw_string):
                self.caller.msg(choice.format_text())
        else:
            for choice in self.menu.relevant_choices:
                if choice.key.lower() == raw_string.lower() or any(
                        raw_string.lower() == alias
                        for alias in choice.aliases):
                    self.menu.move(choice.key)
                    return

            self.msg("|rUnknown command: {}|n.".format(raw_string))
Exemple #4
0
    def func(self):
        "Handle command"

        caller = self.caller
        if not caller:
            return
            
        if caller.db.level < settings.MIN_HONOUR_LEVEL:
            caller.msg({"alert":_("You need to reach level %s." % settings.MIN_HONOUR_LEVEL)})
            return
        
        try:
            # getcandidates
            ids = HONOURS_MAPPER.get_characters(caller, settings.HONOUR_OPPONENTS_NUMBER)
            characters = [caller.search_dbref("#%s" % id) for id in ids]
            candidates = [char for char in characters if char and not char.is_in_combat()]
            if candidates:
                match = random.choice(candidates)
                # create a new combat handler
                chandler = create_script(settings.HONOUR_COMBAT_HANDLER)
                # set combat team and desc
                chandler.set_combat({1:[match], 2:[caller]}, _("Fight of Honour"), settings.AUTO_COMBAT_TIMEOUT)
            else:
                caller.msg({"alert":_("Can not make match.")})
        except Exception, e:
            logger.log_err("Find match error: %s" % e)
            caller.msg({"alert":_("Can not make match.")})
Exemple #5
0
    def add(self, store_key, obj, interval, *args, **kwargs):
        """
        Add new ticker subscriber.

        Args:
            store_key (str): Unique storage hash.
            obj (Object): Object subscribing.
            interval (int): How often to call the ticker.
            args (any, optional): Arguments to send to the hook method.

        Kwargs:
            _start_delay (int): If set, this will be
                used to delay the start of the trigger instead of
                `interval`. It is passed on as-is from this method.
            _hooK_key (str): This carries the name of the hook method
                to call. It is passed on as-is from this method.

        """
        if not interval:
            log_err(
                _ERROR_ADD_INTERVAL.format(store_key=store_key,
                                           obj=obj,
                                           interval=interval,
                                           args=args,
                                           kwargs=kwargs))
            return

        if interval not in self.tickers:
            self.tickers[interval] = self.ticker_class(interval)
        self.tickers[interval].add(store_key, obj, *args, **kwargs)
Exemple #6
0
    def _load_script(self, key):
        self.load_data()

        typeclass = self.typeclass_storage[key]
        found = typeclass.objects.filter(db_key=key).first()
        interval = self.loaded_data[key].get('interval', None)
        start_delay = self.loaded_data[key].get('start_delay', None)
        repeats = self.loaded_data[key].get('repeats', 0)
        desc = self.loaded_data[key].get('desc', '')

        if not found:
            logger.log_info(
                f"GLOBAL_SCRIPTS: (Re)creating {key} ({typeclass}).")
            new_script, errors = typeclass.create(key=key,
                                                  persistent=True,
                                                  interval=interval,
                                                  start_delay=start_delay,
                                                  repeats=repeats,
                                                  desc=desc)
            if errors:
                logger.log_err("\n".join(errors))
                return None

            new_script.start()
            return new_script

        if ((found.interval != interval) or (found.start_delay != start_delay)
                or (found.repeats != repeats)):
            found.restart(interval=interval,
                          start_delay=start_delay,
                          repeats=repeats)
        if found.desc != desc:
            found.desc = desc
        return found
Exemple #7
0
    def add(self, store_key, obj, interval, *args, **kwargs):
        """
        Add new ticker subscriber.

        Args:
            store_key (str): Unique storage hash.
            obj (Object): Object subscribing.
            interval (int): How often to call the ticker.
            args (any, optional): Arguments to send to the hook method.

        Kwargs:
            _start_delay (int): If set, this will be
                used to delay the start of the trigger instead of
                `interval`. It is passed on as-is from this method.
            _hooK_key (str): This carries the name of the hook method
                to call. It is passed on as-is from this method.

        """
        if not interval:
            log_err(_ERROR_ADD_INTERVAL.format(store_key=store_key, obj=obj,
                                       interval=interval, args=args, kwargs=kwargs))
            return

        if interval not in self.tickers:
            self.tickers[interval] = self.ticker_class(interval)
        self.tickers[interval].add(store_key, obj, *args, **kwargs)
Exemple #8
0
def _create_account(session,
                    accountname,
                    password,
                    permissions,
                    typeclass=None,
                    email=None):
    """
    Helper function, creates an account of the specified typeclass.
    """
    try:
        new_account = create.create_account(accountname,
                                            email,
                                            password,
                                            permissions=permissions,
                                            typeclass=typeclass)

    except Exception as e:
        session.msg(
            "There was an error creating the Account:\n%s\n If this problem persists, contact an admin."
            % e)
        logger.log_trace()
        return False

    # This needs to be set so the engine knows this account is
    # logging in for the first time. (so it knows to call the right
    # hooks during login later)
    new_account.db.FIRST_LOGIN = True

    # join the new account to the public channel
    pchannel = ChannelDB.objects.get_channel(
        settings.DEFAULT_CHANNELS[0]["key"])
    if not pchannel or not pchannel.connect(new_account):
        string = "New account '%s' could not connect to public channel!" % new_account.key
        logger.log_err(string)
    return new_account
Exemple #9
0
    def get(self, exclude=None):
        """
        Return the contents of the cache.

        Args:
            exclude (Object or list of Object): object(s) to ignore

        Returns:
            objects (list): the Objects inside this location

        """
        if exclude:
            pks = [
                pk for pk in self._pkcache
                if pk not in [excl.pk for excl in make_iter(exclude)]
            ]
        else:
            pks = self._pkcache
        try:
            return [self._idcache[pk] for pk in pks]
        except KeyError:
            # this can happen if the idmapper cache was cleared for an object
            # in the contents cache. If so we need to re-initialize and try again.
            self.init()
            try:
                return [self._idcache[pk] for pk in pks]
            except KeyError:
                # this means an actual failure of caching. Return real database match.
                logger.log_err("contents cache failed for %s." %
                               (self.obj.key))
                return list(ObjectDB.objects.filter(db_location=self.obj))
Exemple #10
0
def do_unpickle(data):
    """Retrieve pickle from pickled string"""
    try:
        return loads(to_bytes(data))
    except Exception:
        logger.log_err(f"Could not unpickle data from storage: {data}")
        raise
Exemple #11
0
def menu_quit(caller, menu):
    """
    Quit the menu, closing the CmdSet.

    Args:
        caller (Account or Object): the caller.
        menu (BuildingMenu): the building menu to close.

    Note:
        This callback is used by default when using the
        `BuildingMenu.add_choice_quit` method.  This method is called
        automatically if the menu has no parent.

    """
    if caller is None or menu is None:
        log_err(
            "The function `menu_quit` was called with missing "
            "arguments: caller={}, menu={}".format(caller, menu)
        )

    if caller.cmdset.has(BuildingMenuCmdSet):
        menu.close()
        caller.msg("Closing the building menu.")
    else:
        caller.msg("It looks like the building menu has already been closed.")
Exemple #12
0
 def _step_errback(self, e):
     """
     Override to keep the user from getting useless script error, plus grabs
     real traceback for the log.
     """
     estring = e.getTraceback()
     logger.log_err(estring)
Exemple #13
0
    def func(self):
        """Call the proper menu or redirect to nomatch."""
        raw_string = self.args.rstrip()
        if self.menu is None:
            log_err("When CMDNOMATCH was called, the building menu couldn't be found")
            self.caller.msg("|rThe building menu couldn't be found, remove the CmdSet.|n")
            self.caller.cmdset.delete(BuildingMenuCmdSet)
            return

        choice = self.menu.current_choice
        if raw_string in self.menu.keys_go_back:
            if self.menu.keys:
                self.menu.move(back=True)
            elif self.menu.parents:
                self.menu.open_parent_menu()
            else:
                self.menu.display()
        elif choice:
            if choice.nomatch(raw_string):
                self.caller.msg(choice.format_text())
        else:
            for choice in self.menu.relevant_choices:
                if choice.key.lower() == raw_string.lower() or any(raw_string.lower() == alias for alias in choice.aliases):
                    self.menu.move(choice.key)
                    return

            self.msg("|rUnknown command: {}|n.".format(raw_string))
Exemple #14
0
def create_player(playername, password, permissions=None, typeclass=None):
    """
    Helper function, creates a player of the specified typeclass.
    """
    if not permissions:
        permissions = settings.PERMISSION_ACCOUNT_DEFAULT

    new_player = create.create_account(playername,
                                       None,
                                       password,
                                       permissions=permissions,
                                       typeclass=typeclass)

    # This needs to be set so the engine knows this player is
    # logging in for the first time. (so it knows to call the right
    # hooks during login later)
    new_player.db.FIRST_LOGIN = True

    # join the new player to the public channel
    pchannel = ChannelDB.objects.get_channel(
        settings.DEFAULT_CHANNELS[0]["key"])
    if not pchannel.connect(new_player):
        string = "New player '%s' could not connect to public channel!" % new_player.key
        logger.log_err(string)

    return new_player
Exemple #15
0
def do_pickle(data):
    """Perform pickle to string"""
    try:
        return dumps(data, protocol=PICKLE_PROTOCOL)
    except Exception:
        logger.log_err(f"Could not pickle data for storage: {data}")
        raise
Exemple #16
0
    def get(self, exclude=None):
        """
        Return the contents of the cache.

        Args:
            exclude (Object or list of Object): object(s) to ignore

        Returns:
            objects (list): the Objects inside this location

        """
        if exclude:
            pks = [pk for pk in self._pkcache if pk not in [excl.pk for excl in make_iter(exclude)]]
        else:
            pks = self._pkcache
        try:
            return [self._idcache[pk] for pk in pks]
        except KeyError:
            # this can happen if the idmapper cache was cleared for an object
            # in the contents cache. If so we need to re-initialize and try again.
            self.init()
            try:
                return [self._idcache[pk] for pk in pks]
            except KeyError:
                # this means an actual failure of caching. Return real database match.
                logger.log_err("contents cache failed for %s." % (self.obj.key))
                return list(ObjectDB.objects.filter(db_location=self.obj))
    def finalize(self):
        super(MagicDamageConsequence, self).finalize()

        from typeclasses.scripts.combat import attacks, combat_settings

        victims = [participant.character for participant in self.participants]
        names = [obj.name for obj in victims]
        commafied_names = commafy(names)

        attack = attacks.Attack(targets=victims,
                                affect_real_dmg=True,
                                damage=self.damage,
                                use_mitigation=False,
                                can_kill=True,
                                private=False,
                                story="Magic has consequences!",
                                attack_tags=self.attack_tags)
        try:
            attack.execute()
        except combat_settings.CombatError as err:
            logger.log_err("Combat error when applying magical damage: " +
                           str(err))
            inform_staff(
                "|rCombat Error!|n Tried to apply %d damage to %s, but got error %s"
                % (self.damage, commafied_names, str(err)))
        else:
            part = "was"
            if len(victims) > 1:
                part = "were"
            inform_staff(
                "|y%s|n %s harmed for %d by a failed magical working." %
                (commafied_names, part, self.damage))
Exemple #18
0
    def func(self):
        "do action"
        caller = self.caller
        args = self.args

        if not caller.is_alive():
            caller.msg({"alert": _("You are died.")})
            return

        if not args:
            caller.msg({"alert": _("You should act to something.")})
            return

        # Use search to handle duplicate/nonexistant results.
        obj = caller.search_dbref(args, location=caller.location)
        if not obj:
            caller.msg({"alert": _("Can not find it.")})
            return

        try:
            obj.do_action(caller)
        except Exception, e:
            logger.log_err("Can not act to %s %s." %
                           (caller.get_data_key(), e))
            return
Exemple #19
0
def choose_current_weather():
    """
    Picks a new emit for the current weather conditions, and locks it in.
    :return: The emit to use.
    """

    weather_type = get_weather_type()
    weather_intensity = get_weather_intensity()

    emit = pick_emit(weather_type, intensity=weather_intensity)
    while not emit:
        # Just in case there's no available weather for a given
        # target intensity of during our current season/time;
        # we'll advance the weather until we do have something.
        season, time = gametime.get_time_and_season()
        logger.log_err(
            "Weather: No available weather for type {} intensity {} during {} {}".format(
                weather_type, weather_intensity, season, time
            )
        )
        weather_type, weather_intensity = advance_weather()
        emit = pick_emit(weather_type, intensity=weather_intensity)

    ServerConfig.objects.conf(key="weather_last_emit", value=emit)
    return emit
Exemple #20
0
    def create(cls, key, **kwargs):
        """
        Provides a passthrough interface to the utils.create_script() function.

        Args:
            key (str): Name of the new object.

        Returns:
            object (Object): A newly created object of the given typeclass.
            errors (list): A list of errors in string form, if any.

        """
        errors = []
        obj = None

        kwargs["key"] = key

        # If no typeclass supplied, use this class
        kwargs["typeclass"] = kwargs.pop("typeclass", cls)

        try:
            obj = create.create_script(**kwargs)
        except Exception as e:
            errors.append(
                "The script '%s' encountered errors and could not be created."
                % key)
            logger.log_err(e)

        return obj, errors
Exemple #21
0
    def get_objs_with_db_property_value(self, property_name, property_value, candidates=None, typeclasses=None):
        """
        Get objects with a specific field name and value.

        Args:
            property_name (str): Field name to search for.
            property_value (any): Value required for field with `property_name` to have.
            candidates (list, optional): List of objects to limit search to.
            typeclasses (list, optional): List of typeclass-path strings to restrict matches with

        """
        if isinstance(property_value, basestring):
            property_value = to_unicode(property_value)
        if isinstance(property_name, basestring):
            if not property_name.startswith('db_'):
                property_name = "db_%s" % property_name
        querykwargs = {property_name: property_value}
        cand_restriction = candidates is not None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates)
                                                                if obj]) or Q()
        type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
        try:
            return list(self.filter(cand_restriction & type_restriction & Q(**querykwargs)))
        except exceptions.FieldError:
            return []
        except ValueError:
            from evennia.utils import logger
            logger.log_err("The property '%s' does not support search criteria of the type %s." %
                           (property_name, type(property_value)))
            return []
Exemple #22
0
def menu_setattr(menu, choice, obj, string):
    """
    Set the value at the specified attribute.

    Args:
        menu (BuildingMenu): the menu object.
        choice (Chocie): the specific choice.
        obj (Object): the object to modify.
        string (str): the string with the new value.

    Note:
        This function is supposed to be used as a default to
        `BuildingMenu.add_choice`, when an attribute name is specified
        (in the `attr` argument) but no function `on_nomatch` is defined.

    """
    attr = getattr(choice, "attr", None) if choice else None
    if choice is None or string is None or attr is None or menu is None:
        log_err(dedent("""
                The `menu_setattr` function was called to set the attribute {} of object {} to {},
                but the choice {} of menu {} or another information is missing.
            """.format(attr, obj, repr(string), choice, menu)).strip("\n")).strip()
        return

    for part in attr.split(".")[:-1]:
        obj = getattr(obj, part)

    setattr(obj, attr.split(".")[-1], string)
    return True
Exemple #23
0
    def receive_pending_messenger(self):
        packed = self.get_packed_messenger()
        if not packed:
            return
        # get msg object and any delivered obj
        (
            msg,
            obj,
            money,
            mats,
            messenger_name,
            forwarded_by,
        ) = self.unpack_oldest_pending_messenger(packed)
        # adds it to our list of old messages
        if msg and hasattr(msg, "id") and msg.id:
            self.add_messenger_to_history(msg)
            self.display_messenger(msg)
        else:
            from evennia.utils.logger import log_err

            self.msg("Error: The msg object no longer exists.")
            log_err(
                "%s has tried to receive a messenger that no longer exists." %
                self.obj)
        self.notify_of_messenger_arrival(messenger_name)
        # handle anything delivered
        self.handle_delivery(obj, money, mats)
        if forwarded_by:
            self.msg("{yThis message was forwarded by {c%s{n." % forwarded_by)
Exemple #24
0
    def add(self, scriptclass, key=None, autostart=True):
        """
        Add a script to this object.

        Args:
            scriptclass (Scriptclass, Script or str): Either a class
                object inheriting from DefaultScript, an instantiated
                script object or a python path to such a class object.
            key (str, optional): Identifier for the script (often set
                in script definition and listings)
            autostart (bool, optional): Start the script upon adding it.

        """
        if self.obj.__dbclass__.__name__ == "AccountDB":
            # we add to an Account, not an Object
            script = create.create_script(scriptclass,
                                          key=key,
                                          account=self.obj,
                                          autostart=autostart)
        else:
            # the normal - adding to an Object
            script = create.create_script(scriptclass,
                                          key=key,
                                          obj=self.obj,
                                          autostart=autostart)
        if not script:
            logger.log_err("Script %s could not be created and/or started." %
                           scriptclass)
            return False
        return True
Exemple #25
0
    def get_objs_with_db_property_value(self, property_name, property_value, candidates=None, typeclasses=None):
        """
        Get objects with a specific field name and value.

        Args:
            property_name (str): Field name to search for.
            property_value (any): Value required for field with `property_name` to have.
            candidates (list, optional): List of objects to limit search to.
            typeclasses (list, optional): List of typeclass-path strings to restrict matches with

        """
        if isinstance(property_value, basestring):
            property_value = to_unicode(property_value)
        if isinstance(property_name, basestring):
            if not property_name.startswith('db_'):
                property_name = "db_%s" % property_name
        querykwargs = {property_name:property_value}
        cand_restriction = candidates != None and Q(pk__in=[_GA(obj, "id") for obj in make_iter(candidates) if obj]) or Q()
        type_restriction = typeclasses and Q(db_typeclass_path__in=make_iter(typeclasses)) or Q()
        try:
            return list(self.filter(cand_restriction & type_restriction & Q(**querykwargs)))
        except exceptions.FieldError:
            return []
        except ValueError:
            from evennia.utils import logger
            logger.log_err("The property '%s' does not support search criteria of the type %s." % (property_name, type(property_value)))
            return []
Exemple #26
0
    def add(self, scriptclass, key=None, autostart=True):
        """
        Add a script to this object.

        Args:
            scriptclass (Scriptclass, Script or str): Either a class
                object inheriting from DefaultScript, an instantiated
                script object or a python path to such a class object.
            key (str, optional): Identifier for the script (often set
                in script definition and listings)
            autostart (bool, optional): Start the script upon adding it.

        """
        if self.obj.__dbclass__.__name__ == "PlayerDB":
            # we add to a Player, not an Object
            script = create.create_script(scriptclass, key=key, player=self.obj,
                                          autostart=autostart)
        else:
            # the normal - adding to an Object
            script = create.create_script(scriptclass, key=key, obj=self.obj,
                                      autostart=autostart)
        if not script:
            logger.log_err("Script %s could not be created and/or started." % scriptclass)
            return False
        return True
Exemple #27
0
    def data_in(self, data, **kwargs):
        """
        Send data grapevine -> Evennia

        Keyword Args:
            data (dict): Converted json data.

        """
        event = data["event"]
        if event == "authenticate":
            # server replies to our auth handshake
            if data["status"] != "success":
                log_err("Grapevine authentication failed.")
                self.disconnect()
            else:
                log_info("Connected and authenticated to Grapevine network.")
        elif event == "heartbeat":
            # server sends heartbeat - we have to send one back
            self.send_heartbeat()
        elif event == "restart":
            # set the expected downtime
            self.restart_downtime = data["payload"]["downtime"]
        elif event == "channels/subscribe":
            # subscription verification
            if data.get("status", "success") == "failure":
                err = data.get("error", "N/A")
                self.sessionhandler.data_in(
                    bot_data_in=((f"Grapevine error: {err}"), {
                        "event": event
                    }))
        elif event == "channels/unsubscribe":
            # unsubscribe-verification
            pass
        elif event == "channels/broadcast":
            # incoming broadcast from network
            payload = data["payload"]

            print("channels/broadcast:", payload["channel"], self.channel)
            if str(payload["channel"]) != self.channel:
                # only echo from channels this particular bot actually listens to
                return
            else:
                # correct channel
                self.sessionhandler.data_in(
                    self,
                    bot_data_in=(
                        str(payload["message"]),
                        {
                            "event": event,
                            "grapevine_channel": str(payload["channel"]),
                            "sender": str(payload["name"]),
                            "game": str(payload["game"]),
                        },
                    ),
                )
        elif event == "channels/send":
            pass
        else:
            self.sessionhandler.data_in(self, bot_data_in=("", kwargs))
Exemple #28
0
    def after_data_loaded(self):
        """
        Load goods data.

        Returns:
            None
        """
        self.available = False

        self.shop_key = getattr(self.system, "shop", "")
        self.goods_key = getattr(self.system, "goods", "")
        self.goods_level = getattr(self.system, "level", 0)

        if not self.shop_key or not self.goods_key:
            if self.db.goods:
                self.db.goods.delete()
                self.db.goods = None
            return

        # set goods information
        self.price = getattr(self.system, "price", 0)
        self.unit_key = getattr(self.system, "unit", "")
        self.number = getattr(self.system, "number", 0)
        self.condition = getattr(self.system, "condition", "")

        # get price unit information
        unit_record = get_object_record(self.unit_key)
        if not unit_record:
            logger.log_errmsg("Can not find %s price unit %s." %
                              (self.goods_key, self.unit_key))
            return
        self.unit_name = unit_record.name

        # load goods object
        goods = self.db.goods
        if goods:
            if goods.get_data_key() == self.goods_key:
                # Load data.
                try:
                    # Load db data.
                    goods.load_data()
                except Exception as e:
                    logger.log_errmsg("%s(%s) can not load data:%s" %
                                      (self.goods_key, self.dbref, e))
            else:
                goods.set_data_key(self.goods_key, self.goods_level)
        else:
            goods = build_object(self.goods_key)
            if goods:
                self.db.goods = goods
            else:
                logger.log_err("Can not create goods %s." % self.goods_key)
                return

        self.name = goods.get_name()
        self.desc = goods.db.desc
        self.icon = getattr(goods, "icon", None)

        self.available = True
Exemple #29
0
 def _save_tree(self):
     "recursively traverse back up the tree, save when we reach the root"
     if self._parent:
         self._parent._save_tree()
     elif self._db_obj:
         self._db_obj.value = self
     else:
         logger.log_err("_SaverMutable %s has no root Attribute to save to." % self)
Exemple #30
0
 def func(self):
     """Display the menu or choice text."""
     if self.menu:
         self.menu.display()
     else:
         log_err("When CMDNOINPUT was called, the building menu couldn't be found")
         self.caller.msg("|rThe building menu couldn't be found, remove the CmdSet.|n")
         self.caller.cmdset.delete(BuildingMenuCmdSet)
Exemple #31
0
 def __value_set(self, value):
     "Setter. Allows for self.value = value"
     if utils.has_parent('django.db.models.base.Model', value):
         # we have to protect against storing db objects.
         logger.log_err("ServerConfig cannot store db objects! (%s)" % value)
         return
     self.db_value = pickle.dumps(value)
     self.save()
Exemple #32
0
 def func(self):
     """Display the menu or choice text."""
     if self.menu:
         self.menu.display()
     else:
         log_err("When CMDNOINPUT was called, the building menu couldn't be found")
         self.caller.msg("|rThe building menu couldn't be found, remove the CmdSet.|n")
         self.caller.cmdset.delete(BuildingMenuCmdSet)
Exemple #33
0
 def _save_tree(self):
     """recursively traverse back up the tree, save when we reach the root"""
     if self._parent:
         self._parent._save_tree()
     elif self._db_obj:
         self._db_obj.value = self
     else:
         logger.log_err("_SaverMutable %s has no root Attribute to save to." % self)
Exemple #34
0
 def __value_set(self, value):
     "Setter. Allows for self.value = value"
     if utils.has_parent('django.db.models.base.Model', value):
         # we have to protect against storing db objects.
         logger.log_err("ServerConfig cannot store db objects! (%s)" % value)
         return
     self.db_value = pickle.dumps(value)
     self.save()
Exemple #35
0
    def remove_object(self, obj_key, number, mute=False):
        """
        Remove objects from the inventory.

        Args:
            obj_key: object's key
            number: object's number
            mute: send inventory information

        Returns:
            boolean: success
        """
        objects = self.search_inventory(obj_key)

        # get total number
        sum = 0
        for obj in objects:
            obj_num = obj.get_number()
            sum += obj_num

        if sum < number:
            return False

        # remove objects
        to_remove = number
        try:
            for obj in objects:
                obj_num = obj.get_number()
                if obj_num > 0:
                    if obj_num >= to_remove:
                        obj.decrease_num(to_remove)
                        to_remove = 0
                    else:
                        obj.decrease_num(obj_num)
                        to_remove -= obj_num

                    if obj.get_number() <= 0:
                        # If this object can be removed from the inventor.
                        if obj.can_remove:
                            # if it is an equipment, take off it first
                            if getattr(obj, "equipped", False):
                                self.take_off_equipment(obj)
                            obj.delete()

                if to_remove <= 0:
                    break
        except Exception as e:
            logger.log_tracemsg("Can not remove object %s: %s" % (obj_key, e))
            return False

        if to_remove > 0:
            logger.log_err("Remove object error: %s" % obj_key)
            return False

        if not mute:
            self.show_inventory()

        return True
    def restore(self, server_reload=True):
        """
        Restore ticker_storage from database and re-initialize the
        handler from storage. This is triggered by the server at
        restart.

        Args:
            server_reload (bool, optional): If this is False, it means
                the server went through a cold reboot and all
                non-persistent tickers must be killed.

        """
        # load stored command instructions and use them to re-initialize handler
        restored_tickers = ServerConfig.objects.conf(key=self.save_name)
        if restored_tickers:
            # the dbunserialize will convert all serialized dbobjs to real objects

            restored_tickers = dbunserialize(restored_tickers)
            self.ticker_storage = {}
            for store_key, (args, kwargs) in restored_tickers.iteritems():
                try:
                    # at this point obj is the actual object (or None) due to how
                    # the dbunserialize works
                    obj, callfunc, path, interval, idstring, persistent = store_key
                    if not persistent and not server_reload:
                        # this ticker will not be restarted
                        continue
                    if isinstance(callfunc, basestring) and not obj:
                        # methods must have an existing object
                        continue
                    # we must rebuild the store_key here since obj must not be
                    # stored as the object itself for the store_key to be hashable.
                    store_key = self._store_key(obj, path, interval, callfunc,
                                                idstring, persistent)

                    if obj and callfunc:
                        kwargs["_callback"] = callfunc
                        kwargs["_obj"] = obj
                    elif path:
                        modname, varname = path.rsplit(".", 1)
                        callback = variable_from_module(modname, varname)
                        kwargs["_callback"] = callback
                        kwargs["_obj"] = None
                    else:
                        # Neither object nor path - discard this ticker
                        log_err(
                            "Tickerhandler: Removing malformed ticker: %s" %
                            str(store_key))
                        continue
                except Exception:
                    # this suggests a malformed save or missing objects
                    log_trace("Tickerhandler: Removing malformed ticker: %s" %
                              str(store_key))
                    continue
                # if we get here we should create a new ticker
                self.ticker_storage[store_key] = (args, kwargs)
                self.ticker_pool.add(store_key, *args, **kwargs)
Exemple #37
0
    def add(self, timedelay, callback, *args, **kwargs):
        """Add a new persistent task in the configuration.

        Args:
            timedelay (int or float): time in sedconds before calling the callback.
            callback (function or instance method): the callback itself
            any (any): any additional positional arguments to send to the callback

        Keyword Args:
            persistent (bool, optional): persist the task (store it).
            any (any): additional keyword arguments to send to the callback

        """
        persistent = kwargs.get("persistent", False)
        if persistent:
            del kwargs["persistent"]
            now = datetime.now()
            delta = timedelta(seconds=timedelay)

            # Choose a free task_id
            safe_args = []
            safe_kwargs = {}
            used_ids = list(self.tasks.keys())
            task_id = 1
            while task_id in used_ids:
                task_id += 1

            # Check that args and kwargs contain picklable information
            for arg in args:
                try:
                    dbserialize(arg)
                except (TypeError, AttributeError):
                    log_err("The positional argument {} cannot be "
                            "pickled and will not be present in the arguments "
                            "fed to the callback {}".format(arg, callback))
                else:
                    safe_args.append(arg)

            for key, value in kwargs.items():
                try:
                    dbserialize(value)
                except (TypeError, AttributeError):
                    log_err("The {} keyword argument {} cannot be "
                            "pickled and will not be present in the arguments "
                            "fed to the callback {}".format(
                                key, value, callback))
                else:
                    safe_kwargs[key] = value

            self.tasks[task_id] = (now + delta, callback, safe_args,
                                   safe_kwargs)
            self.save()
            callback = self.do_task
            args = [task_id]
            kwargs = {}

        return deferLater(reactor, timedelay, callback, *args, **kwargs)
Exemple #38
0
    def start(self):
        "Connect protocol to remote server"

        try:
            from twisted.internet import ssl
        except ImportError:
            log_err("To use Grapevine, The PyOpenSSL module must be installed.")
        else:
            context_factory = ssl.ClientContextFactory() if self.isSecure else None
            connectWS(self, context_factory)
Exemple #39
0
    def add(self, timedelay, callback, *args, **kwargs):
        """Add a new persistent task in the configuration.

        Args:
            timedelay (int or float): time in sedconds before calling the callback.
            callback (function or instance method): the callback itself
            any (any): any additional positional arguments to send to the callback

        Kwargs:
            persistent (bool, optional): persist the task (store it).
            any (any): additional keyword arguments to send to the callback

        """
        persistent = kwargs.get("persistent", False)
        if persistent:
            del kwargs["persistent"]
            now = datetime.now()
            delta = timedelta(seconds=timedelay)

            # Choose a free task_id
            safe_args = []
            safe_kwargs = {}
            used_ids = self.tasks.keys()
            task_id = 1
            while task_id in used_ids:
                task_id += 1

            # Check that args and kwargs contain picklable information
            for arg in args:
                try:
                    dbserialize(arg)
                except (TypeError, AttributeError):
                    log_err("The positional argument {} cannot be "
                            "pickled and will not be present in the arguments "
                            "fed to the callback {}".format(arg, callback))
                else:
                    safe_args.append(arg)

            for key, value in kwargs.items():
                try:
                    dbserialize(value)
                except (TypeError, AttributeError):
                    log_err("The {} keyword argument {} cannot be "
                            "pickled and will not be present in the arguments "
                            "fed to the callback {}".format(key, value, callback))
                else:
                    safe_kwargs[key] = value

            self.tasks[task_id] = (now + delta, callback, safe_args, safe_kwargs)
            self.save()
            callback = self.do_task
            args = [task_id]
            kwargs = {}

        return deferLater(reactor, timedelay, callback, *args, **kwargs)
Exemple #40
0
    def update(self, init_mode=False):
        """
        Re-adds all sets in the handler to have an updated current
        set.

        Args:
            init_mode (bool, optional): Used automatically right after
                this handler was created; it imports all permanent cmdsets
                from the database.
        """
        if init_mode:
            # reimport all permanent cmdsets
            storage = self.obj.cmdset_storage
            if storage:
                self.cmdset_stack = []
                for pos, path in enumerate(storage):
                    if pos == 0 and not path:
                        self.cmdset_stack = [_EmptyCmdSet(cmdsetobj=self.obj)]
                    elif path:
                        cmdset = self._import_cmdset(path)
                        if cmdset:
                            if cmdset.key == "_CMDSET_ERROR":
                                # If a cmdset fails to load, check if we have a fallback path to use
                                fallback_path = _CMDSET_FALLBACKS.get(path, None)
                                if fallback_path:
                                    err = _ERROR_CMDSET_FALLBACK.format(
                                        path=path, fallback_path=fallback_path
                                    )
                                    logger.log_err(err)
                                    if _IN_GAME_ERRORS:
                                        self.obj.msg(err)
                                    cmdset = self._import_cmdset(fallback_path)
                                # If no cmdset is returned from the fallback, we can't go further
                                if not cmdset:
                                    err = _ERROR_CMDSET_NO_FALLBACK.format(
                                        fallback_path=fallback_path
                                    )
                                    logger.log_err(err)
                                    if _IN_GAME_ERRORS:
                                        self.obj.msg(err)
                                    continue
                            cmdset.permanent = cmdset.key != "_CMDSET_ERROR"
                            self.cmdset_stack.append(cmdset)

        # merge the stack into a new merged cmdset
        new_current = None
        self.mergetype_stack = []
        for cmdset in self.cmdset_stack:
            try:
                # for cmdset's '+' operator, order matters.
                new_current = cmdset + new_current
            except TypeError:
                continue
            self.mergetype_stack.append(new_current.actual_mergetype)
        self.current = new_current
Exemple #41
0
    def infuse_primum(self, amount):
        if self.practitioner or self.is_typeclass('typeclasses.characters.Character'):
            logger.log_err("Tried to infuse a Character with primum as though it were an Object!  Not good.")
            raise ValueError

        self.db.primum = min(self.primum + amount, self.max_potential)
        if self.db.primum > self.potential:
            self.db.potential = self.db.primum

        if self.db.quality_level:
            self.db.quality_level = self.quality_level_from_primum(self.db.primum)
Exemple #42
0
    def add(self, store_key, obj, interval, *args, **kwargs):
        """
        Add new ticker subscriber
        """
        if not interval:
            log_err(_ERROR_ADD_INTERVAL.format(store_key=store_key, obj=obj,
                                       interval=interval, args=args, kwargs=kwargs))
            return

        if interval not in self.tickers:
            self.tickers[interval] = self.ticker_class(interval)
        self.tickers[interval].add(store_key, obj, *args, **kwargs)
Exemple #43
0
    def restore(self, server_reload=True):
        """
        Restore ticker_storage from database and re-initialize the
        handler from storage. This is triggered by the server at
        restart.

        Args:
            server_reload (bool, optional): If this is False, it means
                the server went through a cold reboot and all
                non-persistent tickers must be killed.

        """
        # load stored command instructions and use them to re-initialize handler
        restored_tickers = ServerConfig.objects.conf(key=self.save_name)
        if restored_tickers:
            # the dbunserialize will convert all serialized dbobjs to real objects

            restored_tickers = dbunserialize(restored_tickers)
            self.ticker_storage = {}
            for store_key, (args, kwargs) in restored_tickers.iteritems():
                try:
                    # at this point obj is the actual object (or None) due to how
                    # the dbunserialize works
                    obj, callfunc, path, interval, idstring, persistent = store_key
                    if not persistent and not server_reload:
                        # this ticker will not be restarted
                        continue
                    if isinstance(callfunc, basestring) and not obj:
                        # methods must have an existing object
                        continue
                    # we must rebuild the store_key here since obj must not be
                    # stored as the object itself for the store_key to be hashable.
                    store_key = self._store_key(obj, path, interval, callfunc, idstring, persistent)

                    if obj and callfunc:
                        kwargs["_callback"] = callfunc
                        kwargs["_obj"] = obj
                    elif path:
                        modname, varname = path.rsplit(".", 1)
                        callback = variable_from_module(modname, varname)
                        kwargs["_callback"] = callback
                        kwargs["_obj"] = None
                    else:
                        # Neither object nor path - discard this ticker
                        log_err("Tickerhandler: Removing malformed ticker: %s" % str(store_key))
                        continue
                except Exception:
                    # this suggests a malformed save or missing objects
                    log_trace("Tickerhandler: Removing malformed ticker: %s" % str(store_key))
                    continue
                # if we get here we should create a new ticker
                self.ticker_storage[store_key] = (args, kwargs)
                self.ticker_pool.add(store_key, *args, **kwargs)
Exemple #44
0
def _cache_lockfuncs():
    """
    Updates the cache.
    """
    global _LOCKFUNCS
    _LOCKFUNCS = {}
    for modulepath in settings.LOCK_FUNC_MODULES:
        mod = utils.mod_import(modulepath)
        if mod:
            for tup in (tup for tup in inspect.getmembers(mod) if callable(tup[1])):
                _LOCKFUNCS[tup[0]] = tup[1]
        else:
            logger.log_err("Couldn't load %s from PERMISSION_FUNC_MODULES." % modulepath)
Exemple #45
0
    def errback(self, e, info):
        """
        Error callback.
        Handles errors to avoid dropping connections on server tracebacks.

        Args:
            e (Failure): Deferred error instance.
            info (str): Error string.

        """
        e.trap(Exception)
        logger.log_err("AMP Error for %(info)s: %(e)s" % {'info': info,
                                                          'e': e.getErrorMessage()})
Exemple #46
0
    def update(self, init_mode=False):
        """
        Re-adds all sets in the handler to have an updated current
        set.

        Args:
            init_mode (bool, optional): Used automatically right after
                this handler was created; it imports all permanent cmdsets
                from the database.
        """
        if init_mode:
            # reimport all permanent cmdsets
            storage = self.obj.cmdset_storage
            if storage:
                self.cmdset_stack = []
                for pos, path in enumerate(storage):
                    if pos == 0 and not path:
                        self.cmdset_stack = [_EmptyCmdSet(cmdsetobj=self.obj)]
                    elif path:
                        cmdset = self._import_cmdset(path)
                        if cmdset:
                            if cmdset.key == '_CMDSET_ERROR':
                                # If a cmdset fails to load, check if we have a fallback path to use
                                fallback_path = _CMDSET_FALLBACKS.get(path, None)
                                if fallback_path:
                                    err = _ERROR_CMDSET_FALLBACK.format(path=path, fallback_path=fallback_path)
                                    logger.log_err(err)
                                    if _IN_GAME_ERRORS:
                                        self.obj.msg(err)
                                    cmdset = self._import_cmdset(fallback_path)
                                # If no cmdset is returned from the fallback, we can't go further
                                if not cmdset:
                                    err = _ERROR_CMDSET_NO_FALLBACK.format(fallback_path=fallback_path)
                                    logger.log_err(err)
                                    if _IN_GAME_ERRORS:
                                        self.obj.msg(err)
                                    continue
                            cmdset.permanent = cmdset.key != '_CMDSET_ERROR'
                            self.cmdset_stack.append(cmdset)

        # merge the stack into a new merged cmdset
        new_current = None
        self.mergetype_stack = []
        for cmdset in self.cmdset_stack:
            try:
                # for cmdset's '+' operator, order matters.
                new_current = cmdset + new_current
            except TypeError:
                continue
            self.mergetype_stack.append(new_current.actual_mergetype)
        self.current = new_current
Exemple #47
0
    def after_data_loaded(self):
        """
        Load goods data.

        Returns:
            None
        """
        self.available = False

        self.shop_key = getattr(self.dfield, "shop", "")
        self.goods_key = getattr(self.dfield, "goods", "")

        if not self.shop_key or not self.goods_key:
            if self.db.goods:
                self.db.goods.delete()
                self.db.goods = None
            return

        # set goods information
        self.price = getattr(self.dfield, "price", 0)
        self.unit_key = getattr(self.dfield, "unit", "")
        self.number = getattr(self.dfield, "number", 0)
        self.condition = getattr(self.dfield, "condition", "")

        # get price unit information
        unit_record = get_object_record(self.unit_key)
        if not unit_record:
            logger.log_errmsg("Can not find %s price unit %s." % (self.goods_key, self.unit_key))
            return
        self.unit_name = unit_record.name

        # load goods object
        goods = self.db.goods
        if goods:
            if goods.get_data_key() == self.goods_key:
                goods.load_data()
            else:
                goods.set_data_key(self.goods_key)
        else:
            goods = build_object(self.goods_key)
            if goods:
                self.db.goods = goods
            else:
                logger.log_err("Can not create goods %s." % self.goods_key)
                return

        self.name = goods.get_name()
        self.desc = goods.db.desc
        self.icon = getattr(goods, "icon", None)

        self.available = True
Exemple #48
0
def default(session, cmdname, *args, **kwargs):
    """
    Default catch-function. This is like all other input functions except
    it will get `cmdname` as the first argument.

    """
    err = (
        "Session {sessid}: Input command not recognized:\n"
        " name: '{cmdname}'\n"
        " args, kwargs: {args}, {kwargs}".format(sessid=session.sessid, cmdname=cmdname, args=args, kwargs=kwargs)
    )
    if session.protocol_flags.get("INPUTDEBUG", False):
        session.msg(err)
    log_err(err)
Exemple #49
0
    def _step_errback(self, e):
        """
        Callback for runner errors

        """
        cname = self.__class__.__name__
        estring = _("Script %(key)s(#%(dbid)s) of type '%(cname)s': at_repeat() error '%(err)s'.") % \
                          {"key": self.key, "dbid": self.dbid, "cname": cname,
                           "err": e.getErrorMessage()}
        try:
            self.db_obj.msg(estring)
        except Exception:
            pass
        logger.log_err(estring)
Exemple #50
0
    def start(self):
        """
        Connect session to sessionhandler.

        """
        if self.port:
            if self.ssl:
                try:
                    from twisted.internet import ssl
                    service = reactor.connectSSL(self.network, int(self.port), self, ssl.ClientContextFactory())
                except ImportError:
                    logger.log_err("To use SSL, the PyOpenSSL module must be installed.")
            else:
                service = internet.TCPClient(self.network, int(self.port), self)
            self.sessionhandler.portal.services.addService(service)
Exemple #51
0
    def errback(self, e, info):
        """
        Error callback.
        Handles errors to avoid dropping connections on server tracebacks.

        Args:
            e (Failure): Deferred error instance.
            info (str): Error string.

        """
        global _LOGGER
        if not _LOGGER:
            from evennia.utils import logger as _LOGGER
        e.trap(Exception)
        _LOGGER.log_err("AMP Error for %(info)s: %(e)s" % {'info': info,
                                                           'e': e.getErrorMessage()})
Exemple #52
0
 def _save_tree(self):
     """recursively traverse back up the tree, save when we reach the root"""
     if self._parent:
         self._parent._save_tree()
     elif self._db_obj:
         if not self._db_obj.pk:
             cls_name = self.__class__.__name__
             try:
                 non_saver_name = cls_name.split("_Saver", 1)[1].lower()
             except IndexError:
                 non_saver_name = cls_name
             raise ValueError(_ERROR_DELETED_ATTR.format(cls_name=cls_name, obj=self,
                                                         non_saver_name=non_saver_name))
         self._db_obj.value = self
     else:
         logger.log_err("_SaverMutable %s has no root Attribute to save to." % self)
Exemple #53
0
    def data_out(self, **kwargs):
        """
        Generic hook for sending data out through the protocol.

        Kwargs:
            kwargs (any): Other data to the protocol.

        """
        if AUDIT_CALLBACK and AUDIT_OUT:
            try:
                log = self.audit(src='server', **kwargs)
                if log:
                    AUDIT_CALLBACK(log)
            except Exception as e:
                logger.log_err(e)

        super(AuditedServerSession, self).data_out(**kwargs)
Exemple #54
0
    def data_in(self, **kwargs):
        """
        Hook for protocols to send incoming data to the engine.

        Kwargs:
            kwargs (any): Other data from the protocol.

        """
        if AUDIT_CALLBACK and AUDIT_IN:
            try:
                log = self.audit(src='client', **kwargs)
                if log:
                    AUDIT_CALLBACK(log)
            except Exception as e:
                logger.log_err(e)

        super(AuditedServerSession, self).data_in(**kwargs)
Exemple #55
0
    def add(self, store_key, *args, **kwargs):
        """
        Add new ticker subscriber.

        Args:
            store_key (str): Unique storage hash.
            args (any, optional): Arguments to send to the hook method.

        """
        _, _, _, interval, _, _ = store_key
        if not interval:
            log_err(_ERROR_ADD_TICKER.format(store_key=store_key))
            return

        if interval not in self.tickers:
            self.tickers[interval] = self.ticker_class(interval)
        self.tickers[interval].add(store_key, *args, **kwargs)
Exemple #56
0
def check_evennia_dependencies():
    """
    Checks the versions of Evennia's dependencies including making
    some checks for runtime libraries.

    Returns:
        result (bool): `False` if a show-stopping version mismatch is
            found.

    """

    # check main dependencies
    from evennia.server.evennia_launcher import check_main_evennia_dependencies

    not_error = check_main_evennia_dependencies()

    errstring = ""
    # South is no longer used ...
    if "south" in settings.INSTALLED_APPS:
        errstring += (
            "\n ERROR: 'south' found in settings.INSTALLED_APPS. "
            "\n   South is no longer used. If this was added manually, remove it."
        )
        not_error = False
    # IRC support
    if settings.IRC_ENABLED:
        try:
            import twisted.words

            twisted.words  # set to avoid debug info about not-used import
        except ImportError:
            errstring += (
                "\n ERROR: IRC is enabled, but twisted.words is not installed. Please install it."
                "\n   Linux Debian/Ubuntu users should install package 'python-twisted-words', others"
                "\n   can get it from http://twistedmatrix.com/trac/wiki/TwistedWords."
            )
            not_error = False
    errstring = errstring.strip()
    if errstring:
        mlen = max(len(line) for line in errstring.split("\n"))
        logger.log_err("%s\n%s\n%s" % ("-" * mlen, errstring, "-" * mlen))
    return not_error
Exemple #57
0
    def mask(self, msg):
        """
        Masks potentially sensitive user information within messages before
        writing to log. Recording cleartext password attempts is bad policy.

        Args:
            msg (str): Raw text string sent from client <-> server

        Returns:
            msg (str): Text string with sensitive information masked out.

        """
        # Check to see if the command is embedded within server output
        _msg = msg
        is_embedded = False
        match = re.match(".*Command.*'(.+)'.*is not available.*", msg, flags=re.IGNORECASE)
        if match:
            msg = match.group(1).replace('\\', '')
            submsg = msg
            is_embedded = True

        for mask in AUDIT_MASKS:
            for command, regex in mask.iteritems():
                try:
                    match = re.match(regex, msg, flags=re.IGNORECASE)
                except Exception as e:
                    logger.log_err(regex)
                    logger.log_err(e)
                    continue

                if match:
                    term = match.group('secret')
                    masked = re.sub(term, '*' * len(term.zfill(8)), msg)

                    if is_embedded:
                        msg = re.sub(submsg, '%s <Masked: %s>' % (masked, command), _msg, flags=re.IGNORECASE)
                    else:
                        msg = masked

                    return msg

        return _msg
Exemple #58
0
    def func(self):
        "Buy a goods."
        caller = self.caller

        if not self.args:
            caller.msg({"alert":_("You should buy something.")})
            return

        goods = caller.search(self.args)
        if not goods:
            caller.msg({"alert":_("Can not find this goods.")})
            return

        # buy goods
        try:
            goods.sell_to(caller)
        except Exception, e:
            caller.msg({"alert":_("Can not buy this goods.")})
            logger.log_err("Can not buy %s: %s" % (goods.get_data_key(), e))
            return
Exemple #59
0
def create_help_entry(key, entrytext, category="General", locks=None, aliases=None):
    """
    Create a static help entry in the help database. Note that Command
    help entries are dynamic and directly taken from the __doc__
    entries of the command. The database-stored help entries are
    intended for more general help on the game, more extensive info,
    in-game setting information and so on.

    Args:
        key (str): The name of the help entry.
        entrytext (str): The body of te help entry
        category (str, optional): The help category of the entry.
        locks (str, optional): A lockstring to restrict access.
        aliases (list of str): List of alternative (likely shorter) keynames.

    Returns:
        help (HelpEntry): A newly created help entry.

    """
    global _HelpEntry
    if not _HelpEntry:
        from evennia.help.models import HelpEntry as _HelpEntry

    try:
        new_help = _HelpEntry()
        new_help.key = key
        new_help.entrytext = entrytext
        new_help.help_category = category
        if locks:
            new_help.locks.add(locks)
        if aliases:
            new_help.aliases.add(aliases)
        new_help.save()
        return new_help
    except IntegrityError:
        string = "Could not add help entry: key '%s' already exists." % key
        logger.log_err(string)
        return None
    except Exception:
        logger.log_trace()
        return None